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

2022-04-27  本文已影响0人  半城半离人

翻了好多插件好像也没一个获取手机内存和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自带的并不好用 所以我自己写了一个 字节转换工具

  /// 将文件大小 格式化
  /// [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);
  }
上一篇下一篇

猜你喜欢

热点阅读