Android关于版本更新下载安装之踩坑记录(针对7.0以上)
最近刚刚把古老的项目targetSdk版本升级到26,升级之前是19(非常非常古老了)。那么升级后一些问题开始出现。
Android 8.0 (Android O)为了针对一些流氓软件引导用户安装其他无关应用。在应用权限设置的“特殊访问权限”中,加入了“安装其他应用”的设置,默认是关闭的。所以安装时需要授权用户去开启。
实现
1.清单文件权限声明
<uses-permissionandroid:name="android.permission.REQUEST_INSTALL_PACKAGES"/>
2.点击安装判断是否有权限
1 if (Build.VERSION.SDK_INT >= 26) { 2 //来判断应用是否有权限安装apk 3 boolean installAllowed= getPackageManager().canRequestPackageInstalls(); 4 //有权限 5 if (installAllowed) { 6 //安装apk 7 install(apkPath); 8 } else { 9 //无权限 申请权限 10 ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.REQUEST_INSTALL_PACKAGES}, INSTALL_APK_REQUESTCODE); 11 } 12 } else { 13 install(apkPath); 14 }
权限申请回调
1 @Override 2 public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { 3 super.onRequestPermissionsResult(requestCode, permissions, grantResults); 4 switch (requestCode) { 5 case INSTALL_APK_REQUESTCODE: 6 //有注册权限且用户允许安装 7 if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { 8 install(apkPath); 9 } else { 10 //将用户引导至安装未知应用界面。 11 Intent intent = new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES); 12 startActivityForResult(intent, GET_UNKNOWN_APP_SOURCES); 13 } 14 break; 15 } 16 }
安装APK
1 private void install(String apkPath) { 2 //7.0以上通过FileProvider 3 if (Environment.SYSTEM_VERSION_CODE >= 24) { 4 Uri uri = FileProvider.getUriForFile(context, Environment.FILE_PROVIDER_AUTHORITY, new File(apkPath)); 5 Intent intent = new Intent(Intent.ACTION_VIEW).setDataAndType(uri, "application/vnd.android.package-archive"); 6 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 7 intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); 8 context.startActivity(intent); 9 } else { 10 Intent intent = new Intent(Intent.ACTION_VIEW); 11 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 12 intent.setDataAndType(Uri.parse("file://" + apkPath), "application/vnd.android.package-archive"); 13 context.startActivity(intent); 14 } 15 }
这里需要注意的是7.0引入了“私有目录被限制访问”,“StrictMode API 政策”。” StrictMode API 政策” 是指禁止向你的应用外公开 file:// URI。 如果一项包含文件 file:// URI类型 的 Intent 离开你的应用,应用失败,并出现 FileUriExposedException 异常。
上面用到的代码中的Uri.fromFile 其实就是生成一个file://URL。一旦我们通过这种办法打开其它程序(这里打开系统包安装器)就认为file:// URI类型的 Intent 离开你的应用。这样程序就会发生异常。
解决办法:
用FileProvider
来解决这一问题,首先在清单文件中添加:
1 <!-- FileProvider配置访问路径,适配7.0及其以上--> 2 <provider 3 android:name="android.support.v4.content.FileProvider" 4 android:authorities="${applicationId}.provider" 5 android:exported="false" 6 android:grantUriPermissions="true"> 7 <meta-data 8 android:name="android.support.FILE_PROVIDER_PATHS" 9 android:resource="@xml/provider_paths" /> 10 </provider>
authorities:app的包名;fileProvider grantUriPermissions:true;表示授予 URI 临时访问权限 exported:false ; resource:下一步添加的文件。
然后在res下新建一个名为xml的文件家,再新建文件provider_paths:
1 <?xml version="1.0" encoding="utf-8"?> 2 <paths> 3 <external-path 4 name="files_root" 5 path="Android/data/com.example.downloadapk/"/> 6 <external-path 7 name="external_storage_root" 8 path="."/> 9 </paths>
path:需要临时授权访问的路径(.代表所有路径) name:给访问路径命名。
这样就可以完美解决7.0和8.0的问题啦!
BY LiYing