You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过Jetpack Compose DeepLinking实现TXT文件打开与导航传参

解决Jetpack Compose中通过DeepLink获取TXT文件URI的问题

问题概述

需要实现:用户点击TXT文件时,应用出现在系统「打开方式」列表;选中应用后,获取文件URI并传递给对应的导航Composable。当前应用已能出现在打开方式列表,但无法正确获取文件路径。

现有代码问题分析

  1. Manifest配置问题:
    • 重复的<data>标签导致匹配逻辑混乱
    • BROWSABLE类别为网页链接跳转设计,文件打开场景不需要
  2. 导航DeepLink配置问题:
    • uriPattern仅匹配file:// URI,但Android文件分享大多使用content:// URI,无法覆盖所有场景
    • 路由参数名不一致:路由中用projectPath,参数定义用project,导致参数无法正确映射
  3. 未适配Android文件访问规则:Android 10+ 禁止直接访问文件路径,需通过ContentResolver读取content:// URI指向的文件

修正方案与代码示例

1. 修正Manifest的Intent Filter

合并<data>标签,同时支持content和file scheme,适配不同文件分享场景:

<intent-filter>
    <action android:name="android.intent.action.VIEW" />
    <category android:name="android.intent.category.DEFAULT" />
    <!-- 同时支持content和file类型的URI -->
    <data
        android:scheme="content"
        android:mimeType="text/plain" />
    <data
        android:scheme="file"
        android:mimeType="text/plain" />
</intent-filter>

2. 正确配置导航DeepLink与参数传递

提供两种可靠实现方式,选其一即可:

方式一:直接从Intent获取URI(推荐,适配所有启动场景)

在Activity中获取启动Intent的data,再传递给导航组件:

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            val navController = rememberNavController()
            // 获取启动Intent中的文件URI
            val launchFileUri = intent.data?.toString() ?: ""

            NavHost(navController, startDestination = Screen.HomeScreen.route) {
                composable(
                    route = "${Screen.HomeScreen.route}?fileUri={fileUri}",
                    arguments = listOf(
                        navArgument("fileUri") {
                            type = NavType.StringType
                            defaultValue = ""
                        }
                    )
                ) { backStackEntry ->
                    // 优先取导航参数,没有则取启动时的URI
                    val fileUri = backStackEntry.arguments?.getString("fileUri") ?: launchFileUri
                    HomeScreen(fileUri = fileUri)
                }
            }
        }

        // 如果是从打开方式启动,直接导航到目标页面并传递参数
        intent.data?.let { uri ->
            val encodedUri = Uri.encode(uri.toString())
            navController.navigate("${Screen.HomeScreen.route}?fileUri=$encodedUri")
        }
    }
}

方式二:配置DeepLink匹配URI

通过导航组件的DeepLink直接匹配content和file类型的URI:

NavHost(navController = navController, startDestination = Screen.HomeScreen.route) {
    composable(
        route = "${Screen.HomeScreen.route}?fileUri={fileUri}",
        deepLinks = listOf(
            // 匹配content://开头的URI
            navDeepLink {
                uriPattern = "content://{fileUri}"
                mimeType = "text/plain"
            },
            // 匹配file://开头的URI
            navDeepLink {
                uriPattern = "file://{fileUri}"
                mimeType = "text/plain"
            }
        ),
        arguments = listOf(
            navArgument("fileUri") {
                type = NavType.StringType
                defaultValue = ""
            }
        )
    ) { backStackEntry ->
        val fileUri = backStackEntry.arguments?.getString("fileUri") ?: ""
        HomeScreen(fileUri = fileUri)
    }
}

3. 读取TXT文件内容的工具函数

由于content:// URI无法直接转为文件路径,需使用ContentResolver读取内容:

fun readTxtFileContent(context: Context, fileUri: String): String {
    val uri = Uri.parse(fileUri)
    val contentBuilder = StringBuilder()
    
    context.contentResolver.openInputStream(uri)?.use { inputStream ->
        BufferedReader(InputStreamReader(inputStream)).use { reader ->
            var line: String?
            while (reader.readLine().also { line = it } != null) {
                contentBuilder.append(line).append("\n")
            }
        }
    }
    return contentBuilder.toString()
}

注意事项

  • 参数名一致性:路由中的参数名(如fileUri)必须和navArgument中的名称完全一致
  • 权限处理:访问外部存储文件时,Android 10+ 可使用Scoped Storage无需申请权限;低于Android 10需添加READ_EXTERNAL_STORAGE权限
  • 测试验证:修改Manifest后需重启应用或清除缓存,确保Intent Filter生效
  • URI编码:传递URI参数时需用Uri.encode()编码特殊字符,避免导航失败

内容的提问来源于stack exchange,提问作者Alfin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 20:55:35