Flutter开发:如何获取存储中所有图片与视频的URI(仿图库应用)
Flutter 获取设备所有图片/视频 URI 实现图库功能方案
我来帮你搞定这个问题,实现类似图库的功能不用自己去遍历存储目录(毕竟Android和iOS的媒体存储逻辑差异很大),用成熟的第三方包会省心很多。下面是一步步的实现方案:
1. 添加必要的依赖
首先在pubspec.yaml里添加两个关键包:permission_handler用来处理权限请求,photo_manager专门用来访问系统媒体库:
dependencies: flutter: sdk: flutter permission_handler: ^10.2.0 # 权限处理工具 photo_manager: ^2.7.0 # 媒体库访问工具
添加后执行flutter pub get安装依赖。
2. 配置系统权限
Android 端
在android/app/src/main/AndroidManifest.xml里添加权限:
<!-- 旧版本Android的存储权限 --> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <!-- Android 13+ 需单独申请图片/视频权限 --> <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" /> <uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
iOS 端
在ios/Runner/Info.plist里添加权限说明:
<key>NSPhotoLibraryUsageDescription</key> <string>需要访问您的相册来展示图片和视频</string>
3. 修改你的代码实现核心功能
替换你原来的代码,下面是完整的可运行版本:
import 'package:flutter/material.dart'; import 'package:permission_handler/permission_handler.dart'; import 'package:photo_manager/photo_manager.dart'; class Gallery extends StatefulWidget { @override _GalleryState createState() => _GalleryState(); } class _GalleryState extends State<Gallery> { List<String> _uriList = []; @override void initState() { super.initState(); _fetchAllMediaUris(); // 初始化时触发媒体获取 } // 核心方法:获取所有图片和视频的URI Future<void> _fetchAllMediaUris() async { // 第一步:请求权限 final hasPermission = await _requestMediaPermission(); if (!hasPermission) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('需要开启相册权限才能展示媒体文件')), ); return; } // 第二步:获取系统所有媒体专辑(这里直接取"全部"专辑) final albums = await PhotoManager.getAssetPathList( type: RequestType.all, // 同时获取图片和视频 hasAll: true, // 包含"全部"这个专辑 ); final allMediaAlbum = albums.firstWhere((album) => album.isAll); // 第三步:分页获取媒体资源(避免一次性加载太多卡顿) final mediaAssets = await allMediaAlbum.getAssetListPaged(page: 0, size: 1000); // 第四步:遍历资源获取每个文件的URI final uris = <String>[]; for (final asset in mediaAssets) { final uri = await asset.getMediaUrl(); if (uri != null) uris.add(uri); } // 更新UI状态 setState(() { _uriList = uris; }); } // 请求媒体访问权限 Future<bool> _requestMediaPermission() async { if (await Permission.photos.isGranted) return true; final permissionResult = await Permission.photos.request(); return permissionResult.isGranted; } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('我的图库')), body: _uriList.isEmpty ? const Center(child: CircularProgressIndicator()) : GridView.builder( padding: const EdgeInsets.all(4), gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 3, // 每行3个缩略图 crossAxisSpacing: 4, mainAxisSpacing: 4, ), itemCount: _uriList.length, itemBuilder: (context, index) { return Image.network( _uriList[index], fit: BoxFit.cover, errorBuilder: (context, error, stackTrace) { return const Icon(Icons.broken_image); }, ); }, ), ); } }
一些关键细节说明
- 为什么用
photo_manager:它封装了Android和iOS的媒体库底层逻辑,不用自己去处理不同系统的存储路径差异,还支持分页加载、按相册分类等功能,比手动遍历目录靠谱多了。 - 权限处理:必须先请求权限,否则无法访问媒体库。如果用户永久拒绝权限,可以在代码里添加引导,用
openAppSettings()方法跳转到应用设置页面让用户开启权限。 - 分页加载:示例里只加载了第一页1000条数据,如果你的设备里媒体很多,可以后续实现下拉加载更多的逻辑,调用
getAssetListPaged时递增page参数即可。 - URI使用:获取到的URI是
file://开头的本地文件路径,可以直接用Image.network加载,也可以用File类来操作文件本身。
内容的提问来源于stack exchange,提问作者jitendra purohit
相关产品推荐
相关产品推荐

