React-native-branch-deep-linking-attribution: Feature: Move branch_key and branch_app_domain to the JS side

Created on 12 Apr 2017  路  14Comments  路  Source: BranchMetrics/react-native-branch-deep-linking-attribution

@jdee I've been making my rounds to the various React Native plugins with this request. It'd be great to move the branch_key and branch_app_domain that is put in the Info.plist for iOS and that is put AndroidManifest.xml for Android to the JS side.

Moving the keys to the JS side has several advantages:

  1. We only have to put it in one place. This will reduce bugs (and issues for you guys!) and steps during the installation.

  2. By using 12 Factor best practices, having it in the JS is very easy because we can generate one env.js file and have ALL of our JS files import that file and grab keys like we needed.

  3. If changes to the underlying iOS or Android code is ever made, this protects that as it's agnostic to what happens under the hood.

For example, it could look like this:

import {
  subscribe
  setKey,
  setAppDomain
} from 'react-native-branch';

import {
  BRANCH_KEY,
  BRANCH_APP_DOMAIN
} from '../../../env.js'; // this file is not in the repo!

export function init() {
    setKey(BRANCH_KEY);
    setAppDomain(BRANCH_APP_DOMAIN);  

    subscribe(bundle => {
        console.log('bundle', bundle);

        if (bundle && bundle.params) {
            runAction(bundle.params);
        }
    });
}
enhancement

Most helpful comment

I was wondering if what discussed in the very first comment cannot be achieved using react-native-config?

All 14 comments

@dwilt Thanks. This is a good idea. Actually, one of my to-dos is to produce a script to do the integration one way or another, and I was thinking of something along these lines.

Cool. Also, is subscribe able to be destrutured as I've shown in the example above? In your main example it's not but others (AddToWishlistEvent,PurchasedEvent,PurchaseInitiatedEvent,RegisterViewEvent,ShareCompletedEvent,ShareInitiatedEvent) are.

Also, any idea on a timeline when you think you'd be able to implement this? Right now we have a pretty hacky way to ensure that our key_test and key_live are in the appropriate builds.

@dwilt First, subscribe doesn't seem to be destructurable. I tried just now and got "undefined is not a function." I think the reason is that index.js exports a new Branch object, and when you import branch from 'react-native-branch', branch is just a reference to that object, and subscribe is a property on that exported object, not something that is exported itself. The constants you mention are just export consts so you can destructure them. It would be nice to make this work though. I don't think it's much trouble to change that though.

Regarding the Branch configuration:

The Branch keys can be set in code, and that will be in the react-native-branch module. This also applies to the branch_universal_link_domains key in the Info.plist on iOS. That's not much work.

But there are some realities that can't be coded around. For example, you always need intent-filters for Android and the Associated Domains entitlement/URI scheme for iOS. Some settings changes are always needed to let the OS know that this app supports a certain URI scheme or Universal Links/App Links from a certain domain.

I'd like to be able to customize react-native link and have it make these changes after it runs. For now, a script reading from a config file would be an improvement: one more command you run after react-native link and you're done. But at any rate, JS in the react-native-branch module will never be the whole solution.

But generally this is a one-time configuration setup. I'm not sure why you'd need to automate this when you do builds. I'm sure there's a good reason though. I don't suppose you're using Fastlane? It wouldn't be that hard to provide a Fastlane plugin to do your Branch setup. That might not be a bad idea anyway, if there's a significant need out there to automate this beyond initial setup.

Can you remind me what version of RN and react-native-branch you're using? I think you might still be using RN 0.39. I don't really want to introduce new features into the 0.9 branch. In fact, it's getting harder to support RN 0.39 for certain reasons (mainly setting up a test environment isn't straightforward). At worst, for the time being you could pull the script from the master branch to try it out.

If you can live with a Ruby script or a Fastlane plugin, I can get something done in the next week or two, say. If you need something more polished and integrated with RN/JS, it will require a little research and take a bit longer.

"react-native": "0.41.2",
"react-native-branch": "^2.0.0-beta.1"
  1. Destructuring subscribe: - yep, that's the struggle when it's a method on a class and not just an export const. Probably would be better as an export const. You'd have you rip the methods off the class and then replaces all the this references with local variables/functions.

  2. Branch config:

Some settings changes are always needed to let the OS know that this app supports a certain URI scheme or Universal Links/App Links from a certain domain.

Yep, totally understand. And it would be awesome, as you realize, to make that part of the react-native link script.

And we're using BuddyBuild - not Fastlane - same thing though. I wonder if you're trying to bite off more than you should chew? I think it should be just your plugin's job to expose the key/app_domain setters and leave the way we get those keys in the JS up to the developer.

For the record, I'm not really saying there is a problem with your install steps. I realize there are lots of things to do it in - adding the intent filters, URI Schemes, Associated Domains in Xcode, etc.. I personally think moving those keys to the JS is a higher priority and then optimizing the install process would be second. Developers can get the plugin installed because you have good documentation on how to do it. What we need is for a way to be able to configure the plugin from the JS side. Just my two cents 馃憤

There is actually a much bigger problem with setting the Branch key in JS: It has to be set before the native layer is initialized, and that happens before the JS is loaded. For the same reason, e.g., setDebug() does not work in JS.

That means this requires a pretty big architectural change to the module, and that means it's not going to happen right away. I'd like to change that for other reasons. Since this is important to you, I'll prioritize it and do some research into what is required and what the impact will be. Until now, it's just been something to look into. One definite consequence will be potential delays in getting back any initial link at launch, since the call to the Branch API will not occur until after the JS loads. Currently, these two things happen in parallel.

But maybe there's a simpler way for you to make your life easier without this better solution. I suspect what you're doing is just trying to use the correct Branch key for each build, maybe just use the test key for debug builds and the live key for release builds.

That's pretty simple:

iOS

Add both keys to your Info.plist as described here. (Make the value a dictionary and add both a "test" key and a "live" key.)

Then in AppDelegate.m, in application:didFinishLaunchingWithOptions:, before calling [RNBranch initSessionWithLaunchOptions:isReferrable:], just add:

#ifdef DEBUG
    [RNBranch useTestInstance];
#endif

#### Android

Add both keys to your AndroidManifest.xml as described here. (Add another meta-data for io.branch.sdk.BranchKey.test.)

Which key is used is controlled by another metadata key:

<meta-data android:name="io.branch.sdk.TestMode" android:value="true" /> <!-- Set to true to use Branch_Test_Key -->

To set this flag for certain builds, add it to the manifest for that build type or flavor. For example, you can add that flag to android/app/src/debug/AndroidManifest.xml if you have a buildType called debug in your app's build.gradle. RN defines a release buildType by default, so you can also set the flag to true in the main manifest and set it to false in android/app/src/release/AndroidManifest.xml.

Maybe this isn't exactly what you're trying to do, but you can probably accomplish it using this sort of approach.

If this doesn't help, I'm sure I can provide a script soonish.

@jdee Thanks for the response. Glad you are trying to find a workaround for us. That being said..

#ifdef DEBUG
    [RNBranch useTestInstance];
#endif

What is this DEBUG variable we're checking? If it's the Build Configuration:
image
this won't work because when we do our builds for our users to test, they get "archived" before being sent to iTunesConnect and when a project is archived, it uses the Release (for performance reasons) config:
image
What we define as a "dev" build is what data server the build is pointing at - not the build configuration. Make sense?

DEBUG is a C preprocessor macro that is automatically defined in an Xcode project for the Debug configuration. This is to be found in the build settings:

screen shot 2017-04-13 at 10 46 03 am

You can add your own if you like. You can add USE_BRANCH_TEST_INSTANCE=1 and then in your AppDelegate.m change it to

#ifdef USE_BRANCH_TEST_INSTANCE
    [RNBranch useTestInstance];
#endif

How are you telling the build what the server is? I imagine you have it in your env.js, which is probably not available until the RN app loads. But at the moment you're doing something "hacky," so you must be modifying the Info.plist in the iOS app.

Unfortunately for iOS I may not be able to come up with anything less hacky. The right answer in a native iOS app is to use a custom build configuration and scheme. For example, to archive a build that points to a staging server, you could copy the Release configuration, call it Release-Staging and then create a new scheme called GreatJonesStreet-Staging that would use that configuration in the archive step instead of Release. Then you'd set USE_BRANCH_TEST_INSTANCE in Release-Staging but not in Release.

Then when you archive GreatJonesStreet-Staging, you get a Release build that points to the test environment.

Unfortunately, RN itself doesn't support this on iOS. See #104. People hack up their own support for adding custom build configurations to RN Xcode projects, but that's probably no less hacky than than whatever you're currently doing. The only benefit might be that eventually RN has to support custom configurations, so the hackiness might disappear on its own eventually.

You can certainly do this on Android using productFlavors in Gradle instead of buildTypes. I haven't done that with Android and Gradle myself, but I can advise if you want to try it.

@jdee Why don't we do a Google Hangout and then I can follow-up and right up our solution here? Might be easier to show you what we're doing/trying to do. Shoot me an email to setup a time: [email protected]

@dwilt Good news. I was wrong. Took me a while to recall you're using CocoaPods, so what you want to do on iOS is easy. See PR #166 and the webview_example_native_ios, which also uses the React pod. There's now a separate WebViewExample-Test scheme that uses the Branch test key, while the WebViewExample scheme uses the live key. This is independent of whether you're doing a Debug or Release build, so you can archive both ways.

screen shot 2017-04-14 at 7 48 26 pm

We can go over the details Monday. Have a good weekend.

@dwilt I've added a document with detailed instructions for what I was talking about.

https://github.com/BranchMetrics/react-native-branch-deep-linking/blob/master/docs/branch-environments.md

Option 2 (Advanced) is what I was recommending. The Xcode setup is a little involved, but you do it once, and then you don't have to do anything to the project configuration at build time to choose the key you want. This might simplify your life a bit, or maybe you'll prefer to stick with what you're doing until we can provide JS support.

I also did some work on the Fastlane plugin I talked about. See https://github.com/BranchMetrics/react-native-branch-deep-linking/tree/master/examples#automatically-set-up-ios-branch-configuration-experimental.

That plugin could also eventually offer some automated support for setting up custom flavors and schemes.

I was wondering if what discussed in the very first comment cannot be achieved using react-native-config?

@fabriziomoscon Thanks for the suggestion. If it's possible to read the configuration in the native code before the JS is initialized, that might be a good solution. I'll investigate.

Hi @jdee! Has any progress been made on this? I'd love to be able to set these values in JS for the reason @dwilt suggested above:

having it in the JS is very easy because we can generate one env.js file

I actually use react-native-config, which was suggested by @fabriziomoscon. If we can get Branch to work with react-native-config, that would be fantastic.

Was this page helpful?
0 / 5 - 0 ratings