Flutter不借助权限包请求外部存储权限遇权限拒绝报错
不依赖permission_handler包解决Flutter外部存储权限被拒问题
Android 平台处理步骤
1. 配置AndroidManifest.xml权限
在android/app/src/main/AndroidManifest.xml中添加对应权限声明:
<!-- Android 10及以下读写外部存储所需权限 --> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <!-- Android 11及以上访问全存储目录需添加(可选,需引导用户到设置手动开启) --> <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" android:minSdkVersion="30" />
注意:Android 10(API 29)及以上启用了Scoped Storage机制,直接访问公共目录会受限制。若仅操作应用私有存储,无需申请
WRITE_EXTERNAL_STORAGE;若需访问公共下载目录,可选择使用MANAGE_EXTERNAL_STORAGE权限(需引导用户到设置开启),或通过MediaStore API进行文件操作。
2. 通过MethodChannel实现动态权限请求
Flutter无内置权限API,不依赖三方包时需通过原生代码调用权限请求:
Flutter端代码
import 'package:flutter/services.dart'; class PermissionManager { static const MethodChannel _channel = MethodChannel('permission_channel'); // 请求外部存储权限 static Future<bool> requestStoragePermission() async { try { return await _channel.invokeMethod('requestStoragePermission'); } on PlatformException catch (e) { print('权限请求失败: ${e.message}'); return false; } } // 监听权限请求结果(需配合原生回调) static void listenPermissionResult(void Function(bool) onResult) { _channel.setMethodCallHandler((call) async { if (call.method == 'permissionResult') { onResult(call.arguments as bool); } }); } }
Android原生代码(Kotlin)
在MainActivity.kt中添加MethodChannel处理逻辑:
import android.Manifest import android.content.pm.PackageManager import androidx.core.app.ActivityCompat import androidx.core.content.ContextCompat import io.flutter.embedding.android.FlutterActivity import io.flutter.embedding.engine.FlutterEngine import io.flutter.plugin.common.MethodChannel class MainActivity : FlutterActivity() { private val CHANNEL = "permission_channel" private val REQUEST_STORAGE_PERMISSION = 1 override fun configureFlutterEngine(flutterEngine: FlutterEngine) { super.configureFlutterEngine(flutterEngine) MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler { call, result -> when (call.method) { "requestStoragePermission" -> { val hasPermission = ContextCompat.checkSelfPermission( this, Manifest.permission.WRITE_EXTERNAL_STORAGE ) == PackageManager.PERMISSION_GRANTED if (!hasPermission) { ActivityCompat.requestPermissions( this, arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE), REQUEST_STORAGE_PERMISSION ) result.success(false) } else { result.success(true) } } else -> result.notImplemented() } } } override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) { super.onRequestPermissionsResult(requestCode, permissions, grantResults) if (requestCode == REQUEST_STORAGE_PERMISSION) { val isGranted = grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED MethodChannel(flutterEngine?.dartExecutor?.binaryMessenger, CHANNEL).invokeMethod("permissionResult", isGranted) } } }
3. 正确获取存储路径
避免硬编码路径,改用系统API获取标准目录:
import 'package:path_provider/path_provider.dart'; Future<String> getDownloadPath() async { // 获取Android外部存储目录,拼接Download子目录 final externalDir = await getExternalStorageDirectory(); return "${externalDir?.path}/Download"; }
iOS 平台处理步骤
1. 配置Info.plist权限
在ios/Runner/Info.plist中添加权限说明:
<key>NSPhotoLibraryUsageDescription</key> <string>需要访问相册存储文件</string> <key>NSDocumentsFolderUsageDescription</key> <string>需要访问文档目录存储文件</string>
2. 通过MethodChannel实现权限请求
Flutter端代码(复用前文的PermissionManager)
iOS原生代码(Swift)
在AppDelegate.swift中添加:
import UIKit import Flutter import Photos @UIApplicationMain @objc class AppDelegate: FlutterAppDelegate { private let CHANNEL = "permission_channel" override func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { let controller = window?.rootViewController as! FlutterViewController let channel = FlutterMethodChannel(name: CHANNEL, binaryMessenger: controller.binaryMessenger) channel.setMethodCallHandler { [weak self] call, result in guard call.method == "requestStoragePermission" else { result(FlutterMethodNotImplemented) return } self?.requestPhotoLibraryPermission(result: result) } GeneratedPluginRegistrant.register(with: self) return super.application(application, didFinishLaunchingWithOptions: launchOptions) } private func requestPhotoLibraryPermission(result: FlutterResult) { PHPhotoLibrary.requestAuthorization { status in DispatchQueue.main.async { result(status == .authorized || status == .limited) } } } }
最终使用流程
void main() async { WidgetsFlutterBinding.ensureInitialized(); // 监听权限请求结果 PermissionManager.listenPermissionResult((isGranted) { if (isGranted) { _handleFileOperation(); } else { print("权限被拒绝,无法访问存储"); } }); // 先请求权限 bool hasPermission = await PermissionManager.requestStoragePermission(); if (hasPermission) { _handleFileOperation(); } } Future<void> _handleFileOperation() async { String downloadPath = await getDownloadPath(); File file = File("$downloadPath/events.json"); // 执行读写文件逻辑 }
内容的提问来源于stack exchange,提问作者Карим Бозжанов
相关产品推荐
相关产品推荐

