参考资料:http://blog.csdn.net/qinjuning/article/details/6867806,有改动。
PackageManger的主要职责是管理应用程序包,通过它可以获取应用程序信息。
AnroidManifest.xml文件节点说明:
AndroidManifest.xml文件中所有节点的基类,并不直接使用,而是由子类继承然后调用相应方法。
常用字段:
int icon 资源图片在R文件中的值 (对应于android:icon属性) int labelRes label在R文件中的值(对应于android:label属性) String name 节点的name值 (对应于android:name属性) String packagename 应用程序的包名 (对应于android:packagename属性)
Drawable loadIcon(PackageManager pm) 获得当前应用程序的图标 CharSequence loadLabel(PackageManager pm) 获得当前应用程序的label,从上图可知是app_name
<activity>或者 <receiver>节点信息 。可获取theme 、launchMode、launchmode等属性
<service>节点信息。
<application>节点的信息。
字段说明:
flags字段: FLAG_SYSTEM 系统应用程序 FLAG_EXTERNAL_STORAGE 表示该应用安装在sdcard中
ActivityInfo activityInfo 获取 ActivityInfo对象,即<activity>或<receiver>节点信息 ServiceInfo serviceInfo 获取 ServiceInfo对象,即<service>节点信息
ApplicationInfo与ResolveInfo比较:前者能够得到Icon、Label、meta-data、description。后者只能得到Icon、Label。
AndroidManifest.xml文件的信息
常用字段:
String packageName 包名 ActivityInfo[] activities 所有<activity>节点信息 ApplicationInfo applicationInfo <application>节点信息,只有一个 ActivityInfo[] receivers 所有<receiver>节点信息,多个 ServiceInfo[] services 所有<service>节点信息 ,多个
PackageManager getPackageManager(); // 获得一个PackageManger对象 Drawable getApplicationIcon(String packageName); // 返回给定包名的图标,否则返回null ApplicationInfo getApplicationInfo(String packageName, int flags); // 返回该ApplicationInfo对象 // flags标记通常直接赋予常数0 List<ApplicationInfo> getInstalledApplications(int flags); // 返回给定条件的所有ApplicationInfo // flag为一般为GET_UNINSTALLED_PACKAGES,后续可进一步过滤结果 List<PackageInfo> getInstalledPackages(int flags); // 返回给定条件的所有PackageInfo ResolveInfo resolveActivity(Intent intent, int flags); // 返回给定条件的ResolveInfo对象(本质上是Activity) // intent 是查询条件,Activity所配置的action和category // 可选flags: // MATCH_DEFAULT_ONLY :Category必须带有CATEGORY_DEFAULT的Activity,才匹配 // GET_INTENT_FILTERS :匹配Intent条件即可 // GET_RESOLVED_FILTER :匹配Intent条件即可 List<ResolveInfo> queryIntentActivities(Intent intent, int flags); // 返回给定条件的所有ResolveInfo对象(本质上是Activity) ResolveInfo resolveService(Intent intent, int flags); // 返回给定条件的ResolveInfo对象(本质上是Service) List<ResolveInfo> queryIntentServices(Intent intent, int flags); // 返回给定条件的所有ResolveInfo对象(本质上是Service),集合对象
常用字段:
long cachesize 缓存大小 long codesize 应用程序大小 long datasize 数据大小 String packageName 包名
ApplicationInfo applicationInfo = packageInfo.applicationInfo; // APP 包名 String packageName = packageInfo.packageName; // APP icon Drawable icon = packageManager.getApplicationIcon(applicationInfo); // APP 名称 String appName = packageManager.getApplicationLabel(applicationInfo).toString(); // APP 权限 String[] permissions = packageManager.getPackageInfo(packageName,PackageManager.GET_PERMISSIONS).requestedPermissions;
// APP包名 resolve.activityInfo.packageName; // APP icon resolve.loadIcon(packageManager); // APP名称 resolve.loadLabel(packageManager).toString();
Intent intent = new Intent(Intent.ACTION_MAIN); intent.setPackage(packageName); intent.addCategory(Intent.CATEGORY_LAUNCHER); List<ResolveInfo> resolveInfos = pManager.queryIntentActivities(intent, 0); // 一个App中只有一个主Activity,直接取出。注意不是任何包中都有主Activity String mainActivityName = ""; if (resolveInfos != null && resolveInfos.size() >= 1) { mainActivityName = resolveInfos.get(0).activityInfo.name; }
PackageManager pManager = context.getPackageManager(); PackageInfo packageInfo = pManager.getPackageInfo(packageName, 0); ApplicationInfo appInfo = packageInfo.applicationInfo; // 获取App名 String appName = pManager.getApplicationLabel(appInfo).toString(); //// 也可以使用如下方法 //String appName = appInfo.loadLabel(pManager).toString(); // 获取App Icon Drawable icon = pManager.getApplicationIcon(appInfo); //// 也可以用如下两种方法 //Drawable icon = pManager.getApplicationIcon(packageName); //Drawable icon = appInfo.loadIcon(pManager); // 获取App versionName String versionName = packageInfo.versionName; // versionName在xml的根节点中,只能用PackageInfo获取 // 获取权限 PackageInfo pPermissionInfo = pManager.getPackageInfo(packageName, PackageManager.GET_PERMISSIONS); String[] permissions = pPermissionInfo.requestedPermissions;
PackageManager packageManager = getPackageManager(); // 法一:通过解析AndroidManifest.xml的<application>标签中得到,可获取所有的app。 List<ApplicationInfo> applicationList = packageManager .getInstalledApplications(PackageManager.GET_UNINSTALLED_PACKAGES); // 法二:通过Intent查找相关的Activity,更准确,但无法获取Provider等应用 // 通过解析<Intent-filter>标签得到 // <action android:name=”android.intent.action.MAIN”/> // <action android:name=”android.intent.category.LAUNCHER”/> Intent intent = new Intent(Intent.ACTION_MAIN, null); intent.addCategory(Intent.CATEGORY_LAUNCHER); List<ResolveInfo> resolveList = packageManager.queryIntentActivities(intent, 0);
/** 判断是不是系统APP **/ // FLAG_SYSTEM = 1<<0,if set, this application is installed in the device's system image. // 下面&运算有两种结果: // 1,则flags的末位为1,即系统APP // 0,则flags的末位为0,即非系统APP if ( (applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 1 ){ ...... } /** 判断是不是第三方APP **/ // FLAG_SYSTEM = 1<<0,同上 if ( (applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) { ...... } //本来是系统程序,被用户手动更新后,该系统程序也成为第三方应用程序了 // FLAG_UPDATED_SYSTEM_APP = 1<<7, this is set if this application has been // install as an update to a built-in system application. else if ((applicationInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) == 1) { ...... } /** 判断是不是安装在SDCard的应用程序 **/ // FLAG_EXTERNAL_STORAGE = 1<<18,Set to true if the application is // currently installed on external/removable/unprotected storage if ( (applicationInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) == 1) { ...... }
/** * 获取手机上安装的所有APP的信息 配合AppInfo类使用 */ public class AppInfoUtil { public static final int GET_ALL_APP = 0; // 所有APP public static final int GET_SYSTEM_APP = 1; // 系统预装APP public static final int GET_THIRD_APP = 2; // 第三方APP public static final int GET_SDCARD_APP = 3; // SDCard的APP private static AppInfoUtil infoUtil; private PackageManager pManager; // 所有应用 private List<PackageInfo> allPackageList; // 筛选结果 private List<PackageInfo> result; /** 私有构造器 **/ private AppInfoUtil(Context context) { pManager = context.getPackageManager(); result = new ArrayList<PackageInfo>(); } /** 单例 **/ public static AppInfoUtil getInstance(Context context) { if (infoUtil == null) { infoUtil = new AppInfoUtil(context); } return infoUtil; } /** 获取已安装的APP **/ public List<AppInfo> getInstalledApps(int type) { // 0 表示不接受任何参数。其他参数都带有限制 // 版本号、APP权限只能通过PackageInfo获取,故这里不使用getInstalledApplications()方法 allPackageList = pManager.getInstalledPackages(0); if (allPackageList == null) { Log.e("AppInfoUtil类", "getInstalledApps()方法中的allPackageList为空"); return null; } // 根据APP名排序 Collections.sort(allPackageList, new PackageInfoComparator(pManager)); // 筛选 result.clear(); switch (type) { case GET_ALL_APP: result = allPackageList; break; case GET_SYSTEM_APP: // 系统自带APP for (PackageInfo info : allPackageList) { // FLAG_SYSTEM = 1<<0,if set, this application is installed in // the device's system image. // 下面&运算有两种结果: // 1,则flags的末位为1,即系统APP // 0,则flags的末位为0,即非系统APP if ((info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 1) { result.add(info); } } break; case GET_THIRD_APP: // 第三方APP for (PackageInfo info : allPackageList) { // FLAG_SYSTEM = 1<<0,同上 if ((info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) { result.add(info); } // 本来是系统程序,被用户手动更新后,该系统程序也成为第三方应用程序了 // FLAG_UPDATED_SYSTEM_APP = 1<<7, this is set if this // application has been // install as an update to a built-in system application. else if ((info.applicationInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) == 1) { result.add(info); } } break; case GET_SDCARD_APP: // 安装在SDCard的应用程序 for (PackageInfo info : allPackageList) { // FLAG_EXTERNAL_STORAGE = 1<<18,Set to true if the application // is // currently installed on external/removable/unprotected storage if ((info.applicationInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) == 1) { result.add(info); } } break; } return getAppInfoByPackageInfo(result); } public List<AppInfo> getAppInfoByIntent(Intent intent) { List<ResolveInfo> resolveInfos = pManager.queryIntentActivities(intent, PackageManager.GET_INTENT_FILTERS); // 调用系统排序 , 根据name排序 // 此排序会将系统自带App与用户安装的APP分开排序 Collections.sort(resolveInfos, new ResolveInfo.DisplayNameComparator( pManager)); // // 此排序会将系统自带App与用户安装的APP混合排序 // Collections.sort(resolveInfos, new DisplayNameComparator(pManager)); return getAppInfobyResolveInfo(resolveInfos); } /** 获取单个App图标 **/ public Drawable getAppIcon(String packageName) throws NameNotFoundException { Drawable icon = pManager.getApplicationIcon(packageName); return icon; } /** 获取单个App名称 **/ public String getAppName(String packageName) throws NameNotFoundException { ApplicationInfo appInfo = pManager.getApplicationInfo(packageName, 0); String appName = pManager.getApplicationLabel(appInfo).toString(); return appName; } /** 获取单个App版本号 **/ public String getAppVersion(String packageName) throws NameNotFoundException { PackageInfo packageInfo = pManager.getPackageInfo(packageName, 0); String appVersion = packageInfo.versionName; return appVersion; } /** 获取单个App的所有权限 **/ public String[] getAppPermission(String packageName) throws NameNotFoundException { PackageInfo packageInfo = pManager.getPackageInfo(packageName, PackageManager.GET_PERMISSIONS); String[] permission = packageInfo.requestedPermissions; return permission; } /** 获取单个App的签名 **/ public String getAppSignature(String packageName) throws NameNotFoundException { PackageInfo packageInfo = pManager.getPackageInfo(packageName, PackageManager.GET_SIGNATURES); String allSignature = packageInfo.signatures[0].toCharsString(); return allSignature; } // /** 使用示例 **/ // public static void main(String[] args) { // AppInfoUtil appInfoUtil = AppInfo.getInstance(context); // // // 获取所有APP // List<AppInfo> allAppInfo = appInfoUtil.getInstalledApps(AppInfoUtil.GET_ALL_APP); // for (AppInfo app : allAppInfo) { // String packageName = app.getPackageName(); // String appName = app.getAppName(); // Drawable icon = app.getIcon(); // String versionName = app.getVersionName(); // String[] permissions = app.getPermissions(); // // 自由发挥... // } // // // 获取单个APP的信息 // String appName = appInfoUtil.getAppName(packageName); // ... // } /** 从PackageInfo的List中提取App信息 **/ private List<AppInfo> getAppInfoByPackageInfo(List<PackageInfo> list) { List<AppInfo> appList = new ArrayList<AppInfo>(); for (PackageInfo info : list) { // 获取信息 String packageName = info.applicationInfo.packageName; String appName = pManager.getApplicationLabel(info.applicationInfo) .toString(); Drawable icon = pManager.getApplicationIcon(info.applicationInfo); // // 也可以用如下方法获取APP图标,显然更烦琐 // ApplicationInfo applicationInfo = // pManager.getApplicationInfo(packageName, 0); // Drawable icon = applicationInfo.loadIcon(pManager); String versionName = info.versionName; String[] permissions = info.requestedPermissions; String launchActivityName = getLaunchActivityName(packageName); // 储存信息 AppInfo appInfo = new AppInfo(); appInfo.setPackageName(packageName); appInfo.setAppName(appName); appInfo.setIcon(icon); appInfo.setVersionName(versionName); appInfo.setPermissions(permissions); appInfo.setLaunchActivityName(launchActivityName); appList.add(appInfo); } return appList; } /** 从ResolveInfo的List中提取App信息 **/ private List<AppInfo> getAppInfobyResolveInfo(List<ResolveInfo> list) { List<AppInfo> appList = new ArrayList<AppInfo>(); for (ResolveInfo info : list) { String packageName = info.activityInfo.packageName; String appName = info.loadLabel(pManager).toString(); Drawable icon = info.loadIcon(pManager); String launchActivityName = getLaunchActivityName(packageName); AppInfo appInfo = new AppInfo(); appInfo.setPackageName(packageName); appInfo.setAppName(appName); appInfo.setIcon(icon); appInfo.setLaunchActivityName(launchActivityName); appList.add(appInfo); } return appList; } /** 获取指定包中主Activity的类名,并不是所有包都有主Activity **/ private String getLaunchActivityName(String packageName) { // 根据PackageInfo对象取不出其中的主Activity,须用Intent Intent intent = new Intent(Intent.ACTION_MAIN); intent.setPackage(packageName); List<ResolveInfo> resolveInfos = pManager.queryIntentActivities(intent, 0); String mainActivityName = ""; if (resolveInfos != null && resolveInfos.size() >= 1) { mainActivityName = resolveInfos.get(0).activityInfo.name; } return mainActivityName; } /** 此比较器直接复制Android源码,但是却可以把系统APP与用户APP混合排列,何解? **/ private static class DisplayNameComparator implements Comparator<ResolveInfo> { public DisplayNameComparator(PackageManager pm) { mPM = pm; } public final int compare(ResolveInfo a, ResolveInfo b) { CharSequence sa = a.loadLabel(mPM); if (sa == null) sa = a.activityInfo.name; CharSequence sb = b.loadLabel(mPM); if (sb == null) sb = b.activityInfo.name; return sCollator.compare(sa.toString(), sb.toString()); } private final Collator sCollator = Collator.getInstance(); private PackageManager mPM; } /** 自定义的PackageInfo排序器 **/ private static class PackageInfoComparator implements Comparator<PackageInfo> { public PackageInfoComparator(PackageManager pm) { mPM = pm; } public final int compare(PackageInfo a, PackageInfo b) { CharSequence sa = mPM.getApplicationLabel(a.applicationInfo); CharSequence sb = mPM.getApplicationLabel(b.applicationInfo); return sCollator.compare(sa.toString(), sb.toString()); } private final Collator sCollator = Collator.getInstance(); private PackageManager mPM; } }
/** * App信息类 */ public class AppInfo { // 包名 private String packageName; // APP名 private String appName; // 图标 private Drawable icon; // 版本号 private String versionName; // 权限 private String[] permissions; // 主Activity的类名 private String launchActivityName; public String getLaunchActivityName() { return launchActivityName; } public void setLaunchActivityName(String launchActivityName) { this.launchActivityName = launchActivityName; } public AppInfo() {} public String getPackageName() { return packageName; } public void setPackageName(String packageName) { this.packageName = packageName; } public String getAppName() { return appName; } public void setAppName(String appName) { this.appName = appName; } public Drawable getIcon() { return icon; } public void setIcon(Drawable icon) { this.icon = icon; } public String getVersionName() { return versionName; } public void setVersionName(String versionName) { this.versionName = versionName; } public String[] getPermissions() { return permissions; } public void setPermissions(String[] permissions) { this.permissions = permissions; }; }
AndroidSDK中并没有显式提供方法获得PackageStats对象,只能通过反射机制来调用系统中隐藏的函数(@hide)。
具体方法如下:
第一步、 通过反射机制调用getPackageSizeInfo() ,方法原型为:
/* * @param packageName 应用程序包名 * @param observer 当查询包的信息大小操作完成后 * 将回调给IPackageStatsObserver类中的onGetStatsCompleted()方法, * 并且我们需要的PackageStats对象也封装在其参数里. * @hide //隐藏函数的标记 */ public abstract void getPackageSizeInfo(String packageName, IPackageStatsObserver observer); { // }
内部调用流程如下,这个知识点较为复杂,知道即可:
getPackageSizeInfo方法内部调用getPackageSizeInfoLI(packageName, pStats)方法来完成包状态获取。
getPackageSizeInfoLI方法内部调用Installer.getSizeInfo(String pkgName, String apkPath,String fwdLockApkPath, PackageStats
pStats),继而将包状态信息返回给参数pStats。
getSizeInfo这个方法内部是以本机Socket方式连接到Server,然后向server发送一个文本字符串命令,格式:getsize apkPath fwdLockApkPath 给server。
Server将结果返回,并解析到pStats中。
掌握这个调用知识链即可。
实现代码:
/** 获取指定包的大小信息 **/ public void queryPackageSize(String packageName) throws Exception { Log.i(TAG, "packageName:" + packageName); if (packageName != null) { // 使用反射机制得到PackageManager类的隐藏函数getPackageSizeInfo PackageManager pManager = getPackageManager(); //通过反射机制获得该隐藏函数 Method getPackageSizeInfo = pManager.getClass().getMethod("getPackageSizeInfo" , String.class,IPackageStatsObserver.class); //调用该函数,并且给其分配参数 ,待调用流程完成后会回调PkgSizeObserver类的函数 getPackageSizeInfo.invoke(pManager, packageName,new PkgSizeObserver()); } }
IPackageStatsObserver.aidl 文件:
package android.content.pm; import android.content.pm.PackageStats; /** * API for package data change related callbacks from the Package Manager. * Some usage scenarios include deletion of cache directory, generate * statistics related to code, data, cache usage(TODO) * {@hide} */ oneway interface IPackageStatsObserver { void onGetStatsCompleted(in PackageStats pStats, boolean succeeded); }
package android.content.pm; parcelable PackageStats;
/** aidl文件形成的Bindler机制服务类 **/ public class PkgSizeObserver extends IPackageStatsObserver.Stub{ /*** 回调函数, * @param pStatus ,返回数据封装在PackageStats对象中 * @param succeeded 代表回调成功 */ @Override public void onGetStatsCompleted(PackageStats pStats, boolean succeeded) throws RemoteException { cachesize = pStats.cacheSize; //缓存大小 datasize = pStats.dataSize; //数据大小 codesize = pStats.codeSize; //应用程序大小 totalsize = cachesize + datasize + codesize; } }
第四步、获取pStats的属性值(代码见上),再转换为对应的以kb/mb为计量单位的字符串。下面代码中,1 << 10是二进制的左移,相当于乘以2的10次方,即乘1024
实现代码:
/** 系统函数,字符串转换**/ private String formateFileSize(long size){ String str = ""; double newSize = 0; if (size == 0) { str = "0.00 B"; } else if (size < (1 << 10)) { newSize = size; str = newSize + " B"; } else if (size < (1 << 20)){ newSize = 1.0 * size / (1 << 10); str = String.format("%.2f", newSize) + " KB"; } else if (size < (1 << 30)) { newSize = 1.0 * size / (1 << 20); str = String.format("%.2f", newSize) + " MB"; } return str; }
为了能够通过反射获取应用程序大小,必须加入以下权限,否则会出现警告且得不到实际值。
<uses-permission android:name="android.permission.GET_PACKAGE_SIZE"></uses-permission>