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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 10:59:08