Firebase _upload пишет случайный файл загрузки

# #firebase #flutter #dart #firebase-storage #imagepicker

Вопрос:

Ниже приведен простой загрузчик изображений firebase. Проблема в том, что иногда при записи в Firestore в качестве значения используется файл загрузки другого изображения. Он без проблем загружает мое изображение в облачное хранилище, но затем, когда он записывает местоположение в firestore, он часто использует URL-адрес другого изображения. Полный код приведен ниже, но я опустил пользовательский интерфейс. Как я могу убедиться, что он записывает правильный URL-адрес в firestore?

 import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'dart:io';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_storage/firebase_storage.dart';
import 'package:path/path.dart' as path;
import 'package:image_picker/image_picker.dart';

class ImagePicky2 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      // Remove the debug banner
      debugShowCheckedModeBanner: false,
      theme: ThemeData(primarySwatch: Colors.green),
      home: HomePage(),
    );
  }
}

class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  FirebaseStorage storage = FirebaseStorage.instance;
  double? lat, lng;
  File? file;
  String? name, detail, pathImage, dateString;

  // Select an image from the gallery or take a picture with the camera
  // Then upload to Firebase Storage
  Future<XFile?> _upload(String inputSource) async {
    FirebaseAuth auth = FirebaseAuth.instance;
    User firebaseUser = auth.currentUser!;
    final picker = ImagePicker();
    try {
      final pickedImage = await picker.pickImage(
          source: inputSource == 'camera'
              ? ImageSource.camera
              : ImageSource.gallery,
          imageQuality: 25,
          maxWidth: 1920);

      final String fileName = path.basename(pickedImage!.path);
      File imageFile = File(pickedImage.path);

      try {
        // Uploading the selected image with some custom meta data
        await storage.ref(fileName).putFile(
            imageFile,
            SettableMetadata(customMetadata: {
              'uploaded_by': firebaseUser.displayName!,
              'description': 'Some description...'
            }));

        // Refresh the UI
        setState(() {});
      } on FirebaseException catch (error) {
        print(error);
      }
    } catch (err) {
      print(err);
    }
    photoUploadFirestoreDetails();
  }

  // Retriew the uploaded images
  // This function is called when the app launches for the first time or when an image is uploaded or deleted
  Future<List<Map<String, dynamic>>> _loadImages() async {
    FirebaseAuth auth = FirebaseAuth.instance;
    User firebaseUser = auth.currentUser!;
    List<Map<String, dynamic>> files = [];

    final ListResult result = await storage.ref().list();
    final List<Reference> allFiles = result.items;

    await Future.forEach<Reference>(allFiles, (file) async {
      final String fileUrl = await file.getDownloadURL();
      pathImage = await file.getDownloadURL();
      final FullMetadata fileMeta = await file.getMetadata();
      files.add({
        "url": fileUrl,
        "path": file.fullPath,
        "uploaded_by": fileMeta.customMetadata?['uploaded_by'] ?? firebaseUser.displayName,
        "description":
        fileMeta.customMetadata?['description'] ?? 'No description'
      });
    });

    return files;
  }

  Future<Null> photoUploadFirestoreDetails() async {
    Firebase.initializeApp();
    Map<String, dynamic> map = Map();
    map['PathImage'] = pathImage;

    FirebaseFirestore firestore = FirebaseFirestore.instance;
    CollectionReference collectionReference =
    firestore.collection('MarkerCollect');
    await collectionReference.doc().set(map).then((
        value) {
          });
  }
}```
 

Ответ №1:

Код загружает случайные URL-адреса загрузки в Firestore, потому что вы получаете путь к изображению из _loadImages метода, который загружает файлы в хранилище, вместо использования URL-адреса загрузки только что загруженного файла.

Это проблемный код:

 Future<Null> photoUploadFirestoreDetails() async {
  ...
  map['PathImage'] = pathImage;
  ...
}
 

Решение:

Вы можете исправить это, получив URL-адрес загрузки сразу после загрузки и передав его photoUploadFirestoreDetails методу, который будет использоваться при загрузке в Firestore.

Вы также должны поместить photoUploadFirestoreDetails его в try-catch .

Проверьте обновленный код ниже:

 // _upload method

Future<XFile?> _upload(String inputSource) async {
  FirebaseAuth auth = FirebaseAuth.instance;
  User firebaseUser = auth.currentUser!;
  final picker = ImagePicker();
  try {
    final pickedImage = await picker.pickImage(
        source: inputSource == 'camera'
            ? ImageSource.camera
            : ImageSource.gallery,
        imageQuality: 25,
        maxWidth: 1920);

    final String fileName = path.basename(pickedImage!.path);
    File imageFile = File(pickedImage.path);

    try {
      // Uploading the selected image with some custom meta data
      final Reference storageReference = storage.ref(fileName);
      await storageReference.putFile(
          imageFile,
          SettableMetadata(customMetadata: {
            'uploaded_by': firebaseUser.displayName!,
            'description': 'Some description...'
          }));
      final String downloadUrl = await storageReference.getDownloadURL();

      // Refresh the UI
      setState(() {});

      await photoUploadFirestoreDetails(downloadUrl: downloadUrl);
    } on FirebaseException catch (error) {
      print(error);
    }
  } catch (err) {
    print(err);
  }
}
 
 // photoUploadFirestoreDetails method

Future<Null> photoUploadFirestoreDetails({@required String downloadUrl}) async {
  Firebase.initializeApp();
  Map<String, dynamic> map = Map();
  map['PathImage'] = downloadUrl;

  FirebaseFirestore firestore = FirebaseFirestore.instance;
  CollectionReference collectionReference =
  firestore.collection('MarkerCollect');
  var value = await collectionReference.doc().set(map);
}
 

Комментарии:

1. Это получилось с первой попытки, мне действительно нужно было удалить @ из обязательных или добавить? для Струны и то, и другое, казалось, делало ее счастливой. Большое вам спасибо, вы мне очень благодарны за помощь!

Ответ №2:

Попробуйте эту функцию, чтобы загрузить изображение в fire-хранилище и получить Url

   Future<String?> uploadAndGetUrl(File file) async {
    try {
      final Reference ref = FirebaseStorage.instance
          .ref()
          .child('profilePhoto')
        .child(DateTime.now().microsecondsSinceEpoch.toString());
      UploadTask uploadTask = ref.putFile(file);
      await uploadTask.whenComplete(() {});
      String url = await ref.getDownloadURL();
      return url;
    } catch (e) {
      print('Firebase Storage Error is : $e');
      return null;
    }
  }
 

ИЛИ вы можете просто загрузить изображение и получить URL-адрес изображения позже.

Ваша функция загрузки изображений выглядит нормально. имя должно быть уникальным. в противном случае он возвращает другой URL-адрес изображения.

   Future<String> getUrl(String imageName) async {
    try {
      Reference storageRef = FirebaseStorage.instance.ref().child('profilePhoto/$logo');
      String url = await storageRef.getDownloadURL();

      return url;
    } catch (e) {
      return null;
    }
  }
 

Комментарии:

1. Спасибо за это, в итоге я использовал это решение ниже, но, тем не менее, это очень полезно. Спасибо.