1.静默安装:一般需要该应用是系统级别的应用,经过了平台下发的对应签名apk。
即: 1.内置到ROM,即APK包的安装位置是/system/app下。
2.使用APK的目标安装系统同样的签名。
当然不同平台的签名是不一样的,这个需要根据平台业务来具体确认,第三方Rom这样做也是处于保护系统安全的角度来考虑的。
个人在这只是针对上述分享下静默安装的具体实现方式:
针对 Android 6.0 and up. 静默安装示例如下:
public static boolean installPackage(Context context, InputStream in, String packageName) throws IOException {
PackageInstaller packageInstaller = context.getPackageManager().getPackageInstaller();
PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL);
params.setAppPackageName(packageName);
// set params
int sessionId = packageInstaller.createSession(params);
PackageInstaller.Session session = packageInstaller.openSession(sessionId);
OutputStream out = session.openWrite(packageName, 0, -1);
byte[] buffer = new byte[65536];
int c;
while ((c = in.read(buffer)) != -1) {
out.write(buffer, 0, c);
}
session.fsync(out);
in.close();
out.close();
session.commit(createIntentSender(context, sessionId));
return true;
}
private static IntentSender createIntentSender(Context context, int sessionId) {
PendingIntent pendingIntent = PendingIntent.getBroadcast(context,sessionId,new Intent(Intent.ACTION_PACKAGE_ADDED),PendingIntent.FLAG_UPDATE_CURRENT);
return pendingIntent.getIntentSender();
}
针对 Android 6.0 and up. 静默卸载示例如下:
String appPackage = "com.your.app.package";
Intent intent = new Intent(getActivity(), getActivity().getClass());
PendingIntent sender = PendingIntent.getActivity(getActivity(), 0, intent, 0);
PackageInstaller mPackageInstaller = getActivity().getPackageManager().getPackageInstaller();
mPackageInstaller.uninstall(appPackage, sender.getIntentSender());
低版本Android 6.0以下,大部分app的静默安装都是通过 移植系统源码中的相关AIDL 文件,进行调用pm里面的android方法:
普通情况下肯定是调用不到的。在源码\frameworks\base\core\java\android\content\pm目录下PackageManager.java,应该发现
在注释行里有加上@hide声明。调用的安装下载接口如下:
public abstract void installPackage(Uri packageURI,IPackageInstallObserver observer, int flags,String installerPackageName);
public abstract void deletePackage(String packageName,IPackageDeleteObserver observer, int flags);
最简单的就是直接拷贝4个文件即可:
PackageManager.java
IPackageDeleteObserver.aidl
IPackagerInstallObserver.aidl
IPackageMoveObserver.aidl
然后把PackageManager.java中报的异常的接口都注释掉即可,然后直接调用pm里面的方法。
静默安装示例如下:
/*** 静默安装* */
public static void autoInstallApk(Context context, String fileName,String packageName, String APPName) {
Log.d(TAG, “jing mo an zhuang:” + packageName + “,fileName:” + fileName);File file = new File(fileName);
int installFlags = 0;
if (!file.exists())
return;
installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
if (hasSdcard()) {
installFlags |= PackageManager.INSTALL_EXTERNAL;
}
PackageManager pm = context.getPackageManager();
try {
IPackageInstallObserver observer = new MyPakcageInstallObserver(context, APPName, appId, fileName,packageName,type_name);
Log.i(TAG, “########installFlags:” + installFlags+”packagename:”+packageName);
pm.installPackage(Uri.fromFile(file), observer, installFlags,packageName);
} catch (Exception e) {
}
}
实现静默安装的回调接口如下:
class MyPakcageInstallObserver extends IPackageInstallObserver.Stub {
Context cxt;
String appName;
String filename;
String pkname;
public MyPakcageInstallObserver(Context c, String appName, String filename, String packagename) {
this.cxt = c;
this.appName = appName;
this.filename = filename;
this.pkname = packagename;
}
@Override
public void packageInstalled(String packageName, int returnCode) {
Log.i(TAG, “returnCode = ” + returnCode);// 返回1代表安装成功
if (returnCode == 1) {
//TODO
}
Intent it = new Intent();
it.setAction(CustomAction.INSTALL_ACTION);
it.putExtra(“install_returnCode”, returnCode);
it.putExtra(“install_packageName”, packageName);
it.putExtra(“install_appName”, appName); cxt.sendBroadcast(it);
}
}
下面来看看apk的卸载流程。
[/frameworks/base/core/java/android/app/ApplicationPackageManager.java]
@Override
public void deletePackage(String packageName, IPackageDeleteObserver observer, int flags) {
try {
mPM.deletePackageAsUser(packageName, observer, UserHandle.myUserId(), flags);
} catch (RemoteException e) {
// Should never happen!
}
}
Client端调用PackageManager的deletePackage方法删除对应包名的apk,其中通过注册IPackageDeleteObserver监听卸载结果。实际上通过binder调用pms的deletePackageAsUser方法,在服务中执行卸载动作。