Flutter 1.22.0适配Android13相册权限失败,无需升级的解决办法?
Android 13下Flutter 1.22.0图片选择权限问题
我的应用图片选择功能在Android 13版本前运行正常,但在Android 13上无法获取相册访问权限。项目基于Flutter 1.22.0(搭配Dart 2.10,非空安全版本),已在AndroidManifest中添加以下权限:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="32"/> <uses-permission android:name="android.permission.CAMERA"/> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32" /> <uses-permission android:name="android.permission.READ_MEDIA_IMAGES"/> <uses-permission android:name="android.permission.READ_MEDIA_VIDEO"/> <uses-permission android:name="android.permission.READ_MEDIA_AUDIO"/>
使用image_picker包调用图片选择方法时,抛出如下错误:
PlatformException(photo_access_denied, The user did not allow photo access., null, null)
问题根源是旧版本库未适配Android 13,由于升级Flutter版本耗时较长,想寻求无需升级即可解决的方案。
解决方案
1. 手动用旧版权限请求库适配逻辑
旧版image_picker未适配Android 13的READ_MEDIA_IMAGES权限请求,可搭配支持非空安全的旧版permission_handler(如permission_handler: ^5.1.0+2)手动处理权限:
- 在
pubspec.yaml添加依赖:dependencies: permission_handler: ^5.1.0+2 - 在调用image_picker前先请求权限:
import 'package:permission_handler/permission_handler.dart'; import 'package:image_picker/image_picker.dart'; import 'package:flutter/foundation.dart'; Future<void> pickImage() async { PermissionStatus status; // 区分Android版本处理权限请求 if (defaultTargetPlatform == TargetPlatform.android) { // 需引入device_info_plus旧版本(如^2.1.0)获取Android版本 final androidInfo = await DeviceInfoPlugin().androidInfo; if (androidInfo.version.sdkInt >= 33) { status = await Permission.photos.request(); } else { status = await Permission.storage.request(); } } else { status = await Permission.photos.request(); } if (status.isGranted) { final XFile? image = await ImagePicker().pickImage(source: ImageSource.gallery); // 处理选中的图片 } else { // 处理权限拒绝的逻辑 } }
2. 自定义原生图片选择逻辑(绕开旧库限制)
通过Flutter MethodChannel对接Android原生代码,使用Android 13推荐的ActivityResultContracts.PickVisualMedia实现图片选择,该方式无需手动申请权限(系统自动处理授权流程):
Flutter端:注册MethodChannel并调用原生方法
import 'package:flutter/services.dart'; static const platform = MethodChannel('com.yourapp/image_picker'); Future<void> pickImageFromNative() async { try { final String? imagePath = await platform.invokeMethod('pickImage'); if (imagePath != null) { // 处理图片路径 } } on PlatformException catch (e) { print("图片选择失败: ${e.message}"); } }Android原生端:在MainActivity中实现逻辑
class MainActivity : FlutterActivity() { private val CHANNEL = "com.yourapp/image_picker" private val pickVisualMedia = registerForActivityResult(ActivityResultContracts.PickVisualMedia()) { uri -> val path = uri?.let { getRealPathFromURI(it) } methodChannel.invokeMethod("imageSelected", path) } private lateinit var methodChannel: MethodChannel override fun configureFlutterEngine(flutterEngine: FlutterEngine) { super.configureFlutterEngine(flutterEngine) methodChannel = MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL) methodChannel.setMethodCallHandler { call, result -> when (call.method) { "pickImage" -> { pickVisualMedia.launch(PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageOnly)) result.success(null) } else -> result.notImplemented() } } } // 将Uri转换为真实文件路径的辅助方法 private fun getRealPathFromURI(contentUri: Uri): String? { val projection = arrayOf(MediaStore.Images.Media.DATA) val cursor = contentResolver.query(contentUri, projection, null, null, null) ?: return null val columnIndex = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA) cursor.moveToFirst() val path = cursor.getString(columnIndex) cursor.close() return path } }
3. 升级Android编译版本配合权限配置
将Android项目的compileSdkVersion升级到33(Flutter 1.22.0支持该版本),确保AndroidManifest中已添加READ_MEDIA_IMAGES权限,再结合手动权限请求逻辑,可让旧版image_picker在Android 13上正常工作。
内容的提问来源于stack exchange,提问作者Biruk Ayalew
相关产品推荐
相关产品推荐

