• 9.2 Android Apk应用信息获取之PackageManager" level="2">9.2 Android Apk应用信息获取之PackageManager
    • 9.2.1 PackageManager" level="3">9.2.1 PackageManager

    9.2 Android Apk应用信息获取之PackageManager" class="reference-link">9.2 Android Apk应用信息获取之PackageManager

    在9.1节中,我们将Android的系统信息翻了个遍,却没来得及查看Apk应用信息。Apk应用信息也是我们非常关心的,如果说系统信息好比是国家的GDP,那么Apk应用信息则像是对个人的经济普查,所以我们也来看看如何获取Apk应用程序的相关信息。

    在ADB Shell命令中,提到应用相关的东西,我们会想到两个非常强大的助手——PM和AM命令,在前面讲解ADB命令的文章中,也提到了这两个非常强大的命令集。PM(PackageManager),AM(ActivityManager),PM主宰着应用的包管理,而AM则主宰着应用的活动管理。

    9.2.1 PackageManager" class="reference-link">9.2.1 PackageManager

    下面还是通过实例来看一下,如何通过PackageManager来获得应用的包信息。首先,让我们看一下PackageManager到底管些什么呢?我们来看一幅图,如图9.6所示。

    9.2 Android Apk应用信息获取之PackageManager - 图1 图9.6 Package结构

    在图9.6中,最里面的框代表了整个Activity的信息,系统提供了ActivityInfo类来进行封装。

    最外面的框代表着整个Mainifest文件中节点的信息,系统提供了PackageInfo来进行封装。

    而Android系统提供了PackageManager来负责管理所有已安装的App。

    这些封装信息,就像我们自己封装的Bean对象一样,用来封装程序的相关信息,下面列举了一些常用的系统封装信息。

    • ActivityInfo

    ActivityInfo封装了在Mainifest文件中<activity></ activity>和<receiver></ receiver>之间的所有信息,包括name、icon、label、launchmod等。

    • ServiceInfo

    ServiceInfo与ActivityInfo类似,它封装了< service ></ service >之间的所有信息。

    • ApplicationInfo

    ApplicationInfo也是一样,它封装了< application></ application>之间的信息,不过特别的是,ApplicationInfo包含很多Flag ,FLAG_SYSTEM表示为系统应用,FLAG_EXTERNAL_STORAGE表示为安装在SDCard上的应用等,通过这些Flag,可以很方便地判断应用的类型。

    • PackageInfo

    PackageInfo与前面三个Info类类似,都是用于封装Mainifest文件的相关节点信息,而PackageInfo包含了所有的Activity、Service等信息。

    • ResolveInfo

    ResolveInfo比较特殊,它封装的是包含<intent>信息的上一级信息,所以它可以返回ActivityInfo、ServiceInfo等包含<intent>的信息,它经常用来帮助我们找到那些包含特定Intent条件的信息,如带分享功能、播放功能的应用。

    有了上面这些用于封装的Bean对象之后,PackageManager就可以通过调用各种方法,返回不同类型的Bean对象了。PackageManager经常使用以下方法。

    • getPackageManager:通过调用这个方法返回一个PackageManager对象。
    • getApplicationInfo:以ApplicationInfo的形式返回指定包名的ApplicationInfo。
    • getApplicationIcon:返回指定包名的Icon。
    • getInstalledApplications:以ApplicationInfo的形式返回安装的应用。
    • getInstalledPackages:以PackageInfo的形式返回安装的应用。
    • queryIntentActivities:返回指定intent的ResolveInfo对象、Activity集合。
    • queryIntentServices:返回指定intent的ResolveInfo对象、Service集合。
    • resolveActivity:返回指定intent的Activity。
    • resolveService:返回指定intent的Service。

    看了这么多眼花缭乱的方法后,让我们来看一个实际的例子,了解一下该如何通过PackageManager筛选不同类型的App。

    判断App类型的依据,就是利用ApplicationInfo中的FLAG_SYSTEM来进行判断,代码如下所示。

    1. app.flags & ApplicationInfo.FLAG_SYSTEM)

    通过这样的标志区分,可以判断出以下几种不同的应用类型。

    • 如果当前应用的flags & ApplicationInfo.FLAG_SYSTEM != 0则为系统应用。
    • 如果当前应用的flags & ApplicationInfo.FLAG_SYSTEM <= 0则为第三方应用。
    • 特殊的,当系统应用经过升级后,也将成为第三方应用:flags & ApplicationInfo. FLAG_UPDATED_SYSTEM_APP != 0。
    • 如果当前应用的flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE != 0则为安装在SDCard上的应用。

    继续分析这个实例,同样封装了一个Bean来保存我们所需要的字段,代码如下所示。

    1. package com.imooc.systemtest;
    2.  
    3. import android.graphics.drawable.Drawable;
    4.  
    5. public class PMAppInfo {
    6.  
    7. private String appLabel;
    8. private Drawable appIcon;
    9. private String pkgName;
    10.  
    11. public PMAppInfo() {
    12. }
    13.  
    14. public String getAppLabel() {
    15. return appLabel;
    16. }
    17.  
    18. public void setAppLabel(String appName) {
    19. this.appLabel = appName;
    20. }
    21.  
    22. public Drawable getAppIcon() {
    23. return appIcon;
    24. }
    25.  
    26. public void setAppIcon(Drawable appIcon) {
    27. this.appIcon = appIcon;
    28. }
    29.  
    30. public String getPkgName() {
    31. return pkgName;
    32. }
    33.  
    34. public void setPkgName(String pkgName) {
    35. this.pkgName = pkgName;
    36. }
    37. }

    接下来,通过上面所说的判断方法来判断各种类型的应用,代码如下所示。

    1. private List<PMAppInfo> getAppInfo(int flag) {
    2. //获取PackageManager对象
    3. pm = this.getPackageManager();
    4. //获取应用信息
    5. List<ApplicationInfo> listAppcations = pm
    6. .getInstalledApplications(PackageManager.GET_UNINSTALLED_PACKAGES);
    7. List<PMAppInfo> appInfos = new ArrayList<PMAppInfo>();
    8. //判断应用类型
    9. switch (flag) {
    10. case ALL_APP:
    11. appInfos.clear();
    12.  
    13. for (ApplicationInfo app : listAppcations) {
    14. appInfos.add(makeAppInfo(app));
    15. }
    16. break;
    17. case SYSTEM_APP:
    18. appInfos.clear();
    19. for (ApplicationInfo app : listAppcations) {
    20. if ((app.flags & ApplicationInfo. FLAG_SYSTEM) != 0) {
    21. appInfos.add(makeAppInfo(app));
    22. }
    23. }
    24. break;
    25. case THIRD_APP:
    26. appInfos.clear();
    27. for (ApplicationInfo app : listAppcations) {
    28. if ((app.flags & ApplicationInfo.FLAG_SYSTEM) <= 0) {
    29. appInfos.add(makeAppInfo(app));
    30. } else if ((app.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) {
    31. appInfos.add(makeAppInfo(app));
    32. }
    33. }
    34. break;
    35. case SDCARD_APP:
    36. appInfos.clear();
    37. for (ApplicationInfo app : listAppcations) {
    38. if ((app.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0) {
    39. appInfos.add(makeAppInfo(app));
    40. }
    41. }
    42. break;
    43. default:
    44. return null;
    45.  
    46. }
    47. return appInfos;
    48. }

    其中makeAppInfo()方法是用来保存数据到Bean的一个方法,代码如下所示。

    1. private PMAppInfo makeAppInfo(ApplicationInfo app) {
    2. PMAppInfo appInfo = new PMAppInfo();
    3. appInfo.setAppLabel((String) app.loadLabel(pm));
    4. appInfo.setAppIcon(app.loadIcon(pm));
    5. appInfo.setPkgName(app.packageName);
    6. return appInfo;
    7. }

    程序运行效果如图9.7所示。

    9.2 Android Apk应用信息获取之PackageManager - 图2 图9.7 PackageManager

    当点击不同App类型的按钮时,就可以获取该类型的App列表了。