react-native-sdk icon indicating copy to clipboard operation
react-native-sdk copied to clipboard

[info request] How to configure openUrl push notification to deep-link on iOS

Open alex-a-pereira opened this issue 2 years ago • 5 comments

Hi, I'm running into issues while trying to configure the Iterable react-native SDK to open push notifications that handle "Open URL" action to a specific screen using universal links. It works as expected on Android - i'm only having this problem with iOS.

We use the react-navigation library to handle universal links, which works perfectly find for other links (e.g. a webpage has the link in an <a> tag). However it's not working for push notifications sent by iterable.

Is there some step I'm missing here?? Please let me know if any additional info is required to diagnose the issue.

Thanks in advance!


Expected Behavior: Sending push payload with "Open URL" action and a valid universal link URL (e.g. https://MY_DEEP_LINK_HOST/support_tab) opens up the app to the correct screen specified in the react-navigation deep link config

Observed behavior:

  • if the app is NOT yet opened (not running, was previously hard-closed), the open url action opens up in the device's browser to the URL destination (e.g. https://MY_DEEP_LINK_HOST/support_tab). This is typical universal link behavior when the app is not installed on the device
  • if the app has been opened (running in foreground or background), the open url action will simply open up the app - the deep link path is ignored

Versions:

"react-native": "0.65.2",
"@iterable/react-native-sdk": "^1.0.28",
"@react-navigation/native": "^5.7.3",

alex-a-pereira avatar Apr 28 '22 13:04 alex-a-pereira

I should also note that urlHandler was set to undefined (omitted from IterableConfig object), so the SDK should not be calling Linking.openUrl before navigation is ready as described in this issue https://github.com/Iterable/react-native-sdk/issues/130#issuecomment-850853765

edit: and furthermore, when I try to set config.urlHandler to a function that returns false, the callback function is not called!

alex-a-pereira avatar Apr 28 '22 14:04 alex-a-pereira

A bit more info - I hooked up the react-navigation devtools (for v5 it just logs to the RN debugger) and it doesn't appear that react-navigation is receiving anything (no state changes are logged to devtools)

alex-a-pereira avatar Apr 28 '22 18:04 alex-a-pereira

In case it's helpful - my AppDelegate.m

#pragma mark - UNUserNotificationCenterDelegate
- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler {
    completionHandler(UNAuthorizationOptionAlert | UNAuthorizationOptionBadge | UNAuthorizationOptionSound);
}

- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)(void))completionHandler {
    [IterableAppIntegration userNotificationCenter:center didReceiveNotificationResponse:response withCompletionHandler:completionHandler];
}

// for deep links
- (BOOL)application:(UIApplication *)application
   openURL:(NSURL *)url
   options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options
{
  return [RCTLinkingManager application:application openURL:url options:options];
}

// for universal links
- (BOOL)application:(UIApplication *)application continueUserActivity:(nonnull NSUserActivity *)userActivity
 restorationHandler:(nonnull void (^)(NSArray<id<UIUserActivityRestoring>> * _Nullable))restorationHandler
{
 return [RCTLinkingManager application:application
                  continueUserActivity:userActivity
                    restorationHandler:restorationHandler];
}

alex-a-pereira avatar Apr 28 '22 20:04 alex-a-pereira

Another update:

I added a basic urlHandler to the iterable config to simply return false and allow Linking to handle the links normally.

conf.urlHandler = () => {
      return false
}

With this set, the behavior is:

  • if the app is NOT yet opened (not running, was previously hard-closed), the open url action opens up our app (shows splash screen), then opens up the link the device's browser to the URL destination (e.g. https://MY_DEEP_LINK_HOST/support_tab).
  • if the app has been opened (running in foreground or background), the open url action will simply open up the app - the deep link path is ignored

alex-a-pereira avatar Apr 29 '22 16:04 alex-a-pereira

Update:

Part of the problem was that I was trying to use the universal link URL in notifications instead of just using deep links - the iterable sdk calls Linking.openUrl when urlHandler returns false. This is a known issue for react-native, and using the regular deep link URL is fine for our purposes. https://github.com/facebook/react-native/issues/27486

This doesn't completely solve the issue as hard-quitting the app will cause the "open URL" push action to no longer work. I'm digging into that issue today

alex-a-pereira avatar May 13 '22 16:05 alex-a-pereira

Sorry - forgot to close this out. I ended up solving this by just calling react-native's Linking.openURL myself:

const openDeepLinkPushPayload = async (url: string): Promise<void> => {
  const canOpen = await Linking.canOpenURL(url)
  if (canOpen) {
    try {
      await Linking.openURL(url)
    } catch (e) {
      // log error to error tracking system
    }
  } else {
    // log error to error tracking system
  }
}
   // ....
   // in a hook used to initialize iterable SDK
    const conf = new IterableConfig()
    conf.urlHandler = (url, context) => {
      openDeepLinkPushPayload(url).catch(e => {
        // no need, logging already contained
      })
      // returning true means "our JS code handled the url", iterable SDK doesnt need to call Linking.openUrl
      return true
    }
    ```

alex-a-pereira avatar Jan 25 '23 14:01 alex-a-pereira