Flutter加载Firebase Storage图片失败,URL可正常访问
尝试从Firebase Storage获取图片,已成功获取到下载URL,且URL在浏览器中能正常打开对应图片,但Flutter的Image.network组件始终无法加载图片,抛出ProgressEvent相关异常。
代码示例
import 'package:firebase_storage/firebase_storage.dart'; import 'package:flutter/material.dart'; import 'package:firebase_core/firebase_core.dart'; import 'firebase_options.dart'; import 'package:cloud_firestore/cloud_firestore.dart'; void main() async { WidgetsFlutterBinding.ensureInitialized(); await Firebase.initializeApp( options: DefaultFirebaseOptions.currentPlatform, ); runApp(MaterialApp(home: MyApp())); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( appBar: AppBar( title: Text('I try so hard and got no far:<'), ), body: ImageList(), ), ); } } class ImageList extends StatefulWidget { @override _ImageListState createState() => _ImageListState(); } class _ImageListState extends State<ImageList> { List<String> imageUrls = []; @override void initState() { super.initState(); loadImages(); } Future<void> loadImages() async { String directoryPath = 'Images/'; Reference reference = FirebaseStorage.instance.ref().child(directoryPath); ListResult result = await reference.listAll(); List<String> urls = []; for (Reference ref in result.items) { String url = await ref.getDownloadURL(); urls.add(url); } setState(() { imageUrls = urls; }); } @override Widget build(BuildContext context) { return ListView.builder( itemCount: imageUrls.length, itemBuilder: (context, index) { return Padding( padding: const EdgeInsets.all(8.0), child: Image.network( imageUrls[index], width: 200.0, height: 200.0, fit: BoxFit.cover, ), ); }, ); } }
错误信息
The following ProgressEvent$ object was thrown resolving an image codec:
[object ProgressEvent]When the exception was thrown, this was the stack:
Image provider: NetworkImage("https://firebasestorage.googleapis.com/v0/b/carousel-a996b.appspot.com/o/Images%2F1.png?alt=media&token=017d99a3-b909-4c2f-b2fe-e7ae1f282327", scale: 1.0)
Image key: NetworkImage("https://firebasestorage.googleapis.com/v0/b/carousel-a996b.appspot.com/o/Images%2F1.png?alt=media&token=017d99a3-b909-4c2f-b2fe-e7ae1f282327", scale: 1.0)
解决方案
1. 检查平台网络权限
- Android:确保
android/app/src/main/AndroidManifest.xml中添加了网络权限:<uses-permission android:name="android.permission.INTERNET" /> - iOS:在
ios/Runner/Info.plist中确认App Transport Security设置允许HTTPS请求,若有严格限制需添加Firebase Storage域名例外:<key>NSAppTransportSecurity</key> <dict> <key>NSAllowsArbitraryLoads</key> <false/> <key>NSExceptionDomains</key> <dict> <key>firebasestorage.googleapis.com</key> <dict> <key>NSIncludesSubdomains</key> <true/> <key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key> <false/> </dict> </dict> </dict>
2. 优化异步加载逻辑,添加状态处理
用FutureBuilder替代initState中手动调用异步方法,确保数据加载完成后再构建UI,避免空数据或未就绪状态:
class ImageList extends StatelessWidget { Future<List<String>> loadImages() async { String directoryPath = 'Images/'; Reference reference = FirebaseStorage.instance.ref().child(directoryPath); ListResult result = await reference.listAll(); List<String> urls = []; for (Reference ref in result.items) { String url = await ref.getDownloadURL(); urls.add(url); } return urls; } @override Widget build(BuildContext context) { return FutureBuilder<List<String>>( future: loadImages(), builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { return Center(child: CircularProgressIndicator()); } if (snapshot.hasError) { return Center(child: Text('加载失败: ${snapshot.error}')); } final imageUrls = snapshot.data ?? []; return ListView.builder( itemCount: imageUrls.length, itemBuilder: (context, index) { return Padding( padding: const EdgeInsets.all(8.0), child: Image.network( imageUrls[index], width: 200.0, height: 200.0, fit: BoxFit.cover, errorBuilder: (context, error, stackTrace) { print('图片加载错误详情: $error'); return Icon(Icons.broken_image, size: 100); }, ), ); }, ); }, ); } }
3. 添加错误捕获,排查具体问题
在Image.network中加入errorBuilder,打印详细错误信息,帮助定位问题根源(比如证书问题、网络波动等)。
4. 验证Firebase Storage安全规则
确认Storage的读取权限配置正确,开发阶段可临时设置宽松规则测试:
rules_version = '2'; service firebase.storage { match /b/{bucket}/o { match /{allPaths=**} { allow read: if true; allow write: if request.auth != null; } } }
上线前需调整为符合业务需求的权限规则。
内容的提问来源于stack exchange,提问作者Gigea Nicusor

