- 1、AndroidManifest中添加权限
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
android.permission.REQUEST_INSTALL_PACKAGES 这个不是危险权限,不需要动态申请
android.permission.WRITE_EXTERNAL_STORAGE,android.permission.READ_EXTERNAL_STORAGE,这两个需要动态申请权限
- 2、AndroidManifest中添加provider
<provider android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.fileProvider"
android:grantUriPermissions="true"
android:exported="false">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
android:authorities是用来标识provider的唯一标识,在同一部手机上一个”authority”串只能被一个app使用,冲突的话会导致app无法安装。我们可以利用manifest placeholders来保证authority的唯一性。
android:exported必须设置成false,否则运行时会报错java.lang.SecurityException: Provider must not be exported。
android:grantUriPermissions用来控制共享文件的访问权限,也可以在java代码中设置。
-
3.在工程里添加file_paths.xml
在项目的res目录下创建xml目录,再创建file_paths.xml文件 内容如下:
<?xml version="1.0" encoding="utf-8"?>
<paths>
<paths> <files-path path="Android/data/${applicationId}/" name="files_root" />
<files-path path="." name="files_path" />
<root-path path="." name="root"/>
<external-path path="." name="files"/></paths>
</paths>
- 4.在代码里申请安装未知来源应用的权限
boolean isGranted = getPackageManager().canRequestPackageInstalls();
如果haveInstallPermission 为 true,则说明你的应用有安装未知来源应用的权限,你直接执行安装应用的操作即可。
如果haveInstallPermission 为 false,则说明你的应用没有安装未知来源应用的权限,则无法安装应用。由于这个权限不是运行时权限,所以无法再代码中请求权限,还是需要用户跳转到设置界面中自己去打开权限。
Uri packageURI = Uri.parse("package:"+mActivity.getPackageName());
Intent intent = new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES,packageURI);
mActivity.startActivityForResult(intent,REQUEST_CODE_UNKNOWN_APP_SOURCES);
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case REQUEST_CODE_INSTALL_APP:
Log.i(TAG, "onActivityResult: " + (mIsInstallSuccess?"安装成功" : "安装失败"));
break;
case REQUEST_CODE_UNKNOWN_APP_SOURCES://位置apk资源权限
Log.i(TAG, "onActivityResult: REQUEST_CODE_UNKNOWN_APP_SOURCES" );
if (resultCode == ACTIVITY_RESULT_OK) {
install();
}
break;
}
}
在onActivityResult中去接收结果,如果同意继续执行安装方法
Uri apkUri = FileProvider.getUriForFile(mActivity, BuildConfig.APPLICATION_ID + ".fileProvider", new File(apkpath));
Intent install = new Intent(Intent.ACTION_VIEW);
//添加这一句表示对目标应用临时授权该Uri所代表的文件
//install.setFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
install.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
install.setDataAndType(apkUri, "application/vnd.android.package-archive");
mActivity.startActivityForResult(install,REQUEST_CODE_INSTALL_APP);
上源码:
package com.picovr.install;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.provider.Settings;
import android.util.Log;
import androidx.annotation.RequiresApi;
import androidx.core.content.FileProvider;
import java.io.File;
/**
* @author Admin
* @version $
* @des 安装器安装
* @updateAuthor dawn$
* @updateDes 安装器安装
*/
public class ApkInstall
{
private static final String TAG = "ApkInstall";
public static final int REQUEST_CODE_INSTALL_APP = 2;
public static final int REQUEST_CODE_UNKNOWN_APP_SOURCES = 1;
public static final int ACTIVITY_RESULT_OK = -1;
private MainActivity mActivity;
private String mApkPath;
private boolean mIsInstallSuccess = false;
public interface MainActivityResultCallback {
void onActivityResult(int requestCode, int resultCode, Intent data);
void onInstallUninstallBroadcastReceiver(Context context, Intent intent);
}
public ApkInstall(Context context, String appPath) {
mActivity = (MainActivity) context;
mActivity.setInstallCallback(mInstallCallback);
mApkPath = appPath;
install();
}
public void install() {
File file = new File(mApkPath);
if (file.exists()) {
installBySystem(mApkPath);
}
}
private MainActivityResultCallback mInstallCallback = new MainActivityResultCallback() {
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case REQUEST_CODE_INSTALL_APP:
Log.i(TAG, "onActivityResult: " + (mIsInstallSuccess?"安装成功" : "安装失败"));
break;
case REQUEST_CODE_UNKNOWN_APP_SOURCES://位置apk资源权限
Log.i(TAG, "onActivityResult: REQUEST_CODE_UNKNOWN_APP_SOURCES" );
if (resultCode == ACTIVITY_RESULT_OK) {
install();
}
break;
}
}
@Override
public void onInstallUninstallBroadcastReceiver(Context context, Intent intent) {
String packages = intent.getDataString().split(":")[1];
String action = intent.getAction();
if (Intent.ACTION_PACKAGE_ADDED.equals(action) || Intent.ACTION_PACKAGE_REPLACED.equals(action)) {
Log.d(TAG, packages + "应用程序安装了");
mIsInstallSuccess = true;
} else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
Log.d(TAG, packages + "应用程序卸载了");
}
}
};
private void installBySystem( String apkPath) {
Intent intent = new Intent(Intent.ACTION_VIEW);
File file = new File(apkPath);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Log.d(TAG, String.format("onActivityResult installBySystem:", apkPath));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
installApksO(apkPath);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
installApksN(apkPath);
}else {
installCommon(apkPath);
}
}
/**
* android7以下
*/
private void installCommon(String path){
Intent install = new Intent(Intent.ACTION_VIEW);
install.setDataAndType(Uri.parse("file://" + path), "application/vnd.android.package-archive");
mActivity.startActivityForResult(install,REQUEST_CODE_INSTALL_APP);
}
/**
* android7
* @param path
*/
private void installApksN( String path) {
Uri apkUri = FileProvider.getUriForFile(mActivity, "com.pvr.agent.fileprovider", new File(path));
Intent install = new Intent(Intent.ACTION_VIEW);
install.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
install.setDataAndType(apkUri, "application/vnd.android.package-archive");
mActivity.startActivityForResult(install,REQUEST_CODE_INSTALL_APP);
}
/**
* android8.x
* @param path
*/
@RequiresApi(api = Build.VERSION_CODES.O)
private void installApksO( final String path){
String apkpath = path;
boolean isGranted = mActivity.getPackageManager().canRequestPackageInstalls();
if (isGranted) {
Uri apkUri = FileProvider.getUriForFile(mActivity, BuildConfig.APPLICATION_ID + ".fileProvider", new File(apkpath));
Intent install = new Intent(Intent.ACTION_VIEW);
//添加这一句表示对目标应用临时授权该Uri所代表的文件
// install.setFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
install.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
install.setDataAndType(apkUri, "application/vnd.android.package-archive");
mActivity.startActivityForResult(install,REQUEST_CODE_INSTALL_APP);
} else {
Log.i(TAG, "installMethodThree: 安装应用需要打开未知来源权限,请去设置中开启权限" + path);
Uri packageURI = Uri.parse("package:"+mActivity.getPackageName());
Intent intent = new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES,packageURI);
mActivity.startActivityForResult(intent,REQUEST_CODE_UNKNOWN_APP_SOURCES);
}
}
}
参考连接:https://www.jianshu.com/p/6b7bd2a59096
还看了很多相似链接有点记不清了,这里就不一一列举了