Pixel3设备ACTION_VIEW仅支持图片,其他文件无法启动问题求助
看起来你遇到的核心问题是Android 7.0(API 24)及以上的文件访问权限限制,再加上代码里的几个小错误导致的。让我一步步帮你梳理和修复:
一、核心问题分析
你的代码在API24以上做了这样的处理:
if (Build.VERSION.SDK_INT >= 24) { uri = Uri.parse(fileTemporary!!.getPath()) }
这会生成一个file://格式的Uri,但从Android 7.0开始,系统禁止跨应用直接访问file://Uri(会触发FileUriExposedException,而且第三方应用没有权限读取这个路径),所以除了系统默认能访问图片的应用外,其他类型文件的应用无法获取到文件,自然就会提示"No Activity found to handle Intent"。
另外你第二个代码里还有个明显的错误:处理zip/rar文件时,把MIME类型写成了application/x-wav(音频格式),这肯定无法匹配到解压类应用。
二、修复步骤
1. 配置FileProvider
首先需要在AndroidManifest.xml中注册FileProvider,用于生成安全的content://Uri:
<application> ... <provider android:name="androidx.core.content.FileProvider" android:authorities="${applicationId}.fileprovider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" /> </provider> </application>
这里的authorities建议用你的应用ID加上.fileprovider,确保唯一。
2. 创建文件路径配置文件
在res/xml目录下创建file_paths.xml(如果没有xml目录就新建一个),内容如下,指定允许共享的文件目录:
<?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <external-path name="external_files" path="." /> </paths>
这个配置允许共享外部存储根目录下的所有文件,对应你代码里的Environment.getExternalStorageDirectory()路径。
3. 修改代码生成正确的Uri
替换你第一个代码里的Uri生成逻辑:
var uri: Uri if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { // API24及以上用FileProvider生成content://Uri uri = FileProvider.getUriForFile( activity!!, "${activity!!.packageName}.fileprovider", // 和manifest里的authorities一致 fileTemporary!! ) } else { // 低版本直接用file://Uri uri = Uri.fromFile(fileTemporary) }
注意这里不要用Uri.parse(file.getPath()),而是用FileProvider.getUriForFile()生成合法的content://Uri。
4. 修正第二个代码中的MIME类型错误
处理zip/rar文件时,把错误的MIME类型改成正确的:
else if (url.toString().contains(".zip") || url.toString().contains(".rar")) { // 压缩文件,正确的MIME类型 intent.setDataAndType(url, "application/zip") // 如果要兼容rar,可以再加个判断,或者直接用"application/x-rar-compressed" }
另外,处理mp3时,MIME类型应该用audio/mpeg而不是audio/x-wav,避免匹配不到音频应用。
5. 增加Intent存在性检查
为了避免崩溃,在启动Intent前最好检查是否有Activity可以处理:
if (intent.resolveActivity(activity!!.packageManager) != null) { activity!!.startActivity(intent) } else { // 提示用户没有合适的应用打开该文件 Toast.makeText(activity, "没有找到可以打开该文件的应用", Toast.LENGTH_SHORT).show() }
三、完整修正后的示例代码
这里整合一下第一个代码的修正版本:
var decodedBytes = Base64.decode(filtered.first().contentsB64String, Base64.NO_WRAP) var ext = FilenameUtils.getExtension(commonName) fileTemporary = File(Environment.getExternalStorageDirectory().toString() + "/xelion/xelion_temp." + ext) if (fileTemporary != null) { if (!fileTemporary!!.exists()) { // 确保父目录存在,否则createNewFile会失败 fileTemporary?.parentFile?.mkdirs() fileTemporary?.createNewFile() } FileUtils.writeByteArrayToFile(fileTemporary, decodedBytes) var intent = Intent(Intent.ACTION_VIEW) intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) val uri: Uri = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { FileProvider.getUriForFile( activity!!, "${activity!!.packageName}.fileprovider", fileTemporary!! ) } else { Uri.fromFile(fileTemporary) } intent.setDataAndType(uri, filtered.first().mimeType) // 检查是否有Activity能处理 if (intent.resolveActivity(activity!!.packageManager) != null) { activity!!.startActivity(intent) } else { Toast.makeText(activity, "没有找到合适的应用打开此文件", Toast.LENGTH_SHORT).show() } }
这样修改后,应该就能在Pixel3上正常打开各种类型的文件了。
内容的提问来源于stack exchange,提问作者rosu alin

