> ## Documentation Index
> Fetch the complete documentation index at: https://docs.monad.xyz/llms.txt
> Use this file to discover all available pages before exploring further.

# 如何在基于 Expo 的移动应用中构建自定义深度链接

深度链接是一种 URL,它可以将用户直接带到移动应用或网站中的特定内容,而不仅仅是启动应用的主屏幕。它们的作用类似于快捷方式,能够实现更流畅的导航并改善用户体验。

在本指南中,您将学习将深度链接添加到基于 [Expo](https://docs.expo.dev/) 的移动应用中的基础知识。

## 什么是深度链接?

深度链接由三部分构成:

* **Scheme**:标识应打开该 URL 的应用的 URL scheme(示例:myapp\://)。对于非标准的深度链接,它也可以是 https 或 http。
* **Host**:应打开该 URL 的应用的域名(示例:web-app.com)。
* **Path**:应打开的屏幕的路径(示例:/product)。如果未指定路径,用户将被带到应用的主屏幕。

深度链接也可以像网页链接一样带有参数!

示例:

```
rnwalletapp://swap?from={token}&to={token}&amount={amount}
```

## 构建深度链接

<Note>
  如果您想尝试深度链接的演示,可以克隆[此](https://github.com/monad-developers/expo-swap-template/tree/branch/deeplink?tab=readme-ov-file)仓库并切换到 `branch/deeplink` 分支:

  ```bash theme={null}
  git clone https://github.com/monad-developers/expo-swap-template.git
  ```

  ```bash theme={null}
  git checkout branch/deeplink
  ```
</Note>

### 定义 scheme

第一步是定义一个 scheme;您可以通过编辑 Expo 项目中的 `app.json` 文件来完成。

```json title="app.json" theme={null}
{
  "expo": {
    "scheme": "myapp" // 或您偏好的 scheme
  }
}
```

<Warning>
  像 `myapp://` 这样的自定义 scheme 在 Android 或 iOS 上并非唯一。
  如果两个应用注册了相同的 scheme,系统将不知道要启动哪个,或者可能启动错误的那个。
  请使用应用特有的、不易意外重复的 scheme。
</Warning>

### 监听深度链接事件

在您的应用入口处(例如 `_layout.tsx` 或一个 provider),添加以下逻辑:

* 处理初始深度链接
* 监听深度链接变化

一个好的做法是创建一个 `DeepLinkHandler` 并用它包裹整个应用。

示例(在使用基于文件的路由的 Expo 项目中):

```tsx lines title="app/_layout.tsx" theme={null}
...

// 解析深度链接并获取 hostname 和 queryParams 的函数
function parseSwapDeeplink(url: string): SwapDeeplinkParams | null {
  try {
    const { hostname, queryParams } = Linking.parse(url);
    
    if (hostname !== 'swap' || !queryParams) {
      return null;
    }

    return {
      from: queryParams.from as string | undefined,
      to: queryParams.to as string | undefined,
      amount: queryParams.amount as string | undefined,
    };
  } catch (error) {
    console.error('Error parsing deeplink:', error);
    return null;
  }
}

function DeeplinkHandler({ children }: { children: React.ReactNode }) {
  const router = useRouter();
  
  useEffect(() => {
    
    const handleDeeplink = (url: string) => {
      // 解析深度链接并获取参数(host、path、params 等...)
      const params = parseSwapDeeplink(url);
      if (params) {
        // 此示例在应用中将 params 设为全局可访问,不过您可以使用 React Context 或类似方式让 params 在应用中的任何地方都能访问。
        (global as any).swapDeeplinkParams = params;
        // 根据 path 或 host,您可以将用户重定向到应用中相应的屏幕 
        router.replace('/');
      }
    };

    // 处理初始 URL
    Linking.getInitialURL().then(url => url && handleDeeplink(url));

    // 创建事件监听器,处理应用打开期间的 URL 变化
    const subscription = Linking.addEventListener('url', event => handleDeeplink(event.url));

    // 组件销毁时移除事件监听器(避免内存泄漏)
    return () => subscription.remove();
  }, [router]);

  return <>{children}</>;
}


export default function Layout() {
    ...

    return (
        <DeeplinkHandler>
            <App />
        </DeeplinkHandler>
    );
 }
```

就这样,您的应用已准备好处理深度链接,您可以根据 `hostname` 和 `queryParams` 将用户重定向到相应的屏幕。

此外,如果您让 `queryParams` 可全局访问(通过 context 或其他方式),您还可以预填输入值!

**示例:预填代币兑换金额!**

## 测试深度链接

以下是深度链接在移动应用中如何工作的演示:

<iframe style={{ aspectRatio: "16 / 9" }} src="https://www.youtube.com/embed/506NwDg_kCo?si=49XVbyV-tNjYCryl" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen />

### 在 iOS 模拟器上测试

```bash theme={null}
xcrun simctl openurl booted [deeplink]
```

示例:

```bash theme={null}
xcrun simctl openurl booted "rnwalletapp://swap?from=MON&to=USDC&amount=100"
```

### 在 Android 模拟器上测试

```bash theme={null}
adb shell am start -W -a android.intent.action.VIEW -d [deeplink]
```

示例:

```bash theme={null}
# 重要:使用单引号包裹整个命令,以防止 shell 解析 & 符号
adb shell 'am start -W -a android.intent.action.VIEW -d "rnwalletapp://swap?from=MON&to=USDC&amount=100"'
```

<Warning>
  如果不使用单引号,shell 会将 `&` 解释为命令分隔符,只有第一个参数会被传递给应用。
</Warning>

### 在实体设备上测试

您可以创建一个带有链接的简单 HTML 页面。

示例:

```html theme={null}
<a href="rnwalletapp://swap?from=MON&to=USDC&amount=100">Swap MON to USDC</a>
```

## 尝试演示

如果您想尝试深度链接演示,可以配置[此](https://github.com/monad-developers/expo-swap-template/tree/branch/deeplink?tab=readme-ov-file)仓库并切换到 `branch/deeplink` 分支。

```bash theme={null}
git clone https://github.com/monad-developers/expo-swap-template.git
```

```bash theme={null}
git checkout branch/deeplink
```

以下是您可以尝试的一些深度链接:

1. 将 MON 兑换为 USDC

```
rnwalletapp://swap?from=MON&to=USDC
```

2. 将 100 MON 兑换为 USDC

```
rnwalletapp://swap?from=MON&to=USDC&amount=100
```

3. 将 USDC 兑换为 WMON

```
rnwalletapp://swap?from=USDC&to=WMON&amount=1000
```
