当前位置: 首页 > ai >正文

Android中点击链接跳转到对应App页面的底层原理

一、核心思想:隐式 Intent

这个功能的底层原理基于 Android 的 隐式 Intent 机制。与显式 Intent(明确指定要启动的 PackageName 和 ClassName)不同,隐式 Intent 只描述你想要执行的动作(Action)和操作的数据(Data),系统会负责找到能处理这个意图的应用组件。

e.g.:

  • 显式 Intent: “张三,把这份文件拿去打印。” (指定了具体的人)

  • 隐式 Intent: “谁有空?把这份文件拿去打印。” (只描述了动作,系统会找出所有“有空”且“会打印”的人)

在浏览器中点击一个链接时,发生的就是隐式 Intent 的启动过程。


二、技术实现:Intent Filter (意图过滤器)

一个 App 如果想要响应这种隐式 Intent,必须在它的 AndroidManifest.xml 文件中,为对应的 Activity 注册一个 <intent-filter>

一个典型的用于深度链接(Deep Link)的 Intent Filter 配置如下:

<activityandroid:name=".ProductDetailActivity"android:exported="true"> <!-- 必须设置为 true,允许外部应用启动 --><!-- 定义意图过滤器 --><intent-filter><!-- 动作:主动作,VIEW 表示查看内容 --><action android:name="android.intent.action.VIEW" /><!-- 类别:BROWSABLE 表示允许通过浏览器启动 --><!-- DEFAULT 表示可以作为默认选项出现 --><category android:name="android.intent.category.BROWSABLE" /><category android:name="android.intent.category.DEFAULT" /><!-- 数据:定义能处理的数据格式 --><dataandroid:host="www.myshop.com"android:pathPrefix="/product"android:scheme="https" /></intent-filter><!-- 通常一个App会有多个过滤器,以响应不同格式的链接 --><intent-filter><action android:name="android.intent.action.VIEW" /><category android:name="android.intent.category.BROWSABLE" /><category android:name="android.intent.category.DEFAULT" /><!-- 还可以定义自定义Scheme,如 myapp://product/123 --><dataandroid:host="product"android:scheme="myapp" /></intent-filter>
</activity>

核心属性解释:

  • <action android:name="android.intent.action.VIEW" />: 表示这个 Activity 用于“查看”内容。这是处理链接的标准动作。

  • <category android:name="android.intent.category.BROWSABLE" />: 至关重要。它表明这个 Activity 可以被浏览器(或其他Web内容)安全地启动。没有这个类别,从浏览器点击链接将无法跳转到你的 App。

  • <category android:name="android.intent.category.DEFAULT" />: 允许通过 startActivity() 启动。几乎所有 <intent-filter> 都需要它。

  • <data>: 定义了哪些链接可以唤醒这个 Activity。它可以包含多个部分:

    • android:scheme: 协议,如 httphttpsmyapp(自定义)。

    • android:host: 域名或主机名,如 www.myshop.com

    • android:path / android:pathPrefix / android:pathPattern: 路径,用于更精细地匹配特定页面,如 /product


三、底层工作流程(系统如何匹配)

当用户点击一个链接时,系统会触发一个复杂的匹配查询过程,其核心参与者是 PackageManagerService (PMS)

整个匹配和决策过程的流程图如下所示,它清晰地展示了从点击到应用启动的完整逻辑链:

步骤详解:

  1. Intent 创建: 点击事件会创建一个隐式 Intent,其 Action 为 ACTION_VIEW,Data 为被点击的 URL,并自动添加 CATEGORY_BROWSABLE 类别。

  2. 查询匹配 (Resolving): 系统(实际上是 PackageManagerService)接收到这个 Intent 后,会在其内部维护的所有已安装应用的清单数据库中进行查找。它会遍历每一个注册了 <intent-filter> 的 Activity,检查它们的过滤器是否与当前 Intent 匹配。

    • 检查 Action 是否一致。

    • 检查 Category 是否全部包含(Intent 中的所有 Category 都必须能在过滤器中找到)。

    • 检查 Data(Scheme, Host, Path)是否匹配。

  3. 结果处理

    • 无匹配项: 没有找到任何 App 可以处理此链接,系统会回退到默认行为(通常在浏览器中打开)。

    • 只有一个匹配项: 系统会直接启动那个应用的对应 Activity。

    • 有多个匹配项: 系统会弹出选择器对话框(Disambiguation Dialog),列出所有可以处理此链接的应用,让用户选择“一次”或“始终”用哪个应用打开。

  4. 目标 Activity 启动: 匹配成功后,系统会启动目标 Activity,并将包含 URL 的 Intent 传递给它。在该 Activity 的 onCreate() 方法中,开发者需要通过 getIntent().getData() 来获取传入的链接,并解析其中的参数(如产品ID),从而渲染出对应的页面。

public class ProductDetailActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_product_detail);// 1. 获取触发此Activity的IntentIntent intent = getIntent();// 2. 从Intent中获取Data,也就是被点击的链接Uri data = intent.getData();// 3. 解析链接,获取需要的参数if (data != null) {String productId = data.getLastPathSegment(); // 例如,从 https://www.myapp.com/product/123 中获取 "123"// 4. 根据productId去加载数据,更新UIfetchProductDetail(productId);}}
}

四、总结

Q:“说一下在Android里,点击一个链接跳转到对应App页面的底层原理。”

A:

“这个功能的底层原理是基于Android的隐式IntentIntent Filter机制。

首先,App如果想要被链接唤醒,必须在它的 AndroidManifest.xml 中为目标Activity注册一个 <intent-filter>。这个过滤器里会定义 ACTION_VIEW 动作、BROWSABLE 和 DEFAULT 类别,并通过 <data> 标签声明它能处理的链接格式,包括scheme(如https)、host(域名)和path(路径)。

当用户点击一个链接时,系统会创建一个包含此链接的隐式Intent。然后,系统的核心服务 PackageManagerService (PMS) 会接手,它维护着所有已安装应用的信息。PMS会在全局范围内查询所有注册的Intent Filter,找出那些声明了可以处理此Intent(即匹配链接格式)的Activity。

查询的结果分为三种情况:

  1. 找不到匹配:链接就在浏览器中打开。

  2. 找到一个匹配:系统直接启动对应App的那个Activity。

  3. 找到多个匹配:系统会弹出选择器(Disambiguation Dialog),让用户选择用哪个App来打开。

最后,目标Activity被启动,App可以在 onCreate() 方法中通过 getIntent().getData() 获取到传入的链接URL,解析出里面的参数(比如商品ID),从而跳转到对应的页面并展示正确的内容。

http://www.xdnf.cn/news/18835.html

相关文章:

  • 信号线串扰仿真
  • 【C++】类和对象 --- 类中的6个默认成员函数
  • 达梦数据库-控制文件 (二)
  • 如何在开发工具中使用钉钉MCP
  • 数据结构:在堆中插入元素(Inserting In a Heap)
  • 深度学习-----详解MNIST手写数字数据集的神经网络实现过程
  • Magicodes.IE.Pdf 生成导出PDF文件 bytes Stream FileStreamResult 下载
  • MYSQL---存储过程
  • 能源行业数据库远程运维安全合规实践:Web化平台的落地经验
  • AI 暗战: 回声室攻击 —— 解锁大模型安全防御的隐秘战场
  • [Sync_ai_vid] 唇形同步评判器 | 图像与视频处理器 | GPU测试
  • 【RabbitWQ】基于 Java 实现轻量级消息队列(二)
  • 使用 ROS2 构建客户端-服务器通信:一个简单的计算器示例
  • 储能变流器学习之MPPT
  • 汽车盲点检测系统的网络安全分析和设计
  • k8s-容器化部署论坛和商城服务
  • 开源 | 推荐一套企业级开源AI人工智能训练推理平台(数算岛):完整代码包含多租户、分布式训练、模型市场、多框架支持、边缘端适配、云边协同协议:
  • PMP项目管理知识点-⑮预测型项目概念辨析
  • Web 自动化测试常用函数实战(一)
  • Unity自定义Inspector面板之使用多选框模拟单选框
  • 测试分类(超详解)
  • vue拖动排序,vue使用 HTML5 的draggable拖放 API实现内容拖并排序,并更新数组数据
  • 基于SpringBoot的社区儿童疫苗接种预约系统设计与实现(代码+数据库+LW)
  • 【高级机器学习】3. Convex Optimisation
  • 无限长直导线周围电场分布的MATLAB
  • 【MATLAB例程】二维平面上的多目标TOA定位,目标和TOA基站的数量、位置可自行设置。附代码下载链接
  • 浅谈Elasticsearch数据写入流程的refresh和flush操作
  • ICDE 2025 | 包含OPTIONAL和UNION表达式的SPARQL查询的高效执行方法
  • 硬件开发_基于物联网的儿童座椅系统
  • 3.【鸿蒙应用开发实战: 从入门到精通】开发入门 Hello World