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

Flutter创建备份文件遇权限拒绝错误(errno=13)求助

问题排查与解决方案

核心原因分析

你的错误是Android存储权限被拒绝(errno=13),主要由以下几点导致:

  1. Android 13+ 废弃了WRITE_EXTERNAL_STORAGE和READ_EXTERNAL_STORAGE权限,改用MANAGE_EXTERNAL_STORAGE特殊权限访问共享存储的非媒体文件
  2. 即使在Manifest中声明权限,Android 6+ 仍需动态申请权限,特殊权限还需用户手动在设置中开启
  3. 硬编码外部存储路径/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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 05:16:24