最近需要实现Android应用的静默安装,在网上看了不少帖子,最后在root权限下实现对应用的静默安装和卸载,现在就整个实现的过程做一个总结。
一.第一种方案
第一种方案参考了源码中/packages/apps/PackageInstaller的实现方式,实现的主要代码如下:
importjava.io.File; importjava.io.FileNotFoundException; importjava.io.FileOutputStream; importjava.io.IOException; importandroid.content.Context; importandroid.content.Intent; importandroid.content.pm.PackageInfo; importandroid.content.pm.PackageManager; importandroid.content.pm.IPackageInstallObserver; importandroid.content.pm.PackageManager.NameNotFoundException; importandroid.content.pm.PackageParser; importandroid.net.Uri; importandroid.os.Handler; importandroid.os.Message; importandroid.util.DisplayMetrics; importandroid.util.Log; importandroid.os.FileUtils; publicclass MyPackageInstaller { privatestatic final String PACKAGE_NAME = "test.installservice"; privatefinal int INSTALL_COMPLETE = 1; privateContext context; Uri mPackageURI; privatePackageParser.Package mPkgInfo; privateHandler mHandler = newHandler() { publicvoid handleMessage(Message msg) { switch(msg.what) { caseINSTALL_COMPLETE: // finish the activity posting result //setResultAndFinish(msg.arg1); break; default: break; } } }; voidsetResultAndFinish(intretCode) { // Intent data = new Intent(); // setResult(retCode); // finish(); } publicMyPackageInstaller(Context c) { this.context = c; } publicvoid installPackage() { intinstallFlags = 0; PackageManager pm = context.getPackageManager(); try{ PackageInfo pi = pm.getPackageInfo( mPkgInfo.applicationInfo.packageName, PackageManager.GET_UNINSTALLED_PACKAGES); if(pi != null) { // installFlags |= PackageManager.INSTALL_REPLACE_EXISTING; installFlags |= 2; } }catch(NameNotFoundException e) { } String array[] = null; try{ Runtime.getRuntime().exec("chmod 777 /data/data/" + PACKAGE_NAME); Runtime.getRuntime().exec( "chmod 777 /data/data/" + PACKAGE_NAME + "/files"); array = this.mPackageURI.toString().split("/"); System.out.println("array[last]->"+ array[array.length - 1]); Runtime.getRuntime().exec( "chmod 777 /data/data/" + PACKAGE_NAME + "/files/" + array[array.length - 1]); }catch(IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } PackageInstallObserver observer = newPackageInstallObserver(); pm.installPackage(mPackageURI, observer, installFlags, null); // context.deleteFile(array[array.length-1]); } classPackageInstallObserver extendsIPackageInstallObserver.Stub { publicvoid packageInstalled(String packageName, intreturnCode) { Message msg = mHandler.obtainMessage(INSTALL_COMPLETE); msg.arg1 = returnCode; mHandler.sendMessage(msg); } } privateFile createTempPackageFile(String filePath) { File tmpPackageFile; inti = filePath.lastIndexOf("/"); String tmpFileName; if(i != -1) { tmpFileName = filePath.substring(i + 1); }else{ tmpFileName = filePath; } FileOutputStream fos; try{ // MODE_WORLD_READABLE=1 fos = context.openFileOutput(tmpFileName, 1); }catch(FileNotFoundException e1) { Log.e("Installer","Error opening file " + tmpFileName); returnnull; } try{ fos.close(); }catch(IOException e) { Log.e("Installer","Error opening file " + tmpFileName); returnnull; } tmpPackageFile = context.getFileStreamPath(tmpFileName); File srcPackageFile = newFile(filePath); if(!FileUtils.copyFile(srcPackageFile, tmpPackageFile)) { returnnull; } returntmpPackageFile; } publicvoid makeTempCopyAndInstall(Uri mPackageURI) { mPkgInfo = getPackageInfo(mPackageURI); System.out.println("package="+ mPkgInfo.applicationInfo.packageName); System.out.println("copy file=" + mPackageURI.getPath()); File mTmpFile = createTempPackageFile(mPackageURI.getPath()); if(mTmpFile == null) { // display a dialog Log.e("Installer", "Error copying file locally. Failed Installation"); // showDialogInner(DLG_OUT_OF_SPACE); return; } this.mPackageURI = Uri.parse("file://"+ mTmpFile.getPath()); } publicPackageParser.Package getPackageInfo(Uri packageURI) { finalString archiveFilePath = packageURI.getPath(); PackageParser packageParser = newPackageParser(archiveFilePath); File sourceFile = newFile(archiveFilePath); DisplayMetrics metrics = newDisplayMetrics(); metrics.setToDefaults(); returnpackageParser.parsePackage(sourceFile, archiveFilePath, metrics, 0); } }
在程序中的调用方式:this为Context,path为安装包的绝对路径
MyPackageInstaller mpi = newMyPackageInstaller(this); mpi.makeTempCopyAndInstall(Uri.parse(path)); mpi.installPackage();
这种方式需要在源码下面编译apk,并将apk放入/system/app目录下面。
二.通过shell命令实现
首先,在java中实现安装和卸载apk的命令
publicclass PackageInstaller { publicvoid unInstallApp(String packageName){ try{ Runtime.getRuntime().exec("pm uninstall "+packageName); }catch(IOException e) { e.printStackTrace(); } } publicvoid installApp(String appPath){ try{ Runtime.getRuntime().exec("pm install "+appPath); }catch(IOException e) { e.printStackTrace(); } } publicvoid reInstallApp(String appPath){ try{ Runtime.getRuntime().exec("pm install -r "+appPath); }catch(IOException e) { e.printStackTrace(); } } }
|
然后再源码环境下将该java程序编译为jar包
2.将编译好的jar包放入程序的assets目录下面,通过以下代码在程序中将该jar文件拷贝到/data/data/package/files/目录下面
try{ AssetManager assetManager = context.getResources().getAssets(); InputStream in = assetManager.open(JAR_NAME); if(in == null) { return; } intlength = in.available(); bytefileByte[] = newbyte[length]; in.read(fileByte,0, fileByte.length); in.close(); OutputStream out = context.openFileOutput(JAR_NAME, Context.MODE_WORLD_READABLE | Context.MODE_WORLD_WRITEABLE); out.write(fileByte); out.close(); }catch(Exception e) { e.printStackTrace(); }
在有root权限的情况下,可以在shell中执行该jar包来进行安装和卸载:
String exportClassPath = "export CLASSPATH=/data/data/" + context.getPackageName() + "/files/installpackagejar.jar";
String INSTALL_ACTION_CMD = " exec app_process /system/bin packageName.StartMain install ";
publicboolean installApp(String path) { File temp = newFile(path); if(!temp.exists()) returnfalse; String cmd[] = { exportClassPath, INSTALL_ACTION_CMD + path }; try{ consoleExec(cmd); }catch(IOException e) { e.printStackTrace(); returnfalse; } returntrue; }
privatevoid consoleExec(String[] cmd) throwsIOException { Process process = Runtime.getRuntime().exec("su"); DataOutputStream os = newDataOutputStream(process.getOutputStream()); for(inti = 0; i < cmd.length; i++) { os.writeBytes(cmd<i> + "\n"); } os.writeBytes("exit\n"); os.flush(); os.close(); }