Skip to content

Commit aeade81

Browse files
szakariasslightfoot
authored andcommitted
Add support for updateMetadata (flutter#503)
1 parent 1277692 commit aeade81

File tree

6 files changed

+175
-46
lines changed

6 files changed

+175
-46
lines changed

packages/firebase_storage/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 0.2.6
2+
3+
* Added support for updateMetadata.
4+
15
## 0.2.5
26

37
* Added StorageMetadata class, support for getMetadata, and support for uploading file with metadata.

packages/firebase_storage/android/src/main/java/io/flutter/plugins/firebase/storage/FirebaseStoragePlugin.java

Lines changed: 44 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,9 @@ public void onMethodCall(MethodCall call, final Result result) {
5656
case "StorageReference#getMetadata":
5757
getMetadata(call, result);
5858
break;
59+
case "StorageReference#updateMetadata":
60+
updateMetadata(call, result);
61+
break;
5962
default:
6063
result.notImplemented();
6164
break;
@@ -70,22 +73,28 @@ private void getMetadata(MethodCall call, final Result result) {
7073
new OnSuccessListener<StorageMetadata>() {
7174
@Override
7275
public void onSuccess(StorageMetadata storageMetadata) {
73-
Map<String, Object> map = new HashMap<>();
74-
map.put("name", storageMetadata.getName());
75-
map.put("bucket", storageMetadata.getBucket());
76-
map.put("generation", storageMetadata.getGeneration());
77-
map.put("metadataGeneration", storageMetadata.getMetadataGeneration());
78-
map.put("path", storageMetadata.getPath());
79-
map.put("sizeBytes", storageMetadata.getSizeBytes());
80-
map.put("creationTimeMillis", storageMetadata.getCreationTimeMillis());
81-
map.put("updatedTimeMillis", storageMetadata.getUpdatedTimeMillis());
82-
map.put("md5Hash", storageMetadata.getMd5Hash());
83-
map.put("cacheControl", storageMetadata.getCacheControl());
84-
map.put("contentDisposition", storageMetadata.getContentDisposition());
85-
map.put("contentEncoding", storageMetadata.getContentEncoding());
86-
map.put("contentLanguage", storageMetadata.getContentLanguage());
87-
map.put("contentType", storageMetadata.getContentType());
88-
result.success(map);
76+
result.success(buildMapFromMetadata(storageMetadata));
77+
}
78+
})
79+
.addOnFailureListener(
80+
new OnFailureListener() {
81+
@Override
82+
public void onFailure(@NonNull Exception e) {
83+
result.error("metadata_error", e.getMessage(), null);
84+
}
85+
});
86+
}
87+
88+
private void updateMetadata(MethodCall call, final Result result) {
89+
String path = call.argument("path");
90+
Map<String, Object> metadata = call.argument("metadata");
91+
StorageReference ref = firebaseStorage.getReference().child(path);
92+
ref.updateMetadata(buildMetadataFromMap(metadata))
93+
.addOnSuccessListener(
94+
new OnSuccessListener<StorageMetadata>() {
95+
@Override
96+
public void onSuccess(StorageMetadata storageMetadata) {
97+
result.success(buildMapFromMetadata(storageMetadata));
8998
}
9099
})
91100
.addOnFailureListener(
@@ -175,6 +184,25 @@ private StorageMetadata buildMetadataFromMap(Map<String, Object> map) {
175184
return builder.build();
176185
}
177186

187+
private Map<String, Object> buildMapFromMetadata(StorageMetadata storageMetadata) {
188+
Map<String, Object> map = new HashMap<>();
189+
map.put("name", storageMetadata.getName());
190+
map.put("bucket", storageMetadata.getBucket());
191+
map.put("generation", storageMetadata.getGeneration());
192+
map.put("metadataGeneration", storageMetadata.getMetadataGeneration());
193+
map.put("path", storageMetadata.getPath());
194+
map.put("sizeBytes", storageMetadata.getSizeBytes());
195+
map.put("creationTimeMillis", storageMetadata.getCreationTimeMillis());
196+
map.put("updatedTimeMillis", storageMetadata.getUpdatedTimeMillis());
197+
map.put("md5Hash", storageMetadata.getMd5Hash());
198+
map.put("cacheControl", storageMetadata.getCacheControl());
199+
map.put("contentDisposition", storageMetadata.getContentDisposition());
200+
map.put("contentEncoding", storageMetadata.getContentEncoding());
201+
map.put("contentLanguage", storageMetadata.getContentLanguage());
202+
map.put("contentType", storageMetadata.getContentType());
203+
return map;
204+
}
205+
178206
private void getData(MethodCall call, final Result result) {
179207
Integer maxSize = call.argument("maxSize");
180208
String path = call.argument("path");

packages/firebase_storage/ios/Classes/FirebaseStoragePlugin.m

Lines changed: 40 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ - (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result
5050
[self delete:call result:result];
5151
} else if ([@"StorageReference#getMetadata" isEqualToString:call.method]) {
5252
[self getMetadata:call result:result];
53+
} else if ([@"StorageReference#updateMetadata" isEqualToString:call.method]) {
54+
[self updateMetadata:call result:result];
5355
} else {
5456
result(FlutterMethodNotImplemented);
5557
}
@@ -93,6 +95,29 @@ - (FIRStorageMetadata *)buildMetadataFromDictionary:(NSDictionary *)dictionary {
9395
return metadata;
9496
}
9597

98+
- (NSDictionary *)buildDictionaryFromMetadata:(FIRStorageMetadata *)metadata {
99+
NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] init];
100+
[dictionary setValue:[metadata bucket] forKey:@"bucket"];
101+
[dictionary setValue:[NSString stringWithFormat:@"%lld", [metadata generation]]
102+
forKey:@"generation"];
103+
[dictionary setValue:[NSString stringWithFormat:@"%lld", [metadata metageneration]]
104+
forKey:@"metadataGeneration"];
105+
[dictionary setValue:[metadata path] forKey:@"path"];
106+
[dictionary setValue:@((long)([[metadata timeCreated] timeIntervalSince1970] * 1000.0))
107+
forKey:@"creationTimeMillis"];
108+
[dictionary setValue:@((long)([[metadata updated] timeIntervalSince1970] * 1000.0))
109+
forKey:@"updatedTimeMillis"];
110+
[dictionary setValue:@([metadata size]) forKey:@"sizeBytes"];
111+
[dictionary setValue:[metadata md5Hash] forKey:@"md5Hash"];
112+
[dictionary setValue:[metadata cacheControl] forKey:@"cacheControl"];
113+
[dictionary setValue:[metadata contentDisposition] forKey:@"contentDisposition"];
114+
[dictionary setValue:[metadata contentEncoding] forKey:@"contentEncoding"];
115+
[dictionary setValue:[metadata contentLanguage] forKey:@"contentLanguage"];
116+
[dictionary setValue:[metadata contentType] forKey:@"contentType"];
117+
[dictionary setValue:[metadata name] forKey:@"name"];
118+
return dictionary;
119+
}
120+
96121
- (void)getData:(FlutterMethodCall *)call result:(FlutterResult)result {
97122
NSNumber *maxSize = call.arguments[@"maxSize"];
98123
NSString *path = call.arguments[@"path"];
@@ -121,30 +146,25 @@ - (void)getMetadata:(FlutterMethodCall *)call result:(FlutterResult)result {
121146
if (error != nil) {
122147
result(error.flutterError);
123148
} else {
124-
NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] init];
125-
[dictionary setValue:[metadata bucket] forKey:@"bucket"];
126-
[dictionary setValue:[NSString stringWithFormat:@"%lld", [metadata generation]]
127-
forKey:@"generation"];
128-
[dictionary setValue:[NSString stringWithFormat:@"%lld", [metadata metageneration]]
129-
forKey:@"metadataGeneration"];
130-
[dictionary setValue:[metadata path] forKey:@"path"];
131-
[dictionary setValue:@((long)([[metadata timeCreated] timeIntervalSince1970] * 1000.0))
132-
forKey:@"creationTimeMillis"];
133-
[dictionary setValue:@((long)([[metadata updated] timeIntervalSince1970] * 1000.0))
134-
forKey:@"updatedTimeMillis"];
135-
[dictionary setValue:@([metadata size]) forKey:@"sizeBytes"];
136-
[dictionary setValue:[metadata md5Hash] forKey:@"md5Hash"];
137-
[dictionary setValue:[metadata cacheControl] forKey:@"cacheControl"];
138-
[dictionary setValue:[metadata contentDisposition] forKey:@"contentDisposition"];
139-
[dictionary setValue:[metadata contentEncoding] forKey:@"contentEncoding"];
140-
[dictionary setValue:[metadata contentLanguage] forKey:@"contentLanguage"];
141-
[dictionary setValue:[metadata contentType] forKey:@"contentType"];
142-
[dictionary setValue:[metadata name] forKey:@"name"];
143-
result(dictionary);
149+
result([self buildDictionaryFromMetadata:metadata]);
144150
}
145151
}];
146152
}
147153

154+
- (void)updateMetadata:(FlutterMethodCall *)call result:(FlutterResult)result {
155+
NSString *path = call.arguments[@"path"];
156+
NSDictionary *metadataDictionary = call.arguments[@"metadata"];
157+
FIRStorageReference *ref = [[FIRStorage storage].reference child:path];
158+
[ref updateMetadata:[self buildMetadataFromDictionary:metadataDictionary]
159+
completion:^(FIRStorageMetadata *metadata, NSError *error) {
160+
if (error != nil) {
161+
result(error.flutterError);
162+
} else {
163+
result([self buildDictionaryFromMetadata:metadata]);
164+
}
165+
}];
166+
}
167+
148168
- (void)getDownloadUrl:(FlutterMethodCall *)call result:(FlutterResult)result {
149169
NSString *path = call.arguments[@"path"];
150170
FIRStorageReference *ref = [[FIRStorage storage].reference child:path];

packages/firebase_storage/lib/firebase_storage.dart

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,21 @@ class StorageReference {
6969
}));
7070
}
7171

72+
/// Updates the metadata associated with this [StorageReference].
73+
///
74+
/// Returns a [Future] that will complete to the updated [StorageMetadata].
75+
///
76+
/// This method ignores fields of [metadata] that cannot be set by the public
77+
/// [StorageMetadata] constructor. Writable metadata properties can be deleted
78+
/// by passing the empty string.
79+
Future<StorageMetadata> updateMetadata(StorageMetadata metadata) async {
80+
return new StorageMetadata._fromMap(await FirebaseStorage.channel
81+
.invokeMethod("StorageReference#updateMetadata", <String, dynamic>{
82+
'path': _pathComponents.join("/"),
83+
'metadata': metadata == null ? null : _buildMetadataUploadMap(metadata),
84+
}));
85+
}
86+
7287
String get path => _pathComponents.join('/');
7388
}
7489

@@ -174,16 +189,16 @@ class StorageUploadTask {
174189
_completer
175190
.complete(new UploadTaskSnapshot(downloadUrl: Uri.parse(downloadUrl)));
176191
}
192+
}
177193

178-
Map<String, dynamic> _buildMetadataUploadMap(StorageMetadata metadata) {
179-
return <String, dynamic>{
180-
'cacheControl': metadata.cacheControl,
181-
'contentDisposition': metadata.contentDisposition,
182-
'contentLanguage': metadata.contentLanguage,
183-
'contentType': metadata.contentType,
184-
'contentEncoding': metadata.contentEncoding,
185-
};
186-
}
194+
Map<String, dynamic> _buildMetadataUploadMap(StorageMetadata metadata) {
195+
return <String, dynamic>{
196+
'cacheControl': metadata.cacheControl,
197+
'contentDisposition': metadata.contentDisposition,
198+
'contentLanguage': metadata.contentLanguage,
199+
'contentType': metadata.contentType,
200+
'contentEncoding': metadata.contentEncoding,
201+
};
187202
}
188203

189204
class UploadTaskSnapshot {

packages/firebase_storage/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ description: Flutter plugin for Firebase Cloud Storage, a powerful, simple, and
33
cost-effective object storage service for Android and iOS.
44
author: Flutter Team <flutter-dev@googlegroups.com>
55
homepage: https://github.com/flutter/plugins/tree/master/packages/firebase_storage
6-
version: 0.2.5
6+
version: 0.2.6
77

88
flutter:
99
plugin:

packages/firebase_storage/test/firebase_storage_test.dart

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,68 @@ void main() {
8686
});
8787
});
8888

89+
group('updateMetadata', () {
90+
final List<MethodCall> log = <MethodCall>[];
91+
92+
StorageReference ref;
93+
94+
setUp(() {
95+
FirebaseStorage.channel
96+
.setMockMethodCallHandler((MethodCall methodCall) async {
97+
log.add(methodCall);
98+
switch (methodCall.method) {
99+
case 'StorageReference#getMetadata':
100+
return <String, String>{
101+
'name': 'image.jpg',
102+
};
103+
break;
104+
case 'StorageReference#updateMetadata':
105+
return <String, String>{
106+
'name': 'image.jpg',
107+
'contentLanguage': 'en'
108+
};
109+
break;
110+
default:
111+
break;
112+
}
113+
});
114+
ref = FirebaseStorage.instance
115+
.ref()
116+
.child('avatars')
117+
.child('large')
118+
.child('image.jpg');
119+
});
120+
121+
test('invokes correct method', () async {
122+
await ref.updateMetadata(const StorageMetadata(contentLanguage: 'en'));
123+
124+
expect(log, <Matcher>[
125+
isMethodCall(
126+
'StorageReference#updateMetadata',
127+
arguments: <String, dynamic>{
128+
'path': 'avatars/large/image.jpg',
129+
'metadata': <String, String>{
130+
'cacheControl': null,
131+
'contentDisposition': null,
132+
'contentLanguage': 'en',
133+
'contentType': null,
134+
'contentEncoding': null
135+
},
136+
},
137+
),
138+
]);
139+
});
140+
141+
test('returns correct result', () async {
142+
expect((await ref.getMetadata()).contentLanguage, null);
143+
expect(
144+
(await ref.updateMetadata(
145+
const StorageMetadata(contentLanguage: 'en')))
146+
.contentLanguage,
147+
'en');
148+
});
149+
});
150+
89151
group('getDownloadUrl', () {
90152
final List<MethodCall> log = <MethodCall>[];
91153

0 commit comments

Comments
 (0)