Lsposed中deeplink处理代码
<activity
android:name=".ui.activity.MainActivity"
android:exported="true"
android:launchMode="singleTop">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<action android:name="android.intent.action.APPLICATION_PREFERENCES" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data
android:name="android.app.shortcuts"
android:resource="@xml/shortcuts" />
</activity>
private void handleIntent(Intent intent) {
if (intent == null) {
return;
}
NavHostFragment navHostFragment = (NavHostFragment) getSupportFragmentManager().findFragmentById(R.id.nav_host_fragment);
if (navHostFragment == null) {
return;
}
NavController navController = navHostFragment.getNavController();
var nav = (NavigationBarView) binding.nav;
if (intent.getAction() != null && intent.getAction().equals("android.intent.action.APPLICATION_PREFERENCES")) {
nav.setSelectedItemId(R.id.settings_fragment);
} else if (ConfigManager.isBinderAlive()) {
if (!TextUtils.isEmpty(intent.getDataString())) {
switch (intent.getDataString()) {
case "modules" -> nav.setSelectedItemId(R.id.modules_nav);
case "logs" -> nav.setSelectedItemId(R.id.logs_fragment);
case "repo" -> {
if (ConfigManager.isMagiskInstalled()) {
nav.setSelectedItemId(R.id.repo_nav);
}
}
case "settings" -> nav.setSelectedItemId(R.id.settings_fragment);
default -> {
var data = intent.getData();
if (data != null && Objects.equals(data.getScheme(), "module")) {
navController.navigate(
new Uri.Builder().scheme("lsposed").authority("module").appendQueryParameter("modulePackageName", data.getHost()).appendQueryParameter("moduleUserId", String.valueOf(data.getPort())).build(),
new NavOptions.Builder().setEnterAnim(R.anim.fragment_enter).setExitAnim(R.anim.fragment_exit).setPopEnterAnim(R.anim.fragment_enter_pop).setPopExitAnim(R.anim.fragment_exit_pop).setLaunchSingleTop(true).setPopUpTo(navController.getGraph().getStartDestinationId(), false, true).build());
}
}
}
}
}
}
要彻底搞懂 Jetpack Navigation 中的 DeepLink(深度链接),结合 LSPosed 代码场景,从「定义、核心作用、工作原理、配置方式、参数传递、与示例代码代码的关联」等方面做详细拆解,让你既能理解概念,又能对应到实际使用场景。
一、DeepLink 是什么?
DeepLink(深度链接)是 Jetpack Navigation 组件提供的一种 URI 路由机制,允许通过「自定义 URL」直接跳转到应用内的指定页面(Fragment/Activity),而无需从首页层层导航。
可以把它理解为:应用内页面的「专属网址」 —— 就像网页通过 https://xxx.com/detail/123 直接打开文章详情页一样,App 也能通过 lsposed://module?package=xxx 直接打开模块详情页。
核心价值:
外部唤起:其他应用、网页、桌面快捷方式、通知等,通过 URL 直接跳转到 App 内目标页面(比如LsposedManger代码中接收外部 module://xxx URL 跳转模块详情);
内部路由简化:App 内部页面跳转也可通过 URI 统一管理,无需手动传递复杂参数或维护跳转逻辑;
解耦:发起跳转的一方(如外部应用)无需知道目标页面的类名,只需知道 URL 规则,降低耦合。
二、DeepLink 的工作原理
Jetpack Navigation 的 DeepLink 本质是「URI 与页面(Fragment/Activity)的映射关系」,工作流程如下:
配置映射:在导航图(nav_graph.xml)中,给目标页面(如 ModulesFragment)绑定一个或多个 URL 规则(如 lsposed://module?modulePackageName={xxx}&moduleUserId={xxx});
发起跳转:通过 NavController.navigate(URI) 发起跳转(或外部应用通过 Intent(ACTION_VIEW, URI) 唤起 App);
匹配路由:Navigation 组件解析传入的 URI,对比导航图中所有页面的 DeepLink 规则,找到匹配的目标页面;
跳转并传参:导航到目标页面,并自动将 URI 中的参数(如 modulePackageName)传递给目标页面。
三、DeepLink 的 3 种类型(重点关注前两种)
Jetpack Navigation 支持 3 种 DeepLink,对应不同使用场景:
类型 适用场景 配置方式
显式 DeepLink App 内部页面跳转(如示例代码代码中的场景) 在 nav_graph.xml 中通过 <deepLink> 配置
隐式 DeepLink 外部应用 / 网页唤起 App 内页面(需系统注册) 除了导航图配置,还需在 AndroidManifest.xml 中注册 <intent-filter>
PendingIntent DeepLink 通知、快捷方式唤起页面(确保跳转栈正确) 结合 NavDeepLinkBuilder 构建 PendingIntent
示例代码中用到的是 显式 DeepLink(内部跳转),但如果要支持外部应用通过 module://xxx 唤起,还需要配合「隐式 DeepLink」的配置(后面会讲)。
四、DeepLink 核心配置详解(结合你的代码场景)
示例代码中,跳转 URI 是 lsposed://module?modulePackageName=xxx&moduleUserId=xxx,对应的 ModulesFragment必须在导航图(nav_graph.xml)中配置 DeepLink 规则。以下是完整配置步骤和说明:
- 导航图(nav_graph.xml)配置(核心)
导航图是 DeepLink 的「路由表」,所有页面和 URL 的映射都在这里定义。假设 LSPosed 的导航图路径是 res/navigation/nav_graph.xml,配置如下:
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/nav_graph"
app:startDestination="@id/main_fragment"> <!-- 首页 -->
<!-- 其他页面:首页、模块列表、仓库等 -->
<fragment
android:id="@+id/main_fragment"
android:name="org.lsposed.manager.ui.fragment.MainFragment" />
<fragment
android:id="@+id/modules_nav"
android:name="org.lsposed.manager.ui.fragment.ModulesFragment" />
<!-- 目标页面:模块详情页 ModulesFragment -->
<fragment
android:id="@+id/ModulesFragment"
android:name="org.lsposed.manager.ui.fragment.ModulesFragment">
<!-- 关键:DeepLink 规则配置 -->
<deepLink
android:id="@+id/deepLink_module_detail"
<!-- URI 模板:{参数名} 表示动态参数,会从跳转 URI 中提取 -->
app:uri="lsposed://module?modulePackageName={modulePackageName}&moduleUserId={moduleUserId}"
<!-- 可选:是否自动将参数写入目标页面的 SavedStateHandle(默认 true) -->
app:autoVerify="false" />
</fragment>
</navigation>
配置参数说明:
app:uri:DeepLink 的核心规则,支持 3 种匹配模式:
精确匹配:如 lsposed://module(仅匹配该 exact URL);
动态参数匹配:用 {参数名} 表示可变部分,如 {modulePackageName}(匹配任意字符串作为包名);
通配符匹配:用 * 匹配任意路径 / 参数,如 lsposed://module/*(匹配 lsposed://module/xxx、lsposed://module/yyy?a=b 等);
app:autoVerify:Android 12+ 新增,用于「应用链接验证」(确保只有你的 App 能响应该 URL,避免被其他 App 劫持),普通 DeepLink 可设为 false。
- (可选)外部唤起配置(隐式 DeepLink)
如果需要支持「外部应用 / 网页通过 module://xxx URL 唤起你的 App 并跳转到模块详情页」,还需要在 AndroidManifest.xml 中给 MainActivity 注册 <intent-filter>,告诉系统「你的 App 能处理 module 协议的 URL」:
<activity
android:name="org.lsposed.manager.ui.activity.MainActivity"
android:exported="true"> <!-- 必须设为 exported=true,允许外部唤起 -->
<!-- 隐式 DeepLink 的 Intent-Filter 配置 -->
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" /> <!-- 允许网页唤起 -->
<!-- 匹配 module 协议的 URL -->
<data
android:scheme="module" <!-- 协议名,对应示例代码中的 data.getScheme() -->
android:host="*" /> <!-- 匹配任意 host(即模块包名) -->
</intent-filter>
</activity>
五、参数传递与接收(对应示例代码)
示例代码中,跳转时通过 appendQueryParameter 传递了 modulePackageName 和 moduleUserId 两个参数,目标页面 ModulesFragment如何接收这些参数?
- 目标页面接收参数(ModulesFragment中)
Navigation 会自动将 URI 中的参数存入 Fragment 的 SavedStateHandle(推荐方式),或通过 getArguments() 获取(兼容旧版本):
public class ModulesFragment extends Fragment {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 方式 1:通过 SavedStateHandle 获取(Jetpack 推荐,支持 lifecycle 感知)
SavedStateHandle handle = Navigation.findNavController(requireView()).getCurrentBackStackEntry().getSavedStateHandle();
String modulePackageName = handle.get("modulePackageName"); // 对应 URI 中的参数名
String moduleUserId = handle.get("moduleUserId"); // 注意是字符串类型,需转成 int
// 方式 2:通过 arguments 获取(兼容旧逻辑)
Bundle args = getArguments();
if (args != null) {
String pkg = args.getString("modulePackageName");
int userId = args.getInt("moduleUserId"); // 自动转换类型
}
// 后续逻辑:根据包名和用户 ID 加载模块详情(查询模块信息、启用状态等)
}
}
- 示例代码中参数传递逻辑
原始 URL 是 module://com.example.my.module/0:
data.getHost() → com.example.my.module(作为 modulePackageName 参数);
data.getPort() → 0(作为 moduleUserId 参数,转成字符串传递);
转换后的跳转 URI 是 lsposed://module?modulePackageName=com.example.my.module&moduleUserId=0;
Navigation 解析该 URI 后,自动将参数传递给 ModulesFragment。
六、与你代码的关联总结
示例代码中的这段逻辑,正是「显式 DeepLink」的典型使用场景:
// 1. 接收外部传入的 module://xxx URL
Uri data = intent.getData();
if (data != null && Objects.equals(data.getScheme(), "module")) {
// 2. 转换为导航图中配置的 DeepLink URI(lsposed://module?xxx)
Uri deepLinkUri = new Uri.Builder()
.scheme("lsposed")
.authority("module")
.appendQueryParameter("modulePackageName", data.getHost())
.appendQueryParameter("moduleUserId", String.valueOf(data.getPort()))
.build();
// 3. 通过 NavController 发起 DeepLink 跳转,匹配到 ModulesFragment
navController.navigate(deepLinkUri, navOptions);
}
关键对应关系:
代码部分 DeepLink 概念 作用
lsposed://module?xxx DeepLink URI 规则 匹配导航图中 ModulesFragment的配置
appendQueryParameter 动态参数传递 给目标页面传递模块包名和用户 ID
navController.navigate 发起 DeepLink 跳转 触发页面导航
nav_graph.xml 中的 <deepLink> 路由映射配置 告诉 Navigation 该 URI 对应哪个页面
七、常见问题与注意事项
跳转失败? 检查导航图中 <deepLink> 的 app:uri 规则是否与跳转 URI 完全一致(大小写敏感、参数名一致);
参数接收不到? 确保参数名与 appendQueryParameter 中的键一致,且目标页面在 onCreate 或 onViewCreated 中获取(避免过早获取导致为空);
外部唤起没反应? 检查 AndroidManifest.xml 中是否注册了对应的 <intent-filter>,且 activity 的 exported="true";
重复创建页面? 示例代码中 setLaunchSingleTop(true) 已解决该问题,避免重复创建 ModulesFragment实例。
总结
DeepLink 是 Jetpack Navigation 中用于「URI 路由」的核心功能,核心是「URL 与页面的映射」。示例代码中通过它实现了「外部 URL 唤起 → 转换为内部 DeepLink → 跳转到模块详情页」的完整流程,而导航图配置和参数传递是实现这一流程的关键。
掌握 DeepLink 后,你可以轻松实现:通知跳转详情页、网页唤起 App 内页面、桌面快捷方式直达功能页等常见需求,且逻辑统一、解耦性强。