安卓設備上備份已安裝應用的apk包技術實現方案
需求的目的
在只有安裝應用, 沒有該應用的apk,而我們又想活取應用apk,用來分享給別人,或是應用的備份, 說是應用的增量升級的, 怎麼辦?
本文將告訴你如何靠譜的導出一個已安裝應用的apk.
瞭解相關目錄
安卓設備上根據安卓方式的不同,安裝的數據存放路徑也不同
1. system/app
此類應用是系統初始化時候安裝完成的, 存放在 ‘system/app’ 目錄下, 用戶無法刪除及操作.
2. data/app
通過market下載後安裝(無安裝界面),或是用戶手動安裝(adb,packageinstall等).這類apk安裝過程系統會備份在data/app目錄下
3. /mnt/asec/
安裝到sd卡上的應用,作用同上
4. data/data
應用安裝過程,會在該目錄下存在應用的私有數據
5. data/dalvik-cache
應用安裝過程中,會解析data/app下的安裝包中的dex文件, 拷貝到data/dalvik-cache,以備應用運行時使用.
應用的刪除過程即刪除應用安裝時所產生的這幾個文件
備份apk思路分享
瞭解這個文件夾的作用後, 可以看到導出已安裝應用只要拷貝相關目錄下的應用即可.
通過測試,可以確定除了系統應用安裝的備份數據沒有權限, 第三方應用所產生的文件夾下的內容都是有讀權限的. 所以我們不需要任何特殊權限即可實現安裝應用的備份導出.
那問題來了, 在相關目錄下如:data/app下如何才能知道一個應用的決定路徑?
答案:
> context.getPackageManager().getApplicationInfo("packagename",
> 0).sourceDir;
所以需要了解下 PackageManager 相關api
實現代碼
知道路徑後,那麼我們接可以將文件拷貝到指定地方了,代碼如下:
private void backupApp(String path, String outname) throws IOException {
File in = new File(path);
if (!mBaseFile.exists()) mBaseFile.mkdir();
File out = new File(mBaseFile, outname + ".apk");
if (!out.exists()) out.createNewFile();
FileInputStream fis = new FileInputStream(in);
FileOutputStream fos = new FileOutputStream(out);
int count;
byte[] buffer = new byte[256 * 1024];
while ((count = fis.read(buffer)) > 0) {
fos.write(buffer, 0, count);
}
fis.close();
fos.flush();
fos.close();
}
//活取全面已安裝應用的方法
PackageManager packageManager = getPackageManager();
List<PackageInfo> allPackages = packageManager.getInstalledPackages(0);
for (int i = 0; i < allPackages.size(); i++) {
PackageInfo packageInfo = allPackages.get(i);
String path = packageInfo.applicationInfo.sourceDir;
String name = packageInfo.applicationInfo.loadLabel(packageManager).toString();
}
//判斷是否是第三方應用方法
public boolean isUserApp(PackageInfo pInfo) {
return (((pInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) && ((pInfo.applicationInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) == 0));
}
正確性保障
如何確保拷貝出來的apk的正確性呢?
直接的辦法可以校驗md5或sha1, 當然還可以嘗試解決文件格式等
Demo源代碼
測試小程序已上傳到github, 有興趣的可以直接下載研究學習.