Skip to content

Commit f034c1f

Browse files
authored
Merge pull request #154 from devshackio/android-downloadFile
Implement storage.download() for Android
2 parents 7774ac1 + d50e976 commit f034c1f

File tree

2 files changed

+152
-535
lines changed

2 files changed

+152
-535
lines changed

Diff for: android/src/main/java/io/fullstack/firestack/FirestackStorage.java

+152-17
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55
import android.content.Context;
66

77
import java.io.File;
8+
import java.io.FileOutputStream;
9+
import java.io.IOException;
10+
import java.io.InputStream;
811
import java.util.Map;
912
import java.util.HashMap;
1013

@@ -26,6 +29,8 @@
2629
import com.google.android.gms.tasks.OnFailureListener;
2730
import com.google.android.gms.tasks.OnSuccessListener;
2831

32+
import com.google.firebase.storage.StorageException;
33+
import com.google.firebase.storage.StreamDownloadTask;
2934
import com.google.firebase.storage.UploadTask;
3035
import com.google.firebase.storage.FirebaseStorage;
3136
import com.google.firebase.storage.StorageMetadata;
@@ -49,6 +54,18 @@ class FirestackStorageModule extends ReactContextBaseJavaModule {
4954
private static final String FileTypeRegular = "FILETYPE_REGULAR";
5055
private static final String FileTypeDirectory = "FILETYPE_DIRECTORY";
5156

57+
private static final String STORAGE_UPLOAD_PROGRESS = "upload_progress";
58+
private static final String STORAGE_UPLOAD_PAUSED = "upload_paused";
59+
private static final String STORAGE_UPLOAD_RESUMED = "upload_resumed";
60+
61+
private static final String STORAGE_DOWNLOAD_PROGRESS = "download_progress";
62+
private static final String STORAGE_DOWNLOAD_PAUSED = "download_paused";
63+
private static final String STORAGE_DOWNLOAD_RESUMED = "download_resumed";
64+
private static final String STORAGE_DOWNLOAD_SUCCESS = "download_success";
65+
private static final String STORAGE_DOWNLOAD_FAILURE = "download_failure";
66+
67+
private ReactContext mReactContext;
68+
5269
public FirestackStorageModule(ReactApplicationContext reactContext) {
5370
super(reactContext);
5471

@@ -60,6 +77,118 @@ public String getName() {
6077
return TAG;
6178
}
6279

80+
81+
public boolean isExternalStorageWritable() {
82+
String state = Environment.getExternalStorageState();
83+
if (Environment.MEDIA_MOUNTED.equals(state)) {
84+
return true;
85+
}
86+
return false;
87+
}
88+
89+
@ReactMethod
90+
public void downloadFile(final String urlStr,
91+
final String fbPath,
92+
final String localFile,
93+
final Callback callback) {
94+
Log.d(TAG, "downloadFile: "+urlStr+", "+localFile);
95+
if (!isExternalStorageWritable()) {
96+
Log.w(TAG, "downloadFile failed: external storage not writable");
97+
WritableMap error = Arguments.createMap();
98+
final int errorCode = 1;
99+
error.putDouble("code", errorCode);
100+
error.putString("description", "downloadFile failed: external storage not writable");
101+
callback.invoke(error);
102+
return;
103+
}
104+
FirebaseStorage storage = FirebaseStorage.getInstance();
105+
String storageBucket = storage.getApp().getOptions().getStorageBucket();
106+
String storageUrl = "gs://" + storageBucket;
107+
Log.d(TAG, "Storage url " + storageUrl + fbPath);
108+
109+
StorageReference storageRef = storage.getReferenceFromUrl(storageUrl);
110+
StorageReference fileRef = storageRef.child(fbPath);
111+
112+
fileRef.getStream(new StreamDownloadTask.StreamProcessor() {
113+
@Override
114+
public void doInBackground(StreamDownloadTask.TaskSnapshot taskSnapshot, InputStream inputStream) throws IOException {
115+
int indexOfLastSlash = localFile.lastIndexOf("/");
116+
String pathMinusFileName = localFile.substring(0, indexOfLastSlash) + "/";
117+
String filename = localFile.substring(indexOfLastSlash+1);
118+
File fileWithJustPath = new File(pathMinusFileName);
119+
if (!fileWithJustPath.mkdirs()) {
120+
Log.e(TAG, "Directory not created");
121+
WritableMap error = Arguments.createMap();
122+
error.putString("message", "Directory not created");
123+
callback.invoke(error);
124+
return;
125+
}
126+
File fileWithFullPath = new File(pathMinusFileName, filename);
127+
FileOutputStream output = new FileOutputStream(fileWithFullPath);
128+
int bufferSize = 1024;
129+
byte[] buffer = new byte[bufferSize];
130+
int len = 0;
131+
while ((len = inputStream.read(buffer)) != -1) {
132+
output.write(buffer, 0, len);
133+
}
134+
output.close();
135+
}
136+
}).addOnProgressListener(new OnProgressListener<StreamDownloadTask.TaskSnapshot>() {
137+
@Override
138+
public void onProgress(StreamDownloadTask.TaskSnapshot taskSnapshot) {
139+
WritableMap data = Arguments.createMap();
140+
data.putString("ref", taskSnapshot.getStorage().getBucket());
141+
double percentComplete = taskSnapshot.getTotalByteCount() == 0 ? 0.0f : 100.0f * (taskSnapshot.getBytesTransferred()) / (taskSnapshot.getTotalByteCount());
142+
data.putDouble("progress", percentComplete);
143+
FirestackUtils.sendEvent(mReactContext, STORAGE_DOWNLOAD_PROGRESS, data);
144+
}
145+
}).addOnPausedListener(new OnPausedListener<StreamDownloadTask.TaskSnapshot>() {
146+
@Override
147+
public void onPaused(StreamDownloadTask.TaskSnapshot taskSnapshot) {
148+
WritableMap data = Arguments.createMap();
149+
data.putString("ref", taskSnapshot.getStorage().getBucket());
150+
FirestackUtils.sendEvent(mReactContext, STORAGE_DOWNLOAD_PAUSED, data);
151+
}
152+
}).addOnSuccessListener(new OnSuccessListener<StreamDownloadTask.TaskSnapshot>() {
153+
@Override
154+
public void onSuccess(StreamDownloadTask.TaskSnapshot taskSnapshot) {
155+
final WritableMap data = Arguments.createMap();
156+
StorageReference ref = taskSnapshot.getStorage();
157+
data.putString("fullPath", ref.getPath());
158+
data.putString("bucket", ref.getBucket());
159+
data.putString("name", ref.getName());
160+
ref.getMetadata().addOnSuccessListener(new OnSuccessListener<StorageMetadata>() {
161+
@Override
162+
public void onSuccess(final StorageMetadata storageMetadata) {
163+
data.putMap("metadata", getMetadataAsMap(storageMetadata));
164+
callback.invoke(null, data);
165+
}
166+
})
167+
.addOnFailureListener(new OnFailureListener() {
168+
@Override
169+
public void onFailure(@NonNull Exception exception) {
170+
final int errorCode = 1;
171+
WritableMap data = Arguments.createMap();
172+
StorageException storageException = StorageException.fromException(exception);
173+
data.putString("description", storageException.getMessage());
174+
data.putInt("code", errorCode);
175+
callback.invoke(makeErrorPayload(errorCode, exception));
176+
}
177+
});
178+
}
179+
}).addOnFailureListener(new OnFailureListener() {
180+
@Override
181+
public void onFailure(@NonNull Exception exception) {
182+
final int errorCode = 1;
183+
WritableMap data = Arguments.createMap();
184+
StorageException storageException = StorageException.fromException(exception);
185+
data.putString("description", storageException.getMessage());
186+
data.putInt("code", errorCode);
187+
callback.invoke(makeErrorPayload(errorCode, exception));
188+
}
189+
});
190+
}
191+
63192
@ReactMethod
64193
public void downloadUrl(final String javascriptStorageBucket,
65194
final String path,
@@ -90,16 +219,7 @@ public void onSuccess(Uri uri) {
90219
public void onSuccess(final StorageMetadata storageMetadata) {
91220
Log.d(TAG, "getMetadata success " + storageMetadata);
92221

93-
WritableMap metadata = Arguments.createMap();
94-
metadata.putString("getBucket", storageMetadata.getBucket());
95-
metadata.putString("getName", storageMetadata.getName());
96-
metadata.putDouble("sizeBytes", storageMetadata.getSizeBytes());
97-
metadata.putDouble("created_at", storageMetadata.getCreationTimeMillis());
98-
metadata.putDouble("updated_at", storageMetadata.getUpdatedTimeMillis());
99-
metadata.putString("md5hash", storageMetadata.getMd5Hash());
100-
metadata.putString("encoding", storageMetadata.getContentEncoding());
101-
102-
res.putMap("metadata", metadata);
222+
res.putMap("metadata", getMetadataAsMap(storageMetadata));
103223
res.putString("name", storageMetadata.getName());
104224
res.putString("url", storageMetadata.getDownloadUrl().toString());
105225
callback.invoke(null, res);
@@ -109,7 +229,8 @@ public void onSuccess(final StorageMetadata storageMetadata) {
109229
@Override
110230
public void onFailure(@NonNull Exception exception) {
111231
Log.e(TAG, "Failure in download " + exception);
112-
callback.invoke(makeErrorPayload(1, exception));
232+
final int errorCode = 1;
233+
callback.invoke(makeErrorPayload(errorCode, exception));
113234
}
114235
});
115236

@@ -129,6 +250,18 @@ public void onFailure(@NonNull Exception exception) {
129250
});
130251
}
131252

253+
private WritableMap getMetadataAsMap(StorageMetadata storageMetadata) {
254+
WritableMap metadata = Arguments.createMap();
255+
metadata.putString("getBucket", storageMetadata.getBucket());
256+
metadata.putString("getName", storageMetadata.getName());
257+
metadata.putDouble("sizeBytes", storageMetadata.getSizeBytes());
258+
metadata.putDouble("created_at", storageMetadata.getCreationTimeMillis());
259+
metadata.putDouble("updated_at", storageMetadata.getUpdatedTimeMillis());
260+
metadata.putString("md5hash", storageMetadata.getMd5Hash());
261+
metadata.putString("encoding", storageMetadata.getContentEncoding());
262+
return metadata;
263+
}
264+
132265
// STORAGE
133266
@ReactMethod
134267
public void uploadFile(final String urlStr, final String name, final String filepath, final ReadableMap metadata, final Callback callback) {
@@ -191,9 +324,9 @@ public void onProgress(UploadTask.TaskSnapshot taskSnapshot) {
191324

192325
if (progress >= 0) {
193326
WritableMap data = Arguments.createMap();
194-
data.putString("eventName", "upload_progress");
327+
data.putString("eventName", STORAGE_UPLOAD_PROGRESS);
195328
data.putDouble("progress", progress);
196-
FirestackUtils.sendEvent(getReactApplicationContext(), "upload_progress", data);
329+
FirestackUtils.sendEvent(getReactApplicationContext(), STORAGE_UPLOAD_PROGRESS, data);
197330
}
198331
}
199332
})
@@ -204,13 +337,14 @@ public void onPaused(UploadTask.TaskSnapshot taskSnapshot) {
204337
StorageMetadata d = taskSnapshot.getMetadata();
205338
String bucket = d.getBucket();
206339
WritableMap data = Arguments.createMap();
207-
data.putString("eventName", "upload_paused");
340+
data.putString("eventName", STORAGE_UPLOAD_PAUSED);
208341
data.putString("ref", bucket);
209-
FirestackUtils.sendEvent(getReactApplicationContext(), "upload_paused", data);
342+
FirestackUtils.sendEvent(getReactApplicationContext(), STORAGE_UPLOAD_PAUSED, data);
210343
}
211344
});
212345
} catch (Exception ex) {
213-
callback.invoke(makeErrorPayload(2, ex));
346+
final int errorCode = 2;
347+
callback.invoke(makeErrorPayload(errorCode, ex));
214348
}
215349
}
216350

@@ -221,7 +355,8 @@ public void getRealPathFromURI(final String uri, final Callback callback) {
221355
callback.invoke(null, path);
222356
} catch (Exception ex) {
223357
ex.printStackTrace();
224-
callback.invoke(makeErrorPayload(1, ex));
358+
final int errorCode = 1;
359+
callback.invoke(makeErrorPayload(errorCode, ex));
225360
}
226361
}
227362

0 commit comments

Comments
 (0)