react native webview 拦截大厂scheme

当我们的webview 中嵌入了小红书等app 的分享页面后,一般页面上会展示“打开App”按钮。但如果什么都不做,是没法打开指定App 的,甚至小红书的按钮还会不断的下载小红书apk。

添加scheme白名单

app 允许跳转的scheme 需要在配置文件中先声明。

Android

<manifest ...>
    <queries>
        <intent>
            <action android:name="android.intent.action.VIEW" />
            <data android:scheme="xhsdiscover" />
        </intent>
    </queries>
</manifest>

iOS

<key>LSApplicationQueriesSchemes</key>
<array>
    <string>xhsdiscover</string>
</array>

WebView允许所有请求

如果不配置originWhitelist,你会发现除了http 开头的链接,其他的都拦截不到。

<WebView
      ref={webViewRef}
      source={{ uri: 'https://www.zhihu.com' }}
      onMessage={handleMessage} // 监听 JS 发送的消息
      injectedJavaScript={injectedJavaScript} // 注入 JS 代码
	  onShouldStartLoadWithRequest={handleShouldStartLoadWithRequest}
      originWhitelist={['*']} // 允许所有请求
    />

拦截请求

在onShouldStartLoadWithRequest 函数中拦截请求,检查是否是scheme

const handleShouldStartLoadWithRequest = (request: any) => {
  const { url: targetUrl } = request;
  if (!targetUrl) return false;

  // 拦截 scheme:// 跳转
  if (targetUrl.startsWith('xiaohongshu://') || targetUrl.startsWith('otherapp://')) {
    if (hasUserInteracted) {
      Linking.openURL(targetUrl).catch(err => console.error('Failed to open URL:', err));
    }
    
    return false; // 关键:拦截 WebView 内跳转
  }

  return true; // 其他正常请求放行
};

自动跳转

这个问题也处理了我好久,理论上我们是点击“打开app” 再去打开。但很多第三方页面,在页面加载之后,会立即自动跳转,不确定是设计如此,还是调用了检测app 是否安装的方法,触发了跳转。

常见的唤端方式:在主文档中location.href=”xxx://xxx” 或window.open() 打开。

还有一些可能用iframe 来检测是否安装了对应的app

<iframe src="yourapp://open" style="display:none;"></iframe>

如果 App 已安装,iframesrc 触发 App 打开。 如果 App 未安装,iframe 可能会抛出错误(但部分浏览器不会有明显反应)。

如果检测失败的话,多数会有一个降级的H5 页面来承接“打开app” 按钮的跳转。

因此,在我们拦截了自动跳转之后,网页内部可能认为已经失败了,下次点击“打开app” 会走降级逻辑。这不符合我们的诉求。

目前我的实现是,先拦截自动跳转并存储scheme, 在下次拦截到跳转的降级url 时,替换为scheme。 这块继续探索有没有更好的方案。

打开app

      Linking.openURL(targetUrl).catch(err => console.error('Failed to open URL:', err));

小红书官方deeplink

Leave a Comment

邮箱地址不会被公开。 必填项已用*标注