Sonic 云真機(jī)助手如何做到實(shí)時獲取 APP 列表

前言

v1.3.1-beta即將來襲,其中有一個新功能。用戶可以實(shí)時查看設(shè)備上的App列表。有了該功能,用戶可以快捷地根據(jù)應(yīng)用名或包名搜索對應(yīng)包信息,快捷啟動、卸載。


微信圖片_20220122222510.jpg

以往的方式

如果只是獲取app簡單的信息,我們可以使用兩種方法:

  1. 使用adb shell pm list package
    來獲取應(yīng)用列表,但是僅含包名,想獲取更多版本、中文名等等,還需要根據(jù)包名挨個使用
    adb shell dumpsys package com.tencent.mm
    來獲取app中文名,版本等等
    但是無法獲取應(yīng)用圖標(biāo)

  2. 在sdk里面自帶了aapt工具,可以解析apk文件
    類似的,先查找所有包名及對應(yīng)apk位置
    adb shell pm list packages -f
    我們可以看到apk的位置和包名,把a(bǔ)pk文件拉取到pc本地
    adb pull /data/app/com.tencent.mmxxxxxxxxxxxxxxxxxxxx==/base.apk
    用aapt工具解析這個拉到本地的apk文件
    aapt d badging base.apk
    這樣就能獲取信息了,但是也是沒有應(yīng)用圖標(biāo)

那應(yīng)用圖標(biāo)我們怎么獲取呢?

Sonic的方式

Sonic通過Sonic助手,通過apk的形式,在設(shè)備上獲取信息。步驟如下:

  1. 安卓的Activity的context里邊有g(shù)etPackageManager()方法,我們可以根據(jù)該方法列出設(shè)備所有應(yīng)用。
List<PackageInfo> packages = getPackageManager().getInstalledPackages(PackageManager.GET_UNINSTALLED_PACKAGES);
  1. 這時候會有疑問,如果只按照第一步,會返回大量無關(guān)應(yīng)用,連同設(shè)備系統(tǒng)應(yīng)用一并返回,生成了許多無關(guān)數(shù)據(jù)。我該怎么篩選呢?
    廢話不多說,直接上代碼
for (int i = 0; i < packages.size(); i++) {
            PackageInfo packageInfo = packages.get(i);
            if ((packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
                    //xxxx
            }
}

ApplicationInfo.FLAG_SYSTEM的意思是獲取當(dāng)前flag的末尾,為0即為非系統(tǒng)app

  1. 通過loadIcon方法獲得應(yīng)用圖標(biāo)
tmpInfo.appIcon = ImgUtil.drawableToDataUri(packageInfo.applicationInfo.loadIcon(getPackageManager()));

不過應(yīng)用圖標(biāo)獲取過來是Drawable對象,我們需要將Drawable轉(zhuǎn)換為base64.

  1. 轉(zhuǎn)換為base64,因為我們應(yīng)用圖標(biāo)屬于一次性數(shù)據(jù),不需要持久化,所以我將畫質(zhì)降到10(滿是100),畢竟轉(zhuǎn)換為base64之后,圖標(biāo)大小會變?yōu)?.333倍,無論是前端渲染還是agent的接收都需要關(guān)注這個大小。關(guān)于ByteArrayOutputStream為什么不需要close() 點(diǎn)擊這里
public static String bitmapToDataUri(Bitmap bitmap) {
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        bitmap.compress(Bitmap.CompressFormat.PNG, 10, out);
        String base64 = Base64.encodeToString(out.toByteArray(), Base64.NO_WRAP);
        return base64;
    }
  1. 在Activity的onStart事件開啟一個socket,等Agent連接之后,發(fā)送所有信息給Agent,然后socket就可以斷開釋放資源了。

  2. 前端直接渲染,完成!

不過該方式還是有優(yōu)化空間,目前接收大量base64的時候,前端加載還是會有卡頓的情況,但是將二進(jìn)制發(fā)送給Agent進(jìn)行base64編碼,Agent的工作量又會增加,本地生成再pull到Agent的方式又太慢。如果你有更好的想法,歡迎一起留言討論~

噢對了,apk的開源地址: 這里

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容