react-native: Linking.addEventListener not working: url event never fires

Description

Url event never fires

I followed the indicated setup to handle deep links in react native.

But when I have the app open in background or foreground and I execute command npx uri-scheme open "mychat://bar" --ios, url event doesn’t fire.

I saw there is a similar issue in react-navigation, but the fix indicated for AppDelegate.m doesn’t work for me.

Version

0.76

Output of npx react-native info

System: OS: macOS 12.5.1 CPU: (16) x64 Intel® Core™ i9-9880H CPU @ 2.30GHz Memory: 1.30 GB / 16.00 GB Shell: 5.8.1 - /bin/zsh Binaries: Node: 16.18.1 - /usr/local/opt/node@16/bin/node Yarn: 1.22.11 - /usr/local/bin/yarn npm: 8.19.2 - /usr/local/opt/node@16/bin/npm Watchman: Not Found Managers: CocoaPods: 1.11.2 - /usr/local/bin/pod SDKs: iOS SDK: Platforms: DriverKit 21.4, iOS 16.0, macOS 12.3, tvOS 16.0, watchOS 9.0 Android SDK: API Levels: 28, 31, 33 Build Tools: 30.0.2, 31.0.0, 33.0.0 System Images: android-31 | Google APIs Intel x86 Atom_64, android-31 | Google Play Intel x86 Atom_64 Android NDK: Not Found IDEs: Android Studio: 2021.2 AI-212.5712.43.2112.8815526 Xcode: 14.0.1/14A400 - /usr/bin/xcodebuild Languages: Java: 13.0.2 - /usr/bin/javac npmPackages: @react-native-community/cli: Not Found react: 18.1.0 => 18.1.0 react-native: 0.70.6 => 0.70.6 react-native-macos: Not Found npmGlobalPackages: react-native: Not Found

Steps to reproduce

clone repo https://github.com/leoparis89/deeplink

  1. yarn
  2. cd ios && pod install
  3. yarn ios
  4. put app in background
  5. run command npx uri-scheme open "mychat://bar" --ios. App gets focused but url event never fires in ./App.js line 121.

Snack, code example, screenshot, or link to a repository

https://github.com/leoparis89/deeplink

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Comments: 23

Most upvoted comments

Hi @edwardhsueh, I was using react native 0.68.0 and facing the same problem One thing that you can try is adding the below code to the location that specified by React Navigation Documentation as I am not familiar with Swift and placing the code in the wrong location

// Add the header at the top of the file:
#import <React/RCTLinkingManager.h>

// Add this inside `@implementation AppDelegate` above `@end`:
- (BOOL)application:(UIApplication *)application
   openURL:(NSURL *)url
   options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options
{
  return [RCTLinkingManager application:application openURL:url options:options];
}

It’s working for me now

Yes, I do follow the document but still fail. I can’t run in simulator, so I use browser with button to call the url scheme. if app is closed, it works fine. But if app is in background, the url scheme called just bring app to foreground, but the url listener is not fired. My RN is 0.68.2, older than yours. Will this be a problem? By the way, can your app receive url event when it is in background?

if you use react native +0.71

change AppDelegate.m to AppDelegate.mm

// Add the header at the top of the file:
#import <React/RCTLinkingManager.h>

// Add this inside `@implementation AppDelegate` above `@end`:
- (BOOL)application:(UIApplication *)application
   openURL:(NSURL *)url
   options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options
{
  return [RCTLinkingManager application:application openURL:url options:options];
}
// Add this inside `@implementation AppDelegate` above `@end`:
- (BOOL)application:(UIApplication *)application continueUserActivity:(nonnull NSUserActivity *)userActivity
 restorationHandler:(nonnull void (^)(NSArray<id<UIUserActivityRestoring>> * _Nullable))restorationHandler
{
 return [RCTLinkingManager application:application
                  continueUserActivity:userActivity
                    restorationHandler:restorationHandler];
}

I manage to get it work on iOS need to add the url to the xcode setting refer to https://reactnavigation.org/docs/deep-linking/. At xcode, go to Targets, under the Info tab, go to URL Types, add the appID to the identifier and URL Scheme field the appID would be com.RNProject

however my android does not work

I got a build error on android android/app/src/main/java/com/xxx/usermanagement/testapp/MainApplication.java:61: error: cannot find symbol ReactNativeFlipper.initializeFlipper(this, getReactNativeHost().getReactInstanceManager()); ^ symbol: variable ReactNativeFlipper location: class MainApplication 1 error

I want to add to this issue what I researched, having similar issue:

  • When the app is not running at all, and you select “share/open with” your app the following happens:
    • First, the (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions is called, having the path to the file in the launch options under “UIApplicationLaunchOptionsURLKey” key. This path is not accessible (permission-wise to the app). This path is also what you’d get if you call Linking.getInitialURL
    • Then, the (BOOL)application:(UIApplication *)application openURL:(NSURL *)url options:... is called. This method receives a different URL, which is a copy of the file in your app’s temp/inbox folder - fully accessible to your app. And as suggested, it is implemented with one line: return [RCTLinkingManager application:application openURL:url options:options];, which triggers RCTLinkingManager to send notification via NSNotificationCenter with that (good) url. Now comes the issue: at this point in time, the JS was not yet started and the JS part of the app did not register to listen to “url” event. That is why RCTEventEmitter did not call RCTLinkingManager.startObserving and the notification with the url is lost. and even if it would have been received, the JS did not register yet, and it would not have been fired to the JS part.

Here is how I solved it (and I suggest you implement something more generic/robust for Linking:

  • when RCTLinkingManager application:application openURL:url options:options is called, I save the url in a object’s local variable. the when RCTLinkingManager.startObserving is called, if this variable is not nil, I fire the url event.

  • line 19: static NSString *savedEvent = nil; at startObserving, at its end:

if (savedEvent != nil) {
        NSDictionary<NSString *, id> *payload = @{@"url": savedEvent};
        [self sendEventWithName:@"url" body:payload];
        savedEvent = nil;
    }

at application:openURL:options

    // if event was missed, save it for later firing
    savedEvent = URL.absoluteString;

I hope this helps.