- 文档
- 教程
- 移动开发
【免费下载链接】android-training-course-in-chinese
Android官方培训课程中文版
在 Android 中,深度链接(Deep Link)允许用户在浏览器、搜索结果或其它 App 中点击某个 URI,直接打开你 App 内对应的内容页面。本文以 android-training-course-in-chinese 仓库中的「为App内容开启深度链接」课程(ux/app-indexing/deep-linking.md)为核心,完整讲解如何在 Manifest 中声明 intent filter、如何从传入 Intent 中读取并解析数据、如何遵循导航与用户体验约定,以及如何用 adb 命令验证深度链接能否正确路由到目标 Activity,并结合本仓库中 Intent过滤、为索引指定App内容 等相关课程,帮助你搭建一套可被搜索引擎抓取、可被用户直接点击进入的 App 内容索引体系。
深度链接与 App 内容索引的关系
在介绍具体实现前,先明确深度链接在整个 App 索引(App Indexing)方案中的位置。随着移动 App 越来越普及,用户不仅通过网站查找信息,也会直接在自己安装的 App 中查找内容。通过为 Activity 提供 intent filter,可以让 Google 搜索在你的 App 运行时,为 App 与匹配 URI 的 Intent 建立路径,从而把搜索结果直接导向 App 中的具体内容,而不是网页。
从本仓库的课程结构看,整个「使得你的App内容可被Google搜索」(ux/app-indexing/index.md)包含两个步骤:
- 开启深度链接(ux/app-indexing/deep-linking.md):在 App 的 Manifest 中为相关 Activity 添加 intent filter,使 URI 能够解析到指定 Activity。这是本文的核心主题。
- 为索引指定 App 内容(ux/app-indexing/enable-app-indexing.md):通过网站 Sitemap 或页面
<head>中的注解,把android-app://格式的深度链接 URI 共享给 Google,使 Googlebot 能为 App 内容建立索引。
简而言之:深度链接解决的是「URI 如何路由到 App 内页面」的问题,而内容索引解决的是「Google 如何发现并展示这些深度链接」的问题。两者配合,用户才能在移动端搜索结果中点击链接直接打开 App 内容。
为深度链接添加 Intent Filter
要使 Google 能够抓取你的 App 内容,并允许用户从搜索结果进入 App,必须在 App 的 Manifest 文件中,为相关 Activity 添加 intent filter。这些 intent filter 能使深度链接与你的任意 Activity 相连。例如,用户可以在购物 App 中点击一条深度链接,直接浏览自己所搜索的产品详情页。
Intent Filter 的三个核心组成部分
一条面向深度链接的 intent filter,需要包含以下元素和属性值:
<action>
指定ACTION_VIEW操作(对应字符串常量android.intent.action.VIEW)。ACTION_VIEW是「查看某内容」的通用动作,声明它使得 Google 搜索等外部调用方可以触达该 intent filter。这也符合隐式 Intent 的常规用法——在 Intent的发送 课程中,查看网页、查看地图等场景使用的都是ACTION_VIEW配合 Uri 数据。
<data>
添加一个或多个<data>标签,每一个标签代表 Activity 对一种 URI 格式的解析规则。<data>至少必须包含android:scheme属性(URI 的方案名,如http、https、或自定义的example)。
还可以添加额外属性来精确限定 Activity 所接受的 URI 类型,例如:
android:host:URI 的主机名,用于限定scheme://host部分;android:path:精确匹配路径;android:pathPrefix:匹配路径前缀;android:pathPattern:按正则模式匹配路径;android:mimeType:匹配 MIME 类型(详见 Intent过滤)。
例如,你可能有几个 Activity 可以接受相似的 URI,仅仅是路径名不同。此时使用android:path或它的变体(pathPattern、pathPrefix),系统就能辨别对不同 URI 路径应该启动哪个 Activity。
<category>
必须包含BROWSABLEcategory(对应android.intent.category.BROWSABLE)。BROWSABLE对于使 intent filter 能被浏览器访问是必要的——没有这个 category,在浏览器中点击链接将无法解析到你的 App。
DEFAULTcategory(android.intent.category.DEFAULT)是可选的,但官方建议添加。没有它,Activity 只能通过 App 组件名称以显式(explicit)Intent 方式启动。正如 Intent过滤 课程所强调的:为了接受隐式 intent,必须在 intent filter 中包含CATEGORY_DEFAULT,因为startActivity()和startActivityForResult()会将所有 intent 视为已声明CATEGORY_DEFAULT,未声明该 category 的 Activity 无法响应隐式 Intent。
完整的 Manifest 配置示例
下面这段 XML 展示如何在 Manifest 中为深度链接指定 intent filter。示例中,URIexample://gizmos和http://www.example.com/gizmos都能解析到同一个 Activity:
<activity android:name="com.example.android.GizmosActivity" android:label="@string/title_gizmos" > <intent-filter android:label="@string/filter_title_viewgizmos"> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.BROWSABLE" /> <!-- 接受以"example://gizmos"开头的 URIs --> <data android:scheme="example" android:host="gizmos" /> <!-- 接受以"http://www.example.com/gizmos"开头的 URIs --> <data android:scheme="http" android:host="www.example.com" android:pathPrefix="gizmos" /> </intent-filter> </activity>值得注意的关键点:
- 第一条
<data>使用自定义 schemeexample和 hostgizmos,精确匹配example://gizmos这类 URI; - 第二条
<data>使用标准的httpscheme 和www.example.com主机,配合android:pathPrefix="gizmos",匹配http://www.example.com/gizmos开头的 URL——这通常对应你的网站 URL,从而实现「网页与 App 内容一一对应」; android:label可以为 intent filter 设置一个可读名称,便于用户在解析对话框(Chooser)中识别。
Note:对一个 URI pattern,intent filter 只能包含一个单一的
data元素;如果需要匹配额外的 URI pattern,应创建不同的 intent filter。这一点在 Intent过滤 中也有印证——当 Activity 需要同时处理文本与图片、或同时响应ACTION_SEND与ACTION_SENDTO时,必须拆分成多个独立的 intent filter,避免 action 与 data 组合互相矛盾。
当你把包含指定 Activity 内容 URI 的 intent filter 添加到 App Manifest 后,Android 就可以在 App 运行时,为 App 与匹配 URI 的 Intent 建立路径。
与显式/隐式 Intent 的对照
从本仓库 Intent过滤 与 Intent的发送 两课可以更完整地理解这一机制:
- 显式 Intent 直接指定要启动的组件类名,用于同 App 内 Activity 切换;
- 隐式 Intent 只声明动作(如
ACTION_VIEW)与数据(Uri 或 MIME type),由系统根据已安装 App 的 intent filter 解析出可响应的 Activity; - 当 App 被安装到设备上时,系统会识别 Manifest 中的 intent filter 并记录下来;当其它 App 执行
startActivity()时,系统自动查找可以响应该 intent 的 Activity。
深度链接正是「隐式 Intent + intent filter」模式的典型应用:浏览器或搜索引擎发出一个ACTION_VIEW的隐式 Intent,携带example://gizmos这样的 Uri,系统依据你声明的 intent filter 把请求路由到对应 Activity。
从传入的 Intent 读取数据
一旦系统通过 intent filter 启动了你的 Activity,你就可以使用 Intent 提供的数据来决定需要处理什么内容。
读取 Action 与 Data
调用getData()和getAction()方法,可以取出传入 Intent 中的数据与操作:
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); Intent intent = getIntent(); String action = intent.getAction(); Uri data = intent.getData(); }技术要点:
- 你可以在 Activity 生命周期的任何时候调用这些方法,但一般应该在前期回调中调用,例如
onCreate()或onStart(),以便尽早拿到深度链接的目标内容并完成界面加载; getIntent()返回启动该 Activity 的 Intent(参照 Intent过滤 中的同样用法);- 拿到
Uri data后,可进一步调用data.getScheme()、data.getHost()、data.getPath()等方法来解析 URI 的各个组成部分,从而判断应该展示哪条内容; - 除
onCreate/onStart外,若 Activity 以singleTop等启动模式被复用(例如再次收到相同深度链接),还应处理onNewIntent()回调并通过setIntent()更新当前 Intent,确保 UI 跟随新链接刷新。
根据 Action 分支处理
如果同一个 Activity 的 intent filter 声明了多个动作,可以在读取 Intent 后根据 action 值分支处理。参考 Intent过滤 中的示例思路,可以基于intent.getType()或解析出的 Uri 来决定处理逻辑:
Intent intent = getIntent(); String action = intent.getAction(); Uri data = intent.getData(); if (Intent.ACTION_VIEW.equals(action) && data != null) { // 根据 data 的 scheme/host/path 解析并展示对应内容 }深度链接的用户体验约定
仅仅「能打开」还不够,深度链接的用户体验直接决定用户是否愿意长期使用该入口。原文档给出了两条必须遵守的惯例:
惯例一:直接打开内容,不设任何障碍
深度链接应直接为用户打开内容,不需要任何提示、插播式广告页和登录页面。要确保用户能看到 App 的内容,即使之前从没打开过这个应用——这意味着你不能假设用户已经登录,深度链接指向的页面必须是可匿名访问的。当用户从启动器(Launcher)正常打开 App 时,可以在操作结束后再给出登录等提示。这条准则与网站的 first click free(首次点击免费)体验一脉相承。
惯例二:遵循 Back 与 Up 的导航设计
遵循 提供向上导航与历史导航 中的设计指导,使 App 能够满足用户通过深度链接进入后,向后导航的需求。
从仓库中 提供向上的导航 课程可以得到具体的实现方案:
- 用户通过深度链接从外部(如浏览器、搜索结果的其它 App)进入你的 Activity 时,该 Activity 可能不属于你 App 的默认任务;
- 此时若用户点击 ActionBar 的 Up 按钮,不能简单调用
NavUtils.navigateUpFromSameTask()(该方法仅适用于「当前任务由你的 App 发起」的情况),而应先调用NavUtils.shouldUpRecreateTask()检查当前 Activity 实例是否在另一个 App 的任务中; - 如果返回
true,应使用TaskStackBuilder创建一个带合成返回栈(synthesized back stack)的新任务,通过addNextIntentWithParentStack()把该 Activity 的所有父 Activity 加入返回栈,再调用startActivities()完成向上导航; - 为支撑这一机制,必须在 Manifest 中为每个子 Activity 声明逻辑父 Activity:Android 4.1(API 16)起使用
android:parentActivityName属性,4.0 及以下版本则配合android.support.PARENT_ACTIVITY的<meta-data>元素(见 ux/implement-nav/ancestral.md)。
同样地,启动Activity时保留导航 中介绍的TaskStackBuilder.addParentStack()/addNextIntent()构建返回栈的思路,也可迁移到深度链接场景,保证用户从链接进入后能按 Back 逐级返回而非直接退出 App。
测试你的深度链接
配置完成后,必须验证 intent filter 的 URI 是否能正确解析到对应的 App Activity。官方推荐使用 Android Debug Bridge(adb)的 activity manager(am)工具,在设备或模拟器上直接发起路由测试。
通用测试语法
测试 intent filter URI 的一般 adb 语法是:
$ adb shell am start -W -a android.intent.action.VIEW -d <URI> <PACKAGE>参数含义:
-W:等待启动完成,便于确认是否成功解析;-a android.intent.action.VIEW:指定动作,与 Manifest 中 intent filter 的ACTION_VIEW对应;-d <URI>:指定要测试的深度链接 URI;<PACKAGE>:目标 App 的包名。
测试示例
例如,下面的命令试图浏览与指定 URI 相关的目标 App Activity:
$ adb shell am start -W -a android.intent.action.VIEW -d "example://gizmos" com.example.android针对上一节的 Manifest 示例,该命令中的 URIexample://gizmos会匹配scheme=example、host=gizmos的<data>声明,从而启动com.example.android.GizmosActivity。
测试建议:
- 分别测试你声明的每一种 URI 形态(自定义 scheme、
http/httpsscheme、不同路径前缀),确保path/pathPrefix/pathPattern的匹配范围符合预期; - 观察系统输出中是否存在
Warning: Activity not started之类的提示,若出现,通常意味着没有 Activity 能解析该 URI(可能是 Manifest 中 scheme/host 写错,或缺少BROWSABLE/DEFAULTcategory); - 结合「解析对话框」场景验证:若多个 App 声明了相同的 URI pattern,系统会弹出选择界面,这也是深度链接的常见预期行为(参照 Intent的发送 中多 App 可处理同一 Intent 时的描述)。
让 Google 为 App 内容建立索引
深度链接打通后,要让搜索结果直接展示 App 内容,还需把「网页与 App 内容的对应关系」共享给 Google。这一步在原文档的姊妹课程 为索引指定App内容 中有完整说明,这里提炼其核心,帮助你理解深度链接的完整闭环。
android-app:// 深度链接 URI 格式
共享给 Google 搜索的深度链接必须遵循如下 URI 格式:
android-app://<package_name>/<scheme>/<host_path>各部分含义:
- package_name:你的 APK 在 Google Play Developer Console 中列出的包名;
- scheme:匹配你 intent filter 的 URI 方案(即
<data>中的android:scheme); - host_path:指向 App 内指定内容的部分(对应
<data>中的android:host及路径)。
两种注解方式
方式一:Sitemap 注解
在 Sitemap 文件中使用<xhtml:link>标签,指定用作替代 URI 的深度链接:
<?xml version="1.0" encoding="UTF-8" ?> <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:xhtml="http://www.w3.org/1999/xhtml"> <url> <loc>example://gizmos</loc> <xhtml:link rel="alternate" href="android-app://com.example.android/example/gizmos" /> </url> ... </urlset>方式二:网页<head>注解
在 HTML 页面的<head>标签内为每一个页面添加一个<link>标签:
<html> <head> <link rel="alternate" href="android-app://com.example.android/example/gizmos" /> ... </head> <body> ... </body>用 robots.txt 控制抓取
当 Googlebot 为你的 App 内容建立索引后,你的 App 可能会收到来自 Googlebot 的 HTTP 请求。因此必须正确配置服务器上的robots.txt,允许这些请求。例如,允许 Googlebot 访问/api/目录、限制访问其它目录:
User-Agent: Googlebot Allow: /api/ Disallow: /至此,从「Manifest 声明 intent filter」→「App 内读取并渲染内容」→「Sitemap/网页注解 + robots.txt 放行」→「adb 验证路由」,一条完整的深度链接与 App 内容索引链路就全部打通了。
小结
在 android-training-course-in-chinese 课程体系中,为 App 开启深度链接是「使得你的 App 内容可被 Google 搜索」(ux/app-indexing/index.md)的第一步,核心要点可以归纳为:
- 声明意图:在 Manifest 中为相关 Activity 添加包含
ACTION_VIEW、BROWSABLE(并建议加入DEFAULT)的 intent filter,用<data>声明 scheme、host 及 path 匹配规则; - 读取数据:在
onCreate()/onStart()中通过getIntent().getAction()与getIntent().getData()解析深度链接,并据此展示对应内容; - 遵循体验:深度链接直达内容、不设登录/广告拦截;配合
android:parentActivityName与TaskStackBuilder实现符合规范的 Up/Back 导航; - 验证路由:使用
adb shell am start -W -a android.intent.action.VIEW -d <URI> <PACKAGE>在设备或模拟器上验证 URI 是否解析到正确 Activity; - 接入索引:按
android-app://<package_name>/<scheme>/<host_path>格式,通过 Sitemap 或页面<head>注解共享深度链接,并配置robots.txt允许 Googlebot 抓取。
完成以上步骤后,你的 App 内容就可以被搜索引擎抓取,用户也能从搜索结果中直接点击进入 App 内的具体页面——这正是移动时代「内容可被发现」的关键能力。
- 文档
- 教程
- 移动开发
【免费下载链接】android-training-course-in-chinese
Android官方培训课程中文版
相关推荐
为 Google 搜索索引指定 Android App 内容:App Indexing 深度链接接入指南(Android 官方培训课程中文版)
为 Google 搜索索引指定 Android App 内容:App Indexing 深度链接接入指南(Android 官方培训课程中文版) 本文基于开源仓库
文档教程移动开发Android官方培训课程中文版:使你的App内容可被Google搜索——深度链接与App内容索引实战指南
Android官方培训课程中文版:使你的App内容可被Google搜索——深度链接与App内容索引实战指南 随着移动应用愈发普及,用户不再只从网站上查找信息,也
文档教程移动开发highlight.io 会话搜索深链接(Session Search Deep Linking)实战指南
highlight.io 会话搜索深链接(Session Search Deep Linking)实战指南 在 highlight.io 中,你在会话(Sess
可观测性后端
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考