apk安装

作者: boyrt | 来源:发表于2018-05-30 12:45 被阅读0次

    apk安装场景:app升级时,下载apk后,提示用户安装。

    通过代码实现apk安装,注意,必须判断手机android系统,因为android7.0及其以上和之前版本的安装方式不同。

    • android7.0及其以上系统安装说明
    • 最终apk安装代码

    1. android7.0及其以上系统安装说明

    Android 7.0以下系统,安装方法:

    Intent intent = new Intent(Intent.ACTION_VIEW); 
    intent.setDataAndType(Uri.fromFile(apkFile), “application/vnd.android.package-archive”); 
    context.startActivity(intent);
    

    但是在Android7.0的系统上,运行这段代码,会报如下错误。

    Caused by: android.os.FileUriExposedException

    因为安卓官方为了提高私有文件的安全性,面向 Android 7.0 或更高版本的应用私有目录被限制访问 (0700)。此设置可防止私有文件的元数据泄漏,如它们的大小或存在性.

    传递软件包网域外的 file:// URI 可能给接收器留下无法访问的路径。因此,尝试传递 file:// URI 会触发 FileUriExposedException。分享私有文件内容的推荐方法是使用 FileProvider

    实现android7.0及其以上系统安装apk的基本操作:

    定义一个FileProvider
    添加可用权限的文件目录
    增加到provider
    通过provider生成Uri
    赋予临时权限给Uri

    (1)定义一个FileProvider

    <manifest>
        ...
        <application>
            ...
            <provider
                android:name="android.support.v4.content.FileProvider"
                android:authorities="${applicationId}.fileprovider"
                android:exported="false"
                android:grantUriPermissions="true">
                ...
            </provider>
            ...
        </application>
    </manifest>
    

    (2)添加可用权限的文件目录

    在res目录下,增加xml文件夹,并新建一个名为 file_paths.xml 的文件。文件内容格式如下:

    <paths xmlns:android="http://schemas.android.com/apk/res/android">
            <files-path name="name1" path="test1" />
            ...
    </paths>
    

    标签下面必须至少包含以下标签中的一个或者多个。

    files-path

    <files-path name="name1" path="test1" />
    

    表示Context.getFilesDir()目录或者其子目录。

    示例 : /data/data/包名/files/test1

    cache-path

    <cache-path name="name2" path="test2" />
    

    表示Context.getCacheDir()目录或者其子目录。

    示例 : /data/data/包名/cache/test2

    external-path

    <external-path name="name3" path="test3" />
    

    表示Environment.getExternalStorageDirectory()目录或者其子目录。

    示例 : /storage/emulated/0/test3

    external-files-path

    <external-files-path name="name4" path="test4" />
    

    表示Context.getExternalFilesDir(null)目录或者其子目录。

    示例 : /storage/emulated/0/Android/data/包名/files/test4

    external-cache-path

    <external-cache-path name="name5" path="test5" />
    

    表示Context.getExternalCacheDir()目录或者其子目录。

    示例 : /storage/emulated/0/Android/data/包名/cache/test5

    (3)增加到provider

    通过<meta-data>标签将上面的filepath添加到provider当中。

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

    (4)通过provider生成Uri

    File imagePath = new File(Context.getFilesDir(), "test1");
    File newFile = new File(imagePath, "default_image.jpg");
    Uri contentUri = FileProvider.getUriForFile(getContext(), "包名.fileprovider", newFile);
    

    getUriForFile方法的第二个参数是<provider>标签中的authorities属性的值包名.fileprovider

    (5)赋予临时权限给Uri

    intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
    

    2. 最终apk安装的代码

    public static void installApk(Context context, String apkPath) {
        if (context == null || TextUtils.isEmpty(apkPath)) {
            return;
        }
    
        File file = new File(apkPath);
        Intent intent = new Intent(Intent.ACTION_VIEW);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        //判读版本是否在7.0以上
        if (Build.VERSION.SDK_INT >=Build.VERSION_CODES.N) {
            //provider authorities
            Uri apkUri = FileProvider.getUriForFile(context, context.getPackageName()+".fileprovider, file);
            //Granting Temporary Permissions to a URI
            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
            intent.setDataAndType(apkUri, "application/vnd.android.package-archive");
        } else {
            intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
        }
    
        context.startActivity(intent);
    }
    

    3. 坑

    下载apk包后,保存的路径是:Context.getExternalFilesDir(null),即/storage/emulated/0/Android/data/包名/files/xxx目录下。然后执行安装的时候报异常:

    java.lang.IllegalArgumentException: Failed to find configured root that contains
     /storage/emulated/0/Android/data/com.zjrcu.platform/files/Download/xxx.apk
    

    开始的时候以为是file_paths.xml中的external-files-path配置错误,但是检查后,没问题。
    然后我将apk保存的路径换成 /data/data/包名/files/test1,file_paths.xml中的配置改为files-path,执行安装成功。
    另外,将路径换成 /storage/emulated/0/test3,file_paths.xml中的配置改为external-path,执行安装也能成功。

    这个现象是在魅族7.0系统上测试出来的,没有其它测试机,所以不知道其它手机是否存在该问题。-_-||

    相关文章

      网友评论

          本文标题:apk安装

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