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

 

posted @ 2018-12-11 17:55  WidgetBox  阅读(1308)  评论(1编辑  收藏  举报