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

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

1.PackageManager

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

android 获取app使用时长 android 获取应用的信息_封装

      上图中,最里面的框代表整个Activity的信息,系统提供了ActivityInfo类来进行封装。最外面的框代表着整个Mainifest文件中节点的信息,系统提供了PackageInfo来进行封装。而Android系统提供了PackageManager来负责管理所有已安装的App。

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

  • ActivityInfo

       ActivityInfo封装了在Mainifest文件中<activity></activity>和<receiver></receiver>之间的所有信息。

  • 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的形式返回安装的应用。
  • queryIntentActivities:返回指定intent的ResolveInfo对象、Activity集合。
  • queryIntentServices:返回指定intent的ResolveInfo对象、Service集合。
  • resolveActivity:返回指定intent的Activity。
  • resolveService:返回指定intent的Service。

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

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

app.flags & ApplicationInfo.FLAG_SYSTEM

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

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

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

import android.graphics.drawable.Drawable;

/**
 * Created by 72312 on 2018/1/5.
 */

public class PMAppInfo {
    private String appLabel;
    private Drawable appIcon;
    private String pkgName;

    public PMAppInfo() {
    }

    public void setAppLabel(String appLabel) {
        this.appLabel = appLabel;
    }

    public void setAppIcon(Drawable appIcon) {
        this.appIcon = appIcon;
    }

    public void setPkgName(String pkgName) {
        this.pkgName = pkgName;
    }

    public String getAppLabel() {
        return appLabel;
    }

    public Drawable getAppIcon() {
        return appIcon;
    }

    public String getPkgName() {
        return pkgName;
    }
}

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

private List<PMAppInfo> getAppInfo(int flag) {
        //获取PackageManager对象
        pm = this.getPackageManager();
        //获取应用信息
        List<ApplicationInfo> applicationInfos = pm.getInstalledApplications(PackageManager.GET_UNINSTALLED_PACKAGES);
        List<PMAppInfo> appInfos = new ArrayList<>();
        //判断应用类型
        switch (flag) {
            case ALL_APP:
                appInfos.clear();
                for (ApplicationInfo app : applicationInfos) {
                    appInfos.add(makeAppInfo(app));
                }
                break;
            case SYSTEM_APP:
                appInfos.clear();
                for (ApplicationInfo app : applicationInfos) {
                    if((app.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
                        appInfos.add(makeAppInfo(app));
                    }
                }
                break;
            case THIRD_APP:
                appInfos.clear();
                for (ApplicationInfo app : applicationInfos) {
                    if((app.flags & ApplicationInfo.FLAG_SYSTEM) <= 0) {
                        appInfos.add(makeAppInfo(app));
                    } else if((app.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0){
                        appInfos.add(makeAppInfo(app));
                    }
                }
                break;
            case SDCARD_APP:
                appInfos.clear();
                for (ApplicationInfo app : applicationInfos) {
                    if((app.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0) {
                        appInfos.add(makeAppInfo(app));
                    }
                }
                break;
            default:
                return null;
        }
        return appInfos;
    }

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

 

private PMAppInfo makeAppInfo(ApplicationInfo app) {
        PMAppInfo pmAppInfo = new PMAppInfo();
        pmAppInfo.setPkgName(app.packageName);
        pmAppInfo.setAppIcon(app.loadIcon(pm));
        pmAppInfo.setAppLabel(app.loadLabel(pm).toString());
        return pmAppInfo;
    }

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

android 获取app使用时长 android 获取应用的信息_List_02