Android通过代码安装APK的⽅法详解
在 APK 开发中,通过 Java 代码来打开系统的安装程序以安装 APK 并不是什么难事,⼀般的 Android 系统都有开放这⼀功能。
但随着 Android系统版本的迭代,其对于权限的把控越来越严格,或者说是变得越来越注重安全性。这就导致了以前可以通过很简单的⼏⾏代码就能实现的功能,现在要复杂很多。
对于通过代码打开系统安装程序这⼀功能的限制,其分⽔岭在 Android7.0,即 Android N 上。通常在 Android N以上的系统使⽤⼀种做法,以下则使⽤另⼀种做法。
传统的通过代码安装APK的⽅式
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);
这种⽅法简单粗暴且实⽤,只要知晓要安装的 APK 的位置,并拥有访问权限即可。androidsdk安装步骤
但现在市⾯上主流的 Android ⼿机系统版本都已经要⾼于 7.0 了,这⼀⽅法⼏乎已经没有⽤了
⾼版本系统上的通过代码安装APK的⽅式
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 = UriForFile(this, "com.apk.demo.fileprovider", apk);
intent.setDataAndType(uri, "application/vnd.android.package-archive");
startActivity(intent);
说到权限问题,在Android版本不断提⾼的趋势下,系统得安全性也越来越⾼,很多权限不只是在清单⽂件⾥⾯注册那么简单,内存卡得读写权限属于危险权限,需要我们使⽤代码动态添加,这⾥我使⽤了RxPermiision框架,遇到9.0或者更⾼版本的系统时获取权限的⽅法可能会不同。
private void rxPermission() {
RxPermissions rxPermissions = new RxPermissions(this);
@Override
public void accept(Boolean granted) throws Exception {
if (granted) {
/
/权限允许
//在这⾥可以添加⾃⼰的操作
} else {
// 权限被拒绝
}
}
});
}
上⾯这段代码安装代码看起来似乎和传统的⽅式并没有太⼤的区别是吗?
确实是,但它真正的区别并没有在 Java 代码上体现出来。
在⾼版本系统中,APK 已经不能直接访问其它 APK 的私有数据了。
什么是APK的私有数据?
APK在安装过程中于 data ⽬录下创建的专属⽬录⾃然是其私有数据⽆疑。另外,只要是在应⽤程序中封装的 File 对象,不管这个⽂件本⾝是不是由该程序创建的,那这个⽂件都属于该程序的“私有数据”。举个例⼦来说,假设我们将⼿机连接到电脑,通过 adb push 的⽅式往 sdcard ⽬录下推了⼀个 APK ⽂件进去。然后我们⾃⾏编写了⼀段代码,将这个 sdcard 中的安装包传到系统的 PackageInstaller 中去安装,都会报安全错误,因为这个位于 sdcard ⽬录下⽂件对我们这段代码来说是“私有数据”,不允许直接暴露给 PackageInstaller。
下⾯就来看看在⾼版本系统中暴露“私有数据”给其它程序的⽅法。
在⾼版本中,Android7.0 及以上,开放(暴露)私有数据的唯⼀⽅式是通过 ContentProvider 来实现。
具体的步骤⼤致如下:
配置 l 中的 ContentProvider 信息;
配置要开放的 paths 信息;
在 Java 代码中通过 FileProvider 封装⽂件信息。
1、l 配置
前⾯说过,⾼版本系统中其实就是将以前的直接开放变成通过 ContentProvider 来间接开放。因此我们需要在l 中添加⼀个 provider 标签,⽰例如下:
<provider
android:name="t.FileProvider"
android:authorities="ur.app.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
android:name 属性填写的是 FileProvider 类的完整名称。这个类可以填写两个值,⼀个是位于
support(android.t.FileProvider)包下的,另⼀个是位于
androidx(t.FileProvider)包下的。这两种都可以填写,本质上没有区别。但是要根据实际情况来决定⽤哪个,即要看你的⼯程引的是 androidx ⽀援包还是 support ⽀援包。关于 support 与 androidx 的关系本⽂就不再赘述了。
android:authorities 属性就是和普通的 ContentProvider ⼀样的⽤于访问⽂件资源的 uri 标签头。值内容根据实际需要来填写即可。
android:exported这个属性表⽰的是:其他app能否访问这个provider
android:grantUriPermissions 这个属性⽤于给内容提供器的数据⼦集授权
如果内容提供器的grantUriPermissions属性被设置为true,那么权限能够被授予内容提供器范围内的任何数据。但是,如果grantUriPermission属性被设置为false,那么权限就只能授予这个元素所指定的数据⼦集。⼀个内容提供器能够包含任意多个元素。每个都只能指定⼀个路径(三个可能属性中的⼀个)。
meta-data 标签中的内容需要关注的是 android:resource 属性中的内容。这个属性的值引向⼀个⾃⾏配置的 xml ⽂件,这份 xml ⽂件记载的是设备中的路径信息,简单理解就是你想开放哪些⽬录中的⽂件资源给第三⽅使⽤的意思。关于这个 xml 的配置请看第 2 步的记载。
2、paths 配置
通常的做法是在⼯程 res ⽬录下新建⼀个 xml ⽬录,并在该 xml ⽬录下新建⼀个 xml ⽂件。⽂件的名称必须与第 1 步中@xml/ 属性值中配置的⼀致。
根据第 1 步中的⽰例代码,我们需要新建⼀个 l ⽂件。这⾥我的apk是保留在程序的file⽂件加下得,该⽂件的内容如下所⽰:
<?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>
这表⽰我们想开放程序内存⾥⾯的files⽬录,然后在 files ⽬录下的⼦路径是 /apk,组合成绝对路径就是
/x/files/apk 。⾄于 name 标签则是⽤于 ContentProvider 标识使⽤的,⼀般来讲按需要设置成不同的值就可以了,这⾥我有⼀个⼦⽬录。
3、Java 代码配置
Java 代码的配置就没什么特别的了,直接以章节⾸部的代码来⽤就可以了。关键的代码其实只有⼀⾏:
Uri uri = UriForFile(context, authority, file);
这⾥的三个参数分别为:
context:这⾥表⽰需要传⼀个上下⽂过来
authority:可以通代码在l⾥⾯获得
file:是你需要的安装的⽂件
String authority = new StringBuilder(packageName).append(".provider").toString();
//这⾥的strFile⽂件的路径+名称;例如:/data/file/apk/xxx.apk
File f=new File(strFile);
Uri uri = UriForFile(context, authority, file);
通常我们都会兼顾 Android ⾼低版本的系统,因此会使⽤如下所⽰的“混合型”代码:
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 = ApplicationContext().getPackageName();
String authority = new StringBuilder(packageName).append(".provider").toString();
uri = UriForFile(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();
}
}
总结
到此这篇关于Android 通过代码安装 APK的⽅法详解的⽂章就介绍到这了,更多相关android 代码安装apk内容请搜索以前的⽂章或继续浏览下⾯的相关⽂章希望⼤家以后多多⽀持!

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。