Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(firebase_storage): rework #3612

Merged
merged 24 commits into from
Sep 30, 2020
Merged

feat(firebase_storage): rework #3612

merged 24 commits into from
Sep 30, 2020

Conversation

Salakar
Copy link
Member

@Salakar Salakar commented Sep 22, 2020


Co-authored-by: @Ehesp
Co-authored-by: @greghesp
Co-authored-by: @helenaford
Co-authored-by: @kirstywilliams
Co-authored-by: @Salakar


A firebase_storage dev release is now available - 5.0.0-dev.1.

NEW USAGE DOCUMENTATION.


TODO

  • Update CHANGELOG.md for PI & universal packages
  • Update migration guide to include storage
  • Review deprecation compatibility of old API and add any missing deprecated APIs where possible
  • Test remaining linked issues in related issues section below (the unchecked ones, add tests to confirm working)

Description

As part of our on-going work for #2582 this is our Firebase Storage rework changes.

Overall, Firebase Storage has been heavily reworked to bring it inline with the federated plugin setup along with adding new features, documentation and many more unit and end-to-end tests (tested on Android, iOS & MacOS).

FirebaseStorage

  • DEPRECATED: Constructing an instance is now deprecated, use FirebaseStorage.instanceFor or FirebaseStorage.instance instead.
  • DEPRECATED: getReferenceFromUrl() is deprecated in favor of calling ref() with a path.
  • DEPRECATED: getMaxOperationRetryTimeMillis() is deprecated in favor of the getter maxOperationRetryTime.
  • DEPRECATED: getMaxUploadRetryTimeMillis() is deprecated in favor of the getter maxUploadRetryTime.
  • DEPRECATED: getMaxDownloadRetryTimeMillis() is deprecated in favor of the getter maxDownloadRetryTime.
  • DEPRECATED: setMaxOperationRetryTimeMillis() is deprecated in favor of setMaxUploadRetryTime().
  • DEPRECATED: setMaxUploadRetryTimeMillis() is deprecated in favor of setMaxUploadRetryTime().
  • DEPRECATED: setMaxDownloadRetryTimeMillis() is deprecated in favor of setMaxDownloadRetryTime().
  • NEW: To match the Web SDK, calling ref() creates a new Reference at the bucket root, whereas an optional path (ref('/foo/bar.png')) can be used to create a Reference pointing at a specific location.
  • NEW: Added support for refFromURL, which accepts a Google Storage (gs://) or HTTP URL and returns a Reference synchronously.

Reference

  • BREAKING: StorageReference has been renamed to Reference.
  • DEPRECATED: getParent() is deprecated in favor of .parent.
  • DEPRECATED: getRoot() is deprecated in favor of .root.
  • DEPRECATED: getStorage() is deprecated in favor of .storage.
  • DEPRECATED: getBucket() is deprecated in favor of .bucket.
  • DEPRECATED: getPath() is deprecated in favor of .fullPath.
  • DEPRECATED: getName() is deprecated in favor of .name.
  • NEW: Added support for list(options).
    • Includes ListOptions API (see below).
  • NEW: Added support for listAll().
  • NEW: putString() has been added to accept a string value, of type Base64, Base64Url, a Data URL or raw strings.
    • Data URLs automatically set the Content-Type metadata if not already set.
  • NEW: getData() does not require a maxSize, it can now be called with a default of 10mb.

NEW ListOptions

The list() method accepts a ListOptions instance with the following arguments:

  • maxResults: limits the number of results returned from a call. Defaults to 1000.
  • pageToken: a page token returned from a ListResult - used if there are more items to query.

NEW ListResult

A ListResult class has been added, which is returned from a call to list() or listAll(). It exposes the following properties:

  • items (List<Reference>): Returns the list of reference objects at the current reference location.
  • prefixes (List<Reference>): Returns the list of reference sub-folders at the current reference location.
  • nextPageToken (String): Returns a string (or null) if a next page during a list() call exists.

Tasks

Tasks have been overhauled to be closer to the expected Firebase Web SDK Storage API, allowing users to access and control on-going tasks easier. There are a number of breaking changes & features with this overhaul:

  • BREAKING: StorageUploadTask has been renamed to UploadTask (extends Task).
  • BREAKING: StorageDownloadTask has been renamed to DownloadTask (extends Task).
  • BREAKING: StorageTaskEvent has been removed (see below).
  • BREAKING: StorageTaskSnapshot has been renamed to TaskSnapshot.
  • BREAKING: pause(), cancel() and resume() are now Futures which return a boolean value to represent whether the status update was successful.
    • Previously, these were void methods but still carried out an asynchronous tasks, potentially leading to uncaught exceptions.
  • BREAKING: isCanceled, isComplete, isInProgress, isPaused and isSuccessful have now been removed. Instead you should subscribe to the stream (for paused/progress/complete/error events) or the task Future for task completion/errors.
  • BREAKING: The events stream (now snapshotEvents) previously returned a StorageTaskEvent, containing a StorageTaskEventType and StorageTaskSnapshot Instead, the stream now returns a TaskSnapshot which includes the state.
  • BREAKING: A task failure and cancellation now throw a FirebaseException instead of a new event.
  • DEPRECATED: events stream is deprecated in favor of snapshotEvents.
  • DEPRECATED: lastSnapshot is deprecated in favor of snapshot.

Example

The new API matches the Web SDK API, for example:

UploadTask task = FirebaseStorage.instance.ref('/notes.text').putString('My notes!');

// Optional
task.snapshotEvents.listen((TaskSnapshot snapshot) {
  print('Snapshot state: ${snapshot.state}'); // paused, running, complete
  print('Progress: ${snapshot.totalBytes / snapshot.bytesTransferred}');
}, onError: (Object e) {
  print(e); // FirebaseException
});

// Optional
task
  .then((TaskSnapshot snapshot) {
    print('Upload complete!');
  })
  .catchError((Object e) {
    print(e); // FirebaseException
  });

Subscribing to Stream updates and/or the tasks delegating Future is optional - if you require progress updates on your task use the Stream, otherwise the Future will resolve once its complete. Using both together is also supported.

SettableMetadata

  • BREAKING: StorageMetadata has been renamed to SettableMetadata.
  • BREAKING: Fetching an objects metadata (e.g. via getMetadata() now returns a FullMetadata instance vs StorageMetadata.

Related Issues & PRs

..and more (will be manually linked and closed following merge of this PR).

Breaking Change

Does your PR require plugin users to manually update their apps to accommodate your change?

  • Yes, this is a breaking change (please indicate a breaking change in CHANGELOG.md and increment major revision).
  • No, this is not a breaking change.

@googlebot
Copy link

All (the pull request submitter and all commit authors) CLAs are signed, but one or more commits were authored or co-authored by someone other than the pull request submitter.

We need to confirm that all authors are ok with their commits being contributed to this project. Please have them confirm that by leaving a comment that contains only @googlebot I consent. in this pull request.

Note to project maintainer: There may be cases where the author cannot leave a comment, or the comment is not properly detected as consent. In those cases, you can manually confirm consent of the commit author(s), and set the cla label to yes (if enabled on your project).

ℹ️ Googlers: Go here for more info.

@Ehesp
Copy link
Member

Ehesp commented Sep 22, 2020

@googlebot I consent.

@googlebot
Copy link

CLAs look good, thanks!

ℹ️ Googlers: Go here for more info.

@googlebot
Copy link

All (the pull request submitter and all commit authors) CLAs are signed, but one or more commits were authored or co-authored by someone other than the pull request submitter.

We need to confirm that all authors are ok with their commits being contributed to this project. Please have them confirm that by leaving a comment that contains only @googlebot I consent. in this pull request.

Note to project maintainer: There may be cases where the author cannot leave a comment, or the comment is not properly detected as consent. In those cases, you can manually confirm consent of the commit author(s), and set the cla label to yes (if enabled on your project).

ℹ️ Googlers: Go here for more info.

@greghesp
Copy link
Contributor

@googlebot I consent.

@googlebot
Copy link

CLAs look good, thanks!

ℹ️ Googlers: Go here for more info.

@Salakar Salakar marked this pull request as ready for review September 22, 2020 17:20
@Salakar Salakar requested a review from kroikie as a code owner September 22, 2020 17:20
@Salakar
Copy link
Member Author

Salakar commented Sep 22, 2020

A firebase_storage dev release is now available - 5.0.0-dev.1.

@zmeggyesi
Copy link

Hi,

I believe I did find a few omissions from the changelogs during my migration:

  • StorageMetadata has been renamed to SettableMetadata, constructor signature retained
  • Reference::getMetadata now returns a FullMetadata instance
  • FullMetadata.creationTimeMillis renamed to FullMetadata.timeCreated

So far, this is all I have, but if I find anything else during the actual testing, I'll be sure to comment.

@zmeggyesi
Copy link

When trying to upload a file, I get the following exception:

D/AndroidRuntime(16635): Shutting down VM
E/AndroidRuntime(16635): FATAL EXCEPTION: main
E/AndroidRuntime(16635): Process: tech.provingground.site_overwatch, PID: 16635
E/AndroidRuntime(16635): java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.Class java.lang.Object.getClass()' on a null object reference
E/AndroidRuntime(16635): 	at io.flutter.plugins.firebase.storage.FlutterFirebaseStoragePlugin.parseMetadata(FlutterFirebaseStoragePlugin.java:99)
E/AndroidRuntime(16635): 	at io.flutter.plugins.firebase.storage.FlutterFirebaseStorageTask.parseUploadTaskSnapshot(FlutterFirebaseStorageTask.java:106)
E/AndroidRuntime(16635): 	at io.flutter.plugins.firebase.storage.FlutterFirebaseStorageTask.parseTaskSnapshot(FlutterFirebaseStorageTask.java:131)
E/AndroidRuntime(16635): 	at io.flutter.plugins.firebase.storage.FlutterFirebaseStorageTask.getTaskEventMap(FlutterFirebaseStorageTask.java:296)
E/AndroidRuntime(16635): 	at io.flutter.plugins.firebase.storage.FlutterFirebaseStorageTask.lambda$null$3$FlutterFirebaseStorageTask(FlutterFirebaseStorageTask.java:235)
E/AndroidRuntime(16635): 	at io.flutter.plugins.firebase.storage.-$$Lambda$FlutterFirebaseStorageTask$LM7xczfI-_C_rFWVuwmxMyoLPsM.run(Unknown Source:6)
E/AndroidRuntime(16635): 	at android.os.Handler.handleCallback(Handler.java:883)
E/AndroidRuntime(16635): 	at android.os.Handler.dispatchMessage(Handler.java:100)
E/AndroidRuntime(16635): 	at android.os.Looper.loop(Looper.java:214)
E/AndroidRuntime(16635): 	at android.app.ActivityThread.main(ActivityThread.java:7397)
E/AndroidRuntime(16635): 	at java.lang.reflect.Method.invoke(Native Method)
E/AndroidRuntime(16635): 	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
E/AndroidRuntime(16635): 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:935)
I/Process (16635): Sending signal. PID: 16635 SIG: 9
Lost connection to device.

I managed to track this down to firebase-storage-platform-interface-1.0.0-dev.1 -> method_channel_reference.dart:147, but closer than that, I don't really know where it might be coming from.

What else do you need from me to look into it?

@greghesp
Copy link
Contributor

greghesp commented Sep 23, 2020

@zmeggyesi Do you have a minimal code sample you can provide that is causing the error? Might be best opening an issue following the template with all the info

@zmeggyesi
Copy link

@greghesp I'll try to create a runnable demo tomorrow, but just in case it rings a bell for someone, this is the immediate context:

      Reference child = FirebaseStorage.instance.ref().child("/sites/${_site.id}/images/${Uuid().v4()}");
      File f = File(pf.path);
      UploadTask putFile = child.putFile( // this line is throwing the exception
          f,
          SettableMetadata(
            cacheControl: "public, max-age=3600",
            customMetadata: {
             /* snip */
            },
          ));
      putFile.snapshotEvents.listen((event) {
        dev.log("Upload state: ${event.state}");
      });
      putFile.whenComplete(() async {
        String url = await child.getDownloadURL();
        setState(() {
          /* snip */
        });
      });

@Salakar
Copy link
Member Author

Salakar commented Sep 23, 2020

I think I see the issue @zmeggyesi, I'll push a dev release with a fix in an hour or so. Will ping here

@zmeggyesi
Copy link

@Salakar Do I need to update the pubspec ref to load your fix, or just pub upgrade to have it load the latest version?

…y string

Internally `getCustomMetadata` checks if the metadata string is empty and returns null if it is, we don't want this behaviour for FF.
@zmeggyesi
Copy link

@Salakar As of commit a1c4ba2434335be9df95fd3bcf1a57d5101f9a84, uploading works on Android. Thank you for the change!

As for iOS, I could not find any immediately obvious problems so far.

@Salakar Salakar merged commit 95db674 into firebase:master Sep 30, 2020
@Salakar Salakar deleted the @invertase/storage_v1 branch September 30, 2020 17:31
@firebase firebase locked and limited conversation to collaborators Oct 31, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants