You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何获取设备总存储与可用存储信息?disk_space包数值不准确求助

解决disk_space包存储数值不准确问题:获取设备存储信息的可靠实现

disk_space包(v0.2.1)的数值不准确,通常是因为它未处理平台差异、权限限制或系统预留空间的计算逻辑问题。以下是基于path_provider和原生API的替代方案,能更精准获取总存储空间、可用空间及已用空间:

方案一:Flutter跨平台基础实现(沙盒/外部存储)

依赖path_provider访问对应平台的存储目录,结合dart:io的FileSystemStat获取准确的存储数据。

步骤1:添加依赖

在pubspec.yaml中添加:

dependencies:
  path_provider: ^2.0.15
  permission_handler: ^10.2.0 # 用于Android权限请求

步骤2:实现存储信息获取方法

import 'dart:io';
import 'package:path_provider/path_provider.dart';
import 'package:permission_handler/permission_handler.dart';

Future<Map<String, int>> getStorageDetails() async {
  // Android需先请求存储权限
  if (Platform.isAndroid) {
    final status = await Permission.storage.request();
    if (!status.isGranted) {
      return {'total': 0, 'available': 0, 'used': 0};
    }
  }

  Directory? targetDir;
  try {
    if (Platform.isAndroid) {
      // 访问Android外部存储根目录(对应手机内置存储)
      targetDir = Directory('/storage/emulated/0');
    } else if (Platform.isIOS) {
      // iOS仅能访问应用沙盒目录,若需全局存储见方案二
      targetDir = await getApplicationDocumentsDirectory();
    }

    if (targetDir != null && await targetDir.exists()) {
      final stat = await targetDir.stat();
      final usedSpace = stat.totalSpace - stat.availableSpace;
      return {
        'total': stat.totalSpace, // 总存储空间(字节)
        'available': stat.availableSpace, // 应用可使用的可用空间(字节)
        'used': usedSpace // 已用空间(字节)
      };
    }
  } catch (e) {
    print('获取存储信息失败: $e');
  }
  return {'total': 0, 'available': 0, 'used': 0};
}

权限配置(Android)

在android/app/src/main/AndroidManifest.xml中添加权限:

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<!-- Android 13+ 若需访问公共媒体文件,添加对应媒体权限 -->
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />

方案二:iOS全局存储信息获取(原生Channel)

iOS应用默认只能访问沙盒,若需获取整个设备的存储数据,需通过MethodChannel调用原生代码:

Flutter端Channel代码

import 'dart:async';
import 'dart:io';
import 'package:flutter/services.dart';

static const MethodChannel _storageChannel = MethodChannel('com.example/storage_info');

Future<Map<String, int>> getIOSGlobalStorage() async {
  try {
    final total = await _storageChannel.invokeMethod<int>('getTotalStorage') ?? 0;
    final available = await _storageChannel.invokeMethod<int>('getAvailableStorage') ?? 0;
    return {
      'total': total,
      'available': available,
      'used': total - available
    };
  } on PlatformException catch (e) {
    print('原生调用失败: ${e.message}');
    return {'total': 0, 'available': 0, 'used': 0};
  }
}

iOS原生代码(Swift)

在Runner/ViewController.swift中添加:

import UIKit
import Flutter

class StorageInfoHandler: NSObject, FlutterPlugin {
  static func register(with registrar: FlutterPluginRegistrar) {
    let channel = FlutterMethodChannel(name: "com.example/storage_info", binaryMessenger: registrar.messenger())
    let instance = StorageInfoHandler()
    registrar.addMethodCallDelegate(instance, channel: channel)
  }

  func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
    switch call.method {
    case "getTotalStorage":
      result(getTotalDeviceStorage())
    case "getAvailableStorage":
      result(getAvailableDeviceStorage())
    default:
      result(FlutterMethodNotImplemented)
    }
  }

  private func getTotalDeviceStorage() -> Int64 {
    let url = URL(fileURLWithPath: NSHomeDirectory())
    do {
      let attrs = try url.resourceValues(forKeys: [.volumeTotalCapacityKey])
      return attrs.volumeTotalCapacity ?? 0
    } catch {
      return 0
    }
  }

  private func getAvailableDeviceStorage() -> Int64 {
    let url = URL(fileURLWithPath: NSHomeDirectory())
    do {
      let attrs = try url.resourceValues(forKeys: [.volumeAvailableCapacityForImportantUsageKey])
      return attrs.volumeAvailableCapacityForImportantUsage ?? 0
    } catch {
      return 0
    }
  }
}

然后在Runner/AppDelegate.swift中注册Channel:

override func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
  StorageInfoHandler.register(with: self.registrar(forPlugin: "StorageInfoHandler"))
  GeneratedPluginRegistrant.register(with: self)
  return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}

为什么disk_space包不准确?

  • 未区分系统预留空间和应用实际可用空间:部分系统级存储(如系统分区、缓存)不会开放给应用,但disk_space可能直接返回磁盘总容量,导致可用空间计算偏差。
  • 平台挂载点处理错误:Android的外部存储路径可能因设备而异,旧版包未适配不同厂商的存储路径。
  • 权限适配不足:未处理Android 13+的媒体权限变更,导致无法正确读取存储数据。

内容的提问来源于stack exchange,提问作者Noob Developer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 22:40:40