android 获取其他应用程序的缓存大小以及清理应用缓存

最近在做appStore时,涉及到一个第三方app下载视频后将车机存储撑爆的问题,从而影响到我们车机自带的app使用,问题很是严重,于是就需要提供缓存清理以及垃圾清理的功能,当用户使用第三方app时,存储空间达到一定量的时候会提示用户去清理,否则不允许使用第三方app。

缓存获取

获取各个应用程序的缓存大小,可以通过使用PackageManager.getPackageSizeInfo方法来获取,但是它被隐藏了,所以我们只能通过反射来调用该方法

android 获取其他应用程序的缓存大小以及清理应用缓存_第1张图片

一、首先我们需要获取到系统中所有已安装app的基本信息

List installedPackages = mPackageManager.getInstalledPackages(0);
        for (PackageInfo packageInfo : installedPackages) {
            getCacheSize(packageInfo);//反射调用getPackageSizeInfo
        }

二、反射调用getPackageSizeInfo

/**
     * 获取到缓存的大小
     *
     * @param packageInfo
     */
    private void getCacheSize(PackageInfo packageInfo) {
        try {
            //通过反射获取到当前的方法
            Method method = PackageManager.class.getDeclaredMethod("getPackageSizeInfo", String.class, IPackageStatsObserver.class);
            /**
             * 第一个参数表示当前的这个方法由谁调用的
             * 第二个参数表示包名
             */
            method.invoke(mPackageManager, packageInfo.applicationInfo.packageName, new MyIPackageStatsObserver(packageInfo));
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

三、调用getPackageSizeInfo需要两个参数,第一个参数是应用包名,通过packageInfo可以获取到,第二个参数是一个IPackageStatsObserver类型的回调,所有查询的结果都是从IPackageStatsObserver里面的onGetStatsCompleted方法里面回调回来的。onGetStatsCompleted是异步调用的,所以我们需要通过handler将结果更新到UI上.

public static final int HANDLER_UPDATE_CACHE_MSG = 0XF0F1;

    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            if (HANDLER_UPDATE_CACHE_MSG == msg.what) {
                if (msg.obj != null && msg.obj instanceof CacheInfo) {
                    CacheInfo info = (CacheInfo) msg.obj;
                    mCleanCacheAdapter.addDataAndRefresh(info);
                }
            }
        }
    };

    private class MyIPackageStatsObserver extends IPackageStatsObserver.Stub {
        private PackageInfo packageInfo;

        public MyIPackageStatsObserver(PackageInfo packageInfo) {
            this.packageInfo = packageInfo;
        }

        @Override
        public void onGetStatsCompleted(PackageStats pStats, boolean succeeded) throws RemoteException {
            //获取到当前手机应用的缓存大小
            long cacheSize = pStats.cacheSize;// 缓存大小
            long dataSize = pStats.dataSize; // 数据大小
            //如果当前的缓存大小大于0的话,则表示有缓存
            if (cacheSize > 0) {
                CacheInfo cacheInfo = new CacheInfo();
                Drawable icon = packageInfo.applicationInfo.loadIcon(mPackageManager);
                String appName = packageInfo.applicationInfo.loadLabel(mPackageManager).toString();
                String packageName = packageInfo.packageName;
                cacheInfo.setAppName(appName);
                cacheInfo.setPackageName(packageName);
                cacheInfo.setIcon(icon);
                cacheInfo.setCacheSize(cacheSize);
                Message.obtain(mHandler, HANDLER_UPDATE_CACHE_MSG, cacheInfo).sendToTarget();
                LogUtils.d(mTAG,"---读取缓存中------>" + cacheSize + "---cacheInfos.size()--" + mCacheInfos.size());
            }
        }
    }

四、补充:注意点: IPackageStatsObserver.aidl和PackageStats.aidl文件都是从系统中拿出来的,需要放到指定的文件夹下(android.content.pm),否则会出现找不到的错误。上面的CacheInfo只是一个简单的javaBean用来存放每个应用所查询到的数据。
android 获取其他应用程序的缓存大小以及清理应用缓存_第2张图片

五、前面四步已经成功的将所有的app缓存大小都获取到了,接下来就是如何清理这些缓存,首先说说一键清理,就是一次性清理所有的缓存,可以调用PackageManager的freeStorageAndNotify的方法,同样还是@hide,所以我们依旧要通过反射来调用,直接前几步骤差不多直接看代码
android 获取其他应用程序的缓存大小以及清理应用缓存_第3张图片

public void cleanAll() {
        //获取到当前应用程序里面所有的方法
        try {
            StatFs stat = new StatFs(Environment.getDataDirectory().getAbsolutePath());
            Method mFreeStorageAndNotifyMethod = mPackageManager.getClass().getMethod(
                    "freeStorageAndNotify", long.class, IPackageDataObserver.class);
            mFreeStorageAndNotifyMethod.invoke(mPackageManager,
                    (long) stat.getBlockCount() * (long) stat.getBlockSize(),
                    new MyIPackageDataObserver()
            );
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }

    class MyIPackageDataObserver extends IPackageDataObserver.Stub {
        public MyIPackageDataObserver() {
        }

        @Override
        public void onRemoveCompleted(String packageName, boolean succeeded) throws RemoteException {
            LogUtils.e(mTAG,"当前清理的包名:"+packageName);
            if (succeeded){
                LogUtils.e(mTAG,"清理成功!");
            }else {
                LogUtils.e(mTAG,"清理失败!");
            }
        }
    }

前面那些操作所需要的权限:

<uses-permission android:name="android.permission.CLEAR_APP_CACHE" />
    <uses-permission android:name="android.permission.GET_PACKAGE_SIZE" />

六、到此为止,我所查询到的资料基本都是这些步骤,如果需要单独清理的应用数据的话,大都是直接跳到系统清理界面,通过系统操作清理。不过我们车机很显然不可能跳到系统界面然后清理,所以只能另寻他路,后来查到ActivityManager:clearApplicationUserData这个方法,是用于应用清除用户数据,相当于在设置中清除应用数据,同样也是隐藏的所以我们还是通过反射来调用,具体代码就不提供了,跟上面方式是一样的。
android 获取其他应用程序的缓存大小以及清理应用缓存_第4张图片

七、然后第六步操作之后运行会直接挂掉,提示缺少android.permission.CLEAR_APP_USER_DATA权限,然而加上之后还是会挂掉,还是提示缺少这个权限,也就是说普通的app我们是无法获取到这个权限的,所以我们还需要在AndroidManifest.xml里面配置android:sharedUserId=”android.uid.system”,这句配置的意思就是获取系统的进程权限,然后我们的app还需要调用系统平台的签名,这样就能单独的清理指定应用的缓存数据了。其实这个有很大的缺陷,由于应用和系统签名是绑定在一起的,所以这个应用只能在指定的系统上安装,其他的系统是安装不了的,我们车机系统是自己定制的,所以这个方式,对我这个应用来说是没问题的。

你可能感兴趣的:(android)