15

I'm implementing deep linking with expo in my react native app. I've managed to do it using this code with this tutorial and this documentation for adjusting it to my nested stacks:

const linking = {
  prefixes:[prefix],
  config: {
    screens: {
      Drawer: {
        screens: {
          Tabs: {
            screens: {
              Profile:"profile"
            }
          }
        }
      },
    }
  }
}
return (
  <NavigationContainer linking={linking}>
    <RootStackScreen actions={actions} showLoader={showLoader} user={user} {...props} />
  </NavigationContainer>
)

}

If I use myscheme://profile it works as expected, but only if the app is opened in the background. When the app is closed, then it just open it in my initial home screen, I tried googling and searching but couldn't find any explanation that fits what I did. I also tried adding the getInitialRoute function to linking, which triggers when the app was closed and was opened from a deep link, but couldn't figure how I can use it to activate the navigation.

async getInitialURL() {
  const url = await Linking.getInitialURL(); // This returns the link that was used to open the app
  if (url != null) {
    //const { path, queryParams } = Linking.parse(url);
    //console.log(path,queryParams)
    //Linking.openURL(url) 
    return url;
  }
  
},
sagi
  • 40,026
  • 6
  • 59
  • 84
  • Something similar to this please help https://stackoverflow.com/questions/71245836/react-navigation-deep-linking-if-the-app-is-closed – Enver Köseler Feb 24 '22 at 01:00

5 Answers5

3

I suppose that you confirmed that your function getInitialURL is getting called when your app is launched? Also, the commented code within the if (url != null) { aren't supposed to be commented right?

If the above is fine then the issue could be related to the debugger being enabled. As per React Native's documentation (https://reactnative.dev/docs/linking#getinitialurl):

getInitialURL may return null while debugging is enabled. Disable the debugger to ensure it gets passed.

Ketan Malhotra
  • 1,255
  • 3
  • 16
  • 44
  • Yea, the commented code is different things I tried but didn’t work, and it is being called when app was launched from deep link(it logged the same url I used). I’m testing this in expo go, so maybe it’s related? – sagi Jun 11 '21 at 07:56
  • Expo could be the issue. I haven't used expo in a while. Btw, is there even a possible scenario in which you're going to be opening scheme://xxxxx when the app is closed in the release build? – Ketan Malhotra Jun 11 '21 at 09:21
  • 1
    Worked for me when I stopped the debugger ! Nice – EZECKIEL TOSSEDE NOUDEGBESSI Mar 29 '22 at 07:15
2

I was experiencing this same issue and doing the following helped me

  • From the component at the root of your navigation stack, where you configure deep linking, add the following code:
const ApplicationNavigator = () => {

  
  useEffect(() => {
    // THIS IS THE MAIN POINT OF THIS ANSWER
    const navigateToInitialUrl = async () => {
      const initialUrl = await Linking.getInitialURL()
      if (initialUrl) {
        await Linking.openURL(initialUrl)
      }
    }
    navigateToInitialUrl()
  }, [])

  const linking = {
    prefixes: ['<your_custom_scheme>://'],
    config: {
      /* configuration for matching screens with paths */
      screens: {},
    },
  }

  return (
    // Your components/navigation setup
  )
}

So apparently, your app received the url but somehow "uses" it to wake the app up from background. When it is in the foreground, the useEffect runs and uses the URL to navigate to the intended screen.

PS: Make sure that your linking tree matches your app tree

Pila
  • 5,460
  • 1
  • 19
  • 30
1

Based on https://documentation.onesignal.com/v7.0/docs/react-native-sdk#handlers

Deep linking in iOS from an app closed state

You must be Modify the application:didFinishLaunchingWithOptions in your AppDelegate.m file to use the following:

NSMutableDictionary *newLaunchOptions = [NSMutableDictionary dictionaryWithDictionary:launchOptions];
    if (launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey]) {
        NSDictionary *remoteNotif = launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey];
        if (remoteNotif[@"custom"] && remoteNotif[@"custom"][@"u"]) {
            NSString *initialURL = remoteNotif[@"custom"][@"u"];
            if (!launchOptions[UIApplicationLaunchOptionsURLKey]) {
                newLaunchOptions[UIApplicationLaunchOptionsURLKey] = [NSURL URLWithString:initialURL];
            }
        }
    }

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

also in reactnavigation:

https://reactnavigation.org/docs/deep-linking/

const linking = {
    prefixes: ["https://example.com", "example://"],
    config,
    async getInitialURL() {
      const url = await Linking.getInitialURL();
      if (url != null) {
        return url;
      }
    },
  };

<NavigationContainer linking={linking}>
   ...
</NavigationContainer>
Farhood
  • 197
  • 3
  • 5
  • 9
0

There are a couple of things you can check.

  • Verify that the structure for linking.config matches your navigation structure. I've had a similar issue in the past, and resolved it by making sure my config structure was correct.

  • Ensure that the linking object is setup properly. Refer to the docs to verify. From the looks of it, the linking object you've showed doesn't have the getInitialURL property in it.

  • Confirm that you've setup the native side of things as documented.

Hopefully something works out! Let me know if it doesn't.

Hamza
  • 206
  • 3
  • 6
  • 1
    Thanks for the answer. I assume I configured my config correctly, because the deep link works when the app is already opened. It fails when the app is closed though. I also specified I tried adding the `getInitialURL` property as mentioned at the end of the question, but it didn't change anything, so maybe I used it wrong but I don't know what I can change.. – sagi Jun 09 '21 at 09:42
-1

I was having the same problem. In iOS(flutter build) I solved this by adding "Content Available." The article is here: Apple Content Available Document. I am using OneSignal so in the api I added that field. Now even if the app is forced closed it awakes and deep links work. For Onesignal I had to use "content_available" : true. The complete Onesignal postman code is:

{
  "app_id": "1234",
  "included_segments": ["Test"],
  "content_available" : true,
  "contents": {
                "en": "Hi"
            },
            "data": {
                "dynamic_link": "https://google.com"
            },
            "headings": {
                "en": "Testing"
            }
}