参考资料: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
字段说明:
flags字段:
FLAG_SYSTEM 系统应用程序
FLAG_EXTERNAL_STORAGE 表示该应用安装在sdcard中
ActivityInfo activityInfo 获取 ActivityInfo对象,即或节点信息
ServiceInfo serviceInfo 获取 ServiceInfo对象,即节点信息
ApplicationInfo与ResolveInfo比较:前者能够得到Icon、Label、meta-data、description。后者只能得到Icon、Label。
AndroidManifest.xml文件的信息
常用字段:
String packageName 包名
ActivityInfo[] activities 所有节点信息
ApplicationInfo applicationInfo 节点信息,只有一个
ActivityInfo[] receivers 所有节点信息,多个
ServiceInfo[] services 所有节点信息 ,多个
PackageManager getPackageManager();
// 获得一个PackageManger对象
Drawable getApplicationIcon(String packageName);
// 返回给定包名的图标,否则返回null
ApplicationInfo getApplicationInfo(String packageName, int flags);
// 返回该ApplicationInfo对象
// flags标记通常直接赋予常数0
List getInstalledApplications(int flags);
// 返回给定条件的所有ApplicationInfo
// flag为一般为GET_UNINSTALLED_PACKAGES,后续可进一步过滤结果
List 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 queryIntentActivities(Intent intent, int flags);
// 返回给定条件的所有ResolveInfo对象(本质上是Activity)
ResolveInfo resolveService(Intent intent, int flags);
// 返回给定条件的ResolveInfo对象(本质上是Service)
List 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 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的标签中得到,可获取所有的app。
List applicationList = packageManager
.getInstalledApplications(PackageManager.GET_UNINSTALLED_PACKAGES);
// 法二:通过Intent查找相关的Activity,更准确,但无法获取Provider等应用
// 通过解析标签得到
//
//
Intent intent = new Intent(Intent.ACTION_MAIN, null);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
List 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 allPackageList;
// 筛选结果
private List result;
/** 私有构造器 **/
private AppInfoUtil(Context context) {
pManager = context.getPackageManager();
result = new ArrayList();
}
/** 单例 **/
public static AppInfoUtil getInstance(Context context) {
if (infoUtil == null) {
infoUtil = new AppInfoUtil(context);
}
return infoUtil;
}
/** 获取已安装的APP **/
public List 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 getAppInfoByIntent(Intent intent) {
List 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 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 getAppInfoByPackageInfo(List list) {
List appList = new ArrayList();
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 getAppInfobyResolveInfo(List list) {
List appList = new ArrayList();
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 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 {
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 {
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;
}
为了能够通过反射获取应用程序大小,必须加入以下权限,否则会出现警告且得不到实际值。