Android 7.0 以上安装Apk适配方案总结

解决:FileUriExposedException异常:
最近在 Android版本号大于 N的手机上强更  安装Apk时报错,错误信息如下:

android.os.FileUriExposedException: file:///storage/emulated/0/Download/xxxAppName.apk exposed beyond app through Intent.getData()

手机端调用的代码如下:

Intent intentUpdate = new Intent("android.intent.action.VIEW"); intentUpdate.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); Uri apkUri = Uri.fromFile(new File(upgradeMsg.apkpath));    intentUpdate.setDataAndType(apkUri, "application/vnd.android.package-archive"); startActivity(intentUpdate);  

报这个错误主要是应为google在6.0以后的版本做了权限限制, 应用程序 不能直接通过**file:// Uri向另一个共享资源,需要通过content://Uris **来共享资源,以便平台可以扩展接收应用程序的临时权限以访问资源。但是N之前的版本还是可以通过 file:// 的方式去共享资源的。
主要原因总结如下:

  1. 假如共享的文件是私有的,接收file://Uri 的App无法访问文件
  2. 在Android6.0之后引入运行时权限,如果file://Uri 的app没有申请 Manifest.permission.READ_EXTERNAL_STORAGE权限,在读取文件时 会引发崩溃

解决这种错误的方法google也给出了方案,用FileProvider,它为文件 创建 content://Uri 而不是 file://Uri 来做文件的安全共享。
FileProvider主要步骤:

  1. 定义FileProvider
  2. 指定可用文件
  3. 检索文件内容的URI
  4. 授权URI临时权限
  5. 向另一个应用程序提供内容URI

在AndroidManifest.xml中添加如下代码

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

注意: 
authorities:app的包名.fileProvider 
grantUriPermissions:必须是true,表示授予 URI 临时访问权限 
exported:必须是false 
resource:中的@xml/file_paths是我们接下来要添加的文件

在res目录下新建一个xml文件夹,并且新建一个file_paths的xml文件

  <paths>        <external-path            name="download"            path="" />    paths>

path:需要临时授权访问的路径(.代表所有路径) 
name:就是你给这个访问路径起个名字

现在就差修改安装时候的代码了,代码如下:

 private void installApk() { //安装程序        Intent  intentUpdate = new Intent("android.intent.action.VIEW");        intentUpdate.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {  //对Android N及以上的版本做判断            Uri apkUriN = FileProvider.getUriForFile(MainActivity2.this,            MainActivity2.this.getApplicationContext().getPackageName() + ".FileProvider", new File(upgradeMsg.apkpath));            intentUpdate.addCategory("android.intent.category.DEFAULT");            intentUpdate.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);   //天假Flag 表示我们需要什么权限            intentUpdate.setDataAndType(apkUriN, "application/vnd.android.package-archive");        } else {            Uri apkUri = Uri.fromFile(new File(upgradeMsg.apkpath));             intentUpdate.setDataAndType(apkUri, "application/vnd.android.package-archive");        }        startActivity(intentUpdate);    }

代码写好了,是不是以为就可以了? 当你开开心心的在 6.0 或者7.0 ~ 8.0之间的收做更新安装时候,无丝毫毛病,但是当你在8.0及以上版本做安装的时候,点击更新 会一闪而过,或者解析包出错。为什么呢?
因为在Aandroid 8.0 时候Google又做了一些限制操作

Android 8.0 Oreo 中,Google 移除掉了容易被滥用的“允许位置来源”应用的开关,在安装 Play Store 之外的第三方来源的 Android 应用的时候,竟然没有了“允许未知来源”的检查框,如果你还是想要安装某个被自己所信任的开发者的 app,则需要在每一次都手动授予“安装未知应用”的许可。

我们得适配8.0 及以上的版本机型。
首先需要在AandroidManifest.xml 中增加权限

<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/> 

其次再点击更新时候需要判断手机版本信息:

private static final int INSTALL_PACKAGES_REQUESTCODE = 10011;private static final int GET_UNKNOWN_APP_SOURCES = 10012;private void checkAndroidO() {         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { //系统 Android O及以上版本          //是否需要处理未知应用来源权限。 true为用户信任安装包安装 false 则需要获取授权            boolean canRequestPackageInstalls = getPackageManager().canRequestPackageInstalls();              if (canRequestPackageInstalls) {                  installApk();            } else {              //请求安装未知应用来源的权限              ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.REQUEST_INSTALL_PACKAGES}, INSTALL_PACKAGES_REQUESTCODE);             }        } else {  //直接安装流程            installApk();        }    }    @Override    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {        super.onRequestPermissionsResult(requestCode, permissions, grantResults);        switch (requestCode) {            case INSTALL_PACKAGES_REQUESTCODE:                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {  //如果已经有这个权限 则直接安装 否则跳转到授权界面                    installApk();                } else {                    Uri packageURI = Uri.parse("package:" + getPackageName());   //获取包名,直接跳转到对应App授权界面                    Intent intent = new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES, packageURI);                    startActivityForResult(intent, GET_UNKNOWN_APP_SOURCES);                }                break;        }            //我们还需要在 onActivityResult方法中继续做一些相应的处理,好让授权成功后 返回App可以直接安装       @Override    public void onActivityResult(int requestCode, int resultCode, Intent data) {        super.onActivityResult(requestCode, resultCode, data);        //8.0 以上系统 强更新授权 界面        switch (requestCode) {            case GET_UNKNOWN_APP_SOURCES:                checkAndroidO();                break;            default:                break;        }    }

好了,到这里适配7.0 以上机型 的安装问题就全部解决了。

更多相关文章

  1. android播放视频和视频做背景
  2. FileObserver的使用
  3. NanoHttpd 构建android 手机端的HttpServer
  4. 一个切换的Widget
  5. INSTALL_FAILED_TEST_ONLY
  6. RN: android 显示 gif compile 'com.facebook.fresco:fresco
  7. Android用Webview播放视频问题
  8. Android(安卓)的系统属性(SystemProperties)设置分析
  9. Qt for Android(安卓)使用 手记

随机推荐

  1. No resource found that matches the giv
  2. Android—Animation
  3. android Recorder流程
  4. android setTag (int key, Object tag)抛
  5. Android图片轮播
  6. Android遍历获取指定目录的文件
  7. ListView与其中的Button,EditText等Widge
  8. 在ubuntu10.10上安装android sdk
  9. error:Error parsing XML:unbound prefix
  10. android开发数据存储方式