Android 系统安装--7.0与8.0中遇到的问题

最近项目需要做一个版本检测及更新的功能,这其中遇到两个比较严重的问题。

(一) 7.0的版本中,下载完成后正常流程如下

 Intent intent = new Intent(Intent.ACTION_VIEW);
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
           intent.setDataAndType(Uri.fromFile(file),"application/vnd.android.package-archive");
           startActivity(intent);

但是,在 Android 7.0 系统运行上出现解析包错误。

经过排查,发现应用崩溃前,报出FileUriExposedException异常,搜索,发现在关于 FileUriExposedException 异常的描述:

  1. 对于面向 Android N 的应用,Android 框架执行的 StrictMode,API 禁止向您的应用外公开
    file://URI。 如果一项包含文件 URI 的 Intent 离开您的应用,应用失败,并出现
    FileUriExposedException异常。
  2. 若要在应用间共享文件,您应发送一项 content://URI,并授予 URI 临时访问权限。 进行此授权的最简单方式是使用
    FileProvider类。 如需有关权限和共享文件的更多信息.

知道原因,解决起来也就快了:
1.首先在AndroidManifest文件中声明:

<provider
            android:name="android.support.v4.content.FileProvider"
            android:authorities="这里填你的包名.fileProvider"
            android:grantUriPermissions="true"
            android:exported="false">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_paths" />
        </provider>

exported 一定要设置为false,否则会有异常
android:resource=”@xml/file_paths” 为对应的资源文件

2.在对应的资源文件夹下创建指定的资源文件(如上,则创建file_paths.xml)

<paths>
  <external-path path="images" name="camera_photos" />
</paths>

其中,paths 里边的元素必须是一下的一个或者多个:
<files-path name="name" path="path" /> 对应Context.getFilesDir() + “/path/”,即/data/data/<package-name>/files/path/。
<cache-path name="name" path="path" /> 对应Context.getCacheDir() + “/path/”,即/data/data/<package-name>/cache/path/。
<external-files-path name="name" path="path" /> 对应Context.getExternalFilesDir(null) + “/path/”,即/storage/emulated/0/Android/data/<package_name>/files/path/。
<external-cache-path name="name" path="path" /> 对应Context.getExternalCacheDir() + “/path/”,即/storage/emulated/0/Android/data/<package-name>/cache/path/。
<external-path name="name" path="path" /> 对应Environment.getExternalStorageDirectory() + “/path/”,即/storage/emulated/0/path/。
这些paths里边有相同的子元素,即name和path。

3.然后我们就可以通过FileProvider来获取文件的Uri,修改后的代码如下:

Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N){
        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        Uri contentUri = FileProvider.getUriForFile(context, "包名.fileProvider", file);
        intent.setDataAndType(contentUri, "application/vnd.android.package-archive");
        startActivity(intent);

值得注意的是:Uri contentUri = FileProvider.getUriForFile(context, "包名.fileProvider", file);,这里的(包名.fileProvider)一定要与你在清单文件中定义的android:authorities的值完全相同。

(二)上面的内容是解决Android7.0的文件权限问题,但是,当程序运行在8.0的系统上的时候,问题又出现了:就是在启动系统的安装时,只是闪一下,也不进行安装。
当然,解决问题还得靠搜索。
解答如下:Android 8.0以前,所有的未知来源应用都可以被安装,或者会弹窗给用户一个提示,如此设计虽然方便,但是若被引诱安装了恶意软件,安装”未知来源”的应用有可能会对手机系统带来潜在的危害;而在Android 8.0的系统中,未知来源应用权限的开关被移除掉了,取而代之的是未知来源应用的管理列表,如果你想要安装某个被自己所信任的开发者的app,则需要在每一次都手动授权”安装未知应用”的许可。若某个应用选择的是“不允许”,那么假设app手动升级的时候,就无法成功跳转到安装页面进行正常的App升级流程了,此时需要手动去授权才行。

解决办法也很简单,就是在8.0的时候,需要让用户手动设置安装未知来源的权限。

  1. 首先添加权限:<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
  2. 在打开安装包的代码中添加兼容Android 8.0的代码:
    最终的代码如下:
{
   Intent intent = new Intent(Intent.ACTION_VIEW);
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N){
                intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
                Uri contentUri = FileProvider.getUriForFile(activity.get(), "wallet.linktime.com.wallet" + ".fileProvider", file);
                intent.setDataAndType(contentUri, "application/vnd.android.package-archive");
                //兼容8.0
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                    boolean hasInstallPermission = activity.get().getPackageManager().canRequestPackageInstalls();
                    if (!hasInstallPermission) {
                        startInstallPermissionSettingActivity();
                        return;
                    }
                }
            }else{
                intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
            }
     activity.get().startActivity(intent);
}
     /**
     * 跳转到设置-允许安装未知来源-页面
     */
    @RequiresApi(api = Build.VERSION_CODES.O)
    private void startInstallPermissionSettingActivity() {
        //注意这个是8.0新API
        Intent intent = new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
         startActivityForResult(intent,Constant.INSTALL_PERMISS_CODE);
}      

如果是8.0的系统,就会跳转到授权的界面,用户设置好之后,回调中再次将安装操作执行。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值