Skip to content

Commit

Permalink
pr feedback
Browse files Browse the repository at this point in the history
  • Loading branch information
marklawlor committed Jun 13, 2024
1 parent f1d9cf7 commit be5a706
Showing 1 changed file with 46 additions and 47 deletions.
93 changes: 46 additions & 47 deletions docs/pages/router/advanced/native-intent.mdx
Original file line number Diff line number Diff line change
@@ -1,68 +1,67 @@
---
title: Customizing links
description: Learn how to perform link redirection and working with 3rd-party deep-links
description: Learn how to perform link redirection and utilize with third-party deep-links.
---

import { FileTree } from '~/ui/components/FileTree';
import { APIBox } from '~/components/plugins/APIBox';

Expo Router offers a adaptable solution for managing navigation within your Expo app. However, its URL handling philosophy may not align with every use case or integration with third-party services. There are two common scenarios where you may need to customize a link:
Expo Router uses an extended version of web standards to navigate through an app. However, native apps do not always conform to server-based routing, which can lead to misalignment when integrating with third-party services. For example, apps can be launched with arbitrary strings or intent objects instead of URLs. There are two common scenarios where you may need to customize a link:

- **App Closed**: When the app is not open, incoming deep-link URLs may require rewriting to ensure seamless navigation.

- **App Open**: In instances where the app is already open, URL customization may be necessary based on specific business logic or user interactions. This logic could be global for the entire application, or localized to a set of routes.
- **App Open**: When the app is already open, URL customization may be necessary based on specific business logic or user interactions. This logic can be global for the entire app, or localized to a set of routes.

## Setting up linking

Please refer to the [Linking docs](https://docs.expo.dev/guides/linking/) on instructions on how to setup and test linking to your app.
See the [Linking](/guides/linking/) guide for instructions on how to set up and test linking in your app.

## Rewriting incoming native Deep-links
## Rewriting incoming native deep links

Expo Router will always evaluate a URL with the assumption they target a specific page within the app. However in practice these URLs may vary in nature:
Expo Router will always evaluate a URL with the assumption that the URL targets a specific page within the app. However, in practice, these URLs can vary in nature:

- **Unique/Referred URLs from 3rd-party Providers**: These URLs often follow a specific schema, such as `<my-scheme>:://<provider-hostname>/<uuid>`, and are generated by external sources to navigate users to designated content within the app.
- **Stale URLs from Previous Versions**: Users might encounter URLs from older versions of the app, which could lead to outdated or non-existent content. It's crucial to handle such scenarios gracefully to ensure a smooth user experience."
- **Unique/Referred URLs from third-party Providers**: These URLs often follow a specific schema, such as `<my-scheme>:://<provider-hostname>/<uuid>`, and are generated by external sources to navigate users to designated content within the app.
- **Stale URLs from Previous Versions**: Users might encounter URLs from older versions of the app, which could lead to outdated or non-existent content. It's crucial to handle such scenarios gracefully to ensure a smooth user experience.

In such scenarios, the URL requires rewriting before undergoing evaluation.
In such scenarios, the URL needs to be rewritten to correctly target a route.

To facilitate this, a dedicated `+native-intent` file, should be placed at the top-level of your `app/` folder. This special file exports a unique redirectSystemPath function, designed to handle URL/path processing.
To facilitate this, create a special file called **+native-intent.ts** at the top level of your project's **app** directory. This file exports a unique `redirectSystemPath` function designed to handle URL/path processing.

<FileTree files={['app/_layout.tsx', 'app/index.tsx', 'app/+native-intent.ts']} />
<FileTree files={['app/+native-intent.ts']} />

<APIBox header="redirectSystemPath()">

The `redirectSystemPath` is a special function used to process URLs in native apps. Upon invocation, this function receives an options object with two attributes:
The `redirectSystemPath` is a special function used to process URLs in native apps. When this function is invoked, it receives an `options` object with two attributes:

- **path**: Represents the URL or path undergoing processing.
- **initial**: A boolean flag indicating whether this is the app's initial URL.

The return value of this function should either be a `string` or a `Promise<string>`. It's crucial to note that throwing errors within this function may result in app crashes. Therefore, it's highly recommended to wrap your code within a `try {} catch {}` block and utilize `.catch()` statements when appropriate.
This function's return value should be either a `string` or a `Promise<string>`. Do note that throwing errors within this function may result in app crashes. It's highly recommended to wrap your code within a `try/catch` block and utilize `.catch()` statements when appropriate.

By adhering to these best practices, you can ensure the stability and reliability of your app's URL processing functionality, mitigating the risk of unexpected errors and crashes.
By following these best practices, you can ensure the stability and reliability of your app's URL processing functionality and mitigate the risk of unexpected errors and crashes.

```js app/+native-intent.js
import ThirdPartyService from "third-party-sdk
```ts app/+native-intent.ts
import ThirdPartyService from 'third-party-sdk';

export function redirectSystemPath({ path, initial }) {
try {
if (initial) {
// While the parameter is called `path` there is no guarantee that this is a path or a valid URL
// We advise you to defensively protect your code
const url = new URL(path, "myapp://app.home")
// Detection of 3rd-party URLs will changed based upon the provider.
if (url.hostname === "<third-party-provider-hostname>") {
const url = new URL(path, 'myapp://app.home');
// Detection of third-party URLs will change based on the provider
if (url.hostname === '<third-party-provider-hostname>') {
return ThirdPartyService.processReferringUrl(url).catch(() => {
// Something went wrong
return '/unexpected-error'
})
return '/unexpected-error';
});
}
return page;
return path;
}
return path;
} catch {
// Do not crash inside this function! Instead you should redirect users
// to a custom route to handle unexpected errors, where they are able to report the incident
return '/unexpected-error'
return '/unexpected-error';
}
}
```
Expand All @@ -76,7 +75,7 @@ Handling deep links on the web differs from native platforms, as the initial rou
As a result, you should implement one of the following patterns that best suits your requirements:

- **Server Redirect**: Since all websites, including static pages, are hosted on a server, consider leveraging server-side redirection or middleware options provided by your deployment provider. This approach is well-suited for deployments targeting **server** or **static** outputs.
- **Client Redirect**: Alternatively, you can manage URL redirects within the root `_layout` of your app. This approach is ideal for projects with a single output format targeting client-side rendering.
- **Client Redirect**: Alternatively, you can manage URL redirects within your app's root `_layout`. This approach is ideal for projects with a single output format targeting client-side rendering.

Choose the pattern that aligns with your deployment strategy and technical requirements to ensure seamless handling of incoming deep links on the web platform.

Expand All @@ -85,9 +84,9 @@ Choose the pattern that aligns with your deployment strategy and technical requi
While your app is open, you can react to URL changes within your `_layout` files using the `usePathname()` hook. The location of the `_layout` dictates the scope of the subscription.

- **global**: Add the logic to your root `_layout` file
- **localized**: Add a `_layout` file to an existing directory (or create a new (group directory)[https://docs.expo.dev/router/layouts/#groups])
- **localized**: Add a `_layout` file to an existing directory (or create a new (group directory)[/router/layouts/#groups])

```jsx app/_layout.tsx
```tsx app/_layout.tts
import { Slot, Redirect } from 'expo-router';

export default function RootLayout() {
Expand All @@ -103,51 +102,51 @@ export default function RootLayout() {

### Using `redirectSystemPath`

In native apps, an alternative method to rewrite a URL is to handle it within the redirectSystemPath as described in the section on [Rewriting incoming native deep-links](#redirectsystempath). This approach can be simpler for some use cases but comes with certain drawbacks:
In native apps, an alternative method to rewrite a URL is to handle it within the `redirectSystemPath` as described in the section on [Rewriting incoming native deep-links](#redirectsystempath). This approach can be simpler for some use cases but comes with certain drawbacks:

- **Native-only**: This method will not work on the web, as +native-intent is only available in native apps.
- **Lacks context**: +native-intent is processed outside the context of your app, meaning you won't have access to additional logic, such as user authentication status or the current route's state.
- **Native-only**: This method will not work on the web, as `+native-intent` is only available in native apps.
- **Lacks context**: `+native-intent` is processed outside the context of your app. This means you won't have access to additional logic, such as user authentication status or the current route's state.

## Sending navigation events to 3rd Party Services
## Sending navigation events to third Party Services

Below is a basic example on how to send navigation events to an external service, such an analytics or logging service. Please consult with your provider for specific instructions.
Below is a basic example of how to send navigation events to an external service, such as an analytics or logging service. Please consult with your provider for specific instructions.

```jsx app/_layout.tsx
import ThirdPartyService from "third-party-sdk
```tsx app/_layout.tts
import ThirdPartyService from 'third-party-sdk';
import { Slot, usePathname } from 'expo-router';

const thirdParty = new ThirdPartyService()
const thirdParty = new ThirdPartyService();

export default function RootLayout() {
const pathname = usePathname()
const pathname = usePathname();

// Perform the service initiation logic
useEffect(() => {
thirdParty.register()
thirdParty.register();
return () => {
thirdParty.deregister()
}
}, [thirdParty])
thirdParty.deregister();
};
}, [thirdParty]);

// Send pathname changes to the third party
useEffect(() => {
thirdParty.sendEvent({ pathname })
}, [pathname])
thirdParty.sendEvent({ pathname });
}, [pathname]);

return <Slot />
return <Slot />;
}
```

## Universal Links and multiple domains

Expo Router does not require additional configuration for Universal Links and multiple domains. All URLs provided to your App will be evaluated. To customize the URL scheme(s) for your app, [you should customize the `scheme` value in your Expo app config.](https://docs.expo.dev/versions/latest/config/app/#scheme)
Expo Router does not require additional configuration for Universal Links and multiple domains. All URLs provided to your App will be evaluated. To customize the URL scheme(s) for your app, your should [customize the `scheme` value in your app config.](/versions/latest/config/app/#scheme)

## Forcing web links

If you want a URL to be initially evaluated by the user's browser, you should write the address as a Fully Qualified URL (FQDN) with an `http`/`https` scheme. By using a complete URL you ensure that the link is interpreted as a web URL and opened in the user's browser by default.
If you want a URL to be initially evaluated by the user's browser, write the address as a Fully Qualified URL (FQDN) with an `http`/`https` scheme. Using a complete URL ensures that the link is interpreted as a web URL and opened in the user's browser by default.

This approach is effective for directing users to external websites or Universal Links for other apps.

```jsx
<Link href="https://docs.expo.dev/router/introduction" />
```tts
<Link href="/router/introduction" />
```

0 comments on commit be5a706

Please sign in to comment.