Flutter 学习 之 获取 APP 所在安卓手机中占用的存储空间

翻了好多插件好像也没一个获取手机内存和app相关数据的插件, 那没办法只能从原生获取了

1. 与原生交互首先创建MethodChannel 如果之前有创建直接发送方法

如果没写过可以查看 https://flutter.cn/docs/development/platform-integration/platform-channels?tab=android-channel-java-tab
或者 https://flutter.cn/docs/development/packages-and-plugins/developing-packages
再或者 https://www.jianshu.com/p/afeb4bac1fc8

2.Android 端代码的实现

2.1. Android添加从dart来的方法

在methodCall中添加你的方法名称 记得和Dart中要保持一致的名字

    @Override
    public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {

        switch (call.method) {
            case CommStr.METHOD_APP_DISK_INFO:
                Map<String, Map<String, String>> appDiskInfo = getAppDiskInfo();
                result.success(appDiskInfo);
                break;
            case CommStr.METHOD_BACK_TO_DESKTOP:
                activity.moveTaskToBack(false);
                result.success(true);
                break;
            default:
                result.notImplemented();
                break;
        }
    }

2.2. Android O 以上获取的实现的方法

    //获取当前应用的存储信息
    Map<String, Map<String, String>> getAppDiskInfo() {
        Map<String, Map<String, String>> result = new HashMap<>();
        try {//获取存储管理器
            String packageName = activity.getPackageManager().getPackageInfo(activity.getPackageName(), 0).packageName;
            StorageManager storageManager = (StorageManager) activity.getSystemService(Context.STORAGE_SERVICE);
            //储存统计管理器
            final StorageStatsManager storageStatsManager = (StorageStatsManager) activity.getSystemService(Context.STORAGE_STATS_SERVICE);
         
            final List<StorageVolume> storageVolumes = storageManager.getStorageVolumes();
            //获取当前用户
            final UserHandle user = android.os.Process.myUserHandle();
            //遍历 有多少个储存器 内部 外部 sd卡
            for (StorageVolume storageVolume : storageVolumes) {
                //检测到他是挂载状态的 并且是主要的那个一个
                if ("mounted".equals(storageVolume.getState()) && storageVolume.isPrimary()) {
                  ///获取他的UUID 官方说他的UUID是一样的不能作为唯一凭证什么的...
                    final String uuidStr = storageVolume.getUuid();
                    final UUID uuid = uuidStr == null ? StorageManager.UUID_DEFAULT : UUID.fromString(uuidStr);
                    final StorageStats storageStats = storageStatsManager.queryStatsForPackage(uuid, packageName, user);
                    Map<String, String> resultItem = new HashMap<>();
                    带Str的都是通过代码转好后的 会显示整数 带单位的文字 不过好像是按进率1000算的 按需回传不是必须的
                    resultItem.put("FreeBytesStr", formatFileSize(storageStatsManager.getFreeBytes(uuid)));
                    resultItem.put("TotalBytesStr", formatFileSize(storageStatsManager.getTotalBytes(uuid)));
                    resultItem.put("AppBytesStr", formatFileSize(storageStats.getAppBytes()));
                    resultItem.put("CacheBytesStr", formatFileSize(storageStats.getCacheBytes()));
                    resultItem.put("DataBytesStr", formatFileSize(storageStats.getDataBytes()));
                  这里添加的都是long类型的数字不过转String传回给dart
                  /// 当前磁盘空闲的字节
                    resultItem.put("FreeBytes", String.valueOf(storageStatsManager.getFreeBytes(uuid)));
                     /// 当前磁盘总共的字节
                    resultItem.put("TotalBytes", String.valueOf(storageStatsManager.getTotalBytes(uuid)));
                    /// App 包括安装包什么乱起八糟的大小 具体看官方文档介绍
                    resultItem.put("AppBytes", String.valueOf(storageStats.getAppBytes()));
                    /// 软件的缓存 (内部缓存 外部缓存 加code_cache 一起返回的)
                    resultItem.put("CacheBytes", String.valueOf(storageStats.getCacheBytes()));
                  ////用户的数据 
                    resultItem.put("DataBytes", String.valueOf(storageStats.getDataBytes()));
                ////磁盘名字 外加上面这些东起一起丢回去
                    result.put(storageVolume.getDescription(activity.getContext()), resultItem);
                }
            }
        } catch (Exception ignored) {
            Log.e(getClass().getSimpleName(), "出错了", ignored);
        }
        return result;
    }

    // 将数字转换成文字
    //[number]数字 转换完的是没有小数的 且内存大小按1000计算
    String formatFileSize(long number) {
        return Formatter.formatShortFileSize(activity.getContext(), number);
    }

3. dart中的操作

3.1 发送MedthChannel

class CustomChannelUtil {
  static const MethodChannel _channel =
      MethodChannel(SystemConfig.customChannelName);
   ///获取磁盘信息
  static Future<Map?> get appDiskInfo async {
    final Map? deskInfo = await _channel.invokeMethod(SystemConfig.methodAppDiskInfo);
    return deskInfo;
  }
  static Future<bool?> get backToDesktop async{
    final bool? result = await _channel.invokeMethod(SystemConfig.methodBackToDesktop);
    return result;
  }
}

3.2 dart端解析

注意虽然Android那边写的是Map<String,Map<String,String>> 但是dart这边要用Map<Object?,Object?> 接收或者直接写Map;

      Map? result = await CustomChannelUtil.appDiskInfo;
      if (result != null && result.isNotEmpty) {
        deskInfo = result;
        cacheTitle = result.keys.first;
        Map item = result.values.first;
        totalBytes = double.parse(item["TotalBytes"]);
        freeBytes = double.parse(item["FreeBytes"]);
        appTotalBytes = double.parse(item["AppTotalBytes"]);
        appCacheBytes = double.parse(item["CacheBytes"]);
        appBytes = double.parse(item["AppBytes"]);
        appDataBytes = double.parse(item["DataBytes"]);

3.3 Android自带的并不好用 所以我自己写了一个 字节转换工具

  • 可以将文件大小转成合适的单位
  • 可以将文件大小强制转换成指定单位 (如果差距过大可能显示 0 )
  • 可以选择保留几位小数
  • 可以选择按1000算还是1024算
  /// 将文件大小 格式化
  /// [fileSize] 文件大小
  /// [position] 保留几位小数
  /// [scale] 比例 1000/1024
  /// [specified] 0-5 指定的单位 0是B 1是KB 2是mb 3是GB 4是TB 5是PB
  static String formatFileSize(fileSize,
      {position = 2, scale = 1024, specified = -1}) {
    double num = 0;
     List sizeUnit = ["B", "KB", "MB", "GB", "TB", "PB"];
    if (fileSize is String) {
      num = double.parse(fileSize);
    } else if (fileSize is int || fileSize is double) {
      num = fileSize;
    }
    //获取他的单位
    if (num > 0) {
      int unit = log(num) ~/ log(scale);
      if (specified >= 0 && specified < sizeUnit.length) {
        unit = specified;
      }
      double size = num / pow(scale, unit);
      String numStr = formatNum(num: size, position: position);
      return numStr + " " + sizeUnit[unit];
    }
    return "0 B";
  }

  ///格式化数字 如果小数后面为0则不显示小数点
  ///[num]要格式化的数字 double 类型
  /// [position] 保留几位小数 int类型
  static formatNum({required double num, required int position}) {
    String numStr = num.toString();
    int dotIndex = numStr.indexOf(".");
    ///当前数字有小数且需要小数位数小于需要的 直接返回当前数字
    if (num % 1 != 0 && (numStr.length - 1 - dotIndex < position)) {
      return numStr;
    }
    int numbs = pow(10, position).toInt();
    //模运算 取余数
    double remainder = num * numbs % numbs;
    //小数点后位数如果小于0则表示只保留整数,余数小于1不会进位防止出现200.01保留一位小数出现200.0的情况
    if (position > 0 && remainder >= 0.5) {
      return num.toStringAsFixed(position);
    }
    return num.toStringAsFixed(0);
  }
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,524评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,869评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,813评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,210评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,085评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,117评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,533评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,219评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,487评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,582评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,362评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,218评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,589评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,899评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,176评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,503评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,707评论 2 335

推荐阅读更多精彩内容