EddyVerbruggen / nativescript-plugin-firebase

:fire: NativeScript plugin for Firebase
https://firebase.google.com
MIT License
1.01k stars 444 forks source link

Dynamic Links and android:launchMode #692

Open hettiger opened 6 years ago

hettiger commented 6 years ago

While Dynamic Links seem to work great when the App is completely closed they just don't work correctly when the App is running in the background for me. I think I've found the problem but I don't know how to fix it:

  1. The App is in the background
  2. User clicks on a Dynamic Link somewhere
  3. Because the activities launch mode falls back to standard (The system always creates a new instance of the activity in the target task and routes the intent to it.) the system creates a new instance.
  4. The new instance does not register the onDynamicLinkCallback → The App seems to start as usual but wont handle the Dynamic Link.
  5. If you open up the Multi Tasking App Switcher you see your App twice.
  6. If you switch to the other App instance the Dynamic Link is getting handled properly because on that "old" instance the onDynamicLinkCallback is still registered.

I have tried setting the launch mode to singleTask on the com.tns.NativeScriptActivity Activity as suggested in the React Native Documentation. This prevents the weird multi instance but the Dynamic Link is still not handled when the App is in the background.

Important: The above behavior seems to only apply to a handler that triggers a navigation. When the handler simply triggers an alert it seems to work just fine.

Here's a handler that I can reliably reproduce the issue with:

firebase.init(
    {
        persist: true,
        onDynamicLinkCallback: (result) => {
            this.routerExtensions.navigate(
                ["/about"]
            );
        }
    }
)

I'm not really sure and it's just a wild guess but I think this could maybe be related to https://github.com/EddyVerbruggen/nativescript-plugin-firebase/issues/534

I have already tried firebase.addOnDynamicLinkReceivedCallback. It did not work unfortunately.

I would have shared some repository but I don't know if it makes a lot of sense. (You will need to signing certificate fingerprints in your firebase project etc...)

    "tns-ios": {
      "version": "4.0.1"
    },
    "tns-android": {
      "version": "4.0.1"
    }
"nativescript-plugin-firebase": "^5.3.0",
EddyVerbruggen commented 6 years ago

Hi! If an alert works, but routing doesn't, then i wonder if a simple setTimout would fix it, or maybe something like this:

      application.on(application.resumeEvent, args => {
        if (args.android && this.deeplink) { // store your deeplink somewhere so you can check for it here
          this.routerExtensions.navigate(["/about"]);
          this.deeplink = undefined;
        }
      });
hettiger commented 6 years ago

@EddyVerbruggen setTimeout, application.on and ngZone.run do not work. Interestingly application.on did not fire until i switched to the mentioned "old" instance using the Android Multitasking App Switcher.

By the way: Everything did work just fine on the previous build:

    "tns-ios": {
      "version": "3.4.1"
    },
    "tns-android": {
      "version": "3.4.2"
    }
"nativescript-plugin-firebase": "^5.1.7",

Since then I have made no changes but upgrading.

EddyVerbruggen commented 6 years ago

@hettiger Thanks for checking all those things. Any idea which of NativeScript (3 vs 4) or Firebase plugin (5.1 vs 5.3) is to blame here? Note that it's hard to pinpoint the exact Firebase version used because you're not pinning to the major version (^ vs ~).

hettiger commented 6 years ago

@EddyVerbruggen I have just tried application.on with android:launchMode="singleTask" → The resume event triggers a console.log just fine. But onDynamicLinkCallback doesn't fire at all. (Unless the app is not in the background when clicking the link)

I'm not sure who's to blame here but I guess the fix will have to come from the Firebase plugin. (Probably taking care of executing in the Angular Zone and taking care of multi instances etc. / maybe android:launchMode="singleTask" is going to be part of the solution. Probably React Native had similar difficulties.)

I've debugged quite a few hours already. I think I'm not experienced enough with the Android platform in order to find a solution to this issue unfortunately. If I can help you somehow please let me know.

hettiger commented 6 years ago

@EddyVerbruggen I had following version installed on the last build where everything worked fine:

 "tns-ios": {
      "version": "3.4.1"
    },
    "tns-android": {
      "version": "3.4.2"
    }

"nativescript-plugin-firebase": {
      "version": "5.1.7",
      "resolved": "https://registry.npmjs.org/nativescript-plugin-firebase/-/nativescript-plugin-firebase-5.1.7.tgz",
      "integrity": "sha1-cKi1J3DTOAdiYyvCxfpZc/gw9PY=",
      "requires": {
        "nativescript-hook": "0.2.2",
        "prompt-lite": "0.1.1"
      }
    },

EDIT
I have just built the app the exact same way. (Release build + Webpack...) It made no difference. I will try and downgrade back to 3.4.2, just upgrade the firebase plugin and see if that works. Then we know NativeScript is to blame here.

hettiger commented 6 years ago

@EddyVerbruggen I have successfully downgraded and npm installed yet again from the old package-lock.json file. Then I deployed the app in the exact same way to my device and dynamic links were working perfectly fine as expected.

Next I did tns plugin remove nativescript-plugin-firebase and tns plugin add nativescript-plugin-firebase. I continued to updated my app.gradle file to googlePlayServicesVersion = "12.0.1" and did a tns platform clean android.

Then I deployed yet again in the exact same way and got an error from the CLI: No match found

I found this issue comment and updated the hooks/after-prepare/firebase-build-gradle.js file to use classpath "com.google.gms:google-services:3.1.1" as suggested.¹

After this change I was able to deploy to my device and to my surprise dynamic links would still be working just fine with nativescript-plugin-firebase@5.3.1. Therefore NativeScript is to blame I guess.

How can we continue? Want me to open an issue on the NativeScript repo and post a reference here?

¹ I don't know why this was necessary but it should no be the case I think. Maybe #606 should be reopened so this can get fixed in the future?

EDIT I think this is related to: https://github.com/NativeScript/NativeScript/issues/2747

bzaruk commented 6 years ago

@hettiger @EddyVerbruggen - Any updates here maybe?

I have a similar issue...

hackerunet commented 6 years ago

I have an issue related to this one, if the notification is pressed when the application is closed I get my application launched back again but the onTap action in my configuration object does not get called so I cannot perform any internal navigation., the only case it works is when I receive a notification but the application is in foreground, this does not call the onMessageReceivedCallback function, any thoughts?

hettiger commented 5 years ago

I finally found a working solution:

https://gist.github.com/nilsmehlhorn/1a3ee7447d0c7b60104288bc16c80c13

Do you see any way to make this just work out of the box @EddyVerbruggen ?

EddyVerbruggen commented 5 years ago

@hettiger Thanks, I'll do one better and try to make a PR for tns-core-modules.

hettiger commented 5 years ago

@EddyVerbruggen Awesome. Thank you for all the efforts.

EddyVerbruggen commented 5 years ago

Likewise!

daweedm commented 4 years ago

Is this issue resolved ?

flodaniel commented 4 years ago

So i just had the same issue. It was caused by android:launchMode="singleTop" I am not sure anymore why I had that, but I suspect because of an issue with firebase push notifications..

Removing the android:launchMode resolved the issue!

Edit: I know again why we had the launchMode Property. Check this issue: https://github.com/EddyVerbruggen/nativescript-plugin-firebase/issues/1345

Now we are kinda in a stalemate.. So we have to find a solution for one of the two issues

flodaniel commented 4 years ago

Ok it took me some time but I have a solution for our problem:

 if (isAndroid) {
      app.android.on(app.AndroidApplication.activityNewIntentEvent, (args: app.AndroidActivityNewIntentEventData) => {
        const intent: android.content.Intent = args.intent;
        if (intent.getAction() === android.content.Intent.ACTION_VIEW && intent.getData().toString().length > 0) {
          this.handleDynamicLinkReceived(intent.getData().toString());
          intent.setAction(android.content.Intent.ACTION_MAIN); // change the action so we the referral link is only handled once.
        }
      });
    }

I call setAction to avoid triggering the handleDynamicLinkReceived logic more than once. I am not sure why, but the intent-filter picks up the intent more than once.

manojdcoder commented 4 years ago

You could simply set the intent data to null to avoid handling it again.

ittrad-mobile-lab commented 4 years ago

Ok it took me some time but I have a solution for our problem:

 if (isAndroid) {
      app.android.on(app.AndroidApplication.activityNewIntentEvent, (args: app.AndroidActivityNewIntentEventData) => {
        const intent: android.content.Intent = args.intent;
        if (intent.getAction() === android.content.Intent.ACTION_VIEW && intent.getData().toString().length > 0) {
          this.handleDynamicLinkReceived(intent.getData().toString());
          intent.setAction(android.content.Intent.ACTION_MAIN); // change the action so we the referral link is only handled once.
        }
      });
    }

I call setAction to avoid triggering the handleDynamicLinkReceived logic more than once. I am not sure why, but the intent-filter picks up the intent more than once.

Could you please give us more details? Where exactly should apply this patch?

flodaniel commented 4 years ago

Just wherever you want to handle your dynamic links. So no need to put anything in the node_modules or so.