react-native-branch-deep-linking-attribution icon indicating copy to clipboard operation
react-native-branch-deep-linking-attribution copied to clipboard

Ios configuration with react-native-linking is duplicated with react-native-branch's

Open byyoungjin opened this issue 3 years ago • 7 comments

I'm trying to integrate react navigation with this react-native-branch In react-navigation docs, they say it can be used with branch like this

But I found both of libraries need to configure same function on AppDelegete.m

1 . for react-native-linking

// Linking API (react-native-linking)
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {
  return [RCTLinkingManager application:application openURL:url options:options];
}

// Universal Links(react-native-linking)
- (BOOL)application:(UIApplication *)application continueUserActivity:(nonnull NSUserActivity *)userActivity restorationHandler:(nonnull void (^)(NSArray<id<UIUserActivityRestoring>> * _Nullable))restorationHandler {
 return [RCTLinkingManager application:application
                  continueUserActivity:userActivity
                    restorationHandler:restorationHandler];
}
  1. for react-native-branch
// Branch.io
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {
    if ([RNBranch application:app openURL:url options:options])  {
        // do other deep link routing for the Facebook SDK, Pinterest SDK, etc
    }
    return YES;
}

// Universal Links(Branch.io)
- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void (^)(NSArray<id<UIUserActivityRestoring>> * _Nullable))restorationHandler {
  return [RNBranch continueUserActivity:userActivity];
}

so I needed to chose what to use.

  1. if I chose 1. react-native-linking configuration , I can use linking configuration which react-navigion5 provide. and
  • branch.getFirstReferringsParms()
    work.

-branch.subscribe(({params}) =>{...}) seems to work, but the params it giving me is always {“+clicked_branch_link”: false, “+is_first_session”: false} or {“+clicked_branch_link”: false, “+is_first_session”: false, “+rn_cached_initial_event”: true}

no other custom params,

-branch.getLastesReferringsParams() also return same with subscribe. no custom params.

  1. so I replaced AppDelegate.m with 2. react-native-branch configuration in this way, linking configuration has no effect. Not triggered

but -branch.getLastesReferringsParams() give me the exact params that i sended with. branch.subscribe() also work.

So I'm planning to chose react-native-branch configuration ..

but this means the way doc say is not correct.

Is there any way that i can use react-navigation5 's linking configuration while getting correct latestParams ??

byyoungjin avatar Jul 07 '21 03:07 byyoungjin

same issue :(

hatn98 avatar Jul 30 '21 10:07 hatn98

still an issue

thanhtungkhtn avatar Jul 30 '21 10:07 thanhtungkhtn

Hi Everyone! I'fe found the solution!! Both configurations are compatible (deep linking and branch), but it is not documented anywhere. In order to make the config screens work in react navigation and branch, add or modify these two methods in the AppDelegate.m:

#import <RNBranch/RNBranch.h>
#import <React/RCTLinkingManager.h>


- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {

  if ([RNBranch application:app openURL:url options:options])  {
       // do other deep link routing for the Facebook SDK, Pinterest SDK, etc
    [[FBSDKApplicationDelegate sharedInstance] application:app openURL:url options:options];
   }
  
  
  return [RCTLinkingManager application:app openURL:url options:options];
}

- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void (^)(NSArray<id<UIUserActivityRestoring>> * _Nullable))restorationHandler {
  return [RNBranch continueUserActivity:userActivity] || [RCTLinkingManager application:application continueUserActivity:userActivity restorationHandler:restorationHandler];
}

and the navigator should look like this:

<NavigationContainer
          ref={navigationRef}
          linking={{
            prefixes: ["https://yourapp.com", "yourapp://"],
            config: {
              screens: {
                [EVENT]: {
                  path: "events/:eventId",
                  parse: {
                    eventId: decodeEventId
                  }
                }
              }
            },
            // Custom function to subscribe to incoming links
            subscribe(listener) {
              // First, you may want to do the default deep link handling
              const onReceiveURL = ({ url }) => listener(url);

              // Listen to incoming links from deep linking
              Linking.addEventListener("url", onReceiveURL);

              // Next, you would need to subscribe to incoming links from your third-party integration
              // For example, to get to subscribe to incoming links from branch.io:
              branch.subscribe(({ error, params, uri }) => {
                if (error) {
                  handleError(`Error from Branch: ${error}`);
                  return;
                }
                if (params["+non_branch_link"]) {
                  // const nonBranchUrl = params["+non_branch_link"];
                  // Route non-Branch URL if appropriate.
                  return;
                }

                if (!params["+clicked_branch_link"]) {
                  // Indicates initialization success and some other conditions.
                  // No link was opened.
                  return;
                }

                // A Branch link was opened
                const url = params.$canonical_url;
                const eventId = url.replace("events/", "");

                // routing depending on deep link
                listener(\`/events/${eventId}\`);
              });
              return () => {
                // Clean up the event listeners
                Linking.removeEventListener("url", onReceiveURL);
              };
            },
            async getInitialURL() {
              // First, you may want to do the default deep link handling
              // Check if app was opened from a deep link
              const url = await Linking.getInitialURL();
              // routing depending on deep link

              if (url != null) {
                return url;
              }
              // Next, you would need to get the initial URL from your third-party integration
              // It depends on the third-party SDK you use
              // For example, to get to get the initial URL for branch.io:
              const params = await branch.getFirstReferringParams();

              return params?.$canonical_url;
            }
          }}
        >
          <MainNavigator />
        </NavigationContainer>

This way, all links are opened by the native deep linking system and routed through it. Independently of routing, onsubscribe callback from rn branch is executed so that branch api is aware of your click.

cbarceloc avatar Aug 07 '21 07:08 cbarceloc

Hi Everyone! I'fe found the solution!! Both configurations are compatible (deep linking and branch), but it is not documented anywhere. In order to make the config screens work in react navigation and branch, add or modify these two methods in the AppDelegate.m:

#import <RNBranch/RNBranch.h>
#import <React/RCTLinkingManager.h>


- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {

  if ([RNBranch application:app openURL:url options:options])  {
       // do other deep link routing for the Facebook SDK, Pinterest SDK, etc
    [[FBSDKApplicationDelegate sharedInstance] application:app openURL:url options:options];
   }
  
  
  return [RCTLinkingManager application:app openURL:url options:options];
}

- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void (^)(NSArray<id<UIUserActivityRestoring>> * _Nullable))restorationHandler {
  return [RNBranch continueUserActivity:userActivity] || [RCTLinkingManager application:application continueUserActivity:userActivity restorationHandler:restorationHandler];
}

and the navigator should look like this:

<NavigationContainer
          ref={navigationRef}
          linking={{
            prefixes: ["https://yourapp.com", "yourapp://"],
            config: {
              screens: {
                [EVENT]: {
                  path: "events/:eventId",
                  parse: {
                    eventId: decodeEventId
                  }
                }
              }
            },
            // Custom function to subscribe to incoming links
            subscribe(listener) {
              // First, you may want to do the default deep link handling
              const onReceiveURL = ({ url }) => listener(url);

              // Listen to incoming links from deep linking
              Linking.addEventListener("url", onReceiveURL);

              // Next, you would need to subscribe to incoming links from your third-party integration
              // For example, to get to subscribe to incoming links from branch.io:
              branch.subscribe(({ error, params, uri }) => {
                if (error) {
                  handleError(`Error from Branch: ${error}`);
                  return;
                }
                if (params["+non_branch_link"]) {
                  // const nonBranchUrl = params["+non_branch_link"];
                  // Route non-Branch URL if appropriate.
                  return;
                }

                if (!params["+clicked_branch_link"]) {
                  // Indicates initialization success and some other conditions.
                  // No link was opened.
                  return;
                }

                // A Branch link was opened
                const url = params.$canonical_url;
                const eventId = url.replace("events/", "");

                // routing depending on deep link
                listener(\`/events/${eventId}\`);
              });
              return () => {
                // Clean up the event listeners
                Linking.removeEventListener("url", onReceiveURL);
              };
            },
            async getInitialURL() {
              // First, you may want to do the default deep link handling
              // Check if app was opened from a deep link
              const url = await Linking.getInitialURL();
              // routing depending on deep link

              if (url != null) {
                return url;
              }
              // Next, you would need to get the initial URL from your third-party integration
              // It depends on the third-party SDK you use
              // For example, to get to get the initial URL for branch.io:
              const params = await branch.getFirstReferringParams();

              return params?.$canonical_url;
            }
          }}
        >
          <MainNavigator />
        </NavigationContainer>

This way, all links are opened by the native deep linking system and routed through it. Independently of routing, onsubscribe callback from rn branch is executed so that branch api is aware of your click.

do you know if there is a way to implement this on the android side? because I'm having the same issue but on android, also this

not sure why got this error

Captura de Pantalla 2021-09-07 a la(s) 15 45 47

Vasault avatar Sep 06 '21 22:09 Vasault

Thank you for help me to resolve issue with RCTLinkingManager. I written a plugin to use react-native-branch with expo

giautm avatar Dec 09 '21 20:12 giautm

@Vasault

iOS:

  • replace app with application
  • if you no need routing for FB etc. you can simply return nil

like that:

// Linking API
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {
  if ([RNBranch application:application openURL:url options:options])  {
       // do other deep link routing for the Facebook SDK, Pinterest SDK, etc
    return nil;
   }
  
  return [RCTLinkingManager application:application openURL:url options:options];
}

Android: Make sure that in MainActivity.java onNewIntent method looks like:

    @Override
    public void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        RNBranchModule.onNewIntent(intent);
    }

r1skz3ro avatar Jun 02 '22 12:06 r1skz3ro

@cbarceloc Thank you for this! But shouldn't we add return before

[[FBSDKApplicationDelegate sharedInstance] application:app openURL:url options:options];

miladdev85 avatar Aug 18 '22 13:08 miladdev85