Android 實現Apk的後臺靜默安裝
在Android上安裝其他Apk有兩種方式
1、啟動Android應用安裝器進行安裝
這種方式會彈出一個對話方塊使用者選擇是否安裝,實現程式碼如下,本文不做詳細介紹:
/** * 安裝apk * * @param path apk路徑 */ public void update(String path) { Log.v("正確的安裝路徑", path); Intent intent = new Intent(Intent.ACTION_VIEW); intent.setDataAndType(Uri.fromFile(new File(path)), "application/vnd.android.package-archive"); startActivity(intent); }
2、通過pm命令安裝
通過這種方式可以實現Android apk的後臺靜默安裝。
首先對pm安裝做個簡單的介紹,在平常使用IntelliJ IDEA的過程中可以發現在安裝應用的過程中控制檯會出現如下輸出:
其中有一行 pm install -r "……",這就是執行的 pm 命令進行apk的安裝。Waiting for device. Target device: android-md_1008b-0123456789ABCDEF Uploading file local path: E:\1.1\1.1\App\AndroidAssist\out\production\AppInstall\AppInstall.apk remote path: /data/local/tmp/com.example.AppInstall Installing com.example.AppInstall DEVICE SHELL COMMAND: pm install -r "/data/local/tmp/com.example.AppInstall" pkg: /data/local/tmp/com.example.AppInstall Success
那麼問題來了,如何在Android執行shell命令,方式有兩種,一種是通過Runtime.exec(),另一種是ProcessBuilder。詳見:
終於,重點來了,Android通過pm命令實現apk的靜默安裝:
需要在Manifest.xml中申請安裝應用,以及其他需要的許可權:
應用安裝的許可權需要當前應用和系統Framwork有相同的簽名,在打包的時候必須進行簽名,否則無法實現應用的安裝。<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.INSTALL_PACKAGES"/> <uses-permission android:name="android.permission.DELETE_PACKAGES"/> <uses-permission android:name="android.permission.CLEAR_APP_CACHE"/> <uses-permission android:name="android.permission.CLEAR_APP_USER_DATA"/> <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
對應用簽名時需要以下檔案platform.pk8 platform.x509.pem signapk.jar,將需要簽名的apk放置在同一目錄下然後在cmd視窗執行命令:
java -jar signapk.jar platform.x509.pem platform.pk8 input.apk output.apk
以AppInstall.apk為例:
java -jar signapk.jar platform.x509.pem platform.pk8 AppInstall.apk AppInstall_signed.apk
相關檔案的下載地址
實現apk安裝的關鍵程式碼如下:
/**
* 安裝應用
* @param apkAbsolutePath 安裝應用的路徑
* @return 安裝結果的控制檯輸出
*/
public String install(String apkAbsolutePath) {
//初始化pm指令
String[] args = {"pm", "install", "-r", apkAbsolutePath};
String result = "";
//程序生成器,將指令封裝成獨立的程序,進行呼叫
ProcessBuilder processBuilder = new ProcessBuilder(args);
//程序
Process process = null;
InputStream errIs = null;
InputStream inIs = null;
try {
//位元組流,臨時儲存控制檯的輸出內容
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int read = -1;
//執行安裝apk的pm指令
process = processBuilder.start();
//接收控制檯輸出的異常情況,輸入流
errIs = process.getErrorStream();
while ((read = errIs.read()) != -1) {
baos.write(read);
}
baos.write("\r\n".getBytes());
//正常輸出
inIs = process.getInputStream();
while ((read = inIs.read()) != -1) {
baos.write(read);
}
byte[] data = baos.toByteArray();
//將控制檯輸出轉化為字串返回
result = new String(data);
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
} finally {//最後必須將所有輸入輸出流關閉
try {
if (errIs != null) {
errIs.close();
}
if (inIs != null) {
inIs.close();
}
} catch (IOException e) {
e.printStackTrace();
}
if (process != null) {
process.destroy();
}
}
return result;
}
直接呼叫以上方法就能夠實現apk後臺靜默安裝。
demo的下載地址:
說明:
部分文章說需要在Manifest.xml中新增 android:sharedUserId="android.uid.system"以保證應用uid為system_uid,事實上是不需要的,另外如果添加了該部分的說明,會在靜態引用sdcard路徑時出現如下錯誤
Static storage paths aren’t available from AID_SYSTEM
詳見: