Deep links in a React Native app
@mocco/react-native/links does three things in your app:
When a Mocco link opens the app, it tells you which screen to show.
On Android, when someone installed the app from a link, it finds that link at first launch.
It makes share links for content in your app.
It has no native code of its own. You pass in a few things your app already has.
Before you start
Set up your link host and your app's details, and make links open the app (see Make links open the app). Without that, the phone opens links in the browser instead of your app.
Create a Publishable key with
links:appunder API keys in the project (see Create links from your server or app). It is safe to ship in the app.
Install
npx expo install @mocco/react-native @react-native-async-storage/async-storage expo-applicationIn a bare React Native app, install @mocco/react-native, @react-native-async-storage/async-storage and react-native-play-install-referrer instead.
Set it up
Create it once, when the app starts:
import AsyncStorage from '@react-native-async-storage/async-storage';
import * as Application from 'expo-application';
import { Linking, Platform } from 'react-native';
import { createMoccoLinks } from '@mocco/react-native/links';
export const links = createMoccoLinks({
publishableKey: 'mk_pub_…',
// Your link hosts: your own link domain and Mocco's host for the project.
domains: ['go.example.com', 'acme.<link domain>'],
linking: Linking,
storage: AsyncStorage,
appVersion: Application.nativeApplicationVersion ?? '0.0.0',
platform: Platform.OS,
installReferrer: Platform.OS === 'android' ? () => Application.getInstallReferrerAsync() : undefined,
onError: error => console.warn('Mocco links', error),
});In a bare app, read the referrer with react-native-play-install-referrer and pass a function that returns its installReferrer string.
Use the hosts shown on the Deep links settings page. Links on other hosts, and your app's own URL scheme, are left to your app's usual handling.
Open the right screen
onLink hears the link that started the app and every link that opens it later. Each event has the path into your app (path), the link's params and campaign, and source: link when the phone opened the app with the link, deferred when the link led to the install.
With React Navigation, put your link hosts in prefixes and hand Mocco's path to getStateFromPath:
import { NavigationContainer, getStateFromPath } from '@react-navigation/native';
const linking = {
prefixes: ['https://go.example.com', 'https://acme.<link domain>'],
config: { screens: { Product: 'products/:id' } },
// The phone hands the app the short link; Mocco answers its path.
async getInitialURL() {
return null;
},
subscribe(listener: (url: string) => void) {
const stop = links.onLink(event => {
const query = new URLSearchParams(event.params).toString();
listener(`https://go.example.com${event.path}${query === '' ? '' : `?${query}`}`);
});
return stop;
},
getStateFromPath,
};
export function App() {
return <NavigationContainer linking={linking}>{/* … */}</NavigationContainer>;
}getInitialURL returns null because onLink already delivers the link that started the app, including one that arrives before your first screen subscribes.
Call links.resolveDeferred() once your first screen is ready. On Android, the first launch after an install from a link opens the linked screen through the same onLink listener. It asks Mocco only once per install and never throws: if anything goes wrong, the app just opens as usual.
On iOS, the link's landing page copies a one-time code when someone taps Get the app (see Deferred links on iOS). To pick it up at first launch, add expo-clipboard and opt in:
import * as Clipboard from 'expo-clipboard';
export const links = createMoccoLinks({
// …as above
ios: { readClipboardOnFirstLaunch: true, clipboard: Clipboard },
});resolveDeferred() then reads the clipboard once, at first launch only, and uses it only when it holds exactly a Mocco code. It never writes or clears the clipboard. Reading may show iOS's paste prompt; to avoid it, leave the option off and show expo-clipboard's ClipboardPasteButton on your first screen instead:
<Clipboard.ClipboardPasteButton
acceptedContentTypes={['plain-text']}
onPress={async data => {
if (data.type === 'text') {
await links.resolveFromPaste(data.text);
}
}}
/>Without either, resolveDeferred() on iOS records the first launch and answers none.
Make a share link
const { url } = await links.createLink({
deepLinkPath: '/products/42',
params: { ref: 'share' },
og: { title: 'Ceramic mug', description: 'Hand-made, 350 ml' },
});The same content gets the same link back, so you can make the link each time someone taps Share. Share links always fall back to your app's store pages. createLink throws when the link can't be made, for example when the project has made too many share links today.
What's kept on the phone
The SDK keeps two values in the storage you pass in: a random install ID that it makes once (not a device identifier), and the answer to the first-launch check. Mocco doesn't store the phone's IP address or browser details.
Test it
A link that opens the app: install a build that includes your app's link details, then tap a link in Notes or Messages. A link pasted into the browser's address bar opens the web page instead.
iOS installs from a link: this needs the App Store or TestFlight. Delete the app, open a link in Safari on the iPhone, tap Get the app, install, and open the app. It should land on the linked screen. Then tap Open in app on the same page with the app installed: it should open the app.
Android installs from a link: this needs Google Play, so use an internal testing track. Uninstall the app, tap a link on the phone, install from Play, and open the app. It should land on the linked screen.
Logs: pass
onErrorwhile testing. A link that Mocco doesn't know, or a network error, shows up there.
Related
Deferred deep links — the same calls for apps without the SDK