• 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

     
  • 相关阅读:
    关于JDK和eclipse的安装和汉化
    关于Android SDK Manager更新速度慢的解决方法
    Navicat Premium 11破解补丁下载及安装方法
    win8.1下无法运行vc++6.0的解决方法
    在Editplus中配置java的(带包)编译(javac)和运行(java)的方法
    关于在Editplus中设置内容提示比如syso的快捷输出的方法
    关于win8/win8.1系统不能调节亮度的解决办法
    JDK的安装和Java环境变量配置
    关于classpath
    Genymotion模拟器的安装及常见问题解决方法
  • 原文地址:https://www.cnblogs.com/yfafa/p/9082051.html
Copyright © 2020-2023  润新知