1
votes

I've been wracking my brain for weeks on this. I'm having trouble getting a custom password reset that has the user reset their password inside the app.

So far I'm able to do the following:

  1. Send the password reset email.
  2. When the user clicks the link, open the app if it's installed and direct them to the proper Activity.
  3. Confirm that my Dynamic Link will redirect to my website when put in a browser.
  4. Confirm that my Dynamic Link will redirect user to proper Activity when tested inside Android Studio (and return the deep link data).

The following are the issues that I'm running into:

  1. Clicking on the link in the password reset email on a desktop computer does NOT redirect me, but rather returns a web page error (error code 400).
  2. Clicking on the link in the password reset email in a phone takes me to the proper screen in the App but does NOT return any data, just null.
  3. If I click the link on a Nexus 6 (emulator or real phone) the redirect works, but if I click the link on a Nexus 5x (emulator) the redirect takes me to my login screen but not the correct Activity (No intent-filter is set for the login screen). All of these devices are running the same API (API 25).

I must be missing something, but I'm not sure what it could be. Here's my setup:

My detail link page in the Firebase Console (sensitive info redacted): enter image description here

The following code is the actionCodeSettings and password reset email code (sensitive stuff redacted):

String url = "https://xxxxx.com";
ActionCodeSettings settings = ActionCodeSettings.newBuilder()
        .setAndroidPackageName(
                getPackageName(),
                true, /* install if not available? */
                null   /* minimum app version */)
        .setHandleCodeInApp(true)
        .setUrl(url)
        .build();

mAuth.sendPasswordResetEmail(email, settings)
        .addOnCompleteListener(new OnCompleteListener<Void>() {
            @Override
            public void onComplete(@NonNull Task<Void> task) {
                if (task.isSuccessful()) {
                    Log.d(TAG, "Email sent.");
                    hideProgressDialog();
                    Toast.makeText(ForgotPasswordActivity.this, getString(R.string.alert_passwordResetConfirm),
                            Toast.LENGTH_SHORT).show();
                }
                else {
                    Exception e = task.getException();
                    Log.w(TAG, "passwordResetRequest:failure " + e.getMessage(), task.getException());
                    hideProgressDialog();
                    Toast.makeText(ForgotPasswordActivity.this, e.getMessage(),
                            Toast.LENGTH_SHORT).show();

                    if (e instanceof FirebaseAuthInvalidCredentialsException) {
                        emailText.setError(getString(R.string.validate_email));
                    }
                }
            }
        });

Android manifest xml stuff:

<intent-filter>
        <action android:name="android.intent.action.VIEW"/>
        <category android:name="android.intent.category.DEFAULT"/>
        <category android:name="android.intent.category.BROWSABLE"/>
        <data android:host="xxxxx.app.goo.gl" android:scheme="http"/>
        <data android:host="xxxxx.app.goo.gl" android:scheme="https"/>
    </intent-filter>

Code that grabs the deep link data when user returns to app:

FirebaseDynamicLinks.getInstance()
        .getDynamicLink(getIntent())
        .addOnSuccessListener(this, new OnSuccessListener<PendingDynamicLinkData>() {
            @Override
            public void onSuccess(PendingDynamicLinkData pendingDynamicLinkData) {
                // Get deep link from result (may be null if no link is found)
                Uri deepLink = null;
                if (pendingDynamicLinkData != null) {
                    deepLink = pendingDynamicLinkData.getLink();
                }


                if (deepLink != null) {
                    Log.d(TAG, "Received Deep Link Data: " + deepLink.toString());
                }
                else {
                    Log.d(TAG, "Received Deep Link Data: " + null);
                }
                // Handle the deep link. For example, open the linked
                // content, or apply promotional credit to the user's
                // account.
                // ...

                // ...
            }
        })
        .addOnFailureListener(this, new OnFailureListener() {
            @Override
            public void onFailure(@NonNull Exception e) {
                Log.w(TAG, "getDynamicLink:onFailure", e);
            }
        });

Finally, an example URL that the user would receive in their email:

https://xxxxx.app.goo.gl?link=https://xxxxx-00000.firebaseapp.com/__/auth/action?apiKey%<api key redacted>%26mode%3DresetPassword%26oobCode%3D<reset code redacted>%26continueUrl%3Dhttps://xxxxx.app.goo.gl/pass%26lang%3Den&apn=com.xxxxx.android

Any help would be greatly appreciated.

P.S. There is some mention in the docs that to get the deep data in the app we have call: FirebaseDynamicLinks.getDynamicLink() in the launcher activity as well as the deep link activity. I tried that as well...still got null data.

Additional Note: if I put the following in the activity that is opened by the deep link:

Intent intent = getIntent();
    String action = intent.getAction();
    Uri data = intent.getData();

    Log.d(TAG, "Data Data?: " + data.toString());

I get the full path that the user clicked to bring them to the app.

Thanks in advance for any help!

2

2 Answers

1
votes

I didn't deep dive in your answer but i noticed a red flag as you are setting an FDL link as your deep link "https://xxxxx.app.goo.gl/pass"

// I speculate this is the root cause. You are ending up with a double
// dynamic link. Change this to a webpage you own.
String url = "https://xxxxx.app.goo.gl/pass";
ActionCodeSettings settings = ActionCodeSettings.newBuilder()
    .setAndroidPackageName(
            getPackageName(),
            true, /* install if not available? */
            null   /* minimum app version */)
    .setHandleCodeInApp(true)
    .setUrl(url)
    .build();
0
votes

you have to create a custom action link from your server or it can be from a firebase cloud function. when you generate your action link you can add the domani of your dynamic link , so firebase will send you the action link based in your domain of dynamic link then it will be easier to retrive the params from the URL in your code.

https://firebase.google.com/docs/auth/admin/email-action-links