美文网首页Android进阶之路大前端-BFE学习提效
Android N调用系统安装APK方法报错原理整理及解决方案

Android N调用系统安装APK方法报错原理整理及解决方案

作者: 宋院林 | 来源:发表于2019-04-06 16:50 被阅读3次

    最近在做App的改版(由系统App改为普通App)过程中,经原来的静默安装方式改为调用系统普通安装APK的方式时,报错了,堆栈信息如下:

    fatal error
           java.lang.IllegalArgumentException: Failed to find configured root that contains /storage/emulated/0/Android/data/com.xxx.xxx/cache/com.aaa.bbb.apk
    at android.support.v4.content.FileProvider$SimplePathStrategy.getUriForFile(FileProvider.java:738)
    at android.support.v4.content.FileProvider.getUriForFile(FileProvider.java:417)
    at com.xxx.xxx.service.download.ApkDownloadHelper.installApp(ApkDownloadHelper.java:299)
    at com.xxx.xxx.service.download.ApkDownloadHelper.checkForInstall(ApkDownloadHelper.java:233)
    at com.xxx.xxx.service.download.ApkDownloadHelper.onSuccess(ApkDownloadHelper.java:220)
    at com.xxx.xxx.download.FileDownloader.notifySuccess(FileDownloader.java:246)
    at com.xxx.xxx.download.FileDownloader.onResponse(FileDownloader.java:197)
    at okhttp3.RealCall$AsyncCall.execute(RealCall.java:153)
    at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:32)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
    at java.lang.Thread.run(Thread.java:764)
    

    Failed to find configured root that……

    这里的意思是说:没有找到根目录的配置。

    接下来,我们查阅FileProvider.java源文件,发现有一个常量定义

    private static final String TAG_ROOT_PATH = "root-path";
    

    紧接着,我们寻找使用这个变量的地方,在文件第620行找到,如下:

    private static PathStrategy parsePathStrategy(Context context, String authority)
            throws IOException, XmlPullParserException {
        final SimplePathStrategy strat = new SimplePathStrategy(authority);
    
        final ProviderInfo info = context.getPackageManager()
                .resolveContentProvider(authority, PackageManager.GET_META_DATA);
        final XmlResourceParser in = info.loadXmlMetaData(
                context.getPackageManager(), META_DATA_FILE_PROVIDER_PATHS);
        if (in == null) {
            throw new IllegalArgumentException(
                    "Missing " + META_DATA_FILE_PROVIDER_PATHS + " meta-data");
        }
    
        int type;
        while ((type = in.next()) != END_DOCUMENT) {
            if (type == START_TAG) {
                final String tag = in.getName();
    
                final String name = in.getAttributeValue(null, ATTR_NAME);
                String path = in.getAttributeValue(null, ATTR_PATH);
    
                File target = null;
                
                if (TAG_ROOT_PATH.equals(tag)) {
                    target = DEVICE_ROOT;
                } else if (TAG_FILES_PATH.equals(tag)) {
                    target = context.getFilesDir();
                } else if (TAG_CACHE_PATH.equals(tag)) {
                    target = context.getCacheDir();
                } else if (TAG_EXTERNAL.equals(tag)) {
    

    这个方法主要是“分析路径策略”,主要是解析manifest中配置的provider的meta-data属性中的resource中file_paths文件。

    <provider
        android:name="android.support.v4.content.FileProvider"
        android:authorities="${applicationId}.provider"
        android:exported="false"
        android:grantUriPermissions="true">
        <meta-data
            android:name="android.support.FILE_PROVIDER_PATHS"
            android:resource="@xml/file_paths" />
    </provider>
    

    Android N开始,Google逐步提高了系统的安全性,其中包括文件的访问。所以从Android N开始,提高了文件访问的门槛,需要再file_paths中增加如下配置:

    <?xml version="1.0" encoding="utf-8"?>
    <paths>
        <!--Context.getFilesDir()位于/data/data/安装目录-->
        <files-path
            name="internalPath"
            path="file" />
        <!--Context.getCacheDir()-->
        <cache-path
            name="cachePath"
            path="file" />
        <!--Environment.getExternalStorageDirectory()-->
        <external-path
            name="externalPath"
            path="file" />
        <!--Context.getExternalFilesDir(null)-->
        <external-files-path
            name="externalPath"
            path="file" />
    
        <external-cache-path
            name="externalCachePath"
            path="file" />
        <!--增加根目录配置,特别注意:此处的path要为空字符串-->
        <root-path
            name="rootPath"
            path="" />
    </paths>
    

    其中,要特别注意:root-path中的path属性一定要为""。

    这样,我们就可以解决一开始抛出的文件。

    欢迎大家在评论区留言,一起交流,谢谢。

    相关文章

      网友评论

        本文标题:Android N调用系统安装APK方法报错原理整理及解决方案

        本文链接:https://www.haomeiwen.com/subject/azgriqtx.html