Universal Links with React Native (iOS)

It is initially downloaded on the install of the app and then is periodically (our hypothesis is every 24 hours from initial app install) re-installed.

If changes to the available universal link routes appear to not be taking, try deleting the app and re-installing it.

Handling Universal Links from Within React NativeNow for the fun partShort Version:Manage your Linking callbacks via AppState callbacks for the most seamless integration.

Long Version:Short note before we get started, when you see Navigation in the code, it is the most excellent react-native-navigation library that abstracts modifying the view controller stack.

Substitute it for whatever your team uses to manage the backbone view controller hierarchy of your app.

The way that the iOS native code that handles universal links gets translated into React Native code is via the app life-cycle hook we installed earlier.

The call to RCTLinkingManager goes in one end as Objective-C code and then comes out the other via a callback in React Native on the Linking object.

What this means is we have to begin to get clever about how we handle universal links because React Native is hosted inside the iOS application.

Essentially, we have a problem where there is some design required around which objects handle the Linking callbacks because they may or may not be ready on app launch.

In our particular case, we use CodePush to ensure that our users are on the latest version of the app.

React Native docs recommend that you perform the initial URL fetch and callback registration from within a mounted component, however since we wish to delay execution of handling the URL until after checking the user’s credentials and app version mounted components might get blown away by the latest version download.

Additionally, due to a bug that is expected to be resolved in iOS 13, network calls made before the application’s networking layer is fully online will fail with the fairly cryptic Software caused connection abort.

What we need then is a solution that takes into account the states of Linking (initialURL or callback) as well as AppState (active or not).

This is some of the first code that gets run in the React Native portion of our app.

We register for callbacks that happen when the app state changes (the app gets backgrounded, the app comes back from background, the app terminates).

Then we register for Linking callbacks, events where the user has launched or foregrounded the event via a universal link.

Notably, neither of these callbacks fire at this point because the app has already launched (potentially via a universal link).

We then perform some middle layer of operation.

For us this includes checking to see if the user has valid credentials and waiting for the app to update (if necessary).

We also kick back to the log in screen if the user does not have valid credentials.

Finally, we see if the app happened to be opened via a universal link Linking.

getInitialURL() and handle it at that point.

This is the callback code that fires when the Linking listener gets called.

It also gets called when Linking has an initialURL Our universal links need to make network calls in order to get the data about the resource that the link represents (a pretty typical thing that will need to happen).

In order to avoid the bug I brought up earlier, we perform that network operation await route.

navigationOptions() if and only if the AppState is currently active.

If the AppState is not currently active, we create a “pseudononymous” callback that waits until the AppState change callback is called at which point it deregisters itself and calls the next handler.

We don’t check the app’s state inside the pseudononymous callback because it’s checked in _universalLinksStateChange().

Here we have _genericStateChange which gets fired every time the application changes its state allowing us to pause for updates when it’s foregrounded or when it’s launched.

We also have _universalLinksStateChange which is code that only gets executed if we launched the app from a universal link but had to defer execution of those links due to the app otherwise not being ready.

It’s what is called in the self-deregistering “pseudononymous” listener from above.

These two methods feed into the primary callback _stateChangeFromSource where we update the app and then conditionally handle the universal links if that’s how the app opened.

ConclusionAnd that’s it!.We have a kind of mutex that conditionally waits until two different listener methods are called before proceeding and this allows us to fit inside a nice sweet spot between the primary bundle of our application and the native code that is trying to affect change upon it.

Hope you enjoyed this article and/or found it useful and I’d love to hear additional ideas and feedback if you have them.

Happy coding!.

. More details

Leave a Reply