Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

iOS Linking getInitialURL() always null #24429

Closed
matthieupinte opened this issue Apr 12, 2019 · 76 comments
Closed

iOS Linking getInitialURL() always null #24429

matthieupinte opened this issue Apr 12, 2019 · 76 comments
Labels
API: Linking Bug Platform: iOS iOS applications. Stale There has been a lack of activity on this issue and it may be closed soon.

Comments

@matthieupinte
Copy link

🐛 Bug Report

I can't get the deep link url that was called when my app is started on iOS.
Tried with Linking.getInitialUrl() promise and by listener addEventListener('url'...)
None of these methods return the initial url.

When the app is in background, the listener addEventListener('url', ...) is working well, and we can get the url. But when the app is launched via a deeplink, we don't have it.

I tried on React Native 0.53.3 it's working via getInitialUrl() and listener.
I tried on React Native 0.59.4 not working.

To Reproduce

1. Add URL type to info.plist.

2. Add this to your AppDelegate.m :

#import <React/RCTLinkingManager.h>
...
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url
  sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
{
  return [RCTLinkingManager application:application openURL:url
                      sourceApplication:sourceApplication annotation:annotation];
}

3. and just to test, update your App.js to look like this :

import React, { Component } from 'react';
import {
  Platform,
  StyleSheet,
  Text,
  View,
  Linking
} from 'react-native';

type Props = {};
export default class App extends Component<Props> {
  componentDidMount() {
    Linking.getInitialURL().then((url) => { console.log('1', url) })
    Linking.addEventListener('url', this.handleOpenURL);
  }
  componentWillUnmount() {
    Linking.removeEventListener('url', this.handleOpenURL);
  }
  handleOpenURL(event) {
    console.log('2', event.url);
  }

  render() {
    return (
      <View style={styles.container}>
        <Text style={styles.welcome}>
          Welcome to React Native!
        </Text>
      </View>
    );
  }
}

Expected Behavior

I expect to get the initial URL called via deeplink via getInitialUrl or listener handler.

Environment

info
  React Native Environment Info:
    System:
      OS: macOS 10.14.4
      CPU: (8) x64 Intel(R) Core(TM) i7-6820HQ CPU @ 2.70GHz
      Memory: 205.05 MB / 16.00 GB
      Shell: 5.3 - /bin/zsh
    Binaries:
      Node: 11.11.0 - /usr/local/bin/node
      Yarn: 1.15.2 - /usr/local/bin/yarn
      npm: 6.7.0 - /usr/local/bin/npm
      Watchman: 4.9.0 - /usr/local/bin/watchman
    SDKs:
      iOS SDK:
        Platforms: iOS 12.2, macOS 10.14, tvOS 12.2, watchOS 5.2
      Android SDK:
        API Levels: 19, 23, 24, 25, 26, 27, 28
        Build Tools: 23.0.1, 24.0.1, 25.0.0, 25.0.2, 25.0.3, 26.0.1, 26.0.2, 26.0.3, 27.0.3, 28.0.3
        System Images: android-19 | Google APIs ARM EABI v7a, android-19 | Google APIs Intel x86 Atom, android-23 | Google APIs Intel x86 Atom, android-25 | Google Play Intel x86 Atom, android-27 | Google APIs Intel x86 Atom
    IDEs:
      Android Studio: 3.3 AI-182.5107.16.33.5264788
      Xcode: 10.2/10E125 - /usr/bin/xcodebuild
    npmPackages:
      react: 16.8.3 => 16.8.3
      react-native: 0.59.4 => 0.59.4
    npmGlobalPackages:
      create-react-native-app: 1.0.0
      react-native-git-upgrade: 0.2.7

Thanks for your time ;)

@dmitri-wm
Copy link

dmitri-wm commented Apr 14, 2019

same here
https://github.com/dmitri-wm/deep-linking-sample sample fresh installed app with deep linking setup for IOS
@matthieupinte did you find workaround?

@dmitri-wm
Copy link

React native 0.58.5 works fine

@matthieupinte
Copy link
Author

matthieupinte commented Apr 23, 2019

@dmitri-wm No, I don't have more information... and we can't go back to 0.58.5 because of Android requirements.

Android has supported 64-bit CPUs since 5.0 Lollipop, and the Play Store in 2017 announced that apps using native code must provide a 64-bit version in light of future chips that only support 64-bit code.

And I heard somewhere that only RN 0.59.x has support for Android 64-bit...

@alangumer
Copy link

On Android getInitialURL() works as expected, the issue is on iOS, url always comes up null.
react-native 0.59.x

@nicolegrinstead
Copy link

I just encountered the same issue. getInitialURL was always null on iOS with react-native 0.59.x. I downgraded to 0.58.5 and it works as expected.

@delch
Copy link

delch commented May 6, 2019

Have the same problem on RN 0.59.

npmPackages:
  react: 16.8.3 => 16.8.3 
  react-native: 0.59.4 => 0.59.4 

@jsellam
Copy link

jsellam commented May 6, 2019

Hi,
In my project with react-navigation 3.9.1 and react-native 0.59.5 deep linking don't work on ios simulator when "Debug JS remotely" is enabled, but work well when the debug is disabled.
Could you try getInitialURL() without debug mode ?

@jsellam
Copy link

jsellam commented May 7, 2019

I confirm getInitialURL() is always null when Debug JS remotely is enabled ( I use React Native debugger 0.9.7)

@MatthewPattell
Copy link

MatthewPattell commented May 10, 2019

Hi,
I have same problem in IOS. (Working only when remote debugging is disabled)

  react: 16.8.3 
  react-native: 0.59.5 (and 0.59.8)

Xcode:

- (BOOL)application:(UIApplication *)application
            openURL:(NSURL *)url
            options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {
  
  BOOL handledFB = [[FBSDKApplicationDelegate sharedInstance] application:application
                                                                openURL:url
                                                      sourceApplication:options[UIApplicationOpenURLOptionsSourceApplicationKey]
                                                             annotation:options[UIApplicationOpenURLOptionsAnnotationKey]
                  ];
  
  BOOL handleCustom = [RCTLinkingManager application:application openURL:url options:options];

  return handledFB || handleCustom;
}

@GioLogist
Copy link

GioLogist commented May 11, 2019

I can second this. Working on Android, not iOS

"react": "16.8.3",
"react-native": "0.59.3",

Edit: Can also confirm that its only when remote debugging is enabled.

@ValerianThomas
Copy link

ValerianThomas commented May 11, 2019

Hi,
In my project with react-navigation 3.9.1 and react-native 0.59.5 deep linking don't work on ios simulator when "Debug JS remotely" is enabled, but work well when the debug is disabled.
Could you try getInitialURL() without debug mode ?

I also confirm : Linking.getInitialURL() will return your url once Debug JS Remotely is disabled

@ducNgbk
Copy link

ducNgbk commented May 13, 2019

Confirm Linking.getInitialURL() and Linking.addEventListener('url', () => {}) not work

  • iOS
  • 0.59.5
  • Simulator
  • Universal Link

#UPDATE: my mistake. I solved it by adding this method to AppDelegate.m

- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void (^)(NSArray * _Nullable))restorationHandler {
  return [RCTLinkingManager application:application
                   continueUserActivity:userActivity
                     restorationHandler:restorationHandler];
}

@chenliez
Copy link

chenliez commented May 14, 2019

Confirmed Linking.getInitialURL() always returns null when remote debug is enabled.
iOS
0.59.8
Simulator
Universal Link

@r281GQ
Copy link

r281GQ commented May 16, 2019

Strange enough. Android simulator, android real device works. Real iPhone works. Simulator only works when debugging disabled.

Info
React Native Environment Info:
System:
OS: macOS 10.14.4
CPU: (8) x64 Intel(R) Core(TM) i7-6700HQ CPU @ 2.60GHz
Memory: 74.79 MB / 16.00 GB
Shell: 5.3 - /bin/zsh
Binaries:
Node: 10.10.0 - /usr/local/bin/node
Yarn: 1.15.2 - /usr/local/bin/yarn
npm: 6.7.0 - /usr/local/bin/npm
Watchman: 4.9.0 - /usr/local/bin/watchman
SDKs:
iOS SDK:
Platforms: iOS 12.2, macOS 10.14, tvOS 12.2, watchOS 5.
IDEs:
Android Studio: 3.1 AI-173.4720617
Xcode: 10.2.1/10E1001 - /usr/bin/xcodebuild
npmPackages:
react: 16.8.3 => 16.8.3
react-native: 0.59.5 => 0.59.5
npmGlobalPackages:
react-native-cli: 2.0.1
react-native-git-upgrade: 0.2.7

@ryanliszewski
Copy link

I can also confirm it's not working on iOS when remote debugging is enabled.

"react": "16.8.3",
"react-native": "0.59.3",

@Bardiamist
Copy link
Contributor

Bardiamist commented Jun 1, 2019

I checked in my application using react-native@0.59.8 and Xcode 10.2.1.

It works. Try it:

- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options
{
  return [RCTLinkingManager application:app openURL:url options:options];
}

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

Update: I see what problem exist only when Debug JS Remotely enabled.
Suggestion: Use Reactotron for debug this.
Also I think it can be related with this commit.

@argentounce
Copy link

It also happens when Live Reload is active or with any instance that refreshes bundled JS. To test is needed to be disconnected from debug and reload react-native@0.59.9 && Xcode 10.2.1

@marf
Copy link

marf commented Jun 29, 2019

Same problem here

@uguraktas
Copy link

can you try ?

getInitialUrl = async () => { const url = await Linking.getInitialURL() return url }

@todorone
Copy link

todorone commented Jul 5, 2019

Yeah, pretty annoying issue, does anybody tracked commit, that introduced this regression?

@iljadaderko I see You fixed universal links recently, maybe some ideas on where it has been introduced?

@xzilja
Copy link
Contributor

xzilja commented Jul 5, 2019

@todorone hard to tell. My change didn't touch that area.

For iOS native code is defined here
https://github.com/facebook/react-native/blob/master/Libraries/LinkingIOS/RCTLinkingManager.m#L147-L161

And JavaScript implementation is here
https://github.com/facebook/react-native/blob/master/Libraries/Linking/Linking.js#L86-L92

Judging by what I can see, these are being worked on right now, there was also change to use TurboModules, perhaps that affected it somehow?

@KurtMakesWeb
Copy link

KurtMakesWeb commented Aug 7, 2019

Same here, also getting null back from getInitialURL on iOS.

Edit: Seems to work but only when debug/live reload is not active.

@alexsoul95
Copy link

Any updates on this issue?
Can confirm that is not working on react-native: 0.59.10, iOS + debugging on
As a workaround, turn off debugging and use Reactotron or maybe Alert dialog to show urls.

@ghost
Copy link

ghost commented Oct 26, 2020

I believe that we still have an issue with this.

I'm trying to implement OneSignal for React Native, but, I can't make DeepLinking work properly wen iOS app is closed / killed. Initial URL is always null in this scenario.

                                     Android | iOS
              Deep link (app in bg):    ✅   |  ✅
             Deep link (app closed):    ✅   |  ✅
 Notification Deep link (app in bg):    ✅   |  ✅
Notification Deep link (app closed):    ✅   |  ❌

I don't know if it is something related to RN or OS

Could anyone help me with that?

RN 0.63.2

@hellochirag
Copy link

Just discovered this gem. After trying to debug why our deep links don't work on iOS. and here is solution

import dynamicLinks from '@react-native-firebase/dynamic-links';

dynamicLinks().getInitialLink()
      .then(link => {
    // this method will call when app is closer or killed
        console.log('dynamicLinksnew :', link);
      });
dynamicLinks().onLink(async (link) => {
      // this method call when app is in background or foreground 
     console.log('dynamicLinks :', link);
 });

@yuriiforlita
Copy link

@emilioheinz Do you have any ways how to resolve this issue?

@ghost
Copy link

ghost commented Nov 20, 2020

@yuriiforlita Nope, no idea!

@FFMerlin-aracom
Copy link

FFMerlin-aracom commented Nov 27, 2020

This is still an issue. I'm on react-native 0.61.5 and XCode 12.1. Even with the remote debugger disabled,Linking.getInitialURL()always returns null. I've debugged through the AppDelegate file and the RCTLinkingManager receives the correct deeplink url.

@hnqlv
Copy link

hnqlv commented Dec 16, 2020

I can confirm that disabling the debug mode as suggested above was enough for me to get the initial URL 👍

"react-native": "^0.63.2",
"@react-navigation/native": "^5.7.4"

@joelrorseth
Copy link

joelrorseth commented Jan 15, 2021

I have been experiencing this issue as well, I can also confirm that Linking.getInitialUrl() always returns null when "Debug JS Remotely" is enabled. My experiments on iOS, with react-native 0.60.6:

"Debug JS Remotely" disabled "Debug JS Remotely" enabled
App running
App not running

However, I spent days trying every solution posted above, only to realize that I simply misunderstood how Linking works. From the docs:

1. If the app is already open, the app is foregrounded and a Linking event is fired
You can handle these events with Linking.addEventListener('url', callback).

2. If the app is not already open, it is opened and the url is passed in as the initialURL
You can handle these events with Linking.getInitialURL() -- it returns a Promise that resolves to the url, if there is one.

You must use the appropriate method of retrieving the url, depending on whether the app is currently open. In my experiments, if the app is already running, Linking.getInitialURL() will always return null. And if it is not running, Linking's url event won't be fired.

This is obviously a bit cumbersome if you are trying to accommodate deep linking regardless of whether the app is open. I would abstract this by calling Linking.getInitialUrl() and listening for the url event in your root App component, then seed your other components through props, redux, etc.

I imagine some other people here have also misunderstood this, hopefully this helps a few people out.

@pebehb
Copy link

pebehb commented Feb 12, 2021

I imagine some other people here have also misunderstood this, hopefully this helps a few people out.

@joelrorseth, Can you post here how did you solve it?

@dzpt
Copy link

dzpt commented Mar 23, 2021

got null result on release mode also if app is inactive / closed on iOS.
"react": "16.13.1",
"react-native": "0.63.4",
"@react-navigation/bottom-tabs": "^5.11.3",
"@react-navigation/drawer": "^5.11.5",
"@react-navigation/native": "^5.9.0",
"@react-navigation/stack": "^5.13.0",

@anija
Copy link

anija commented Mar 24, 2021

Disabling debug on simulator solved the problem for me.

@dzpt
Copy link

dzpt commented Mar 24, 2021

@anjia doesn't work for me.
if app is inactive or is killed (have you tested with these cases), notification will not pass any URL.
have to workaround with @melvynhills solution

@lrusso
Copy link

lrusso commented Apr 9, 2021

After three days, for me the solution in iOS was to:

  • Go to the project target, then Build Settings / Search Paths / Header Search Paths and there add the path $(SRCROOT)/../node_modules/react-native/Libraries/LinkingIOS in recursive mode.
  • Adding to the info.plist file the key FirebaseAppDelegateProxyEnabled with a false value.

In iOS, Firebase was blocking the Linking events and the documentation in the Linking page in the React Native website is incomplete regarding how to add the LinkingiOS module.

Hope it may help someone.

@Aurelienlajoinie
Copy link

Aurelienlajoinie commented Jun 10, 2021

Hello,
In my case the problem appears only with deeplink into push notifications (app open by click on notification).
I use a workaround in AppDelegate > didFinishLaunchingWithOptions. This patch allow to "translate" UIApplicationLaunchOptionsRemoteNotificationKey into UIApplicationLaunchOptionsURLKey. In that way RN Linking can consume it and then getInitialURL return the good value :

 NSMutableDictionary *newLaunchOptions = [NSMutableDictionary dictionaryWithDictionary:launchOptions];
  if (launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey]) {
      NSDictionary *remoteNotif = launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey];
    
      // here goes specific selection according to your payload structure 
     // exemple here: { MySubObject : { MysDeeplinkUrlKey : 'my.url.scheme://zizou?number=10' }}
      if (remoteNotif[@"MySubObject"] && remoteNotif[@"MySubObject"][@"MysDeeplinkUrlKey"]) {
          NSString *initialURL = remoteNotif[@"MySubObject"][@"MysDeeplinkUrlKey"];
          if (!launchOptions[UIApplicationLaunchOptionsURLKey]) {
              newLaunchOptions[UIApplicationLaunchOptionsURLKey] = [NSURL URLWithString:initialURL];
          }
      }
  }

  RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:newLaunchOptions];

Hope it can help someone :)

@lucafronterotta
Copy link

Aurelienlajoinie that's exactly what I was looking for my use case, you saved me a lot of time.
THANKS!

@manish-patwari
Copy link

Solved the issue by passing LaunchOptions in RCTBridge. In my case it was nil and hence breaking.

RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions];

@pantomath91
Copy link

After updating my pods with pod install --repo-update, its began to work for me

@fondue-tech
Copy link

This is still issue when you enable debugger.

@github-actions
Copy link

This issue is stale because it has been open 180 days with no activity. Remove stale label or comment or this will be closed in 7 days.

@github-actions github-actions bot added the Stale There has been a lack of activity on this issue and it may be closed soon. label Jul 14, 2023
@github-actions
Copy link

This issue was closed because it has been stalled for 7 days with no activity.

@MatheusLima7
Copy link

Nothing worked for me

@gilons
Copy link

gilons commented May 24, 2024

 
  NSMutableDictionary *newLaunchOptions = [NSMutableDictionary dictionaryWithDictionary:launchOptions];
  // Check if launched from notification
  NSDictionary *notification = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
  if (notification) {
    NSDictionary *custom = notification[@"custom"];
    if (custom) {
      NSString *deepLink = custom[@"u"];
      if (deepLink) {
        if (!launchOptions[UIApplicationLaunchOptionsURLKey]) {
          newLaunchOptions[UIApplicationLaunchOptionsURLKey] = [NSURL URLWithString:deepLink];
        }
      }
    }
  }
  
  RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:newLaunchOptions];
  
  BOOL didFinishLaunchingWithOptions = [super application:application didFinishLaunchingWithOptions:newLaunchOptions];
  

@gilons
Copy link

gilons commented May 24, 2024

Hello, In my case the problem appears only with deeplink into push notifications (app open by click on notification). I use a workaround in AppDelegate > didFinishLaunchingWithOptions. This patch allow to "translate" UIApplicationLaunchOptionsRemoteNotificationKey into UIApplicationLaunchOptionsURLKey. In that way RN Linking can consume it and then getInitialURL return the good value :

 NSMutableDictionary *newLaunchOptions = [NSMutableDictionary dictionaryWithDictionary:launchOptions];
  if (launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey]) {
      NSDictionary *remoteNotif = launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey];
    
      // here goes specific selection according to your payload structure 
     // exemple here: { MySubObject : { MysDeeplinkUrlKey : 'my.url.scheme://zizou?number=10' }}
      if (remoteNotif[@"MySubObject"] && remoteNotif[@"MySubObject"][@"MysDeeplinkUrlKey"]) {
          NSString *initialURL = remoteNotif[@"MySubObject"][@"MysDeeplinkUrlKey"];
          if (!launchOptions[UIApplicationLaunchOptionsURLKey]) {
              newLaunchOptions[UIApplicationLaunchOptionsURLKey] = [NSURL URLWithString:initialURL];
          }
      }
  }

  RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:newLaunchOptions];

Hope it can help someone :)

We are in 2024, I'm still experiencing this issue. In my case, I had deeplinking properly setup with applinks. I wanted to open deeplink from notifications. I'm using Onesignal to forward my notifications to APNs.

From the solution provided by @Aurelienlajoinie, I modified as follows

 
  NSMutableDictionary *newLaunchOptions = [NSMutableDictionary dictionaryWithDictionary:launchOptions];
  // Check if launched from notification
  NSDictionary *notification = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
  if (notification) {
    NSDictionary *custom = notification[@"custom"];
    if (custom) {
      NSString *deepLink = custom[@"u"];
      if (deepLink) {
        if (!launchOptions[UIApplicationLaunchOptionsURLKey]) {
          newLaunchOptions[UIApplicationLaunchOptionsURLKey] = [NSURL URLWithString:deepLink];
        }
      }
    }
  }

@gilons
Copy link

gilons commented May 24, 2024

PS: don't ask me how I managed to know where One Signal store the app_url 😆.

@adriancuadrado
Copy link
Contributor

@gilons

From the solution provided by @adriancuadrado, I modified as follows...

What solution do you mean? I just got a notification and I have no idea what this thread is about. Did you @mention the correct username?

@gilons
Copy link

gilons commented May 24, 2024

Apologies for the wrong mention. This thread is so long.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
API: Linking Bug Platform: iOS iOS applications. Stale There has been a lack of activity on this issue and it may be closed soon.
Projects
None yet
Development

No branches or pull requests