Matt's Tidbits #103 - Launching an app from a URL
Tags: mattstidbits, android, ios, reactnative
Published: 2021-11-02 15:12:38

This week's tidbit will show you how to launch an app when a user clicks on a link. [Last time, I wrote about debugging a view binding issue in Android.](https://medium.com/nerd-for-tech/matts-tidbits-102-debugging-a-perplexing-view-binding-issue-69d2bb81999c)

Have you ever had an app launch on your mobile device when you click a link in an email, on a webpage, etc. and wondered how to do the same thing for your app? Wonder no more, because in this simple guide I will show you how to accomplish this!

#Android
On Android, this can be accomplished by defining an `<intent-filter>` in your app's `AndroidManifest.xml`.

Here's a simple example:
```xml
<intent-filter>
  <action android:name="android.intent.action.VIEW" />
  <category android:name="android.intent.category.DEFAULT" />
  <category android:name="android.intent.category.BROWSABLE" />
  <data 
    android:scheme="https"
    android:host="matthew-b-groves.medium.com"
  >
</intent-filter>
```

Doing something like this would cause any link that began with `https://matthew-b-groves.medium.com` (the URL for my Medium profile) to launch this app instead.

You can even define multiple `<data>` listings to allow multiple URL patterns to invoke your app. *(Note that any possible combination of schemes/hosts that you have defined will match - even across `<data>` entries)*

Depending on your desired behavior, you can even use something completely custom for the `android:scheme`, such as `mattstidbits`, and omit the `android:host` property entirely. This would allow any URL starting with `mattstidbits://` to launch your app. However, this will only work if the user has your app is installed. If you want to direct the user to the Play Store listing for your app if they don't have it installed, you'll want to use an `http` or `https` scheme and a host/domain that you own. Then, you can follow [these instructions](https://developer.android.com/studio/write/app-link-indexing#associatesite) to create a JSON file that you can embed on your website that will instruct browsers to redirect users to the Play Store listing page for your app.

If you want to have your app access information that's embedded in the URL (so you can take them to a specific screen within the app), you'll want to add something like the following to your application's `onCreate` method:
```kotlin
val action: String? = intent?.action
val uri: Uri? = intent?.data
```

You can then verify that the action was `Intent.ACTION_VIEW` and grab the `uri` that was passed in and use the methods/properties of the `Uri` class to pull out information from the URI to help you handle the request.

It's also a good idea to test your deep linking, which you can do on a simulator or physical device using the `adb` command, like this:
```
adb shell am start -d "your-deep-link-url"
```

The Android developer documentation for implementing deep linking is really excellent, which you can find here: https://developer.android.com/training/app-links/deep-linking

#iOS
*Disclaimer: I am not an iOS developer by trade, so I can't provide nearly the level of detail that I can for Android.*

Apple appears to offer two different mechanisms for launching an app from a URL - URL Schemes and Universal Links.

* [URL Schemes](https://developer.apple.com/documentation/xcode/defining-a-custom-url-scheme-for-your-app) are easier/faster to implement, but prompt the user for permission and don't work if the app is not installed.

* [Universal Links](https://developer.apple.com/ios/universal-links/) require you to have control of the domain (much like Google's App Links that I described above), so they require more work to set up, but they won't prompt the user and allow you to provide a fallback URL if the user doesn't have the app installed.

This article does a good job of explaining some of the differences: https://medium.com/wolox/ios-deep-linking-url-scheme-vs-universal-links-50abd3802f97

For now, let's focus on URL Schemes, since that's the approach I have worked with before. To set one up, all you have to do is specify the scheme in Xcode via the Info tab in your project's settings. Note that unlike Android, iOS only lets you define the scheme (the part that comes before the `://` in a URL). So, you could enter `mattstidbits` in the "URL Schemes" field, so any links beginning with `mattstidbits://` would launch your app (if it's installed).

In your `Info.plist` file this shows up under the `CFBundleURLSchemes` key.

If you want your app to access the information that's stored in the URL, then you'll need to handle this inside of your app delegate's `application()` method. There's a `url` argument that will contain the data.

As with Android, you can test these deep links by running the following terminal command:
```
xcrun simctl openurl booted "your-deep-link-url"
```

(Again, I don't pretend to be an iOS developer, so please see the [official documentation](https://developer.apple.com/documentation/xcode/defining-a-custom-url-scheme-for-your-app) for how to do this.)

#React Native
If you've been following my tidbits for a while, you probably wondered if I would touch on this - here's how to do this in React Native!

React Native has two different setups - if you are using Expo, follow [these instructions](https://reactnavigation.org/docs/deep-linking/#set-up-with-expo-projects) to specify the scheme you'd like to use within Expo's JSON config.

However, if you are not using Expo, you generally need to follow the same steps above for iOS/Android to set up deep linking in your `AndroidManifest.xml` and `Info.plist`. To get this working in a React Native CLI project, you should follow [these instructions](https://reactnavigation.org/docs/deep-linking/#set-up-with-bare-react-native-projects) to configure your project. Note that for iOS you'll need to add some special code to your AppDelegate to make this work.

Note that both of these options assume you are using React Navigation for managing navigation within your app (which I highly recommend you do!)

If you want to be able to actually do something with the URL (and not just simply invoke the app), you will need to configure a `linking` object and assign that to your `NavigationContainer`.

The `linking` object is a little funky, in that it's like a copy of your navigation graph. It gives you the power to map URL parameters to internal route names/paths, but does require you to match your app's navigation graph precisely.

For example, you might set this up as follows:
```typescript
const config = {
  screens: {
    Tidbit: 'post/:id',
    Profile: 'user',
  },
};

const linking = {
  prefixes: ['https://matthew-b-groves.medium.com'],
  config,
};

function App() {
  return (
    <NavigationContainer linking={linking}>
      <Stack.Navigator>
        <Stack.Screen name="Tidbit" component={PostDetailScreen} />
        <Stack.Screen name="Profile" component={ProfileScreen} />
      </Stack.Navigator>
    </NavigationContainer>
  );
}
```

Where this can start to get a little tedious is if you have nested navigators (which you likely do), your `linking` object will need to also match that nesting.

For more details, see [this article](https://reactnavigation.org/docs/configuring-links).

To test the link with an Expo project, run the following command (substituting `ios` in place of `android` below if you'd like to change what platform you're targeting):
```
npx uri-scheme open "your-deep-link-url://127.0.0.1:19000" --android
```

For a non-Expo project, you can test the deep linking via the native iOS/Android commands described in the sections above.

#Overall strategies
What can we take away from this?

* Deep linking on both iOS/Android/React Native provides sophisticated functionality.
* In nearly all cases, you probably want your links to have the same format across iOS/Android for consistency's sake (having links work on either platform seamlessly)
* I would recommend starting with the simplest approach and building from there - there can be a lot of red tape to work through to get files changed in your company's/project's website in order to use the more sophisticated App Links (Android) or Universal Links (iOS), so if you're able to get by with the more basic deep linking/URL schemes (where you don't need to modify a website), then start with that.

***

Interested in working with me in the awesome Digital Products team here at Accenture? We have an opening:
* [Mobile Developer (Northeast locations)](https://www.accenture.com/us-en/careers/jobdetails?id=00960583_en&title=Mobile+Developer)

***

Do you have other deep linking tips you'd like to share? Let me know in the comments below!