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

On iOS associated domain links may be recognized as +non_branch_link on startup

Open jrobichaud opened this issue 4 years ago • 4 comments

Description

When using react native iOS with the app closed and a branch associated domain link is clicked, the link is incorrectly recognized as a +non_branch_link.

Specifications

react-native-branch: 5.0.3

Example

Let assume link.example.com is one of our associated domains.

When the app is opened in the background and we click on a branch link (ex: https://link.example.com/BAFAHHXjIgb) we get something like this in branch.subscribe's onOpenComplete which is perfect:

{
  "error": null,
  "params": {
    "$marketing_title": "Test deferred deep link",
    "$one_time_use": false,
    "+click_timestamp": 1622552464,
    "+clicked_branch_link": true,
    "+is_first_session": false,
    "+match_guaranteed": true,
    "screen": "MyScreen",
    "~creation_source": 1,
    "~id": 012345678901234567,
    "~marketing": true,
    "~referring_link": "https://link.example.com/BAFAHHXjIgb"
  },
  "uri": "https://link.example.com/BAFAHHXjIgb"
}

However when the app is killed we get something like this:

{
  "error": null,
  "params": {
    "+clicked_branch_link": false,
    "+is_first_session": false,
    "+non_branch_link": "link.example.com/BAFAHHXjIgb",
    "+rn_cached_initial_event": true
  },
  "uri": null
}

Notice the https:// is missing but it is really the associated domain.

Note: it does not do that with android.

Workarounds

Patch it in the javascript

branch.subscribe({
    onOpenComplete: (res) => {
        const {params, error} = res;
        if (error) {
            console.warn(`Error from Branch: ${error}`);
            return;
        }

        const nonBranchUrl = params['+non_branch_link'];
        if (!params['+clicked_branch_link'] && !nonBranchUrl) {
            // Indicates initialization success and some other conditions.
            // No link was opened.
            return;
        }

        // Route non-Branch URL if appropriate.
        if (nonBranchUrl) {
            // START PATCH incorrect +non_branch_link
            if (
                nonBranchUrl.startsWith(Config.BranchLinkUrl) ||
                nonBranchUrl.startsWith(Config.BranchLinkAltUrl) ||
                nonBranchUrl.startsWith(Config.BranchLinkTestUrl) ||
                nonBranchUrl.startsWith(Config.BranchLinkTestAltUrl)
            ) {
                branch.openURL(`https://${nonBranchUrl}`);
                return;
            }
            // END PATCH incorrect +non_branch_link
            //...
        }
    },
    checkCachedEvents: true,
})

Fix it in the iOS SDK (ios-branch-deep-linking-attribution)

I managed to "patch" the problem directly in the iOS sdk but the problem may come from elsewhere, not sure what is the root cause of the problem.

In: https://github.com/BranchMetrics/ios-branch-deep-linking-attribution/blob/a8eed23b6257382f878d1594827d82f2080502c2/Branch-SDK/Branch.m#L719-L724

I changed:

    NSString *scheme = [url scheme];
    if ([scheme isEqualToString:@"http"] || [scheme isEqualToString:@"https"]) {
        return [self handleUniversalDeepLink_private:url.absoluteString sceneIdentifier:sceneIdentifier];
    } else {
        return [self handleSchemeDeepLink_private:url sceneIdentifier:sceneIdentifier];
    }

For:

    NSString *scheme = [url scheme];
    if (!scheme) {
        return [self handleUniversalDeepLink_private:[NSString stringWithFormat:@"https://%@", url.absoluteURL] sceneIdentifier:sceneIdentifier];
    }
    else if ([scheme isEqualToString:@"http"] || [scheme isEqualToString:@"https"]) {
        return [self handleUniversalDeepLink_private:url.absoluteString sceneIdentifier:sceneIdentifier];
    } else {
        return [self handleSchemeDeepLink_private:url sceneIdentifier:sceneIdentifier];
    }

It worked but it might have a few drawbacks (ex: not supporting http urls).

jrobichaud avatar Jun 01 '21 20:06 jrobichaud

Interesting. Thanks for the detailed report!

The workaround on bottom will have issue if you're depending on URI fallbacks. But if you're just using universal links it should be fine.

I'm wondering how the https was removed from what should be a universal link. Gonna spin up a ticket to take a look at this hopefully next sprint.

echo-branch avatar Jun 01 '21 20:06 echo-branch

@echo-branch in the meantime I am going to use the javascript workaround. The second option was more of a POC.

jrobichaud avatar Jun 01 '21 21:06 jrobichaud

Workarounds

Patch it in the javascript

branch.subscribe({
    onOpenComplete: (res) => {
        const {params, error} = res;
        if (error) {
            console.warn(`Error from Branch: ${error}`);
            return;
        }

        const nonBranchUrl = params['+non_branch_link'];
        if (!params['+clicked_branch_link'] && !nonBranchUrl) {
            // Indicates initialization success and some other conditions.
            // No link was opened.
            return;
        }

        // Route non-Branch URL if appropriate.
        if (nonBranchUrl) {
            // START PATCH incorrect +non_branch_link
            if (
                nonBranchUrl.startsWith(Config.BranchLinkUrl) ||
                nonBranchUrl.startsWith(Config.BranchLinkAltUrl) ||
                nonBranchUrl.startsWith(Config.BranchLinkTestUrl) ||
                nonBranchUrl.startsWith(Config.BranchLinkTestAltUrl)
            ) {
                branch.openURL(`https://${nonBranchUrl}`);
                return;
            }
            // END PATCH incorrect +non_branch_link
            //...
        }
    },
    checkCachedEvents: true,
})

How do you import Config for Config.BranchLinkUrl?

rukmanary avatar Jul 06 '21 15:07 rukmanary

Workarounds

Patch it in the javascript

branch.subscribe({
    onOpenComplete: (res) => {
        const {params, error} = res;
        if (error) {
            console.warn(`Error from Branch: ${error}`);
            return;
        }

        const nonBranchUrl = params['+non_branch_link'];
        if (!params['+clicked_branch_link'] && !nonBranchUrl) {
            // Indicates initialization success and some other conditions.
            // No link was opened.
            return;
        }

        // Route non-Branch URL if appropriate.
        if (nonBranchUrl) {
            // START PATCH incorrect +non_branch_link
            if (
                nonBranchUrl.startsWith(Config.BranchLinkUrl) ||
                nonBranchUrl.startsWith(Config.BranchLinkAltUrl) ||
                nonBranchUrl.startsWith(Config.BranchLinkTestUrl) ||
                nonBranchUrl.startsWith(Config.BranchLinkTestAltUrl)
            ) {
                branch.openURL(`https://${nonBranchUrl}`);
                return;
            }
            // END PATCH incorrect +non_branch_link
            //...
        }
    },
    checkCachedEvents: true,
})

How do you import Config for Config.BranchLinkUrl?

@rukmanary we use react-native-config

import Config from 'react-native-config';

jrobichaud avatar Jul 06 '21 17:07 jrobichaud