最近在作App的改版(由系统App改成普通App)过程当中,经原来的静默安装方式改成调用系统普通安装APK的方式时,报错了,堆栈信息以下:java
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……android
这里的意思是说:没有找到根目录的配置。web
接下来,咱们查阅FileProvider.java源文件,发现有一个常量定义安全
private static final String TAG_ROOT_PATH = "root-path";
紧接着,咱们寻找使用这个变量的地方,在文件第620行找到,以下:app
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文件。ide
<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中增长以下配置:svg
<?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>
这样,咱们就能够解决一开始抛出的文件。spa
欢迎你们在评论区留言,一块儿交流,谢谢。code