使用系统自带的安装程序来实现程序的安装:
android自带了一个安装程序---/system/app/PackageInstaller.apk.大多数情况下,我们手机上安装应用都是通过这个apk来安装
代码使用:
/* 安装apk */
public static void installApk(Context context, String fileName) {
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setDataAndType(Uri.parse("file://" + fileName),"application/vnd.android.package-archive");
context.startActivity(intent);
}
/* 卸载apk */
public static void uninstallApk(Context context, String packageName) {
Uri uri = Uri.parse("package:" + packageName);
Intent intent = new Intent(Intent.ACTION_DELETE, uri);
context.startActivity(intent);
}
同时,我们还可以监听apk文件的安装:
在我们的系统安装和卸载程序的时候,系统会发送以下广播:
在安装和卸载完后,android系统会发一个广播
android.intent.action.PACKAGE_ADDED(安装)
android.intent.action.PACKAGE_REMOVED(卸载)
我们可以自定义一个广播接收者:
public void onReceive(Context context, Intent intent){
//接收安装广播
if (intent.getAction().equals("android.intent.action.PACKAGE_ADDED")) {
//TODO
}
//接收卸载广播
if (intent.getAction().equals("android.intent.action.PACKAGE_REMOVED")) {
//TODO
}
}
可是如果我们需要实现静默安装,这样显然是无法满足的,下面实现两种静默安装的方式:
通过运行命令来进行安装:
在adb shell中通过pm install -f apk文件路径
我们新建一个方法,用来在adb shell环境下执行pm install命令
final String path = "/storage/sdcard0/183/test/pertest.apk";
实现一个用来执行命令的方法:
public static String execCommand(String ...command) {
Process process=null;
InputStream errIs=null;
InputStream inIs=null;
String result="";
try {
process=new ProcessBuilder().command(command).start();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int read = -1;
errIs=process.getErrorStream();
while((read=errIs.read())!=-1){
baos.write(read);
}
inIs=process.getInputStream();
while((read=inIs.read())!=-1){
baos.write(read);
}
result=new String(baos.toByteArray());
if(inIs!=null)
inIs.close();
if(errIs!=null)
errIs.close();
process.destroy();
} catch (IOException e) {
result = e.getMessage();
}
return result;
}
其实,真正运行安装代码的只有这么一句话:process=new ProcessBuilder().command(command).start(); 剩下的只是为了返回给一个安装结果给用户
在mainactivity的onCreate方法中执行如下代码即可:
String result = execCommand("pm","install","-f",path);//安装apk
String result = execCommand("pm","uninstall", "com.qihoo360.mobilesafe"); //卸载apk
此时这个result就是系统返回给我们的一个安装或是卸载结果
注意需要在Manifest.xml中添加如下权限:
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
注意android系统出于安全考虑,我们是不能进行静默安装的,那么我们需要给该Manifest.xml中添加如下一句:
android:sharedUserId="android.uid.system"
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.cmddemo"
android:versionCode="1"
android:versionName="1.0"
android:sharedUserId="android.uid.system">
表示该apk和系统程序运行在统一个进程中,即具有系统应用程序的权限:
此时运行我们的apk文件,会出现如下错误:
Installation error: INSTALL_FAILED_SHARED_USER_INCOMPATIBLE
Please check logcat output for more details.
Launch canceled!
说明我们需要对该apk进行系统签名,我们刚才已经手动运行了一边该工程,虽然不能直接运行,可是还是有用的,因为它会在该工程的bin目录下生成一个apk文件,接下来我们进行系统签名的时候就需要用到这个apk
对apk进行系统签名,我们需要以下三个文件:
对apk进行系统签名,我们需要以下三个文件:
platform.pk8,platform.x509.pem,signapk.jar这三个文件进行签名,注意这三个签名文件是在系统的源码中才有的:
platform.x509.pem和platform.pk8这两个文件是在/build/target/product/security/路径下
signapk.jar : /out/host/linux-x86/framework/signapk.jar
将三个文件拷贝到统一个目录中,然后将我们之前生成的apk同样拷贝到该目录下,然后进入该目录中,执行如下命令进行签名:
java -jar signapk.jar platform.x509.pem platform.pk8 CmdDemo.apk afterMo.apk
其中CmdDemo.apk是我们之前生命的apk,afterMo.apk是我们生成之后的签名的apk,此时安装这个afterMo.apk,就可以实现静默安装了。
注意这里有一个限制,就是我们只能在已知的平台上来进行静默安装,也就是说我们必须需要获得该平台的以上三个签名文件才可以的,因为现在的手机厂商都会进行自己的签名来确保安全性。
通过aidl实现静默安装
进入android源码目录
在android源码目录下有一个/frameworks/base/core/java/android/content/pm包
在这个包里边有以下几个文件:
IPackageInstallObserver.aidl、IPackageDeleteObserver.aidl 和IPackageMoveObserver.aidl以及PackageManager.java文件
如果需要实现静默安装,我们需要在自己的工程里边新建一个包android.content.pm(这里需要注意,由于我们使用到了aidl,所以这里的包名必须和源码中的一样即"android.content.pm"),然后将我们需要用到的以上几个文件拷贝到该目录下:
因为用到了aidl,所以我们需要在bin目录下,新建一个aidl目录,在aidl目录下,继续新建以下目录:android/content/pm,在pm目录下,将我们需要用到的IPackageInstallObserver.aidl、IPackageDeleteObserver.aidl 和IPackageMoveObserver.aidl这三个接口文件拷贝到该目录下
安装apk程序的代码:
String fileName = "/storage/sdcard0/183/test/plug.apk";
Uri uri = Uri.fromFile(new File(fileName));
int installFlags = 0;
PackageManager pm = getPackageManager();
try {
PackageInfo pi = pm.getPackageInfo("com.example.plug",PackageManager.GET_UNINSTALLED_PACKAGES);
if(pi != null) {
installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
}
} catch (NameNotFoundException e) {
}
MyPakcageInstallObserver observer = new MyPakcageInstallObserver();
pm.installPackage(uri, observer, installFlags, "com.example.plug");
/*静默安装回调*/
class MyPakcageInstallObserver extends IPackageInstallObserver.Stub{
@Override
public void packageInstalled(String packageName, int returnCode) {
if (returnCode == 1) {
Log.e("DEMO","安装成功");
new ToastThread(InstallActivity.this,"安装成功").start();
}else{
Log.e("DEMO","安装失败,返回码是:"+returnCode);
new ToastThread(InstallActivity.this,"安装失败,返回码是:"+returnCode).start();
}
}
}
卸载程序的代码:
PackageManager pm = InstallActivity.this.getPackageManager();
IPackageDeleteObserver observer = new MyPackageDeleteObserver();
pm.deletePackage("com.example.plug", observer, 0);
/* 静默卸载回调 */
class MyPackageDeleteObserver extends IPackageDeleteObserver.Stub {
@Override
public void packageDeleted(String packageName, int returnCode) {
if (returnCode == 1) {
Log.e("DEMO","卸载成功...");
new ToastThread(InstallActivity.this,"卸载成功...").start();
}else{
Log.e("DEMO","卸载失败...返回码:"+returnCode);
new ToastThread(InstallActivity.this,"卸载失败...返回码:"+returnCode).start();
}
}
}
另外需要在Manifest.xml文件中添加如下权限:
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.INSTALL_PACKAGES" />
<uses-permission android:name="android.permission.DELETE_PACKAGES" />
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
同样需要添加android:sharedUserId="android.uid.system",来告诉系统我们的工程是系统进程
最后运行该工程,同样会出现如下错误:
[2015-04-06 11:05:51 - androidauto] Installation error: INSTALL_FAILED_SHARED_USER_INCOMPATIBLE
[2015-04-06 11:05:51 - androidauto] Please check logcat output for more details.
[2015-04-06 11:05:51 - androidauto] Launch canceled!
此时我们需要对之前bin目录生成的apk进行系统签名:
java -jar signapk.jar platform.x509.pem platform.pk8 需要签名的apk 签名之后的apk
此时签名之后的apk是拥有系统权限的,此时这个apk就可以实现静默安装。