在 APK 开发中,通过 Java 代码来打开系统的安装程序以安装 APK 并不是什么难事,一般的 Android 系统都有开放这一功能。 但随着 Android系统版本的迭代,其对于权限的把控越来越严格,或者说是变得越来越注重安全性。这就导致了以前可以通过很简单的几行代码就能实现的功能,现在要复杂很多。 对于通过代码打开系统安装程序这一功能的限制,其分水岭在 Android7.0,即 Android N 上。通常在 Android N以上的系统使用一种做法,以下则使用另一种做法。 传统的通过代码安装APK的方式 这种方法简单粗暴且实用,只要知晓要安装的 APK 的位置,并拥有访问权限即可。 说到权限问题,在Android版本不断提高的趋势下,系统得安全性也越来越高,很多权限不只是在清单文件里面注册那么简单,内存卡得读写权限属于危险权限,需要我们使用代码动态添加,这里我使用了RxPermiision框架,遇到9.0或者更高版本的系统时获取权限的方法可能会不同。 Android更多权限得查询:https://www.jianshu.com/p/24f79a70025b 上面这段代码安装代码看起来似乎和传统的方式并没有太大的区别是吗? 确实是,但它真正的区别并没有在 Java 代码上体现出来。 在高版本系统中,APK 已经不能直接访问其它 APK 的私有数据了。 什么是APK的私有数据? APK在安装过程中于 data 目录下创建的专属目录自然是其私有数据无疑。另外,只要是在应用程序中封装的 File 对象,不管这个文件本身是不是由该程序创建的,那这个文件都属于该程序的“私有数据”。举个例子来说,假设我们将手机连接到电脑,通过 adb push 的方式往 sdcard 目录下推了一个 APK 文件进去。然后我们自行编写了一段代码,将这个 sdcard 中的安装包传到系统的 PackageInstaller 中去安装,都会报安全错误,因为这个位于 sdcard 目录下文件对我们这段代码来说是“私有数据”,不允许直接暴露给 PackageInstaller。 下面就来看看在高版本系统中暴露“私有数据”给其它程序的方法。 在高版本中,Android7.0 及以上,开放(暴露)私有数据的唯一方式是通过 ContentProvider 来实现。 具体的步骤大致如下: 1、AndroidManifest.xml 配置 前面说过,高版本系统中其实就是将以前的直接开放变成通过 ContentProvider 来间接开放。因此我们需要在 AndroidManifest.xml 中添加一个 provider 标签,示例如下: 2、paths 配置 其他路径的的配置方式请参考:https://editor.csdn.net/md?articleId=106670247 简单来说,就是将你要开放出去的路径的类型选好,然后填上该类型下的相对路径即可。 这表示我们想开放 程序内存里面的files目录,然后在 files 目录下的子路径是 /apk,组合成绝对路径就是 /data/con.xxx.xxx/files/apk 。至于 name 标签则是用于 ContentProvider 标识使用的,一般来讲按需要设置成不同的值就可以了,这里我有一个子目录。 3、Java 代码配置 Java 代码的配置就没什么特别的了,直接以章节首部的代码来用就可以了。关键的代码其实只有一行: Uri uri = FileProvider.getUriForFile(context, authority, file); 这里的三个参数分别为: 通常我们都会兼顾 Android 高低版本的系统,因此会使用如下所示的“混合型”代码:
 File apk = new File(...);  Uri uri = Uri.fromFile(apk);  Intent intent = new Intent();  intent.setClassName("com.android.packageinstaller", "com.android.packageinstaller.PackageInstallerActivity");  intent.setData(uri);  intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);  startActivity(intent); 
 但现在市面上主流的 Android 手机系统版本都已经要高于 7.0 了,这一方法几乎已经没有用了
 File apk = new File(...);  Intent intent = new Intent(Intent.ACTION_VIEW);  intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);  intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);  Uri uri = FileProvider.getUriForFile(this, "com.apk.demo.fileprovider", apk);  intent.setDataAndType(uri, "application/vnd.android.package-archive");  startActivity(intent); private void rxPermission() {         RxPermissions rxPermissions = new RxPermissions(this);         rxPermissions.request(Manifest.permission.WRITE_EXTERNAL_STORAGE).subscribe(new Consumer<Boolean>() {             @Override             public void accept(Boolean granted) throws Exception {                 if (granted) {                     //权限允许                     //在这里可以添加自己的操作                 } else {                     // 权限被拒绝                 }             }         });     } 
<provider     android:name="androidx.core.content.FileProvider"     android:authorities="com.your.app.fileprovider"     android:exported="false"      android:grantUriPermissions="true">     <meta-data         android:name="android.support.FILE_PROVIDER_PATHS"         android:resource="@xml/file_paths" /> </provider> 
 如果内容提供器的grantUriPermissions属性被设置为true,那么权限能够被授予内容提供器范围内的任何数据。但是,如果grantUriPermission属性被设置为false,那么权限就只能授予这个元素所指定的数据子集。一个内容提供器能够包含任意多个元素。每个都只能指定一个路径(三个可能属性中的一个)。
<?xml version="1.0" encoding="utf-8"?> <paths>     <files-path path="apk/" name="apk" /> </paths> 
 我们以示例详细说说:<?xml version="1.0" encoding="utf-8"?> <paths>     <files-path path="apk/" name="apk" /> </paths> 
String authority =  new StringBuilder(packageName).append(".provider").toString(); //这里的strFile文件的路径+名称;例如:/data/file/apk/xxx.apk File f=new File(strFile); Uri uri = FileProvider.getUriForFile(context, authority, file);  public void install(){  try{//这里有文件流的读写,需要处理一下异常   Intent intent = new Intent(Intent.ACTION_VIEW);   intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);   intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);   if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N){    //如果SDK版本>=24,即:Build.VERSION.SDK_INT >= 24      String packageName = context.getApplicationContext().getPackageName();      String authority =  new StringBuilder(packageName).append(".provider").toString();      uri = FileProvider.getUriForFile(context, authority, file);      intent.setDataAndType(uri, "application/vnd.android.package-archive");      } else{       uri = Uri.fromFile(file);       intent.setDataAndType(uri, "application/vnd.android.package-archive");   }   context.startActivity(intent);  }catch (Exception e) {             e.printStackTrace();     } } 
本网页所有视频内容由 imoviebox边看边下-网页视频下载, iurlBox网页地址收藏管理器 下载并得到。
ImovieBox网页视频下载器 下载地址: ImovieBox网页视频下载器-最新版本下载
本文章由: imapbox邮箱云存储,邮箱网盘,ImageBox 图片批量下载器,网页图片批量下载专家,网页图片批量下载器,获取到文章图片,imoviebox网页视频批量下载器,下载视频内容,为您提供.
阅读和此文章类似的: 全球云计算
 官方软件产品操作指南 (170)
官方软件产品操作指南 (170)