העלאת קבצים באמצעות Cloud Storage ב-Flutter

בעזרת Cloud Storage for Firebase אפשר להעלות בקלות ובמהירות קבצים לקטגוריה של Cloud Storage ש-Firebase מספקת ומנהלת.

העלאת קבצים

כדי להעלות קובץ ל-Cloud Storage, קודם צריך ליצור הפניה לנתיב המלא של הקובץ, כולל שם הקובץ.

// Create a storage reference from our app
final storageRef = FirebaseStorage.instance.ref();

// Create a reference to "mountains.jpg"
final mountainsRef = storageRef.child("mountains.jpg");

// Create a reference to 'images/mountains.jpg'
final mountainImagesRef = storageRef.child("images/mountains.jpg");

// While the file names are the same, the references point to different files
assert(mountainsRef.name == mountainImagesRef.name);
assert(mountainsRef.fullPath != mountainImagesRef.fullPath);

אחרי שיוצרים את ההפניה המתאימה, צריך להפעיל את השיטה putFile(),‏ putString() או putData() כדי להעלות את הקובץ ל-Cloud Storage.

אי אפשר להעלות נתונים עם הפניה לשורש הקטגוריה ב-Cloud Storage. ההפניה חייבת להפנות לכתובת URL של צאצא.

העלאה מקובץ

כדי להעלות קובץ, קודם צריך לקבל את הנתיב המוחלט למיקום שלו במכשיר. לדוגמה, אם קובץ קיים בספריית המסמכים של האפליקציה, אפשר להשתמש בחבילה הרשמית path_provider כדי ליצור נתיב לקובץ ולהעביר אותו ל-putFile():

Directory appDocDir = await getApplicationDocumentsDirectory();
String filePath = '${appDocDir.absolute}/file-to-upload.png';
File file = File(filePath);

try {
  await mountainsRef.putFile(file);
} on firebase_core.FirebaseException catch (e) {
  // ...
}

העלאה ממחרוזת

אפשר להעלות נתונים כמחרוזת קודמת, base64, base64url או data_url, באמצעות השיטה putString(). לדוגמה, כדי להעלות מחרוזת טקסט שמקודדת בתור כתובת URL של נתונים:

String dataUrl = 'data:text/plain;base64,SGVsbG8sIFdvcmxkIQ==';

try {
  await mountainsRef.putString(dataUrl, format: PutStringFormat.dataUrl);
} on FirebaseException catch (e) {
  // ...
}

העלאת נתונים גולמיים

במקרים שבהם לא מעשי להעלות מחרוזת או File, אפשר להעלות נתונים מוקלדים ברמה נמוכה יותר בצורת Uint8List. במקרה כזה, צריך להפעיל את השיטה putData() עם הנתונים:

try {
  // Upload raw data.
  await mountainsRef.putData(data);
} on firebase_core.FirebaseException catch (e) {
  // ...
}

קבלת כתובת URL להורדה

אחרי שמעלים קובץ, אפשר לקבל כתובת URL להורדת הקובץ על ידי קריאה ל-method getDownloadUrl() ב-Reference:

await mountainsRef.getDownloadURL();

הוספת מטא-נתונים של קבצים

אפשר גם לכלול מטא-נתונים כשאתם מעלים קבצים. המטא-נתונים האלה מכילים מאפייני מטא-נתונים אופייניים של קבצים, כמו contentType (שנקרא בדרך כלל סוג MIME). השיטה putFile() מסיקה באופן אוטומטי את סוג ה-MIME מהתוסף File, אבל אפשר לשנות את הסוג שזוהה באופן אוטומטי על ידי ציון contentType במטא-נתונים. אם לא מספקים contentType ו-Cloud Storage לא יכול להסיק מהי ברירת המחדל מסיומת הקובץ, Cloud Storage ישתמש ב-application/octet-stream. כדאי לעיין במאמר שימוש במטא-נתונים של קבצים.

try {
  await mountainsRef.putFile(file, SettableMetadata(
    contentType: "image/jpeg",
  ));
} on firebase_core.FirebaseException catch (e) {
  // ...
}

נהל העלאות

בנוסף להפעלת העלאות, אפשר להשהות, להמשיך ולבטל העלאות באמצעות השיטות pause(), ‏resume() ו-cancel(). אירועי השהיה והפעלה מחדש מפעילים שינויים בסטטוס pause ו-progress, בהתאמה. ביטול ההעלאה גורם לכך שההעלאה נכשלת עם שגיאה שמציינת שההעלאה בוטלה.

final task = mountainsRef.putFile(largeFile);

// Pause the upload.
bool paused = await task.pause();
print('paused, $paused');

// Resume the upload.
bool resumed = await task.resume();
print('resumed, $resumed');

// Cancel the upload.
bool canceled = await task.cancel();
print('canceled, $canceled');

מעקב אחר התקדמות ההעלאה

אפשר להאזין למקור האירועים של המשימה כדי לטפל בהצלחה, בכישלון, בהתקדמות או בהשהיות של משימה ההעלאה:

סוג האירוע שימוש אופייני
TaskState.running האירוע הזה נשלח מדי פעם במהלך העברת הנתונים, וניתן להשתמש בו כדי לאכלס אינדיקטור של העלאה/הורדה.
TaskState.paused האירוע הזה נשלח בכל פעם שהמשימה מושהית.
TaskState.success מופעל כשהמשימה הושלמה.
TaskState.canceled האירוע הזה מופעל בכל פעם שהמשימה מבוטלת.
TaskState.error האירוע הזה מופעל כשההעלאה נכשלה. זה יכול לקרות בגלל תפוגת זמן הקצוב לרשת, כשלים באימות או אם מבטלים את המשימה.
mountainsRef.putFile(file).snapshotEvents.listen((taskSnapshot) {
  switch (taskSnapshot.state) {
    case TaskState.running:
      // ...
      break;
    case TaskState.paused:
      // ...
      break;
    case TaskState.success:
      // ...
      break;
    case TaskState.canceled:
      // ...
      break;
    case TaskState.error:
      // ...
      break;
  }
});

טיפול בשגיאות

יש כמה סיבות לכך שעשויות להתרחש שגיאות בהעלאה, כולל הקובץ המקומי לא קיים או שהמשתמש לא קיבל הרשאה להעלות את הקובץ הרצוי. מידע נוסף על שגיאות מופיע בקטע טיפול בשגיאות במסמכים.

דוגמה מלאה

בהמשך מופיעה דוגמה מלאה להעלאה עם מעקב אחר התקדמות וטיפול בשגיאות:

final appDocDir = await getApplicationDocumentsDirectory();
final filePath = "${appDocDir.absolute}/path/to/mountains.jpg";
final file = File(filePath);

// Create the file metadata
final metadata = SettableMetadata(contentType: "image/jpeg");

// Create a reference to the Firebase Storage bucket
final storageRef = FirebaseStorage.instance.ref();

// Upload file and metadata to the path 'images/mountains.jpg'
final uploadTask = storageRef
    .child("images/path/to/mountains.jpg")
    .putFile(file, metadata);

// Listen for state changes, errors, and completion of the upload.
uploadTask.snapshotEvents.listen((TaskSnapshot taskSnapshot) {
  switch (taskSnapshot.state) {
    case TaskState.running:
      final progress =
          100.0 * (taskSnapshot.bytesTransferred / taskSnapshot.totalBytes);
      print("Upload is $progress% complete.");
      break;
    case TaskState.paused:
      print("Upload is paused.");
      break;
    case TaskState.canceled:
      print("Upload was canceled");
      break;
    case TaskState.error:
      // Handle unsuccessful uploads
      break;
    case TaskState.success:
      // Handle successful uploads on complete
      // ...
      break;
  }
});

עכשיו, אחרי שהעליתם את הקבצים, נלמד איך להוריד אותם מ-Cloud Storage.