React Native getInitialUrl returns null on iOS build

458 views Asked by At

I recently implemented push notifications into my React Native app using node-apn and fcm-node. This is working fine, and the next step was to implement deep linking.

At the moment, there are two different screens we want to deep link to, and I have already got this working to some extent, both on Android and iOS. Clicking a link on either device in the form of myappscheme://messages/1 for example, opens the app on the relevant screen, whether the app is closed down entirely or in the background.

I did the necessary changes on my node backend to attach a link to the push notifications, and Android is working as expected. For iOS, I have only been partially successful, where the tapping the push notification opens the app and takes me to the correct screen, only if the app is in the background, and not entirely shut down.

I did this by using

useEffect(() => {
   const linkingEvent = Linking.addEventListener('url', handleDeepLink);
   linkingEvent.remove();
});

I read that this will not work from a cold start, and to use

Linking.getInitialURL().then(function (url) {
  alert('getInitialURL')
  if (url) {
    alert(url)
    handleDeepLink(url)
  }
}

But, I also have read that without certain configurations, iOS does not store the url in the location where getInitialUrl searches, and thus changes are required in other places.

I have followed many different sources instructions, some suggesting changes to the Info.plist, and all suggesting changes to the AppDelegate.mm.

So far, I have had no success with this. I have very minimal experience with C++ and Swift.

I am using React Native 0.70.8, and Xcode 14.2 (I had issues building my IPA with 14.3 so downgraded back to 14.2).

Anyway, when I launch my app via a push notification when the app is closed entirely, I do not get a url.

I Appreciate any suggestions.

1

There are 1 answers

0
noisiveRevision On

I was facing the same issue and your question provided me the clue necessary to figure out what the underlying cause was. Specifically, this part:

iOS does not store the url in the location where getInitialUrl searches

This is the problem. When a push notification launches the app, it is passed in launchOptions with UIApplicationLaunchOptionsRemoteNotificationKey, which is not passed to Linking's getInitialURL. It does not appear that any changes will be made to React Native's Linking implementation to address this issue, since (I assume) the shape of the data passed from a notification is not straightforward like when a link alone opens the app. There is, however, a workaround to re-map the URL to the key that is used by RN Linking's getInitialURL (UIApplicationLaunchOptionsURLKey). Here's a snippet:

  NSMutableDictionary *newLaunchOptions = [NSMutableDictionary dictionaryWithDictionary:launchOptions];
  if (launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey]) {
    NSDictionary *remoteNotif = launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey];
    
    if (remoteNotif[@"{ENTRY_YOU_WANT}"]) {
      NSString *initialURL = remoteNotif[@"{ENTRY_YOU_WANT}"];
      if (!launchOptions[UIApplicationLaunchOptionsURLKey]) {
        newLaunchOptions[UIApplicationLaunchOptionsURLKey] = [NSURL URLWithString:initialURL];
      }
    }
  }

  RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self
                                            launchOptions:newLaunchOptions];

This goes in your AppDelegate and you may need to update to make sure the entry's value is what you expect before passing things along, but that's the gist.

This workaround worked for me and several RN issues reference doing this as a solution to handling deep links (explicitly or implicitly from push notifications): 5047, 24429, 32350. I saw one alternative approach that I didn't try that seems like it might also work. I didn't try it because I don't want to add another dependency to address this, but I want to mention it in case it's a better option for others. It seems you could leverage react-native-notifications to implement a listener for the notification launching the app and proceed with handling it that way instead. There's an example for doing this in this comment.