braze-inc / braze-react-native-sdk

Public repo for the Braze React Native SDK
https://www.braze.com
Other
64 stars 83 forks source link

[Bug]: Deeplink not working when iOS app is open/background #227

Closed sregg closed 1 year ago

sregg commented 1 year ago

Which Platforms?

iOS

Which React Native Version?

0.71.8

Which @braze/react-native-sdk SDK version?

6.0.1

Repro Rate

100%

Steps To Reproduce

Example:

  1. setup Braze RN SDK
  2. send push notification with deeplink
  3. open the app
  4. (optional) background the app
  5. click on the notification

Expected Behavior

the screen associated with the deeplink is opened

Actual Incorrect Behavior

the home screen of the app is opened

Verbose Logs

There are no logs at all when opening the notification when the app is opened.

Additional Information

It's working fine when the iOS app is fully closed. Android is working fine wether is app is closed or opened.

Here's our AppDelegate.mm

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
  /* React native delegate implementation */

  self.moduleName = @"CookinMarketplace";
  // You can add your custom initial props in the dictionary below.
  // They will be passed down to the ViewController used by React Native.
  self.initialProps = @{};

  /* Braze Configuration */
  NSString *brazeApiKey = [RNCConfig envFor:@"IOS_BRAZE_API_KEY"];
  NSString *brazeEndpoint = [RNCConfig envFor:@"BRAZE_ENDPOINT"];

  BRZConfiguration *configuration = [[BRZConfiguration alloc] initWithApiKey:brazeApiKey endpoint:brazeEndpoint];
  configuration.triggerMinimumTimeInterval = 1;
  configuration.logger.level = BRZLoggerLevelDebug;
  Braze *braze = [BrazeReactBridge initBraze:configuration];
  AppDelegate.braze = braze;

  [self registerForPushNotifications];
  [[BrazeReactUtils sharedInstance] populateInitialUrlFromLaunchOptions:launchOptions];

  BOOL didFinish = [super application:application didFinishLaunchingWithOptions:launchOptions];

  [RNSplashScreen show];

  return didFinish;
}

- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url options:(NSDictionary *) options {
  NSLog(@"SIMONHERE openURL %@", url);
  [[AppsFlyerAttribution shared] handleOpenUrl:url options:options];
  [RCTLinkingManager application:application openURL:url options:options];
  return YES;
}

- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void (^)(NSArray * _Nullable))restorationHandler {
  NSLog(@"SIMONHERE continueUserActivity %@", userActivity);
  [[AppsFlyerAttribution shared] continueUserActivity:userActivity restorationHandler:restorationHandler];
  [RCTLinkingManager application:application
            continueUserActivity:userActivity
              restorationHandler:restorationHandler];
  return YES;
}

#pragma mark - Push notifications with Braze

- (void)registerForPushNotifications {
  UNUserNotificationCenter* center = [UNUserNotificationCenter currentNotificationCenter];
  center.delegate = self;
  [center setNotificationCategories:BRZNotifications.categories];
  [[UIApplication sharedApplication] registerForRemoteNotifications];
}

- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
  [AppDelegate.braze.notifications registerDeviceToken:deviceToken];
}

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
  NSLog(@"SIMONHERE didReceiveRemoteNotification %@", userInfo);
  BOOL processedByBraze = AppDelegate.braze != nil && [AppDelegate.braze.notifications handleBackgroundNotificationWithUserInfo:userInfo fetchCompletionHandler:completionHandler];
  if (processedByBraze) {
    return;
  }

  completionHandler(UIBackgroundFetchResultNoData);
}

- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)(void))completionHandler {
  NSLog(@"SIMONHERE didReceiveNotificationResponse %@", response);
  [[BrazeReactUtils sharedInstance] populateInitialUrlForCategories:response.notification.request.content.userInfo];
    BOOL processedByBraze = AppDelegate.braze != nil && [AppDelegate.braze.notifications handleUserNotificationWithResponse:response withCompletionHandler:completionHandler];
    if (processedByBraze) {
      return;
    }

    completionHandler();
}

- (void)userNotificationCenter:(UNUserNotificationCenter *)center
       willPresentNotification:(UNNotification *)notification
         withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler {
  NSLog(@"SIMONHERE willPresentNotification %@", notification);
  completionHandler(UNNotificationPresentationOptionList | UNNotificationPresentationOptionBanner);
}

#pragma mark - AppDelegate.braze

static Braze *_braze = nil;

+ (Braze *)braze {
  return _braze;
}

+ (void)setBraze:(Braze *)braze {
  _braze = braze;
}

@end

and part of our RootNavigator

Braze.getInitialURL((url) => {
  console.log('Braze.getInitialURL is ' + url);
  if (url) {
    handleNotificationDeepLink(url);
  }
});

Linking.getInitialURL()
  .then((url) => {
    console.log('Linking.getInitialURL is ' + url);
    if (url) {
      handleNotificationDeepLink(url);
    }
  })
  .catch((err) => console.error('Error getting initial URL', err));

const handleOpenUrl = (event: { url: string }) => {
  console.log('handleOpenUrl called on url ' + event.url);
  handleNotificationDeepLink(event.url);
};

const listener = Linking.addEventListener('url', handleOpenUrl);

None of the SIMONHERE logs in objc or the console.logs in JS are being triggered. There are when opening the notification from a fully closed state.

sregg commented 1 year ago

Found the issue. Very strange. I removed Notifee and it's all working again. I'm using it only to dismiss current notifications so I'll remove it for now that will find another lib that allows me to do so later. You guys should add that in your doc a Notifee is a common lib these days.

sregg commented 1 year ago

I managed to keep Notifee and make iOS deeplinks work too:

const notifeeEventCallback = async ({ type, detail }: Event) => {
  if (type === EventType.PRESS) {
    // open deeplink if any (data.link from Firebase/BE or data.ab_uri from Braze)
    const link =
      detail.notification?.data?.link || detail.notification?.data?.ab_uri;
    if (link && typeof link === 'string') {
      handleNotificationDeepLink(link);
    }
  }
};
notifee.onBackgroundEvent(notifeeEventCallback);
notifee.onForegroundEvent(notifeeEventCallback);