android学习笔记一 PackageManager

主要作用:管理应用程序包,通过它获取应用程序信息

摘自 https://blog.csdn.net/u012532559/article/details/52805632

AnroidManifest.xml文件节点说明:

 

一 、相关类介绍

1. PackageItemInfo类

AndroidManifest.xml文件中所有节点的基类,并不直接使用,而是由子类继承然后调用相应方法。

常用字段:

 

[java] view plain copy
 
 
 
  1. int icon             资源图片在R文件中的值 (对应于android:icon属性)  
  2. int labelRes         label在R文件中的值(对应于android:label属性)  
  3. String name          节点的name值 (对应于android:name属性)  
  4. String packagename   应用程序的包名 (对应于android:packagename属性)  

 

常用方法:
[java] view plain copy
 
 
 
  1. Drawable loadIcon(PackageManager pm)          获得当前应用程序的图标  
  2. CharSequence loadLabel(PackageManager pm)     获得当前应用程序的label,从上图可知是app_name  
 
PackageItemInfo继承关系图:
 

2. ActivityInfo类

<activity>或者 <receiver>节点信息 。可获取theme 、launchMode、launchmode等属性

常用方法继承自PackageItemInfo类,下同。
 

3. ServiceInfo类

<service>节点信息。

 

4. ApplicationInfo类

<application>节点的信息。

字段说明:

[java] view plain copy
 
 
 
  1. flags字段:  
  2. FLAG_SYSTEM 系统应用程序  
  3. FLAG_EXTERNAL_STORAGE 表示该应用安装在sdcard中  

5. ResolveInfo类

根据<intent-filter>节点获取其上一层目录的信息,通常是<activity>、<receiver>、<service>节点信息。
常用字段:
[java] view plain copy
 
 
 
  1. ActivityInfo activityInfo    获取 ActivityInfo对象,即<activity>或<receiver>节点信息  
  2. ServiceInfo serviceInfo     获取 ServiceInfo对象,即<service>节点信息  

ApplicationInfo与ResolveInfo比较:前者能够得到Icon、Label、meta-data、description。后者只能得到Icon、Label。

 

6. PackageInfo类

AndroidManifest.xml文件的信息

常用字段:

 

[java] view plain copy
 
 
 
  1. String packageName               包名  
  2. ActivityInfo[] activities        所有<activity>节点信息  
  3. ApplicationInfo applicationInfo  <application>节点信息,只有一个  
  4. ActivityInfo[] receivers         所有<receiver>节点信息,多个  
  5. ServiceInfo[] services           所有<service>节点信息 ,多个  

 

7. PackageManger 类

通过getPackageManager()方法获得。
常用方法:
[java] view plain copy
 
 
 
  1. PackageManager getPackageManager();  
  2. // 获得一个PackageManger对象  
  3.   
  4. Drawable getApplicationIcon(String packageName);  
  5. // 返回给定包名的图标,否则返回null  
  6.   
  7. ApplicationInfo getApplicationInfo(String packageName, int flags);  
  8. // 返回该ApplicationInfo对象  
  9. // flags标记通常直接赋予常数0  
  10.   
  11. List<ApplicationInfo> getInstalledApplications(int flags);  
  12. // 返回给定条件的所有ApplicationInfo  
  13. // flag为一般为GET_UNINSTALLED_PACKAGES,后续可进一步过滤结果  
  14.   
  15. List<PackageInfo> getInstalledPackages(int flags);  
  16. // 返回给定条件的所有PackageInfo  
  17.   
  18. ResolveInfo resolveActivity(Intent intent, int flags);  
  19. // 返回给定条件的ResolveInfo对象(本质上是Activity)   
  20. // intent 是查询条件,Activity所配置的action和category  
  21. // 可选flags:  
  22. // MATCH_DEFAULT_ONLY :Category必须带有CATEGORY_DEFAULT的Activity,才匹配  
  23. // GET_INTENT_FILTERS :匹配Intent条件即可  
  24. // GET_RESOLVED_FILTER :匹配Intent条件即可  
  25.   
  26. List<ResolveInfo> queryIntentActivities(Intent intent, int flags);  
  27. // 返回给定条件的所有ResolveInfo对象(本质上是Activity)  
  28.   
  29. ResolveInfo resolveService(Intent intent, int flags);  
  30. // 返回给定条件的ResolveInfo对象(本质上是Service)   
  31.   
  32. List<ResolveInfo> queryIntentServices(Intent intent, int flags);  
  33. // 返回给定条件的所有ResolveInfo对象(本质上是Service),集合对象  


 
 
 

8. PackageStats 类

安装包的大小信息。AndroidSDK中并没有显式提供方法获得PackageStats对象,只能通过反射机制来调用系统中隐藏的函数(@hide)。

常用字段:

 

[java] view plain copy
 
 
 
  1. long cachesize      缓存大小  
  2. long codesize       应用程序大小  
  3. long datasize       数据大小  
  4. String packageName  包名  

 

 

PS:应用程序的总大小 = cachesize  + codesize  + datasize。

 

二、常用代码片

1.根据PackageInfo对象获取APP信息:

 

[java] view plain copy
 
 
 
  1. ApplicationInfo applicationInfo = packageInfo.applicationInfo;  
  2. // APP 包名  
  3. String packageName = packageInfo.packageName;  
  4. // APP icon  
  5. Drawable icon = packageManager.getApplicationIcon(applicationInfo);  
  6. // APP 名称  
  7. String appName = packageManager.getApplicationLabel(applicationInfo).toString();  
  8. // APP 权限  
  9. String[] permissions = packageManager.getPackageInfo(packageName,PackageManager.GET_PERMISSIONS).requestedPermissions;  
 

2.根据ResolveInfo对象获取APP信息:

 

[java] view plain copy
 
 
 
  1. // APP包名  
  2. resolve.activityInfo.packageName;  
  3. // APP icon  
  4. resolve.loadIcon(packageManager);  
  5. // APP名称  
  6. resolve.loadLabel(packageManager).toString();  
 

3.根据包名获取APP中的主Activity:

[java] view plain copy
 
 
 
  1. Intent intent = new Intent(Intent.ACTION_MAIN);      
  2. intent.setPackage(packageName);    
  3. intent.addCategory(Intent.CATEGORY_LAUNCHER);   
  4. List<ResolveInfo> resolveInfos = pManager.queryIntentActivities(intent, 0);  
  5. // 一个App中只有一个主Activity,直接取出。注意不是任何包中都有主Activity  
  6. String mainActivityName = "";  
  7. if (resolveInfos != null && resolveInfos.size() >= 1) {  
  8.     mainActivityName = resolveInfos.get(0).activityInfo.name;  
  9. }  
 

4.根据包名获取APP信息:

[java] view plain copy
 
 
 
  1. PackageManager pManager = context.getPackageManager();  
  2. PackageInfo packageInfo = pManager.getPackageInfo(packageName, 0);  
  3. ApplicationInfo appInfo = packageInfo.applicationInfo;  
  4.   
  5. // 获取App名  
  6. String appName = pManager.getApplicationLabel(appInfo).toString();  
  7. //// 也可以使用如下方法  
  8. //String appName = appInfo.loadLabel(pManager).toString();  
  9. // 获取App Icon  
  10. Drawable icon = pManager.getApplicationIcon(appInfo);  
  11. //// 也可以用如下两种方法  
  12. //Drawable icon = pManager.getApplicationIcon(packageName);  
  13. //Drawable icon = appInfo.loadIcon(pManager);  
  14. // 获取App versionName  
  15. String versionName = packageInfo.versionName; // versionName在xml的根节点中,只能用PackageInfo获取  
  16. // 获取权限  
  17. PackageInfo pPermissionInfo = pManager.getPackageInfo(packageName, PackageManager.GET_PERMISSIONS);   
  18. String[] permissions = pPermissionInfo.requestedPermissions;  
 

5.批量获取App信息的两种方法:

[java] view plain copy
 
 
 
  1. PackageManager packageManager = getPackageManager();  
  2.   
  3. // 法一:通过解析AndroidManifest.xml的<application>标签中得到,可获取所有的app。  
  4. List<ApplicationInfo> applicationList = packageManager  
  5.                   .getInstalledApplications(PackageManager.GET_UNINSTALLED_PACKAGES);  
  6.   
  7. // 法二:通过Intent查找相关的Activity,更准确,但无法获取Provider等应用  
  8. // 通过解析<Intent-filter>标签得到  
  9. // <action android:name=”android.intent.action.MAIN”/>  
  10. // <action android:name=”android.intent.category.LAUNCHER”/>  
  11. Intent intent = new Intent(Intent.ACTION_MAIN, null);  
  12. intent.addCategory(Intent.CATEGORY_LAUNCHER);  
  13. List<ResolveInfo> resolveList = packageManager.queryIntentActivities(intent, 0);  

6.区分系统APP、第三方APP、安装在SDCard上的APP:

[java] view plain copy
 
 
 
  1. /** 判断是不是系统APP **/  
  2. // FLAG_SYSTEM = 1<<0,if set, this application is installed in the device's system image.  
  3. // 下面&运算有两种结果:  
  4. // 1,则flags的末位为1,即系统APP  
  5. // 0,则flags的末位为0,即非系统APP  
  6. if ( (applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 1 ){  
  7.     ......  
  8. }  
  9.   
  10. /** 判断是不是第三方APP **/  
  11. // FLAG_SYSTEM = 1<<0,同上  
  12. if ( (applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {  
  13.      ......  
  14. }  
  15. //本来是系统程序,被用户手动更新后,该系统程序也成为第三方应用程序了  
  16. // FLAG_UPDATED_SYSTEM_APP = 1<<7, this is set if this application has been   
  17. // install as an update to a built-in system application.  
  18. else if ((applicationInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) == 1) {  
  19.      ......  
  20. }  
  21.   
  22. /** 判断是不是安装在SDCard的应用程序 **/  
  23. // FLAG_EXTERNAL_STORAGE = 1<<18,Set to true if the application is  
  24. // currently installed on external/removable/unprotected storage  
  25. if ( (applicationInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) == 1) {  
  26.     ......  
  27. }   

三、工具类

获取APP信息:
[java] view plain copy
 
 
 
  1. /** 
  2.  * 获取手机上安装的所有APP的信息 配合AppInfo类使用 
  3.  */  
  4. public class AppInfoUtil {  
  5.     public static final int GET_ALL_APP = 0; // 所有APP  
  6.     public static final int GET_SYSTEM_APP = 1; // 系统预装APP  
  7.     public static final int GET_THIRD_APP = 2; // 第三方APP  
  8.     public static final int GET_SDCARD_APP = 3; // SDCard的APP  
  9.   
  10.     private static AppInfoUtil infoUtil;  
  11.   
  12.     private PackageManager pManager;  
  13.   
  14.     // 所有应用  
  15.     private List<PackageInfo> allPackageList;  
  16.   
  17.     // 筛选结果  
  18.     private List<PackageInfo> result;  
  19.   
  20.     /** 私有构造器 **/  
  21.     private AppInfoUtil(Context context) {  
  22.         pManager = context.getPackageManager();  
  23.         result = new ArrayList<PackageInfo>();  
  24.     }  
  25.   
  26.     /** 单例 **/  
  27.     public static AppInfoUtil getInstance(Context context) {  
  28.         if (infoUtil == null) {  
  29.             infoUtil = new AppInfoUtil(context);  
  30.         }  
  31.         return infoUtil;  
  32.     }  
  33.   
  34.     /** 获取已安装的APP **/  
  35.     public List<AppInfo> getInstalledApps(int type) {  
  36.         // 0 表示不接受任何参数。其他参数都带有限制  
  37.         // 版本号、APP权限只能通过PackageInfo获取,故这里不使用getInstalledApplications()方法  
  38.         allPackageList = pManager.getInstalledPackages(0);  
  39.         if (allPackageList == null) {  
  40.             Log.e("AppInfoUtil类", "getInstalledApps()方法中的allPackageList为空");  
  41.             return null;  
  42.         }  
  43.         // 根据APP名排序  
  44.         Collections.sort(allPackageList, new PackageInfoComparator(pManager));  
  45.         // 筛选  
  46.         result.clear();  
  47.         switch (type) {  
  48.         case GET_ALL_APP:  
  49.             result = allPackageList;  
  50.             break;  
  51.         case GET_SYSTEM_APP: // 系统自带APP  
  52.             for (PackageInfo info : allPackageList) {  
  53.                 // FLAG_SYSTEM = 1<<0,if set, this application is installed in  
  54.                 // the device's system image.  
  55.                 // 下面&运算有两种结果:  
  56.                 // 1,则flags的末位为1,即系统APP  
  57.                 // 0,则flags的末位为0,即非系统APP  
  58.                 if ((info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 1) {  
  59.                     result.add(info);  
  60.                 }  
  61.             }  
  62.             break;  
  63.         case GET_THIRD_APP: // 第三方APP  
  64.             for (PackageInfo info : allPackageList) {  
  65.                 // FLAG_SYSTEM = 1<<0,同上  
  66.                 if ((info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {  
  67.                     result.add(info);  
  68.                 }  
  69.                 // 本来是系统程序,被用户手动更新后,该系统程序也成为第三方应用程序了  
  70.                 // FLAG_UPDATED_SYSTEM_APP = 1<<7, this is set if this  
  71.                 // application has been  
  72.                 // install as an update to a built-in system application.  
  73.                 else if ((info.applicationInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) == 1) {  
  74.                     result.add(info);  
  75.                 }  
  76.             }  
  77.             break;  
  78.         case GET_SDCARD_APP: // 安装在SDCard的应用程序  
  79.             for (PackageInfo info : allPackageList) {  
  80.                 // FLAG_EXTERNAL_STORAGE = 1<<18,Set to true if the application  
  81.                 // is  
  82.                 // currently installed on external/removable/unprotected storage  
  83.                 if ((info.applicationInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) == 1) {  
  84.                     result.add(info);  
  85.                 }  
  86.             }  
  87.             break;  
  88.         }  
  89.         return getAppInfoByPackageInfo(result);  
  90.     }  
  91.   
  92.     public List<AppInfo> getAppInfoByIntent(Intent intent) {  
  93.         List<ResolveInfo> resolveInfos = pManager.queryIntentActivities(intent,  
  94.                 PackageManager.GET_INTENT_FILTERS);  
  95.         // 调用系统排序 , 根据name排序  
  96.         // 此排序会将系统自带App与用户安装的APP分开排序  
  97.         Collections.sort(resolveInfos, new ResolveInfo.DisplayNameComparator(  
  98.                 pManager));  
  99.         // // 此排序会将系统自带App与用户安装的APP混合排序  
  100.         // Collections.sort(resolveInfos, new DisplayNameComparator(pManager));  
  101.         return getAppInfobyResolveInfo(resolveInfos);  
  102.     }  
  103.   
  104.     /** 获取单个App图标 **/  
  105.     public Drawable getAppIcon(String packageName) throws NameNotFoundException {  
  106.         Drawable icon = pManager.getApplicationIcon(packageName);  
  107.         return icon;  
  108.     }  
  109.   
  110.     /** 获取单个App名称 **/  
  111.     public String getAppName(String packageName) throws NameNotFoundException {  
  112.         ApplicationInfo appInfo = pManager.getApplicationInfo(packageName, 0);  
  113.         String appName = pManager.getApplicationLabel(appInfo).toString();  
  114.         return appName;  
  115.     }  
  116.   
  117.     /** 获取单个App版本号 **/  
  118.     public String getAppVersion(String packageName)  
  119.             throws NameNotFoundException {  
  120.         PackageInfo packageInfo = pManager.getPackageInfo(packageName, 0);  
  121.         String appVersion = packageInfo.versionName;  
  122.         return appVersion;  
  123.     }  
  124.   
  125.     /** 获取单个App的所有权限 **/  
  126.     public String[] getAppPermission(String packageName)  
  127.             throws NameNotFoundException {  
  128.         PackageInfo packageInfo = pManager.getPackageInfo(packageName,  
  129.                 PackageManager.GET_PERMISSIONS);  
  130.         String[] permission = packageInfo.requestedPermissions;  
  131.         return permission;  
  132.     }  
  133.   
  134.     /** 获取单个App的签名 **/  
  135.     public String getAppSignature(String packageName)  
  136.             throws NameNotFoundException {  
  137.         PackageInfo packageInfo = pManager.getPackageInfo(packageName,  
  138.                 PackageManager.GET_SIGNATURES);  
  139.         String allSignature = packageInfo.signatures[0].toCharsString();  
  140.         return allSignature;  
  141.     }  
  142.   
  143.     // /** 使用示例 **/  
  144.     // public static void main(String[] args) {  
  145.     // AppInfoUtil appInfoUtil = AppInfo.getInstance(context);  
  146.     //  
  147.     // // 获取所有APP  
  148.     // List<AppInfo> allAppInfo = appInfoUtil.getInstalledApps(AppInfoUtil.GET_ALL_APP);  
  149.     // for (AppInfo app : allAppInfo) {  
  150.     // String packageName = app.getPackageName();  
  151.     // String appName = app.getAppName();  
  152.     // Drawable icon = app.getIcon();  
  153.     // String versionName = app.getVersionName();  
  154.     // String[] permissions = app.getPermissions();  
  155.     // // 自由发挥...  
  156.     // }  
  157.     //  
  158.     // // 获取单个APP的信息  
  159.     // String appName = appInfoUtil.getAppName(packageName);  
  160.     // ...  
  161.     // }  
  162.   
  163.     /** 从PackageInfo的List中提取App信息 **/  
  164.     private List<AppInfo> getAppInfoByPackageInfo(List<PackageInfo> list) {  
  165.         List<AppInfo> appList = new ArrayList<AppInfo>();  
  166.         for (PackageInfo info : list) {  
  167.             // 获取信息  
  168.             String packageName = info.applicationInfo.packageName;  
  169.             String appName = pManager.getApplicationLabel(info.applicationInfo)  
  170.                     .toString();  
  171.             Drawable icon = pManager.getApplicationIcon(info.applicationInfo);  
  172.             // // 也可以用如下方法获取APP图标,显然更烦琐  
  173.             // ApplicationInfo applicationInfo =  
  174.             // pManager.getApplicationInfo(packageName, 0);  
  175.             // Drawable icon = applicationInfo.loadIcon(pManager);  
  176.             String versionName = info.versionName;  
  177.             String[] permissions = info.requestedPermissions;  
  178.             String launchActivityName = getLaunchActivityName(packageName);  
  179.             // 储存信息  
  180.             AppInfo appInfo = new AppInfo();  
  181.             appInfo.setPackageName(packageName);  
  182.             appInfo.setAppName(appName);  
  183.             appInfo.setIcon(icon);  
  184.             appInfo.setVersionName(versionName);  
  185.             appInfo.setPermissions(permissions);  
  186.             appInfo.setLaunchActivityName(launchActivityName);  
  187.             appList.add(appInfo);  
  188.         }  
  189.         return appList;  
  190.     }  
  191.   
  192.     /** 从ResolveInfo的List中提取App信息 **/  
  193.     private List<AppInfo> getAppInfobyResolveInfo(List<ResolveInfo> list) {  
  194.         List<AppInfo> appList = new ArrayList<AppInfo>();  
  195.         for (ResolveInfo info : list) {  
  196.             String packageName = info.activityInfo.packageName;  
  197.             String appName = info.loadLabel(pManager).toString();  
  198.             Drawable icon = info.loadIcon(pManager);  
  199.             String launchActivityName = getLaunchActivityName(packageName);  
  200.             AppInfo appInfo = new AppInfo();  
  201.             appInfo.setPackageName(packageName);  
  202.             appInfo.setAppName(appName);  
  203.             appInfo.setIcon(icon);  
  204.             appInfo.setLaunchActivityName(launchActivityName);  
  205.             appList.add(appInfo);  
  206.         }  
  207.         return appList;  
  208.     }  
  209.   
  210.     /** 获取指定包中主Activity的类名,并不是所有包都有主Activity **/  
  211.     private String getLaunchActivityName(String packageName) {  
  212.         // 根据PackageInfo对象取不出其中的主Activity,须用Intent  
  213.         Intent intent = new Intent(Intent.ACTION_MAIN);  
  214.         intent.setPackage(packageName);  
  215.         List<ResolveInfo> resolveInfos = pManager.queryIntentActivities(intent,  
  216.                 0);  
  217.         String mainActivityName = "";  
  218.         if (resolveInfos != null && resolveInfos.size() >= 1) {  
  219.             mainActivityName = resolveInfos.get(0).activityInfo.name;  
  220.         }  
  221.         return mainActivityName;  
  222.     }  
  223.   
  224.     /** 此比较器直接复制Android源码,但是却可以把系统APP与用户APP混合排列,何解? **/  
  225.     private static class DisplayNameComparator implements  
  226.             Comparator<ResolveInfo> {  
  227.         public DisplayNameComparator(PackageManager pm) {  
  228.             mPM = pm;  
  229.         }  
  230.   
  231.         public final int compare(ResolveInfo a, ResolveInfo b) {  
  232.             CharSequence sa = a.loadLabel(mPM);  
  233.             if (sa == null)  
  234.                 sa = a.activityInfo.name;  
  235.             CharSequence sb = b.loadLabel(mPM);  
  236.             if (sb == null)  
  237.                 sb = b.activityInfo.name;  
  238.             return sCollator.compare(sa.toString(), sb.toString());  
  239.         }  
  240.   
  241.         private final Collator sCollator = Collator.getInstance();  
  242.         private PackageManager mPM;  
  243.     }  
  244.   
  245.     /** 自定义的PackageInfo排序器 **/  
  246.     private static class PackageInfoComparator implements  
  247.             Comparator<PackageInfo> {  
  248.         public PackageInfoComparator(PackageManager pm) {  
  249.             mPM = pm;  
  250.         }  
  251.   
  252.         public final int compare(PackageInfo a, PackageInfo b) {  
  253.             CharSequence sa = mPM.getApplicationLabel(a.applicationInfo);  
  254.             CharSequence sb = mPM.getApplicationLabel(b.applicationInfo);  
  255.             return sCollator.compare(sa.toString(), sb.toString());  
  256.         }  
  257.   
  258.         private final Collator sCollator = Collator.getInstance();  
  259.         private PackageManager mPM;  
  260.     }  
  261.   
  262. }  

配套Model,AppInfo.java:
[java] view plain copy
 
 
 
  1. /** 
  2.  * App信息类 
  3.  */  
  4. public class AppInfo {  
  5.     // 包名  
  6.     private String packageName;  
  7.     // APP名  
  8.     private String appName;  
  9.     // 图标  
  10.     private Drawable icon;  
  11.     // 版本号  
  12.     private String versionName;  
  13.     // 权限  
  14.     private String[] permissions;  
  15.     // 主Activity的类名  
  16.     private String launchActivityName;   
  17.       
  18.     public String getLaunchActivityName() {  
  19.         return launchActivityName;  
  20.     }  
  21.   
  22.     public void setLaunchActivityName(String launchActivityName) {  
  23.         this.launchActivityName = launchActivityName;  
  24.     }  
  25.   
  26.     public AppInfo() {}  
  27.   
  28.     public String getPackageName() {  
  29.         return packageName;  
  30.     }  
  31.   
  32.     public void setPackageName(String packageName) {  
  33.         this.packageName = packageName;  
  34.     }  
  35.   
  36.     public String getAppName() {  
  37.         return appName;  
  38.     }  
  39.   
  40.     public void setAppName(String appName) {  
  41.         this.appName = appName;  
  42.     }  
  43.   
  44.     public Drawable getIcon() {  
  45.         return icon;  
  46.     }  
  47.   
  48.     public void setIcon(Drawable icon) {  
  49.         this.icon = icon;  
  50.     }  
  51.   
  52.     public String getVersionName() {  
  53.         return versionName;  
  54.     }  
  55.   
  56.     public void setVersionName(String versionName) {  
  57.         this.versionName = versionName;  
  58.     }  
  59.   
  60.     public String[] getPermissions() {  
  61.         return permissions;  
  62.     }  
  63.   
  64.     public void setPermissions(String[] permissions) {  
  65.         this.permissions = permissions;  
  66.     };  
  67.       
  68.       
  69. }  


四、通过反射获取APP包的大小

AndroidSDK中并没有显式提供方法获得PackageStats对象,只能通过反射机制来调用系统中隐藏的函数(@hide)。

具体方法如下:
第一步、  通过反射机制调用getPackageSizeInfo() ,方法原型为:

 

[java] view plain copy
 
 
 
  1. /* 
  2.  * @param packageName 应用程序包名 
  3.  * @param observer 当查询包的信息大小操作完成后 
  4.  * 将回调给IPackageStatsObserver类中的onGetStatsCompleted()方法, 
  5.  * 并且我们需要的PackageStats对象也封装在其参数里. 
  6.  * @hide //隐藏函数的标记 
  7.  */  
  8. public abstract void getPackageSizeInfo(String packageName, IPackageStatsObserver observer);  
  9. {  
  10.     //  
  11. }  

 

内部调用流程如下,这个知识点较为复杂,知道即可:
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中。
掌握这个调用知识链即可。

 

实现代码:

 

[java] view plain copy
 
 
 
  1. /** 获取指定包的大小信息 **/  
  2. public void queryPackageSize(String packageName) throws Exception {  
  3.     Log.i(TAG, "packageName:" + packageName);  
  4.     if (packageName != null) {  
  5.         // 使用反射机制得到PackageManager类的隐藏函数getPackageSizeInfo    
  6.         PackageManager pManager = getPackageManager();  
  7.         //通过反射机制获得该隐藏函数    
  8.         Method getPackageSizeInfo = pManager.getClass().getMethod("getPackageSizeInfo"  
  9.                                     , String.class,IPackageStatsObserver.class);    
  10.         //调用该函数,并且给其分配参数 ,待调用流程完成后会回调PkgSizeObserver类的函数    
  11.         getPackageSizeInfo.invoke(pManager, packageName,new PkgSizeObserver());    
  12.     }  
  13. }  


 

第二步、由于需要获得系统级的服务或类,我们必须加入Android系统形成的AIDL文件,共两个: IPackageStatsObserver.aidl 和 PackageStats.aidl文件。将它们放置在android.content.pm包路径下。 

 

IPackageStatsObserver.aidl 文件:

 

[java] view plain copy
 
 
 
  1. package android.content.pm;    
  2.     
  3. import android.content.pm.PackageStats;    
  4. /**  
  5.  * API for package data change related callbacks from the Package Manager.  
  6.  * Some usage scenarios include deletion of cache directory, generate  
  7.  * statistics related to code, data, cache usage(TODO)  
  8.  * {@hide}  
  9.  */    
  10. oneway interface IPackageStatsObserver {    
  11.         
  12.     void onGetStatsCompleted(in PackageStats pStats, boolean succeeded);    
  13. }    

 

 

PackageStats.aidl文件:

 

[java] view plain copy
 
 
 
  1. package android.content.pm;    
  2.     
  3. parcelable PackageStats;   

第三步、创建一个类继承至IPackageStatsObserver.Stub()它本质上实现了Binder机制。当我们把该类的一个实例通过getPackageSizeInfo()调用时,该函数启动中间流程去获取相关包的信息大小,扫描完成后,将查询信息回调至该类的onGetStatsCompleted(PackageStats pStats, boolean succeeded)方法,信息大小封装在此实例上。
 
实现代码:
[java] view plain copy
 
 
 
  1. /** aidl文件形成的Bindler机制服务类 **/  
  2. public class PkgSizeObserver extends IPackageStatsObserver.Stub{    
  3.     /*** 回调函数,  
  4.      * @param pStatus ,返回数据封装在PackageStats对象中  
  5.      * @param succeeded  代表回调成功  
  6.      */     
  7.     @Override    
  8.     public void onGetStatsCompleted(PackageStats pStats, boolean succeeded) throws RemoteException {    
  9.         cachesize = pStats.cacheSize; //缓存大小    
  10.         datasize = pStats.dataSize;  //数据大小     
  11.         codesize = pStats.codeSize;  //应用程序大小    
  12.         totalsize = cachesize + datasize + codesize;   
  13.     }    
  14. }    
 

第四步、获取pStats的属性值(代码见上),再转换为对应的以kb/mb为计量单位的字符串。下面代码中,1 << 10是二进制的左移,相当于乘以2的10次方,即乘1024

实现代码:

 

[java] view plain copy
 
 
 
  1. /** 系统函数,字符串转换**/  
  2. private String formateFileSize(long size){  
  3.     String str = "";  
  4.     double newSize = 0;  
  5.     if (size == 0) {  
  6.         str = "0.00 B";  
  7.     } else if (size < (1 << 10)) {  
  8.         newSize = size;  
  9.         str = newSize + " B";  
  10.     } else if (size < (1 << 20)){  
  11.         newSize = 1.0 * size / (1 << 10);  
  12.         str = String.format("%.2f", newSize) + " KB";  
  13.     } else if (size < (1 << 30)) {  
  14.         newSize = 1.0 * size / (1 << 20);  
  15.         str = String.format("%.2f", newSize) + " MB";  
  16.     }  
  17.     return str;     
  18. }    

 

为了能够通过反射获取应用程序大小,必须加入以下权限,否则会出现警告且得不到实际值。

[html] view plain copy
 
 
 
  1. <uses-permission android:name="android.permission.GET_PACKAGE_SIZE"></uses-permission>   

流程图如下:
 

五、Demo

 
posted @ 2018-05-24 11:42  大一脚步  阅读(508)  评论(0编辑  收藏  举报