Android 獲取應(yīng)用列表

前言

目前正是Android 11 馬上要發(fā)布的時(shí)期,當(dāng)前在Android手機(jī)上獲取應(yīng)用安裝列表,要從三個(gè)維度上區(qū)分:獲取方法、系統(tǒng)版本、是否系統(tǒng)應(yīng)用。

  • 獲取方法:至少有兩種方法,它們的行為結(jié)果會(huì)有所差異
  • 系統(tǒng)版本:從 Android 11 開始,應(yīng)用列表的獲取將受到限制
  • 是否系統(tǒng)應(yīng)用:系統(tǒng)應(yīng)用與非系統(tǒng)應(yīng)用的獲取結(jié)果,也不盡相同

獲取方法介紹

獲取所有應(yīng)用列表(系統(tǒng)應(yīng)用+非系統(tǒng)應(yīng)用),常用的方法有2種:Shell命令行、系統(tǒng)API。

而要進(jìn)一步區(qū)分是否系統(tǒng)應(yīng)用,只要對(duì)上述結(jié)果進(jìn)行一次過濾即可。下面分別介紹:

1.shell命令行

pm list packages

示例代碼:

private List<String> getPkgList() {
    List<String> packages = new ArrayList<String>();
    try {
        Process p = Runtime.getRuntime().exec("pm list packages");
        InputStreamReader isr = new InputStreamReader(p.getInputStream(), "utf-8");
        BufferedReader br = new BufferedReader(isr);
        String line = br.readLine();
        while (line != null) {
            line = line.trim();
            if (line.length() > 8) {
                String prefix = line.substring(0, 8);
                if (prefix.equalsIgnoreCase("package:")) {
                    line = line.substring(8).trim();
                    if (!TextUtils.isEmpty(line)) {
                        packages.add(line);
                    }
                }
            }
            line = br.readLine();
        }
        br.close();
        p.destroy();
    } catch (Throwable t) {
        t.printStacktraces();
    }
    return packages;
}

2.系統(tǒng)API

PackageManager.getInstalledPackages()

示例代碼:

private List<String> getPkgListNew() {
    List<String> packages = new ArrayList<String>();
    try {
        List<PackageInfo> packageInfos = context.getPackageManager().getInstalledPackages(PackageManager.GET_ACTIVITIES |
                PackageManager.GET_SERVICES);
        for (PackageInfo info : packageInfos) {
            String pkg = info.packageName;
            packages.add(pkg);
        }
    } catch (Throwable t) {
        t.printStackTrace();;
    }
    return packages;
}

判斷是否系統(tǒng)應(yīng)用

// 通過packName得到PackageInfo,作為參數(shù)傳入即可
private boolean isSystemApp(PackageInfo pi) {
    boolean isSysApp = (pi.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 1;
    boolean isSysUpd = (pi.applicationInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) == 1;
    return isSysApp || isSysUpd;
}

總結(jié)對(duì)比

  • 測(cè)試機(jī):Google Pixel 3 XL
  • 系統(tǒng)應(yīng)用:262個(gè)
  • 非系統(tǒng)應(yīng)用:2個(gè)(包括測(cè)試demo)

說明:

  • 這里說的權(quán)限是:QUERY_ALL_PACKAGES,Android 11 新增權(quán)限,不用動(dòng)態(tài)申請(qǐng)
  • 這里說的 >= Android 11 是:targetSdkVersion 為 Android 11 且 運(yùn)行在11的設(shè)備上

補(bǔ)充:廣播監(jiān)聽?wèi)?yīng)用安裝/卸載的行為變化

如果使用了廣播,監(jiān)聽?wèi)?yīng)用安裝與卸載動(dòng)作,那么在 Android 11 上也有一些行為變化。

概括來(lái)講,就是 Android 11 下,若無(wú) QUERY_ALL_PACKAGES 權(quán)限,則無(wú)法監(jiān)聽到 安裝 動(dòng)作。

Android 11 之前
  • 能監(jiān)聽到 安裝/卸載
Android 11 開始
  • 若無(wú) QUERY_ALL_PACKAGES 權(quán)限:只能監(jiān)聽到 卸載
  • 若有 QUERY_ALL_PACKAGES 權(quán)限:仍能監(jiān)聽到 安裝/卸載
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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