From 3921f05f594691285e79a379897ed698e081a705 Mon Sep 17 00:00:00 2001 From: Pieter De Baets Date: Mon, 14 Nov 2022 03:38:52 -0800 Subject: [PATCH] Do not use InteractionManager to wait for Activity (#35289) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/35289 This was originally added in D15258046 (https://github.com/facebook/react-native/commit/c802d0b757912358d703d4d8a114073377a905b9) but seems to be the wrong solution to the problem from my perspective. InteractionManager does not provide timing information on the activity being available, but ReactContext's LifecycleEventListener does. This should also address some of the issues raised in https://github.com/facebook/react-native/issues/25675 Changelog: [Android][Fixed] Linking.getInitialUrl should not wait for InteractionManager Reviewed By: mdvacca Differential Revision: D41157646 fbshipit-source-id: 6e23969212570204a7e076b6d4d9db004412da09 --- Libraries/Linking/Linking.js | 5 +- .../react/modules/intent/IntentModule.java | 61 ++++++++++++++++--- 2 files changed, 52 insertions(+), 14 deletions(-) diff --git a/Libraries/Linking/Linking.js b/Libraries/Linking/Linking.js index a59fa72973a3a2..76d187988ff6e2 100644 --- a/Libraries/Linking/Linking.js +++ b/Libraries/Linking/Linking.js @@ -11,7 +11,6 @@ import type {EventSubscription} from '../vendor/emitter/EventEmitter'; import NativeEventEmitter from '../EventEmitter/NativeEventEmitter'; -import InteractionManager from '../Interaction/InteractionManager'; import Platform from '../Utilities/Platform'; import NativeIntentAndroid from './NativeIntentAndroid'; import NativeLinkingManager from './NativeLinkingManager'; @@ -96,9 +95,7 @@ class Linking extends NativeEventEmitter { */ getInitialURL(): Promise { return Platform.OS === 'android' - ? InteractionManager.runAfterInteractions().then(() => - nullthrows(NativeIntentAndroid).getInitialURL(), - ) + ? nullthrows(NativeIntentAndroid).getInitialURL() : nullthrows(NativeLinkingManager).getInitialURL(); } diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/intent/IntentModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/intent/IntentModule.java index 7b532d4975b7bf..c0da2164e435fb 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/intent/IntentModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/intent/IntentModule.java @@ -17,6 +17,7 @@ import androidx.annotation.Nullable; import com.facebook.fbreact.specs.NativeIntentAndroidSpec; import com.facebook.react.bridge.JSApplicationIllegalArgumentException; +import com.facebook.react.bridge.LifecycleEventListener; import com.facebook.react.bridge.Promise; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.ReadableArray; @@ -30,6 +31,8 @@ public class IntentModule extends NativeIntentAndroidSpec { public static final String NAME = "IntentAndroid"; + private @Nullable LifecycleEventListener mInitialURLListener = null; + private static final String EXTRA_MAP_KEY_FOR_VALUE = "value"; public IntentModule(ReactApplicationContext reactContext) { @@ -41,6 +44,15 @@ public String getName() { return NAME; } + @Override + public void invalidate() { + if (mInitialURLListener != null) { + getReactApplicationContext().removeLifecycleEventListener(mInitialURLListener); + mInitialURLListener = null; + } + super.invalidate(); + } + /** * Return the URL the activity was started with * @@ -50,18 +62,20 @@ public String getName() { public void getInitialURL(Promise promise) { try { Activity currentActivity = getCurrentActivity(); - String initialURL = null; + if (currentActivity == null) { + waitForActivityAndGetInitialURL(promise); + return; + } - if (currentActivity != null) { - Intent intent = currentActivity.getIntent(); - String action = intent.getAction(); - Uri uri = intent.getData(); + Intent intent = currentActivity.getIntent(); + String action = intent.getAction(); + Uri uri = intent.getData(); - if (uri != null - && (Intent.ACTION_VIEW.equals(action) - || NfcAdapter.ACTION_NDEF_DISCOVERED.equals(action))) { - initialURL = uri.toString(); - } + String initialURL = null; + if (uri != null + && (Intent.ACTION_VIEW.equals(action) + || NfcAdapter.ACTION_NDEF_DISCOVERED.equals(action))) { + initialURL = uri.toString(); } promise.resolve(initialURL); @@ -72,6 +86,33 @@ public void getInitialURL(Promise promise) { } } + private void waitForActivityAndGetInitialURL(final Promise promise) { + if (mInitialURLListener != null) { + promise.reject( + new IllegalStateException( + "Cannot await activity from more than one call to getInitialURL")); + return; + } + + mInitialURLListener = + new LifecycleEventListener() { + @Override + public void onHostResume() { + getInitialURL(promise); + + getReactApplicationContext().removeLifecycleEventListener(this); + mInitialURLListener = null; + } + + @Override + public void onHostPause() {} + + @Override + public void onHostDestroy() {} + }; + getReactApplicationContext().addLifecycleEventListener(mInitialURLListener); + } + /** * Starts a corresponding external activity for the given URL. *