美文网首页
应用内更新版本apk & FileUriExposedExcep

应用内更新版本apk & FileUriExposedExcep

作者: 南窗云 | 来源:发表于2018-06-20 23:13 被阅读0次

    本文对7.0 & 8.0分别做了兼容处理

    正常解决方案报错如下:

    Caused by: android.os.FileUriExposedException: file:///storage/emulated/0/Rise/rise_parent.apk exposed beyond app through Intent.getData()
    

    需要兼容7.0+版本
    解决方案:

    1. 在清单文件 application 标签下 注册

    android:name是写死的。
    android:authorities 是用来标识该provider的唯一标识,可以结合包名
    android:exported必须设置成 false,否则运行时会报错java.lang.SecurityException: Provider must not be exported 。
    android:grantUriPermissions用来控制共享文件的访问权限。

            <!-- 兼容7.0+ 版本的下载安装APK -->
            <provider
                android:name="android.support.v4.content.FileProvider"
                android:authorities="com.fileprovider"
                android:exported="false"
                android:grantUriPermissions="true">
                <meta-data
                    android:name="android.support.FILE_PROVIDER_PATHS"
                    android:resource="@xml/file_provider" />
            </provider>
    
    1. 指定配置文件file_provider,需要再res下创建xml包,并新建file_provider.xml文件,名字随意
    <?xml version="1.0" encoding="utf-8"?>
    <paths xmlns:android="http://schemas.android.com/apk/res/android">
        <external-path
            name="version"
            path="Rise" />
    </paths>
    

    注意路径的配置要一致,否则会出现:

    万恶的报错,找不到文件
     Caused by: java.lang.IllegalArgumentException: Failed to find configured root that contains /storage/emulated/0/Rise/rise_parent.apk
    

    如下设置路径即可,不用去对应,
    path="." 表示该标签对应的根路径下的所有文件夹
    此处表示 Environment.getExternalStorageDirectory() 下的所有文件夹

    <?xml version="1.0" encoding="utf-8"?>
    <paths xmlns:android="http://schemas.android.com/apk/res/android">
        <!--<external-files-path-->
            <!--name="external-files-path"-->
            <!--path="." />-->
        <external-path
            name="version"
            path="." />
    </paths>
    

    或者指定特定文件夹下,如 Rise,则表示:
    Environment.getExternalStorageDirectory()对应的路径+ /Rise 路径下的所有文件夹

    <external-path
            name="version"
            path="Rise" />
    

    切记不要用错标签

    根元素<paths>是固定的
    <files-path name="name" path="path" /> 对应getFilesDir()。
    <cache-path name="name" path="path" /> 对应getCacheDir()。
    <external-path name="name" path="path" /> 对应Environment.getExternalStorageDirectory()。
    <external-files-path name="name" path="path" /> 对应getExternalFilesDir()。
    <external-cache-path name="name" path="path" /> 对应getExternalCacheDir()。
    

    最后说明

    7.0 以下版本安装无问题,已测试
    Android 7.0 出现解析错误

    配置build.gradle,关掉V2签名 >> v2SigningEnabled false

    // 解析包时出现问题
    // 配置build.gradle,关掉V2签名  >>  v2SigningEnabled false
      signingConfigs {
            release {
                storeFile file("key.jks")
                storePassword "1234"
                keyAlias "1234"
                keyPassword "1234"
                //  应用内更新 Android7.0 兼容
                v2SigningEnabled false
            }
        }
    

    请看这篇文章Android 7.0解析包时出现问题 的解决方案(应用内更新)

    Android 8.0 需要新添加权限 & 处理 解析包时出现问题 的bug

    第一步

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

    第二步 ,虽然7.0 关掉V2签名 >> v2SigningEnabled false,但是8.0仍遇到解析包出现问题的情况

    解决方案

    去掉 intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK 的设置即可

    //  去掉这句话 去掉这句话 去掉这句话 去掉这句话
    intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
    

    请看这篇文章Android 实现应用更新适配 Android O (Android 8.0)

    附代码:
       private fun installApk(t: File) {
            val intent = Intent()
            intent.action = "android.intent.action.VIEW"
    
            var data : Uri
            // 判断版本大于等于7.0
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                // "com.risecenter.parent.fileprovider"即是在清单文件中配置的authorities
                data = FileProvider.getUriForFile(context, "com.risecenter.parent.fileprovider", t)
                // 给目标应用一个临时授权
                intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
            } else {
                data = Uri.fromFile(t)
                intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
            }
    
            //显示完成和打开按钮
    //        intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
            intent.addCategory("android.intent.category.DEFAULT")
            intent.setDataAndType(data, "application/vnd.android.package-archive")
            mContext!!.startActivity(intent)
            android.os.Process.killProcess(android.os.Process.myPid())
        }
    

    题外之意

    你可能会说,我这边怎么只用传统解决方式就可以了,没有这么复杂。
    我的 targetSdkVersion = 27 > 26

    相关文章

      网友评论

          本文标题:应用内更新版本apk & FileUriExposedExcep

          本文链接:https://www.haomeiwen.com/subject/pmfxyftx.html