代码中执行apk静默安装
背景:
应用需要升级来添加一些功能,但是需求是静默升级,也就是不需要用户直接去操作.
方法总结:
开始在网上看了一下资料,测试成功之后整理了一下相关修改.实现当前的需求是需要应用用的是当前的签名.
如何获取权限和修改未平台签名:
1、首先,我们要做的就是从Android的系统源码的/build/target/product/security目录中,找到两个签名文件: platform.x509.pem和platform.pk8
2、在/build/tools/signapk目录下找到signapk.jar文件的源码,编译成signapk.jar文件
3、然后在Android项目的manifest.xml文件中,加上INSTALL_PACKAGES的权限。
4、导出apk文件,这里选择签名文件导出。右键项目->"Android Tools"->"Export Signed application Package..."
5、最后就是执行
java -jar signapk.jar platform.x509.pem platform.pk8 input.apk output.apk
方法1:调用PackageManager 的installPackage()方法
代码修改:
这里使用的PackageManager 的installPackage()方法.由于这个方法不是标准的Android公开的API,所以我们要调用需要把Android 编译出的framework.jar 导入到eclipse 工程里面,并把这个jar包顺序提前.由于调用installPackage需要传入
IPackageInstallObserver,所以我们要超级一个
IPackageInstallObserver实例.
public static void installSilent(Context context, String filePath, String pmParams) {
if (filePath == null || filePath.length() == 0) {
return ;
}
File file = new File(filePath);
if (file == null || file.length() <= 0 || !file.exists() || !file.isFile()) {
return ;
}
int installFlags = 0;
Uri packageUri = Uri.fromFile(file);//file是要安装的apk文件
PackageManager pm = context.getPackageManager();
installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
MyPackageInstallObserver observer = new MyPackageInstallObserver();
pm.installPackage(packageUri, observer, installFlags, null);
}
private static class MyPackageInstallObserver implements IPackageInstallObserver{
@Override
public IBinder asBinder() {
// TODO Auto-generated method stub
return null;
}
@Override
public void packageInstalled(String arg0, int arg1)throws RemoteException {
// TODO Auto-generated method stub
}
}
其他关于判断和获取下载apk的代码,后续再补上.
方法2:执行命令pm install -r xxx.apk
注意这个方法是不用导入Android编码编译出来的framework.jar,当时同样也是需要使用平台签名和在AndroidManifest.xml里面添加INSTALL_PAKCAGE的权限.
方法3:参考系统安装apk的方式(不要验证相关过程),然后调用java反射来实现
在手机里面安装app的时候最好是调用的com.android.packageinstaller.InstallAppProgress.java这个Activity.在它的initView里面可以看到他最后是调用 pm.installPackageWithVerificationAndEncryption(mPackageURI, observer, installFlags,installerPackageName, verificationParams, null);来实现的,
其中pm就是PackageManger,当是PackageManger只是一个抽象类,这个方法的实现是在ApplicationPackageManager.java里面的.
public void installPackageWithVerificationAndEncryption(Uri packageURI,
IPackageInstallObserver observer, int flags, String installerPackageName,
VerificationParams verificationParams, ContainerEncryptionParams encryptionParams)
在ApplicationPackageManager里面可以看到还有一个方法可以实现上面这个安装功能就是
public void installPackage(Uri packageURI, IPackageInstallObserver observer, int flags,String installerPackageName).
由于我们现在是准备通过反射来实现,为了减少难度和创建参数的麻烦(这里observe的创建就很麻烦),我们就直接使用反射来调用installPakcage()来实现.
但是我们目前不能拿到
IPackageInstallObserver observer对象,因为这个对象只能通过
IPackageInstallObserver
.Stub.
asInterface(IBinder binder)来获得.而我们不能得到binder对象,所以不能直接调用反射.
这里我们可以直接参考
out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/android/content/pm/IPackageInstallObserver.java ,将IPackageInstallObserver.stub部分拷贝出来.
定义一个系统不可见的接口IPackageInstallObserver,所以包名是不能变的
public void installSlient() {
String newAppPath = getNewAppPath();
try {
Runtime.getRuntime().exec("pm install "+ newAppPath+ File.separator + "111.apk");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private String getNewAppPath() {
try {
String f = Environment.getExternalStorageDirectory().getCanonicalPath();
Log.d(TAG,"getNewAppPath f=" +f);
return f;
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
package android.content.pm;
public interface IPackageInstallObserver extends android.os.IInterface {
public abstract static class Stub extends android.os.Binder implements android.content.pm.IPackageInstallObserver {
public Stub() {
throw new RuntimeException("Stub!");
}
public static android.content.pm.IPackageInstallObserver asInterface(android.os.IBinder obj) {
throw new RuntimeException("Stub!");
}
public android.os.IBinder asBinder() {
throw new RuntimeException("Stub!");
}
public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags)
throws android.os.RemoteException {
throw new RuntimeException("Stub!");
}
}
public abstract void packageInstalled(java.lang.String packageName, int returnCode) throws android.os.RemoteException;
}
创建一个回调接口
OnInstalledPackaged
(参考InstallAppProgress.java就可以)
package com.example.install;
public interface OnInstalledPackaged {
public void packageInstalled(String packageName, int returnCode);
}
实现
ApplicationManager(这个主要是参考InstallAppProgress,设置了回调接口
)
package com.example.install;
import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import android.content.Context;
import android.content.pm.IPackageInstallObserver;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.RemoteException;
public class ApplicationManager {
public final int INSTALL_REPLACE_EXISTING = 2;
public static final int INSTALL_SUCCEEDED = 1;
private PackageInstallObserver observer;
private PackageManager pm;
private Method method;
private OnInstalledPackaged onInstalledPackaged;
class PackageInstallObserver extends IPackageInstallObserver.Stub {
public void packageInstalled(String packageName, int returnCode) throws RemoteException {
if (onInstalledPackaged != null) {
onInstalledPackaged.packageInstalled(packageName, returnCode);
}
}
}
public ApplicationManager(Context context) throws SecurityException, NoSuchMethodException {
observer = new PackageInstallObserver();
pm = context.getPackageManager();
Class<?>[] types = new Class[] {Uri.class, IPackageInstallObserver.class, int.class, String.class};
method = pm.getClass().getMethod("installPackage", types);
}
public void setOnInstalledPackaged(OnInstalledPackaged onInstalledPackaged) {
this.onInstalledPackaged = onInstalledPackaged;
}
public void installPackage(String apkFile) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
installPackage(new File(apkFile));
}
public void installPackage(File apkFile) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
if (!apkFile.exists()) throw new IllegalArgumentException();
Uri packageURI = Uri.fromFile(apkFile);
installPackage(packageURI);
}
public void installPackage(Uri apkFile) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
method.invoke(pm, new Object[] {apkFile, observer, INSTALL_REPLACE_EXISTING, null});
}
}
调用反射
public void installSlient2() {
try {
final ApplicationManager am = new ApplicationManager(this);
am.setOnInstalledPackaged(new OnInstalledPackaged() {
public void packageInstalled(String packageName, int returnCode) {
if (returnCode == ApplicationManager.INSTALL_SUCCEEDED) {
Log.d(TAG, "Install succeeded");
} else {
Log.d(TAG, "Install failed: " + returnCode);
}
}
});
String newAppPath = getNewAppPath();
am.installPackage(newAppPath+ File.separator + "111.apk");
} catch (Exception e) {
Log.e(TAG, "", e);
}
}
后来发现方法3太麻烦了,可以参考方法2 直接在ApplicationManager里面创建一个实现了IPackageInstallObserver接口的MyPackageInstallObserver内部类.
参考
http://blog.csdn.net/liliang497/article/details/8479668
android静默安装探讨: http://blog.csdn.net/sdvch/article/details/16832941
http://blog.csdn.net/sdvch/article/details/16832959
http://www.cnblogs.com/brucenan/archive/2012/10/04/2711817.html