3. Intent Filter 配置详解:Android Manifest 中 <intent-filter> 标签、action/category/data 匹配规则、优先级控制
3.1 原理概述
Intent Filter 是 Android 系统声明式导航的核心。组件(Activity、Service、BroadcastReceiver)通过在 AndroidManifest.xml 中声明 <intent-filter>,告知系统自己能够响应哪些隐式 Intent。当应用调用 startActivity() 或 startService() 并传入隐式 Intent 时,PackageManager 会遍历所有已安装应用的 Intent Filter,按照 action、category、data 三重规则进行匹配,最终确定唯一或最佳的组件。若多个组件都匹配成功,则弹出选择器(Disambiguation Dialog)或依据优先级(priority)排序。
核心原则:Intent 必须通过所有声明检查(action 至少匹配一个、category 全部匹配、data 完全匹配)才能被视作候选。未被声明的属性系统不会强制检查,但声明后必须严格匹配。
3.2 匹配规则详解
3.2.1 Action 匹配
android:name指定所支持的 Action 字符串(如android.intent.action.VIEW)。- Intent 中的 Action 可以缺省(
null),此时只能匹配未声明任何 Action 的 Filter(极少使用)。 - Filter 可以声明多个
<action>,Intent 只要匹配其中之一即通过 Action 检查。
3.2.2 Category 匹配
- Filter 中的每个
<category>都必须被 Intent 包含(即 Intent 的 Categories 集合是 Filter Categories 的超集)。 - 隐式 Intent 默认带有
android.intent.category.DEFAULT(由系统自动添加),因此 Filter 必须至少包含android.intent.category.DEFAULT才能接收隐式 Intent。 - 例外:
CATEGORY_BROWSABLE常用于深层链接,允许 Web 浏览器跳转。
3.2.3 Data 匹配
| 属性 | 说明 | 匹配规则 |
|---|---|---|
android:scheme |
URI 协议(如 https、http、content) |
必须与 Intent 的 scheme 完全一致(区分大小写)。 |
android:host |
URI 主机名(如 example.com) |
若声明了 host,则必须精确匹配;支持通配符?不,需精确字符串。推荐使用 *.example.com 模式?不支持,只能声明已知域名。 |
android:port |
URI 端口号(如 8080) |
仅在 host 存在时生效;省略 port 则匹配任意端口或默认端口。 |
android:path / android:pathPrefix / android:pathPattern |
路径精确匹配、前缀匹配、通配符模式匹配 | 三者互斥。pathPattern 支持 *(匹配任意字符)和 .*(正则)。 |
android:mimeType |
MIME 类型(如 text/plain) |
支持通配符 text/*;与 scheme/host 组合使用时需谨慎。 |
3.2.4 优先级控制
通过 android:priority 属性(整数,值越大优先级越高)控制同类型 Intent 候选组件的排序。优先级仅在多个 Filter 完全匹配且属于同一 Activity 时才参与选择;跨应用时优先级行为可能受系统限制(Android 12+ 默认禁用外部应用的优先级影响,除非用户明确设置默认应用)。
<activity android:name=".DeepLinkActivity"
android:priority="10">
<intent-filter>
<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="app.example.com"
android:pathPrefix="/product" />
</intent-filter>
</activity>
3.3 实现流程 & 配置示例
- 在 AndroidManifest.xml 中为目标组件添加
<intent-filter>:一个组件可声明多个 Filter(例如支持 web 链接和自定义 scheme)。 - 至少声明一个
<action>:通常为android.intent.action.VIEW。 - 必须包含
android.intent.category.DEFAULT:否则不在隐式 Intent 候选列表中。 - 按需添加
<category android:name="android.intent.category.BROWSABLE" />:使链接可从浏览器直接跳转。 - 配置
<data>元素:指定 scheme、host、path 等。若需要支持多个 domain,重复添加<data>标签(注意:<data>多个标签之间是 OR 关系)。 - 设置
android:priority(可选):仅在需要提升自身匹配优先级时使用,注意系统策略变化。
调试技巧:使用 adb 命令
adb shell dumpsys package <package-name> 查看已注册的 Intent Filter 列表。或者使用 adb shell am start -W -a android.intent.action.VIEW -d "https://app.example.com/product/123" 测试深层链接能否正确启动目标 Activity。
3.4 常见错误与避坑
- 忘记添加 DEFAULT Category:隐式 Intent 自动携带 DEFAULT,Filter 必须显式声明,否则匹配失败。
- Data 元素未声明 scheme:仅声明 host 或 path 而不带 scheme 会导致匹配不生效(scheme 是必须的顶级属性)。
- 多个 data 标签混乱:同一 Filter 内多个
<data>是 OR 关系,但若某个<data>只声明了 scheme 而其他 data 声明了 host+path,系统会合并所有声明再做检查,容易产生非预期行为。最佳实践:每个<intent-filter>只放一组数据规则;多组规则用多个 filter 分开。 - priority 在外部应用失效:Android 12+ 默认 Priority 仅在包内生效,跨包优先级通常被忽略,改用
role picker或系统设置。 - MIME Type 与 URI 同时声明时的额外限制:若同时声明了
android:mimeType和android:scheme,则 filter 只接受符合 scheme 且 MIME type 匹配的 Intent;此时 host/path 若未声明则不检查。
安全警告:切勿在 export 组件的 Intent Filter 中暴露敏感的 Activity(如登录或支付页面)。隐式 Intent 可被任意应用发起,若无权限检查,可能导致意图劫持或信息泄露。建议结合
android:permission 或运行时验证 caller 的签名。
3.5 生产环境配置清单
| 场景 | 必需声明 | 推荐设置 |
|---|---|---|
| 标准 Web 链接(Android App Links) | ACTION_VIEW, DEFAULT, BROWSABLE, scheme=http/https, host(已验证域名) | 添加 android:autoVerify="true" 开启自动验证 |
| 自定义 scheme(如 myapp://) | ACTION_VIEW, DEFAULT, BROWSABLE, scheme=myapp | 避免使用通用 scheme(如 file、content) |
| 文件打开/分享 | ACTION_VIEW 或 ACTION_SEND, mimeType 通配符 | 配合 FileProvider 或 content:// URI |
| 后台服务启动 | 自定义 action 字符串(建议使用包名前缀),DEFAULT(但 Android 8+ 隐式启动后台服务受限) | 改用 JobIntentService 或显式 Intent |
3.6 调试与验证
- 命令行测试:
# 测试深层链接(隐式 Intent) adb shell am start -a android.intent.action.VIEW -d "https://app.example.com/product/42" # 查看系统如何处理该 Intent(打印候选 Activity 列表,部分系统需要 root) adb shell dumpsys activity a -i | grep "example" - 使用 Android Studio 的 “App Links Assistant”:配置 URL 映射并自动生成 intent-filter 代码,同时提供调试工具发送测试 intent。
- 日志检查:在目标 Activity 的
onCreate()中打印 Intent 数据:Log.d("DeepLink", "Action: " + getIntent().getAction()); Log.d("DeepLink", "Data: " + getIntent().getDataString()); Log.d("DeepLink", "Categories: " + getIntent().getCategories());
3.7 性能与稳定性优化
- 最小化 Filter 声明:为每个 Activity 只声明必要的
<intent-filter>,避免滥用通配符或过多 action,减少 PackageManager 的匹配计算量。 - 使用 Android App Links 替代自定义 scheme:自定义 scheme 无法保证唯一性,易被其他应用劫持;App Links 结合 HTTPS 域名的自动验证可提供更强确定性。
- 合理设置 priority:仅在需要处理同一 Intent 时控制本应用内 Activity 的优先级;对外部应使用
android:autoVerify和系统默认排序。 - 避免在 BroadcastReceiver 的 Intent Filter 中动态修改优先级:使用
Context.registerReceiver()时可通过IntentFilter.setPriority()设置运行时优先级,但注意与静态注册的优先级叠加效果复杂,容易引发混乱。