最近在开发中有个需求就是要实现静默安装与卸载app的功能,而在PackageManager的api中安装与卸载的接口被隐藏,所以在另辟蹊径,下面把实现的代码分享下
import android.app.PendingIntent;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
public class InstallApkActivity extends AppCompatActivity implements View.OnClickListener{
private String TAG ="MainActivity";
private Button install_btn,uninstall_btn;
private int mSessionId = -1;
private PackageInstaller.SessionCallback mSessionCallback;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_install);
init();
}
private void init() {
install_btn = (Button) findViewById(R.id.btn_install);
install_btn.setOnClickListener(this);
uninstall_btn = (Button) findViewById(R.id.btn_uninstall);
uninstall_btn.setOnClickListener(this);
mSessionCallback = new InstallSessionCallback();
getPackageManager().getPackageInstaller().registerSessionCallback(mSessionCallback);
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.btn_install:
installApp("mnt/usb/26A8-0362/MyApp.apk");
break;
case R.id.btn_uninstall:
uninstall("com.xinrui.myapplication");
break;
}
}
/**
* 根据包名卸载应用
*
* @param packageName
*/
public void uninstall(String packageName) {
Intent broadcastIntent = new Intent(this, UnInstallResultReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 1,
broadcastIntent, PendingIntent.FLAG_UPDATE_CURRENT);
PackageInstaller packageInstaller = getPackageManager().getPackageInstaller();
packageInstaller.uninstall(packageName, pendingIntent.getIntentSender());
}
/**
* 适配android9的安装方法。
* 全部替换安装
*/
public void installApp(String apkFilePath) {
File apkFile = new File(apkFilePath);
if (!apkFile.exists()) {
Log.d("MainActivity", "文件不存在");
return;
}
PackageInfo packageInfo = mContext.getPackageManager().getPackageArchiveInfo(apkFilePath, PackageManager.GET_ACTIVITIES | PackageManager.GET_SERVICES);
if (packageInfo != null) {
String packageName = packageInfo.packageName;
int versionCode = packageInfo.versionCode;
String versionName = packageInfo.versionName;
//Log.d("ApkActivity", "packageName=" + packageName + ", versionCode=" + versionCode + ", versionName=" + versionName);
}
PackageInstaller packageInstaller = mContext.getPackageManager().getPackageInstaller();
PackageInstaller.SessionParams sessionParams
= new PackageInstaller.SessionParams(PackageInstaller
.SessionParams.MODE_FULL_INSTALL);
sessionParams.setSize(apkFile.length());
try {
mSessionId = packageInstaller.createSession(sessionParams);
} catch (IOException e) {
e.printStackTrace();
}
//Log.d(TAG, "sessionId---->" + mSessionId);
if (mSessionId != -1) {
boolean copySuccess = onTransfesApkFile(apkFilePath);
//Log.d(TAG, "copySuccess---->" + copySuccess);
if (copySuccess) {
execInstallAPP();
}
}
}
/**
* 通过文件流传输apk
*
* @param apkFilePath
* @return
*/
private boolean onTransfesApkFile(String apkFilePath) {
InputStream in = null;
OutputStream out = null;
PackageInstaller.Session session = null;
boolean success = false;
try {
File apkFile = new File(apkFilePath);
session = mContext.getPackageManager().getPackageInstaller().openSession(mSessionId);
out = session.openWrite("base.apk", 0, apkFile.length());
in = new FileInputStream(apkFile);
int total = 0, c;
byte[] buffer = new byte[1024 * 1024];
while ((c = in.read(buffer)) != -1) {
total += c;
out.write(buffer, 0, c);
}
session.fsync(out);
//Log.d(TAG, "streamed " + total + " bytes");
success = true;
} catch (IOException e) {
e.printStackTrace();
} finally {
if (null != session) {
session.close();
}
try {
if (null != out) {
out.close();
}
if (null != in) {
in.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return success;
}
/**
* 执行安装并通知安装结果
*
*/
private void execInstallAPP() {
PackageInstaller.Session session = null;
try {
session = mContext.getPackageManager().getPackageInstaller().openSession(mSessionId);
Intent intent = new Intent(mContext, InstallResultReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext,
1, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
session.commit(pendingIntent.getIntentSender());
} catch (IOException e) {
e.printStackTrace();
} finally {
if (null != session) {
session.close();
}
}
}
private class InstallSessionCallback extends PackageInstaller.SessionCallback {
@Override
public void onCreated(int sessionId) {
// empty
}
@Override
public void onBadgingChanged(int sessionId) {
// empty
}
@Override
public void onActiveChanged(int sessionId, boolean active) {
// empty
}
@Override
public void onProgressChanged(int sessionId, float progress) {
if (sessionId == mSessionId) {
int progres = (int) (Integer.MAX_VALUE * progress);
}
}
@Override
public void onFinished(int sessionId, boolean success) {
// empty, finish is handled by InstallResultReceiver
if (mSessionId == sessionId) {
if (success) {
Log.d("MainActivity", "onFinished() 安装成功");
} else {
Log.d("MainActivity", "onFinished() 安装失败");
}
}
}
}
}
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInstaller;
import android.util.Log;
public class InstallResultReceiver extends BroadcastReceiver {
private static final String TAG = "MainActivity";
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
Log.d(TAG, "收到安装反馈广播了 action:" + action);
if (intent != null) { //安装的广播
final int status = intent.getIntExtra(PackageInstaller.EXTRA_STATUS,
PackageInstaller.STATUS_FAILURE);
if (status == PackageInstaller.STATUS_SUCCESS) {
// success
Log.d(TAG, "APP Install Success!");
// InstallAPP.getInstance().sendInstallSucces();
} else {
String msg = intent.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE);
Log.e(TAG, "Install FAILURE status_massage" + msg);
//InstallAPP.getInstance().sendFailure(msg);
}
}
}
}
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInstaller;
import android.util.Log;
public class UnInstallResultReceiver extends BroadcastReceiver {
private static final String TAG = "MainActivity";
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
Log.d(TAG, "收到卸载反馈广播了");
if (intent != null) { //安装的广播
final int status = intent.getIntExtra(PackageInstaller.EXTRA_STATUS,
PackageInstaller.STATUS_FAILURE);
if (status == PackageInstaller.STATUS_SUCCESS) {
// success
Log.d(TAG, "APP UnInstall Success!");
// InstallAPP.getInstance().sendInstallSucces();
} else {
String msg = intent.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE);
Log.e(TAG, "UnInstall FAILURE status_massage" + msg);
//InstallAPP.getInstance().sendFailure(msg);
}
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.xinrui.headsettest">
<!--静默安装权限-->
<uses-permission
android:name="android.permission.INSTALL_PACKAGES"
tools:ignore="ProtectedPermissions" />
<!--应用卸载权限-->
<uses-permission android:name="permission.REQUEST_INSTALL_PACKAGES" />
<uses-permission android:name="permission.REQUEST_DELETE_PACKAGES" />
<uses-permission
android:name="android.permission.DELETE_PACKAGES"
tools:ignore="ProtectedPermissions" />
<!--读写外部存储权限-->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<!--允许装载和卸载文件系统权限-->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<!--<intent-filter>-->
<!--<action android:name="android.intent.action.MAIN" />-->
<!--<category android:name="android.intent.category.LAUNCHER" />-->
<!--</intent-filter>-->
</activity>
<activity android:name=".AlamActivity">
<!-- <intent-filter> -->
<!-- <action android:name="android.intent.action.MAIN" /> -->
<!-- <category android:name="android.intent.category.LAUNCHER" /> -->
<!-- </intent-filter> -->
</activity>
<activity android:name=".InstallApkActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver android:name=".AlarmBroadCast" />
<receiver android:name=".AlarmBroadcastReciver" />
<receiver
android:name=".InstallResultReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.content.pm.extra.STATUS"/>
</intent-filter>
</receiver>
<receiver
android:name=".UnInstallResultReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.content.pm.extra.STATUS"/>
</intent-filter>
</receiver>
</application>
</manifest>