如何为ReactJS Ionic Android项目配置深度链接
问题描述
我有一个基础ReactJS项目,通过Ionic Capacitor转为Android项目,输出文件存于build目录,已生成可用APK。现在需要实现:移动端任意浏览器打开https://example.com/这类URL时,直接唤起已安装的我的应用。
目前已完成以下配置,但点击链接时仍会在浏览器中打开,仅在浏览器角落显示唤起图标:
- 配置了AndroidManifest.xml中的intent-filter
- 部署了assetlinks.json文件
- 编写了React端的URL打开事件处理代码
已配置内容
1. 初始intent-filter配置
<intent-filter android:label="@string/title_activity_main"> <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="m.clipdrop.io" android:pathPrefix="/" /> </intent-filter> <intent-filter android:label="@string/title_activity_main"> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.BROWSABLE" /> <data android:scheme="http" android:host="m.clipdrop.io" android:pathPrefix="/" /> </intent-filter> <!-- Accepts URIs that begin with "clipdrop://login” --> <intent-filter android:label="@string/title_activity_main"> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.BROWSABLE" /> <data android:scheme="clipdrop" android:host="login" /> </intent-filter>
2. 点击链接示例
https://m.clipdrop.io/login?b=datahere
3. React端URL处理代码
import React, { useEffect } from 'react'; import { useHistory } from 'react-router-dom'; import { App, URLOpenListenerEvent } from '@capacitor/app'; export default function AppUrlListener(){ let history = useHistory(); useEffect(() => { App.addListener('appUrlOpen', (event) => { var url = new URL(event.url); var benc = url.searchParams.get("b")?.replace("%3D", "="); if(benc){ window.location.href = "/login?b=" + benc; } // If no match, do nothing - let regular routing // logic take over }); }, []); return null; };
4. 最终AndroidManifest.xml配置
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="io.clipdrop.clipdrop"> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|smallestScreenSize|screenLayout|uiMode" android:name="io.clipdrop.clipdrop.MainActivity" android:label="@string/title_activity_main" android:theme="@style/AppTheme.NoActionBarLaunch" android:launchMode="singleTask" android:exported="true"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> <!-- Accepts URIs that begin with "http(s)://m.clipdrop.io --> <intent-filter android:autoVerify="true"> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.BROWSABLE" /> <data android:scheme="http" /> <data android:scheme="https" /> <data android:host="m.clipdrop.io" /> </intent-filter> </activity> <provider android:name="androidx.core.content.FileProvider" android:authorities="${applicationId}.fileprovider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths"></meta-data> </provider> </application> <!-- Permissions --> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.MICROPHONE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-feature android:name="android.hardware.camera" android:required="true" /> <uses-permission android:name="android.permission.RECORD_AUDIO" /> <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" /> <uses-feature android:name="android.hardware.microphone"/> <uses-permission android:name="android.permission.AUDIO_CAPTURE" /> </manifest>
解决方案
1. 确保数字资产链接验证通过
- 检查assetlinks.json内容:必须包含应用的包名
io.clipdrop.clipdrop和正式签名的SHA-256指纹 - 验证服务器配置:确保assetlinks.json能通过HTTPS访问,返回的Content-Type为
application/json,且开启跨域访问 - 使用官方验证工具确认链接有效性(需用正式签名APK测试,debug包无法通过验证)
2. 优化AndroidManifest.xml配置
- 保持
android:launchMode="singleTask"不变,确保应用从浏览器唤起时不会重复创建实例 - 确认
android:autoVerify="true"已添加到intent-filter中,这是实现直接唤起的关键
3. 调整React端URL处理逻辑
改用react-router的history.push替代window.location.href,更符合React路由机制:
import React, { useEffect } from 'react'; import { useHistory } from 'react-router-dom'; import { App } from '@capacitor/app'; export default function AppUrlListener(){ const history = useHistory(); useEffect(() => { const listener = App.addListener('appUrlOpen', (event) => { const url = new URL(event.url); const benc = url.searchParams.get("b")?.replace("%3D", "="); if(benc){ history.push(`/login?b=${benc}`); } }); return () => { listener.remove(); }; }, [history]); return null; };
4. 处理浏览器行为差异
- 部分浏览器(如Chrome)首次打开链接时需用户手动点击唤起图标,后续会默认唤起
- 可在网页中添加引导提示,引导用户点击唤起图标
- 清除浏览器缓存或使用隐私模式测试,避免缓存影响
5. 测试注意事项
- 必须使用正式签名的APK测试,debug签名包无法通过数字资产链接验证
- 测试设备需为Android 6.0及以上版本,该版本才支持
autoVerify功能
内容的提问来源于stack exchange,提问作者X3R0
相关产品推荐
相关产品推荐

