Flutter创建备份文件遇权限拒绝错误(errno=13)求助
问题排查与解决方案
核心原因分析
你的错误是Android存储权限被拒绝(errno=13),主要由以下几点导致:
- Android 13+ 废弃了
WRITE_EXTERNAL_STORAGE和READ_EXTERNAL_STORAGE权限,改用MANAGE_EXTERNAL_STORAGE特殊权限访问共享存储的非媒体文件 - 即使在Manifest中声明权限,Android 6+ 仍需动态申请权限,特殊权限还需用户手动在设置中开启
- 硬编码外部存储路径
/storage/emulated/0/存在兼容性问题,不同设备路径可能不同
具体修复步骤
1. 更新AndroidManifest.xml权限配置
修改权限声明,适配不同Android版本:
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.untitled16"> <!-- Android 12及以下版本使用的存储权限 --> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="32"/> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32"/> <!-- Android 13+ 访问共享存储的特殊权限 --> <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" /> <application android:requestLegacyExternalStorage="true" <!-- 仅对Android 10/11有效 --> android:label="untitled16" android:name="${applicationName}" android:icon="@mipmap/ic_launcher"> <!-- 你的activity配置 --> </application> </manifest>
2. 添加权限处理依赖
在pubspec.yaml中添加必要依赖:
dependencies: flutter: sdk: flutter permission_handler: ^10.2.0 # 可替换为最新版本 path_provider: ^2.0.15 # 用于获取标准存储路径
执行flutter pub get安装依赖。
3. 修改代码:权限检查+正确路径获取
权限检查逻辑
添加权限请求方法,确保操作存储前获得权限:
import 'package:permission_handler/permission_handler.dart'; Future<bool> _checkStoragePermission() async { if (await Permission.manageExternalStorage.isGranted) { return true; } // 请求权限 final status = await Permission.manageExternalStorage.request(); if (status.isGranted) { return true; } else if (status.isDenied) { // 引导用户到设置开启权限 await openAppSettings(); return await Permission.manageExternalStorage.isGranted; } return false; }
替换硬编码路径
用path_provider获取标准外部存储路径,避免兼容性问题:
import 'package:path_provider/path_provider.dart'; Future<Directory> _getDirectory() async { // 获取应用专属外部存储目录 Directory? externalDir = await getExternalStorageDirectory(); if (externalDir == null) { throw Exception("无法访问外部存储"); } Directory passmanDir = Directory('${externalDir.path}/Passman/'); if (!await passmanDir.exists()) { await passmanDir.create(recursive: true); } return passmanDir; }
更新主函数逻辑
在执行存储操作前先检查权限:
import 'package:flutter/material.dart'; import 'dart:convert'; import 'dart:io'; void main() async { // 必须初始化Flutter绑定才能在main中使用异步操作 WidgetsFlutterBinding.ensureInitialized(); // 检查存储权限 bool hasPermission = await _checkStoragePermission(); if (!hasPermission) { print("未获得存储权限,无法创建备份"); return; } List<TransactionModel> trans = [ TransactionModel( date: DateTime.now(), id: '1', ), ]; String result = jsonEncode(trans); Directory dir = await _getDirectory(); String formattedDate = DateTime.now() .toString() .replaceAll('.', '-') .replaceAll(' ', '-') .replaceAll(':', '-'); String path = '${dir.path}/$formattedDate.json'; // 修复路径拼接的多余斜杠问题 File backupFile = File(path); await backupFile.writeAsString(result); print(result); } // 确保TransactionModel有toJson方法 class TransactionModel { final DateTime date; final String id; TransactionModel({required this.date, required this.id}); Map<String, dynamic> toJson() { return { 'date': date.toIso8601String(), 'id': id, }; } }
额外注意事项
requestLegacyExternalStorage="true"仅对Android 10(API 29)和Android 11(API 30)生效,Android 12+ 会忽略该属性- 如果你的备份文件属于媒体类型(如图片/音频),可改用对应媒体权限(如
READ_MEDIA_IMAGES),无需申请MANAGE_EXTERNAL_STORAGE - 避免直接操作共享存储根目录,优先使用应用专属存储目录(通过
getExternalStorageDirectory()获取),无需特殊权限即可访问
内容的提问来源于stack exchange,提问作者Irfan Ganatra
相关产品推荐
相关产品推荐

