韌館-LearnHouse

[Android]實現APK靜默安裝(Silent Install)

當初為了達到自動安裝APK,而不會跳出任何訊息,且又不能使用非法的API或Java Reflection。
研究超久,試了網路上好多人的做法,一直無法成功,直到以下的方法才有效達到我想要的效果。
由於是很久以前試出來的,我也忘記出處在哪了,為了預防哪天我寫的的測試程式不小心被我清掉。因此在這裡備份一下程式碼。

private void autoInstall(Context context) {
	String apkfile = context.getFilesDir() + "/MyTest.apk";
	String ACTION_INSTALL_COMPLETE = "cm.android.intent.action.INSTALL_COMPLETE";
	try {
		PackageInstaller pi = context.getPackageManager().getPackageInstaller();
		//給定模式,創建新的參數,創建新安裝會話,返回唯一 Id
		int sessionId= pi.createSession(new PackageInstaller.SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL));
		//打開現有會話,主動執行工作
		PackageInstaller.Session session = pi.openSession(sessionId);
		long sizeBytes = 0;
		final File file = new File(apkfile);
		if (file.isFile()) {
			sizeBytes = file.length();
		}
		InputStream in = null;
		OutputStream out = null;
		in = new FileInputStream(apkfile);
		//打開一個流,將一個APK文件寫入會話
		//指定有效長度系統將預先分配底層磁盤空間以優化磁盤上的放置
		out = session.openWrite("app_store_session", 0, sizeBytes);
		int total = 0;
		byte[] buffer = new byte[65536];
		int len;
		while ((len= in.read(buffer)) != -1) {
			total += len;
			out.write(buffer, 0, len);
		}
		//根據需要調用,用來確保字節已保留到磁盤
		session.fsync(out);
		in.close();
		out.close();
		Log.d(TAG,"InstallApkViaPackageInstaller - Success: streamed apk " + total + " bytes");
		PendingIntent broadCastTest = PendingIntent.getBroadcast(
				context,
				sessionId,
				new Intent(ACTION_INSTALL_COMPLETE),
				PendingIntent.FLAG_UPDATE_CURRENT);
		//提交之前必須關閉所有流
		session.commit(broadCastTest.getIntentSender());
		session.close();
	} catch (Exception ex) {
		ex.printStackTrace();
	}
}

由於apk須放置在你執行的APP下,因此要在執行的app建立assets,複製到/data/data/< package name >/files/…
做法如下;

private void copyAssets(Context context) {
	Log.d(TAG, "Do copyAssets");
	AssetManager assetManager = context.getAssets();
	String[] files = null;
	try {
		files = assetManager.list("");
	} catch (IOException e) {
		Log.e(TAG, "Failed to get asset file list.", e);
	}
	if (files != null) for (String filename : files) {
		InputStream in = null;
		OutputStream out = null;
		try {
			Log.d(TAG, "Copy " + filename + "......");
			in = assetManager.open(filename);
			//File outFile = new File(context.getExternalFilesDir(null), filename);
			//File outFile = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/", filename);
			File outFile = new File(context.getFilesDir(), filename);
			Log.d(TAG, "outFile:" + outFile);
			out = new FileOutputStream(outFile);
			copyFile(in, out);
		} catch(IOException e) {
			Log.e(TAG, "Failed to copy asset file: " + filename, e);
		}
		finally {
			if (in != null) {
				try {
					in.close();
				} catch (IOException e) {
					// NOOP
				}
			}
			if (out != null) {
				try {
					out.close();
				} catch (IOException e) {
					// NOOP
				}
			}
		}
	}
	Log.d(TAG, "Finished copyAssets");
}

private void copyFile(InputStream in, OutputStream out) throws IOException {
	byte[] buffer = new byte[1024];
	int read;
	while((read = in.read(buffer)) != -1){
		out.write(buffer, 0, read);
	}
}
2020年7 月 posted by admin in 程式&軟體 and have No Comments

Place your comment

Please fill your data and comment below.
名稱:
信箱:
網站:
您的評論: