翻了好多插件好像也没一个获取手机内存和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 以上获取的实现的方法
- 获取自身APP的数据是不需要额外的权限的,获取别人的需要增加权限
- 相关文档 :https://developer.android.google.cn/reference/kotlin/android/os/storage/StorageManager?hl=en
https://developer.android.google.cn/reference/android/app/usage/StorageStatsManager?hl=en
https://developer.android.google.cn/reference/kotlin/android/os/storage/StorageVolume?hl=en
//获取当前应用的存储信息
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);
}
网友评论