Skip to content

Commit 03b19fd

Browse files
committed
Implement downloads for iOS
1 parent 167d179 commit 03b19fd

File tree

3 files changed

+143
-21
lines changed

3 files changed

+143
-21
lines changed

ios/Firestack/FirestackEvents.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ static NSString *const DATABASE_CHILD_MOVED_EVENT = @"child_moved";
3838
static NSString *const STORAGE_UPLOAD_PROGRESS = @"upload_progress";
3939
static NSString *const STORAGE_UPLOAD_PAUSED = @"upload_paused";
4040
static NSString *const STORAGE_UPLOAD_RESUMED = @"upload_resumed";
41+
static NSString *const STORAGE_DOWNLOAD_PROGRESS = @"download_progress";
42+
static NSString *const STORAGE_DOWNLOAD_PAUSED = @"download_paused";
43+
static NSString *const STORAGE_DOWNLOAD_RESUMED = @"download_resumed";
4144

4245
// Messaging
4346
static NSString *const MESSAGING_SUBSYSTEM_EVENT = @"messaging_event";
@@ -47,4 +50,4 @@ static NSString *const MESSAGING_TOKEN_REFRESH = @"messaging_token_refresh";
4750
static NSString *const MESSAGING_MESSAGE_RECEIVED_REMOTE = @"messaging_remote_event_received";
4851
static NSString *const MESSAGING_MESSAGE_RECEIVED_LOCAL = @"messaging_local_event_received";
4952

50-
#endif
53+
#endif

ios/Firestack/FirestackStorage.m

Lines changed: 111 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -52,15 +52,15 @@ @implementation FirestackStorage
5252
[err setValue:@"Call setStorageUrl() first" forKey:@"description"];
5353
return callback(@[err]);
5454
}
55-
55+
5656
if ([path hasPrefix:@"assets-library://"]) {
5757
NSURL *localFile = [[NSURL alloc] initWithString:path];
5858
PHFetchResult* assets = [PHAsset fetchAssetsWithALAssetURLs:@[localFile] options:nil];
5959
PHAsset *asset = [assets firstObject];
6060
[asset requestContentEditingInputWithOptions:nil
6161
completionHandler:^(PHContentEditingInput *contentEditingInput, NSDictionary *info) {
6262
NSURL *imageFile = contentEditingInput.fullSizeImageURL;
63-
63+
6464
[self performUpload:urlStr
6565
name:name
6666
file:imageFile
@@ -70,14 +70,14 @@ @implementation FirestackStorage
7070
} else {
7171
NSURL *localFile = [NSURL fileURLWithPath:path];
7272
FIRStorageMetadata *firmetadata = [[FIRStorageMetadata alloc] initWithDictionary:metadata];
73-
73+
7474
[self performUpload:urlStr
7575
name:name
7676
file:localFile
7777
metadata:firmetadata
7878
callback:callback];
7979
}
80-
80+
8181
}
8282

8383
- (void) performUpload:(NSString *) urlStr
@@ -88,10 +88,10 @@ - (void) performUpload:(NSString *) urlStr
8888
{
8989
FIRStorageReference *storageRef = [[FIRStorage storage] referenceForURL:urlStr];
9090
FIRStorageReference *uploadRef = [storageRef child:name];
91-
91+
9292
FIRStorageUploadTask *uploadTask = [uploadRef putFile:imageFile
9393
metadata:firmetadata];
94-
94+
9595
// Listen for state changes, errors, and completion of the upload.
9696
[uploadTask observeStatus:FIRStorageTaskStatusResume handler:^(FIRStorageTaskSnapshot *snapshot) {
9797
// Upload resumed, also fires when the upload starts
@@ -100,7 +100,7 @@ - (void) performUpload:(NSString *) urlStr
100100
@"ref": snapshot.reference.bucket
101101
}];
102102
}];
103-
103+
104104
[uploadTask observeStatus:FIRStorageTaskStatusPause handler:^(FIRStorageTaskSnapshot *snapshot) {
105105
// Upload paused
106106
[self sendJSEvent:STORAGE_UPLOAD_PAUSED props:@{
@@ -116,17 +116,17 @@ - (void) performUpload:(NSString *) urlStr
116116
} else {
117117
percentComplete = 100.0 * (snapshot.progress.completedUnitCount) / (snapshot.progress.totalUnitCount);
118118
}
119-
119+
120120
[self sendJSEvent:STORAGE_UPLOAD_PROGRESS props:@{
121121
@"eventName": STORAGE_UPLOAD_PROGRESS,
122122
@"progress": @(percentComplete)
123123
}];
124-
124+
125125
}];
126-
126+
127127
[uploadTask observeStatus:FIRStorageTaskStatusSuccess handler:^(FIRStorageTaskSnapshot *snapshot) {
128128
[uploadTask removeAllObservers];
129-
129+
130130
// Upload completed successfully
131131
FIRStorageReference *ref = snapshot.reference;
132132
NSDictionary *props = @{
@@ -135,14 +135,14 @@ - (void) performUpload:(NSString *) urlStr
135135
@"name": ref.name,
136136
@"metadata": [snapshot.metadata dictionaryRepresentation]
137137
};
138-
138+
139139
callback(@[[NSNull null], props]);
140140
}];
141-
141+
142142
[uploadTask observeStatus:FIRStorageTaskStatusFailure handler:^(FIRStorageTaskSnapshot *snapshot) {
143143
if (snapshot.error != nil) {
144144
NSDictionary *errProps = [[NSMutableDictionary alloc] init];
145-
145+
146146
switch (snapshot.error.code) {
147147
case FIRStorageErrorCodeObjectNotFound:
148148
// File doesn't exist
@@ -161,17 +161,112 @@ - (void) performUpload:(NSString *) urlStr
161161
[errProps setValue:@"Unknown error" forKey:@"description"];
162162
break;
163163
}
164-
164+
165+
callback(@[errProps]);
166+
}}];
167+
}
168+
169+
RCT_EXPORT_METHOD(downloadFile: (NSString *) urlStr
170+
path:(NSString *) path
171+
localFile:(NSString *) file
172+
callback:(RCTResponseSenderBlock) callback)
173+
{
174+
if (urlStr == nil) {
175+
NSError *err = [[NSError alloc] init];
176+
[err setValue:@"Storage configuration error" forKey:@"name"];
177+
[err setValue:@"Call setStorageUrl() first" forKey:@"description"];
178+
return callback(@[err]);
179+
}
180+
181+
FIRStorageReference *storageRef = [[FIRStorage storage] referenceForURL:urlStr];
182+
FIRStorageReference *fileRef = [storageRef child:path];
183+
184+
NSURL *localFile = [NSURL fileURLWithPath:file];
185+
186+
FIRStorageDownloadTask *downloadTask = [fileRef writeToFile:localFile];
187+
// Listen for state changes, errors, and completion of the download.
188+
[downloadTask observeStatus:FIRStorageTaskStatusResume handler:^(FIRStorageTaskSnapshot *snapshot) {
189+
// Upload resumed, also fires when the upload starts
190+
[self sendJSEvent:STORAGE_DOWNLOAD_RESUMED props:@{
191+
@"eventName": STORAGE_DOWNLOAD_RESUMED,
192+
@"ref": snapshot.reference.bucket
193+
}];
194+
}];
195+
196+
[downloadTask observeStatus:FIRStorageTaskStatusPause handler:^(FIRStorageTaskSnapshot *snapshot) {
197+
// Upload paused
198+
[self sendJSEvent:STORAGE_DOWNLOAD_PAUSED props:@{
199+
@"eventName": STORAGE_DOWNLOAD_PAUSED,
200+
@"ref": snapshot.reference.bucket
201+
}];
202+
}];
203+
[downloadTask observeStatus:FIRStorageTaskStatusProgress handler:^(FIRStorageTaskSnapshot *snapshot) {
204+
// Upload reported progress
205+
float percentComplete;
206+
if (snapshot.progress.totalUnitCount == 0) {
207+
percentComplete = 0.0;
208+
} else {
209+
percentComplete = 100.0 * (snapshot.progress.completedUnitCount) / (snapshot.progress.totalUnitCount);
210+
}
211+
212+
[self sendJSEvent:STORAGE_DOWNLOAD_PROGRESS props:@{
213+
@"eventName": STORAGE_DOWNLOAD_PROGRESS,
214+
@"progress": @(percentComplete)
215+
}];
216+
217+
}];
218+
219+
[downloadTask observeStatus:FIRStorageTaskStatusSuccess handler:^(FIRStorageTaskSnapshot *snapshot) {
220+
[downloadTask removeAllObservers];
221+
222+
// Upload completed successfully
223+
FIRStorageReference *ref = snapshot.reference;
224+
NSDictionary *props = @{
225+
@"fullPath": ref.fullPath,
226+
@"bucket": ref.bucket,
227+
@"name": ref.name
228+
};
229+
230+
callback(@[[NSNull null], props]);
231+
}];
232+
233+
[downloadTask observeStatus:FIRStorageTaskStatusFailure handler:^(FIRStorageTaskSnapshot *snapshot) {
234+
if (snapshot.error != nil) {
235+
NSDictionary *errProps = [[NSMutableDictionary alloc] init];
236+
237+
switch (snapshot.error.code) {
238+
case FIRStorageErrorCodeObjectNotFound:
239+
// File doesn't exist
240+
[errProps setValue:@"File does not exist" forKey:@"description"];
241+
break;
242+
case FIRStorageErrorCodeUnauthorized:
243+
// User doesn't have permission to access file
244+
[errProps setValue:@"You do not have permissions" forKey:@"description"];
245+
break;
246+
case FIRStorageErrorCodeCancelled:
247+
// User canceled the upload
248+
[errProps setValue:@"Download canceled" forKey:@"description"];
249+
break;
250+
case FIRStorageErrorCodeUnknown:
251+
// Unknown error occurred, inspect the server response
252+
[errProps setValue:@"Unknown error" forKey:@"description"];
253+
break;
254+
}
255+
165256
callback(@[errProps]);
166257
}}];
167258
}
168259

260+
169261
// Not sure how to get away from this... yet
170262
- (NSArray<NSString *> *)supportedEvents {
171263
return @[
172264
STORAGE_UPLOAD_PAUSED,
173265
STORAGE_UPLOAD_RESUMED,
174-
STORAGE_UPLOAD_PROGRESS
266+
STORAGE_UPLOAD_PROGRESS,
267+
STORAGE_DOWNLOAD_PAUSED,
268+
STORAGE_DOWNLOAD_RESUMED,
269+
STORAGE_DOWNLOAD_PROGRESS
175270
];
176271
}
177272

lib/modules/storage.js

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,36 @@ class StorageRef extends ReferenceBase {
1010
constructor(storage, path) {
1111
super(storage.firestack, path);
1212

13-
this.storageUrl = storage.storageUrl;
13+
this.storage = storage;
1414
}
1515

1616
downloadUrl() {
1717
const path = this.pathToString();
18-
return promisify('downloadUrl', FirestackStorage)(this.storageUrl, path);
18+
return promisify('downloadUrl', FirestackStorage)(this.storage.storageUrl, path);
19+
}
20+
21+
/**
22+
* Downloads a reference to the device
23+
* @param {String} downloadPath Where to store the file
24+
* @return {Promise}
25+
*/
26+
download (downloadPath, cb) {
27+
let callback = cb;
28+
if (!callback || typeof callback !== 'function') {
29+
callback = (evt) => {};
30+
}
31+
32+
const listeners = [];
33+
listeners.push(this.storage._addListener('download_progress', callback));
34+
listeners.push(this.storage._addListener('download_paused', callback));
35+
listeners.push(this.storage._addListener('download_resumed', callback));
36+
37+
const path = this.pathToString();
38+
return promisify('downloadFile', FirestackStorage)(this.storage.storageUrl, path, downloadPath)
39+
.then((res) => {
40+
listeners.forEach(this.storage._removeListener);
41+
return res;
42+
});
1943
}
2044
}
2145

@@ -42,7 +66,7 @@ export class Storage extends Base {
4266
}
4367
return this.refs[key];
4468
}
45-
69+
4670
/**
4771
* Upload a filepath
4872
* @param {string} name The destination for the file
@@ -91,4 +115,4 @@ export class Storage extends Base {
91115
}
92116
}
93117

94-
export default Storage
118+
export default Storage

0 commit comments

Comments
 (0)