I'm developing a React Native app for iOS.
This app has to be able to open deeplinks and it works fine when the app is opened in background. When the app is close, the native iOS code (Objective-C) does not get the URL the app has been opened with.
As I understand how it works, I have to check the NSDictionary of the launchOptions to see if the app has been started through an URL. If the key corresponding to URL initialization exists then I return true to execute the following code
- (BOOL)application:(UIApplication *)application
openURL:(NSURL *)url
options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {
return [RCTLinkingManager application:application openURL:url options:options];
return YES;
}
This is the function that has to bee executed to get the Initial Url which the app has been opened with. Here is my code of app didFinishWithLaunchOptions:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
if ([launchOptions objectForKey:UIApplicationLaunchOptionsURLKey]) {
return true;
}
}
Deep link is a technology that launches an app and opens a specific page in the app once the user clicks a URL on a web page or in another app. Implementing deep links is an exciting way to enhance the user experience by seamlessly allowing users to access the specific page without interruption.
Prompt a non-app user on a smartphone to download the app before directing to specific page or content within the app when the launch it. Direct a user on a desktop or laptop computer to an appropriate page on your website instead of mobile app. Provide attribution data when each link has been clicked.
How to Handle Deep Linking in a React Native Ios App? 1 React Native projects setup in iOS : Configure iOS application to open based on the mymoc:// URI scheme. ... 2 Configuration : In this article we will see how to handle external URIs and after that get a call back from that URIs and move to a specific page in ... 3 References: More items...
If the app wasn't previously open, the deep link needs to set the initial state If the app was already open, the deep link needs to update the state to reflect the incoming link React Native provides a Linking to get notified of incoming links. React Navigation can integrate with the Linking module to automatically handle deep links.
Before we start I would like to explain what deep linking is. Mobile app deep links (also known simply as “deep links”) point to content inside an app. It is useful sometimes to navigate user to a certain screen on app start rather than open a home screen. A general structure of a deep link is the following schemename://path?query_string.
It uses only JavaScript to build a mobile application. It is like React, which uses native components rather than using web components as building blocks. Deep Linking is a technique in which a given URL is used to open a specific page or specific screen in a mobile app, providing a better experience.
The core issue of Intercom not handling deep links for me was that react-native-intercom
does not pass an initial URL to an application through didFinishLaunchingWithOptions
if it's opened from the background.
Instead react-native-intercom
calls the openURL
method immediately after the application is launched and the react-native
part of the application misses this event.
The solution for this was to create a new thread in the openURL
method. Lock it to stop the execution and then unlock the tread when React application gives a signal to the native code, that it's ready to handle deep link. The fix is slightly complicated, so I've created a separate repository, describing the problem and the solution.
The core idea can be described in code as:
dispatch_queue_t queue = dispatch_queue_create("<yourAppName>.openUrlQueue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
while (!DeepLink.canHandleDeepLinks) {
[DeepLink.canHandleDeepLinksLock wait];
}
[DeepLink.canHandleDeepLinksLock unlock];
dispatch_async(dispatch_get_main_queue(), ^{
// This method call will trigger the Linking event with URL to be dispatched to your 'javascript' code
[RCTLinkingManager application:application openURL:url options:options];
});
});
I've created a repository with the solution to this problem. Go, check it out.
While definitely not an answer, I've (terribly) worked around this issue (at least until a canonical solution is available) by changing (or if you don't already have, adding) the - (BOOL)application:(UIApplication *)application continueUserActivity:(nonnull NSUserActivity *)userActivity restorationHandler:(nonnull void (^)(NSArray<id<UIUserActivityRestoring>> * _Nullable))restorationHandler {
in AppDelegate.m
to:
- (BOOL)application:(UIApplication *)application continueUserActivity:(nonnull NSUserActivity *)userActivity
restorationHandler:(nonnull void (^)(NSArray<id<UIUserActivityRestoring>> * _Nullable))restorationHandler
{
NSURL *url = [userActivity webpageURL];
BOOL result = [RCTLinkingManager application:application
continueUserActivity:userActivity
restorationHandler:restorationHandler];
if([userActivity webpageURL]){
#if DEBUG
float seconds = 3.5;
#else
float seconds = 1.5;
#endif
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(seconds * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSURL *newUrl = [NSURL URLWithString:[NSString stringWithFormat:@"MYAPPSCHEME:/%@", url.path]];
[[UIApplication sharedApplication] openURL:newUrl options:@{} completionHandler:nil];
});
}
return result;
}
It basically checks if there's a URL available that caused the launch, and invokes an open URL call to the app after "things have settled down" (as in debug mode it takes longer to load, I've changed to 3.5 seconds which handles it just well). Change the seconds
and of course MYAPPSCHEME
accordingly. And YES, there is a single slash (/) after MYAPPSCHEME:
instead of double as url.path
seems to have a leading slash already. The reason for replacing http[s]
with my app scheme is that for some reason it launches Safari instead of handling deep link if I leave http[s]://
(which is not the case when app is already running and an URL is handled). My app handles custom schemes the same way with regular http links so it works well, but make sure you set it up accordingly for it to work.
After making the above changes and recompiling (don't forget that you're at Objective-C part, not JS/React Native) it worked. I'd love to see an actual solution rather than a hacky workaround, but until then, this fixed it for me.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With