react-native icon indicating copy to clipboard operation
react-native copied to clipboard

iOS Linking getInitialURL() always null

Open matthieupinte opened this issue 6 years ago • 68 comments

🐛 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 ;)

matthieupinte avatar Apr 12 '19 09:04 matthieupinte

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 avatar Apr 14 '19 13:04 dmitri-wm

React native 0.58.5 works fine

dmitri-wm avatar Apr 15 '19 23:04 dmitri-wm

@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...

matthieupinte avatar Apr 23 '19 09:04 matthieupinte

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

alangumer avatar May 01 '19 19:05 alangumer

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.

nicolegrinstead avatar May 05 '19 20:05 nicolegrinstead

Have the same problem on RN 0.59.

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

delch avatar May 06 '19 13:05 delch

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 avatar May 06 '19 17:05 jsellam

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

jsellam avatar May 07 '19 08:05 jsellam

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;
}

MatthewPattell avatar May 10 '19 13:05 MatthewPattell

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.

GioLogist avatar May 11 '19 01:05 GioLogist

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

ValerianThomas avatar May 11 '19 17:05 ValerianThomas

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];
}

ducNgbk avatar May 13 '19 07:05 ducNgbk

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

chenliez avatar May 14 '19 07:05 chenliez

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

r281GQ avatar May 16 '19 10:05 r281GQ

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

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

ryanliszewski avatar May 19 '19 01:05 ryanliszewski

I checked in my application using [email protected] 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.

Bardiamist avatar Jun 01 '19 08:06 Bardiamist

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 [email protected] && Xcode 10.2.1

argentounce avatar Jun 26 '19 23:06 argentounce

Same problem here

marf avatar Jun 29 '19 15:06 marf

can you try ?

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

uguraktas avatar Jul 04 '19 09:07 uguraktas

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?

todorone avatar Jul 05 '19 10:07 todorone

@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?

xzilja avatar Jul 05 '19 13:07 xzilja

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

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

KurtMakesWeb avatar Aug 07 '19 14:08 KurtMakesWeb

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.

alexsoul95 avatar Aug 08 '19 08:08 alexsoul95

having the same issue with RN 60.4, works if turn off remote debugger

jamalx31 avatar Aug 23 '19 21:08 jamalx31

on 0.59.10, tried without the remote debugger, no live reload. Unfortunately, Linking.getInitialURL() is not working for me.

Linking.addListener is working fine... but I need Linking.getInitialURL...

benevbright avatar Sep 08 '19 21:09 benevbright

getInitialUrl() does not work on both ios & android even if I turn off remote debugging mode:

[email protected]
[email protected](10E125)

luatnd avatar Sep 09 '19 10:09 luatnd

Same here. Not working on Anroid with react-native: 0.61.2

jartes avatar Oct 25 '19 10:10 jartes

Sames goes for me, does not work without debug mode

franj0 avatar Oct 29 '19 11:10 franj0

getInitialURL is null on iOS even when not remote debugging or live loading when the app is returning from a dead state opening a deeplink. Hence deeplinks from dead state are broken in the wild.

application openURL gets the correct url in Xcode.

"react-native": "0.59.9",
"react": "16.8.3",

Xcode 11.1.

CooperCodeComposer avatar Oct 30 '19 23:10 CooperCodeComposer

I thought we were having this same issue until I realized it was because our RCTBridge was being torn down and re-initialized between the application launching and getInitialURL being called.

If you look at how RCTLinking works, it fetches the initialURL from the bridge (which is set up when the application launches). If the bridge is re-initialized, so is the state it collected when it was first started, so it returns null. If the bridge does not re-initialize between app launch and getInitialURL (no JS debugging session, etc), it should retain the value it collected at launch.

I recommend checking to see if your RCTBridge is getting invalidated and then re-initialized (as it does when debugging / live-loading). You can look for a line like this in your Xcode console:

Invalidating <RCTCxxBridge: 0x7fb6e7708810> (parent: <RCTBridge: 0x60000341ee60>, executor: RCTWebSocketExecutor)

If you see that, you likely need to figure out why your bridge is being torn down (and losing your launchOptions which contains the initialURL).

You can confirm that this is an issue with the bridge (on iOS) by doing the following:

Add this to the very top of your AppDelegate's application:didFinishLaunchingWithOptions:

[[[UIAlertView alloc] initWithTitle:@"AppDelegate"
                            message:[NSString stringWithFormat:@"%@", launchOptions]
                           delegate:nil
                  cancelButtonTitle:@"OK" otherButtonTitles:nil] show];

And this to RCTLinkingManager's RCT_EXPORT_METHOD(getInitialURL (RCTPromiseResolveBlock)resolve reject:(__unused RCTPromiseRejectBlock)reject)

[[[UIAlertView alloc] initWithTitle:@"getInitialURL"
                            message:[NSString stringWithFormat:@"%@", self.bridge.launchOptions]
                           delegate:nil
                  cancelButtonTitle:@"cancel" otherButtonTitles:nil] show];

Now you won't need to be connected to the debugger to see what the application sees when it launches vs. what RCTLinking fetches from those options.

Also keep in mind that if you're using a push notification service with their own SDK, they might not be using the UIApplicationLaunchOptionsURLKey to store the initial URL, so you may have to dig it out of the UIApplicationLaunchOptionsRemoteNotificationKey instead 🙃

donholly avatar Nov 06 '19 05:11 donholly