调用系统安装应用的界面来安装 apk
说明
调用系统的安装界面来安装 apk ,也就是说需要跳转 activity ,而且只能隐式启动,那就需要使用 Intent 并设置 action 和 data 等,这里需要的为 Intent 作如下设置:
设置 action: Intent.ACTION_VIEW 即 “android.intent.action.VIEW”
设置 category: Intent.CATEGORY_DEFAULT 即 “android.intent.category.DEFAULT”
设置 data 和 type
要使用 setDataAndType 方法同时设置 data和 type
data: 一般是格式为 “file:// ” 开头的 URI,例如 Uri.parse(“file:///storage/test.apk”)
type: “application/vnd.android.package-archive”
不能单独设置,原因看如下源码:
//单独设置 data 会清空 type
public Intent setData(Uri data) {
mData = data;
mType = null;
return this;
}
//单独设置 type 会清空 data
public Intent setType(String type) {
mData = null;
mType = type;
return this;
}
//同时设置 data 和 type
public Intent setDataAndType(Uri data, String type) {
mData = data;
mType = type;
return this;
}
综上:
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.addCategory(Intent.CATEGORY_DEFAULT);
intent.setDataAndType(Uri.parse("file:///storage/test.apk"),"application/vnd.android.package-archive");
Demo
主要使用的是如下代码,先声明:我把要安装的 apk 文件拷贝到了 SD 卡的 /demos/data/ 目录下
private void installApp() {
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {//sd 卡已挂载
//获取外部存储(SD 卡)根路径 我的模拟器是:/storage/emulated/0
String path = Environment.getExternalStorageDirectory().getAbsolutePath();
//apk 文件 放在 SD 卡的 /demos/data/ 下,名称是 JianShu-1.11.1.apk
File targetFile = new File(path + "/demos/data","JianShu-1.11.1.apk");
if (targetFile.exists()) {//先判断文件是否已存在
Log.i(TAG,"targetFile: " + targetFile.getPath());
//Log.i(TAG,"Uri: " + Uri.fromFile(targetFile));
//1. 创建 Intent 并设置 action
Intent intent = new Intent(Intent.ACTION_VIEW);
//2. 设置 category
intent.addCategory(Intent.CATEGORY_DEFAULT);
//添加 flag ,不记得在哪里看到的,说是解决:有些机器上不能成功跳转的问题
//intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
//3. 设置 data 和 type
intent.setDataAndType(Uri.fromFile(targetFile),"application/vnd.android.package-archive");
//3. 设置 data 和 type (效果和上面一样)
//intent.setDataAndType(Uri.parse("file://" + targetFile.getPath()),"application/vnd.android.package-archive");
//4. 启动 activity
startActivity(intent);
}else {
Toast.makeText(getApplicationContext(), "apk 文件不存在",Toast.LENGTH_SHORT).show();
}
}
}
效果图
p.s.不要在意右上角的 “你” 字….
备注
在本 demo 中,一开始我是把 apk 文件放在项目的 assets 资源文件夹下的,然后在应用启动的时候,通过代码把它从 assets 文件夹下拷贝到 SD 卡中 (说白了就是读取 assets 目录下的 apk 文件内容,写入 SD 卡中),但是在这个过程中遇到了两个问题:
最初我把 apk 安装包从 assets 文件夹下拷贝到了 内部存储路径 即 /data/data/包名/file/ 目录下,然后在跳转安装界面的时候,总是出现 软件包解析错误 的问题,折腾好久才意识到 系统安装界面是没有访问当前应用内部存储的权限的(内部存储只有当前应用自己有读写权限),好吧,我承认自己 SB 了…
后来我决定把 apk 文件拷贝文件 SD 卡中(最终目录是 /storage/emulated/0/demos/data/JianShu-1.11.1.apk)但是创建文件夹 /demos/data/ 的时候总是失败,读写 SD 卡的权限也配置了,并且特么的没有报错也没有警告!!也是弄了很久,发现自己用的模拟器 是 Android 6.0 即 API 23 ,在这个版本及以上读写 SD 卡需要检查运行时权限才行… 配置后才终于搞定了…
权限:
写 SD 卡的权限:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
创建/删除文件的权限:
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>