Android获取安装应用Apk包大小 缓存大小 getPackageSizeInfo StorageManager

Android获取安装应用Apk包大小 缓存大小 getPackageSizeInfo StorageManager,第1张

Android获取安装应用Apk包大小 缓存大小 getPackageSizeInfo StorageManager

获取安装应用Apk包大小、缓存大小以及应用占用存储总大小
可以通过 PackageManager类的getPackageSizeInfo方法获取,但是这个方法被Google标记成隐藏方法,不能直接调用;
解决方法:可以通过反射调用,但在Android8.0及以上通过反射调用会报错,不过Android8.0及以上可以通过StorageManager 获取

Android8.0以下获取Apk大小方法:
通过反射调用getPackageSizeInfo获取

  1. 创建AIDL文件
  • 创建文件 IPackageStatsObserver.aidl
package android.content.pm;

import android.content.pm.PackageStats;

oneway interface IPackageStatsObserver {

    void onGetStatsCompleted(in PackageStats pStats, boolean succeeded);
}

  • 创建文件 PackageStats.aidl
package android.content.pm;

parcelable PackageStats;

注意包名路径创建正确

如下图:

创建完成后依次点击 Build --> Make Project 以生成AIDL文件

  1. 在AndroidManifest.xml 中添加权限

  1. 代码实现
    public static void handlePackageSizeInfo(Context context, String packageName) {
        PackageManager mPackageManager = context.getPackageManager();
        Method getPackageSizeInfo = null;
        try {
            getPackageSizeInfo = mPackageManager.getClass().getMethod("getPackageSizeInfo", String.class, IPackageStatsObserver.class);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        MyPackageStatsObserver mSecurityPackageStatsObserver = new MyPackageStatsObserver();
        if (getPackageSizeInfo != null) {
            try {
                getPackageSizeInfo.setAccessible(true);
                // 调用该函数,待调用完成后会回调MyPackageStatsObserver
                getPackageSizeInfo.invoke(mPackageManager, packageName, mSecurityPackageStatsObserver);
            } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
                e.printStackTrace();
            }
        }
    }

    static class MyPackageStatsObserver extends IPackageStatsObserver.Stub {

        @Override
        public void onGetStatsCompleted(PackageStats pStats, boolean succeeded) {
            long mCacheSize = pStats.cacheSize;
            long mCodeSize = pStats.codeSize;
            long mDataSize = pStats.dataSize;
            long mTotalSize = mCacheSize + mCodeSize + mDataSize;
            Log.d("AppLog", succeeded+ " cacheSize = " + mCacheSize + "; appSize = " + mCodeSize + "; " + "dataSize = " + mDataSize + "; totalSize = " + mTotalSize);
        }
    }

Android8.0及以上获取Apk大小方法:
通过系统服务 StorageManager 获取Apk大小,需要申请权限 PACKAGE_USAGE_STATS

  1. 在AndroidManifest.xml 中添加权限

  1. 代码实现
	@RequiresApi(api = Build.VERSION_CODES.O)
    public static void getAppSize(Context context, String packageName){
        if (!hasUsageStatsPermission(context)){
            requestAppUsagePermission(context);
        } else {
            new Thread(() -> {
                final StorageStatsManager storageStatsManager = (StorageStatsManager) context.getSystemService(Context.STORAGE_STATS_SERVICE);
                final StorageManager storageManager = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE);
                final List storageVolumes = storageManager.getStorageVolumes();
                final UserHandle user = android.os.Process.myUserHandle();
                try {
                    for (StorageVolume storageVolume : storageVolumes) {
                        final String uuidStr = storageVolume.getUuid();
                        final UUID uuid = uuidStr == null ? StorageManager.UUID_DEFAULT : UUID.fromString(uuidStr);
                        Log.d("AppLog", "storage:" + uuid + " : " + storageVolume.getDescription(context) + " : " + storageVolume.getState());
                        Log.d("AppLog", "getFreeBytes:" + Formatter.formatShortFileSize(context, storageStatsManager.getFreeBytes(uuid)));
                        Log.d("AppLog", "getTotalBytes:" + Formatter.formatShortFileSize(context, storageStatsManager.getTotalBytes(uuid)));
                        StorageStats storageStats = storageStatsManager.queryStatsForPackage(uuid, packageName, user);
                        Log.d("AppLog", "storage stats for app of package name:" + packageName + " : ");
                        Log.d("AppLog", "getAppBytes:" + Formatter.formatShortFileSize(context, storageStats.getAppBytes()) + " getCacheBytes:" + Formatter.formatShortFileSize(context,
                                storageStats.getCacheBytes()) + " getDataBytes:" + Formatter.formatShortFileSize(context, storageStats.getDataBytes()));
                    }
                }catch (PackageManager.NameNotFoundException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }

    public static boolean hasUsageStatsPermission(Context context) {
        UsageStatsManager usageStatsManager = null;
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP_MR1) {
            usageStatsManager = (UsageStatsManager) context.getSystemService(Context.USAGE_STATS_SERVICE);
        }
        if (usageStatsManager == null) {
            return false;
        }
        long currentTime = System.currentTimeMillis();
        // try to get app usage state in last 2 min
        List stats = usageStatsManager.queryUsageStats(UsageStatsManager.INTERVAL_DAILY, currentTime - 2 * 60 * 1000, currentTime);
        return stats != null && stats.size() > 0;
    }

    public static void requestAppUsagePermission(Context context) {
        Intent intent = new Intent(android.provider.Settings.ACTION_USAGE_ACCESS_SETTINGS);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        try {
            context.startActivity(intent);
        } catch (ActivityNotFoundException e) {
            Log.e("AppLog", "Start usage access settings activity fail!", e);
        }
    }

总结

	public static void getInstallApkSize(Context context, String packageName){
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            getAppSize(context, packageName);
        } else {
            handlePackageSizeInfo(context, packageName);
        }
	}

Android8.0以下可以通过反射getPackageSizeInfo方法获取Apk大小;
Android8.0及以上可以通过申请权限 PACKAGE_USAGE_STATS 获取其他已安装应用的Apk大小
还有一种比较复杂方法是 编译一下的android2.3的framework框架,把jar包拷出来,再把框架导入到library,之后就可以直接调用已经hide 的方法 getPackageSizeInfo() 了,具体 *** 作可以搜一下

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5682070.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存