1.安裝應用
//下載應用到自己的手機上,本例將安裝包放在asset上,直接讀取寫入手機的存儲卡路徑中
清單文件聲明權限
//android8.0需要install_packages權限,清單文件註冊即可,無需動態申請權限
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"></uses-permission>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"></uses-permission>
android 7.0以上使用FileProvider
清單文件中聲明
<provider
android:name="cn.demo.android8demo.traction.FileProviderUtil"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/provide_paths"></meta-data>
</provider>
provide_paths.xml文件 (寫出所需的目錄即可)
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<!--內部存儲空間應用私有目錄下cache/目錄,等同於Context.getCacheDir()-->
<cache-path
name="cache_path"
path="."></cache-path>
<!--外部存儲空間根目錄,等同於Environment.getExternalStorageDirectory()-->
<external-path
name="external_path"
path="."></external-path>
<!--外面存儲空間應用私有目錄下files/目錄,等同於Context.getExternalFilesDir(null)-->
<external-files-path
name="exteranl_files_path"
path="."></external-files-path>
<!--外部存儲空間應用私有目錄下cache/目錄,等同於Context.getExternalCacheDir()-->
<external-cache-path
name="external_cache_path"
path="."></external-cache-path>
<!--內部存儲空間私有目錄files目錄等同於Context.getFilesDir()-->
<files-path
name="files_path"
path="."></files-path>
</paths>
1) . 適配android6.0以上
//android8.0以後,權限申請的話,一個權限組的,只要同意一個權限就會默認整個權限組同意,即android8.0以下兩個權限只有同意一個即可。
//該執行需要兩個權限
String[] permissions = new String[]{
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE
};
//判斷當前權限 低版本直接通過,高版本判斷權限
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.M) {
if (ActivityCompat.checkSelfPermission(this, permissions[0]) == PackageManager.PERMISSION_GRANTED &&
ActivityCompat.checkSelfPermission(this, permissions[1]) == PackageManager.PERMISSION_GRANTED) {
installApk();
} else {
ActivityCompat.requestPermissions(this, permissions, 11);
}
} else {
installApk();
}
處理權限申請
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case 11:
if (grantResults[0] == PackageManager.PERMISSION_GRANTED && grantResults[1] == PackageManager.PERMISSION_GRANTED) {
installApk();
}
break;
}
}
2)、準備安裝的apk文件
private void installApk(){
File cacheDir = getExternalCacheDir();
String CACHE_PATH;
if (cacheDir != null) {
CACHE_PATH = cacheDir.getAbsolutePath();
} else {
CACHE_PATH = Environment.getExternalStorageDirectory().getAbsolutePath();
}
String path = CACHE_PATH + System.getProperty("file.separator") + "test.apk";
final File apkFile = new File(path);//創建存儲路徑
if (!apkFile.exists()) {
Executor executor = Executors.newSingleThreadExecutor();
executor.execute(new Runnable() {
@Override
public void run() {
try {//將asset目錄下的文件讀取出來
InputStream inputStream = getAssets().open("test.apk");
OutputStream os = null;
os = new BufferedOutputStream(new FileOutputStream(apkFile, false));
byte data[] = new byte[8192];
int len;
while ((len = inputStream.read(data, 0, 8192)) != -1) {
os.write(data, 0, len);
}
if (inputStream != null)
inputStream.close();
if (os != null)
os.close();
} catch (IOException e) {
e.printStackTrace();
}//讀取文件之後執行安裝
install(apkFile);
}
});
} else {//有文件的時候直接執行安裝
install(apkFile);
}
}
3)、開始安裝文件 android8.0添加一個允許安裝第三方應用,需要用戶手動授權處理
可以用canRequestPackageInstalls來判斷用戶是否授權,未授權,跳轉到相應的頁面進行操作。
/**
* 跳轉到安裝頁面
*
* @param apkFile
*/
private void install(File apkFile) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
boolean b = getPackageManager().canRequestPackageInstalls();
if (b) {
startInstall(apkFile);
} else {//跳轉到應用授權安裝第三方應用權限
Intent intent = new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES);
startActivity(intent);
}
} else {
startInstall(apkFile);
}
}
4)、跳轉到應用的安裝頁面,將文件帶到安裝頁面進行安裝
android8.0需要添加授權fileprovider授權權限,不能使用newtask標誌位
private void startInstall(File apkFile) {
Intent intent1 = new Intent(Intent.ACTION_VIEW);
Uri data;
String type = "application/vnd.android.package-archive";
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
data = Uri.fromFile(apkFile);
intent1.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
} else {
intent1.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
String authority = getPackageName() + ".provider";
data = FileProvider.getUriForFile(this, authority, apkFile);
intent1.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
}
intent1.setDataAndType(data, type);
startActivity(intent1);
}
2.靜默安裝應用
獲取文件跟上面的一樣
判斷當前設備是否有root權限
private boolean isRoot(){
String su = "su";
//手機本來已經有root權限(/system/bin/su已經存在,adb shell裏面執行su就可以切換root權限下)
String[] locations = {"/system/bin/", "/system/xbin/", "/sbin/", "/system/sd/xbin/",
"/system/bin/failsafe/", "/data/local/xbin/", "/data/local/bin/", "/data/local/"};
for (String location : locations) {
if (new File(location + su).exists()) {
return true;
}
}
return false;
}
private boolean installSilent(File apkFile) {
boolean isDeviceRoot = isRoot();
String filePath = '"' + apkFile.getAbsolutePath() + '"';
String command = "LD_LIBRARY_PATH=/vendor/lib*:/system/lib* pm install " + filePath;
CommandResult commandResult = execCmd(new String[]{command}, isDeviceRoot, true);
if (commandResult.successMsg != null && commandResult.successMsg.toLowerCase().contains("success")) {
return true;//安裝成功
} else {
return false;//安裝失敗
}
}
命令行執行
private static final String LINE_SEP = System.getProperty("line.separator");
private CommandResult execCmd(String[] commands, boolean isRoot, boolean isNeedResultMsg) {
int result = -1;
if (commands == null || commands.length == 0) {
return new CommandResult(result, null, null);
}
Process process = null;
BufferedReader successResult = null;
BufferedReader errorResult = null;
StringBuffer successMsg = null;
StringBuffer errorMsg = null;
DataOutputStream os = null;
try {
//root過的手機上面獲得root權限
process = Runtime.getRuntime().exec(isRoot ? "su" : "sh");
os = new DataOutputStream(process.getOutputStream());
for (String command : commands) {
if (command == null)
continue;
os.write(command.getBytes());
os.writeBytes(LINE_SEP);
os.flush();
}
os.writeBytes("exit" + LINE_SEP);
os.flush();
result = process.waitFor();
if (isNeedResultMsg) {
successMsg = new StringBuffer();
errorMsg = new StringBuffer();
successResult = new BufferedReader(new InputStreamReader(process.getInputStream(),
"UTF-8"));
errorResult = new BufferedReader(new InputStreamReader(process.getErrorStream(),
"UTF-8"));
String line;
if ((line = successResult.readLine()) != null) {
successMsg.append(line);
while ((line = successResult.readLine()) != null) {
successMsg.append(LINE_SEP).append(line);
}
}
if ((line = errorResult.readLine()) != null) {
errorMsg.append(line);
while ((line = errorResult.readLine()) != null) {
errorMsg.append(LINE_SEP).append(line);
}
}
}
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
try {
if (os != null)
os.close();
if (successResult != null)
successResult.close();
if (errorResult != null)
errorResult.close();
if (process != null)
process.destroy();
} catch (IOException e) {
e.printStackTrace();
}
}
return new CommandResult(result, successMsg == null ? null : successMsg.toString(),
errorMsg == null ? null : errorMsg.toString());
}
模型
public class CommandResult {
public int result;
public String successMsg;
public String errorMsg;
public CommandResult(int result, String successMsg, String errorMsg) {
this.result = result;
this.successMsg = successMsg;
this.errorMsg = errorMsg;
}
}
3.卸載應用
Intent intent=new Intent(Intent.ACTION_DELETE);
intent.setData(Uri.parse("package:包名"));
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
4.靜默卸載應用
/**
* 卸載應用成功&失敗
* @param packageName
* @param isKeepData
* @return
*/
private boolean uninstallSilent(String packageName,boolean isKeepData){
boolean isRoot=isRoot();
String command="LD_LIBRARY_PATH=/vendor/lib*:/system/lib* pm uninstall "+(isKeepData?"-k":"")+packageName;
CommandResult commandResult=execCmd(new String[]{command},isRoot,true);
if (commandResult.successMsg!=null
&& commandResult.successMsg.toLowerCase().contains("success")){
return true;
}else {
return false;
}
}