Browse Source

Fix Android upload progress #94

Ben Hsieh 7 years ago
parent
commit
0fb6635c6a
1 changed files with 73 additions and 96 deletions
  1. 73
    96
      src/android/src/main/java/com/RNFetchBlob/RNFetchBlobBody.java

+ 73
- 96
src/android/src/main/java/com/RNFetchBlob/RNFetchBlobBody.java View File

@@ -1,7 +1,6 @@
1 1
 package com.RNFetchBlob;
2 2
 
3 3
 import android.util.Base64;
4
-import android.util.Log;
5 4
 
6 5
 import com.facebook.react.bridge.Arguments;
7 6
 import com.facebook.react.bridge.ReactApplicationContext;
@@ -13,23 +12,14 @@ import com.facebook.react.modules.core.DeviceEventManagerModule;
13 12
 import java.io.ByteArrayInputStream;
14 13
 import java.io.File;
15 14
 import java.io.FileInputStream;
16
-import java.io.FileNotFoundException;
17 15
 import java.io.FileOutputStream;
18 16
 import java.io.IOException;
19 17
 import java.io.InputStream;
20
-import java.nio.ByteBuffer;
21
-import java.nio.MappedByteBuffer;
22 18
 import java.util.ArrayList;
23
-import java.util.HashMap;
24 19
 
25 20
 import okhttp3.MediaType;
26 21
 import okhttp3.RequestBody;
27
-import okhttp3.FormBody;
28
-import okio.Buffer;
29 22
 import okio.BufferedSink;
30
-import okio.ForwardingSink;
31
-import okio.Okio;
32
-import okio.Sink;
33 23
 
34 24
 /**
35 25
  * Created by wkh237 on 2016/7/11.
@@ -38,7 +28,6 @@ public class RNFetchBlobBody extends RequestBody{
38 28
 
39 29
     InputStream requestStream;
40 30
     long contentLength = 0;
41
-    long bytesWritten = 0;
42 31
     ReadableArray form;
43 32
     String mTaskId;
44 33
     String rawBody;
@@ -47,6 +36,13 @@ public class RNFetchBlobBody extends RequestBody{
47 36
     File bodyCache;
48 37
 
49 38
 
39
+    /**
40
+     * Single file or raw content request constructor
41
+     * @param taskId
42
+     * @param type
43
+     * @param form
44
+     * @param contentType
45
+     */
50 46
     public RNFetchBlobBody(String taskId, RNFetchBlobReq.RequestType type, ReadableArray form, MediaType contentType) {
51 47
         this.mTaskId = taskId;
52 48
         this.form = form;
@@ -54,52 +50,70 @@ public class RNFetchBlobBody extends RequestBody{
54 50
         mime = contentType;
55 51
         try {
56 52
             bodyCache = createMultipartBodyCache();
53
+            requestStream = new FileInputStream(bodyCache);
57 54
             contentLength = bodyCache.length();
58
-        } catch (IOException e) {
59
-            e.printStackTrace();
55
+        } catch(Exception ex) {
56
+            ex.printStackTrace();
57
+            RNFetchBlobUtils.emitWarningEvent("RNFetchBlob failed to create request multipart body :" + ex.getLocalizedMessage());
60 58
         }
61 59
     }
62 60
 
61
+    /**
62
+     * Multipart request constructor
63
+     * @param taskId
64
+     * @param type
65
+     * @param rawBody
66
+     * @param contentType
67
+     */
63 68
     public RNFetchBlobBody(String taskId, RNFetchBlobReq.RequestType type, String rawBody, MediaType contentType) {
64 69
         this.mTaskId = taskId;
65 70
         requestType = type;
66 71
         this.rawBody = rawBody;
67 72
         mime = contentType;
68
-        if(rawBody != null) {
69
-            if(requestType == RNFetchBlobReq.RequestType.AsIs)
70
-                contentLength = rawBody.length();
71
-            else
72
-                contentLength = caculateOctetContentLength();
73
+        if(rawBody == null) {
74
+            this.rawBody = "";
75
+            requestType = RNFetchBlobReq.RequestType.AsIs;
76
+        }
77
+        try {
78
+            switch (requestType) {
79
+                case SingleFile:
80
+                    requestStream = getReuqestStream();
81
+                    contentLength = requestStream.available();
82
+                    break;
83
+                case AsIs:
84
+                    contentLength = this.rawBody.getBytes().length;
85
+                    break;
86
+                case Others:
87
+                    break;
88
+            }
89
+        } catch(Exception ex) {
90
+            ex.printStackTrace();
91
+            RNFetchBlobUtils.emitWarningEvent("RNFetchBlob failed to create single content request body :" + ex.getLocalizedMessage() + "\r\n");
73 92
         }
93
+
74 94
     }
75 95
 
76 96
     @Override
77 97
     public long contentLength() {
78 98
         return contentLength;
79 99
     }
100
+
80 101
     @Override
81 102
     public MediaType contentType() {
82 103
         return mime;
83 104
     }
84 105
 
85 106
     @Override
86
-    public void writeTo(BufferedSink sink) throws IOException {
87
-
88
-        ProgressReportingSource source = new ProgressReportingSource(sink, mTaskId);
89
-        BufferedSink buffer = Okio.buffer(source);
90
-        switch (requestType) {
91
-            case Form:
92
-                pipeStreamToSink(new FileInputStream(bodyCache), sink);
93
-                break;
94
-            case SingleFile:
95
-                if(requestStream != null)
96
-                    pipeStreamToSink(requestStream, sink);
97
-                break;
98
-            case AsIs:
99
-				writeRawData(sink);
100
-				break;
107
+    public void writeTo(BufferedSink sink) {
108
+        try {
109
+            if (requestType == RNFetchBlobReq.RequestType.AsIs)
110
+                sink.write(rawBody.getBytes());
111
+            else
112
+                pipeStreamToSink(requestStream, sink);
113
+        } catch(Exception ex) {
114
+            RNFetchBlobUtils.emitWarningEvent(ex.getLocalizedMessage());
115
+            ex.printStackTrace();
101 116
         }
102
-        buffer.flush();
103 117
     }
104 118
 
105 119
     boolean clearRequestBody() {
@@ -114,8 +128,8 @@ public class RNFetchBlobBody extends RequestBody{
114 128
         return true;
115 129
     }
116 130
 
117
-    private long caculateOctetContentLength() {
118
-        long total = 0;
131
+    private InputStream getReuqestStream() throws Exception {
132
+
119 133
         // upload from storage
120 134
         if (rawBody.startsWith(RNFetchBlobConst.FILE_PREFIX)) {
121 135
             String orgPath = rawBody.substring(RNFetchBlobConst.FILE_PREFIX.length());
@@ -124,32 +138,30 @@ public class RNFetchBlobBody extends RequestBody{
124 138
             if (RNFetchBlobFS.isAsset(orgPath)) {
125 139
                 try {
126 140
                     String assetName = orgPath.replace(RNFetchBlobConst.FILE_PREFIX_BUNDLE_ASSET, "");
127
-                    total += RNFetchBlob.RCTContext.getAssets().openFd(assetName).getLength();
128
-                    requestStream = RNFetchBlob.RCTContext.getAssets().open(assetName);
129
-                } catch (IOException e) {
130
-                    RNFetchBlobUtils.emitWarningEvent(e.getLocalizedMessage());
141
+                    return RNFetchBlob.RCTContext.getAssets().open(assetName);
142
+                } catch (Exception e) {
143
+                    throw new Exception("error when getting request stream from asset : " +e.getLocalizedMessage());
131 144
                 }
132 145
             } else {
133 146
                 File f = new File(RNFetchBlobFS.normalizePath(orgPath));
134 147
                 try {
135 148
                     if(!f.exists())
136 149
                         f.createNewFile();
137
-                    total += f.length();
138
-                    requestStream = new FileInputStream(f);
150
+                    return new FileInputStream(f);
139 151
                 } catch (Exception e) {
140
-                    RNFetchBlobUtils.emitWarningEvent("RNetchBlob error when counting content length: " +e.getLocalizedMessage());
152
+                    throw new Exception("error when getting request stream: " +e.getLocalizedMessage());
141 153
                 }
142 154
             }
143
-        } else {
155
+        }
156
+        // base 64 encoded
157
+        else {
144 158
             try {
145 159
                 byte[] bytes = Base64.decode(rawBody, 0);
146
-                requestStream = new ByteArrayInputStream(bytes);
147
-                total += requestStream.available();
160
+                return  new ByteArrayInputStream(bytes);
148 161
             } catch(Exception ex) {
149
-                RNFetchBlobUtils.emitWarningEvent("RNetchBlob error when counting content length: " +ex.getLocalizedMessage());
162
+                throw new Exception("error when getting request stream: " + ex.getLocalizedMessage());
150 163
             }
151 164
         }
152
-        return total;
153 165
     }
154 166
 
155 167
     /**
@@ -192,7 +204,7 @@ public class RNFetchBlobBody extends RequestBody{
192 204
                             InputStream in = ctx.getAssets().open(assetName);
193 205
                             pipeStreamToFileStream(in, os);
194 206
                         } catch (IOException e) {
195
-                            RNFetchBlobUtils.emitWarningEvent("RNFetchBlob Failed to create form data asset :" + orgPath + ", " + e.getLocalizedMessage() );
207
+                            RNFetchBlobUtils.emitWarningEvent("Failed to create form data asset :" + orgPath + ", " + e.getLocalizedMessage() );
196 208
                         }
197 209
                     }
198 210
                     // data from normal files
@@ -203,7 +215,7 @@ public class RNFetchBlobBody extends RequestBody{
203 215
                             pipeStreamToFileStream(fs, os);
204 216
                         }
205 217
                         else {
206
-                            RNFetchBlobUtils.emitWarningEvent("RNFetchBlob Failed to create form data from path :" + orgPath + ", file not exists.");
218
+                            RNFetchBlobUtils.emitWarningEvent("Failed to create form data from path :" + orgPath + ", file not exists.");
207 219
                         }
208 220
                     }
209 221
                 }
@@ -211,8 +223,6 @@ public class RNFetchBlobBody extends RequestBody{
211 223
                 else {
212 224
                     byte[] b = Base64.decode(data, 0);
213 225
                     os.write(b);
214
-                    bytesWritten += b.length;
215
-                    emitUploadProgress();
216 226
                 }
217 227
 
218 228
             }
@@ -222,7 +232,6 @@ public class RNFetchBlobBody extends RequestBody{
222 232
                 header += "Content-Type: " + field.mime + "\r\n\r\n";
223 233
                 os.write(header.getBytes());
224 234
                 byte[] fieldData = field.data.getBytes();
225
-                bytesWritten += fieldData.length;
226 235
                 os.write(fieldData);
227 236
             }
228 237
             // form end
@@ -236,28 +245,22 @@ public class RNFetchBlobBody extends RequestBody{
236 245
         return outputFile;
237 246
     }
238 247
 
239
-	/**
240
-     * Write data to request body as-is
241
-     * @param sink
242
-     */
243
-	private void writeRawData(BufferedSink sink) throws IOException {
244
-        byte[] bytes = rawBody.getBytes();
245
-        contentLength = bytes.length;
246
-		sink.write(bytes);
247
-	}
248
-
249 248
     /**
250 249
      * Pipe input stream to request body output stream
251 250
      * @param stream    The input stream
252 251
      * @param sink      The request body buffer sink
253 252
      * @throws IOException
254 253
      */
255
-    private void pipeStreamToSink(InputStream stream, BufferedSink sink) throws IOException {
254
+    private void pipeStreamToSink(InputStream stream, BufferedSink sink) throws Exception {
255
+
256 256
         byte [] chunk = new byte[10240];
257
+        int totalWritten = 0;
257 258
         int read;
258 259
         while((read = stream.read(chunk, 0, 10240)) > 0) {
259 260
             if(read > 0) {
260 261
                 sink.write(chunk, 0, read);
262
+                totalWritten += read;
263
+                emitUploadProgress(totalWritten);
261 264
             }
262 265
         }
263 266
         stream.close();
@@ -356,10 +359,14 @@ public class RNFetchBlobBody extends RequestBody{
356 359
         }
357 360
     }
358 361
 
359
-    private void emitUploadProgress() {
362
+    /**
363
+     * Emit progress event
364
+     * @param written
365
+     */
366
+    private void emitUploadProgress(int written) {
360 367
         WritableMap args = Arguments.createMap();
361 368
         args.putString("taskId", mTaskId);
362
-        args.putString("written", String.valueOf(bytesWritten));
369
+        args.putString("written", String.valueOf(written));
363 370
         args.putString("total", String.valueOf(contentLength));
364 371
 
365 372
         // emit event to js context
@@ -367,34 +374,4 @@ public class RNFetchBlobBody extends RequestBody{
367 374
                 .emit(RNFetchBlobConst.EVENT_UPLOAD_PROGRESS, args);
368 375
     }
369 376
 
370
-    private final class ProgressReportingSource extends ForwardingSink {
371
-
372
-        private long bytesWritten = 0;
373
-        private String mTaskId;
374
-        private Sink delegate;
375
-
376
-        public ProgressReportingSource (Sink delegate, String taskId) {
377
-            super(delegate);
378
-            this.mTaskId = taskId;
379
-            this.delegate = delegate;
380
-        }
381
-
382
-        @Override
383
-        public void write(Buffer source, long byteCount) throws IOException {
384
-            delegate.write(source, byteCount);
385
-            // on progress, emit RNFetchBlobProgress upload progress event with ticketId,
386
-            // bytesWritten, and totalSize
387
-            bytesWritten += byteCount;
388
-            WritableMap args = Arguments.createMap();
389
-            args.putString("taskId", mTaskId);
390
-            args.putString("written", String.valueOf(bytesWritten));
391
-            args.putString("total", String.valueOf(contentLength));
392
-
393
-            if(RNFetchBlobReq.isReportUploadProgress(mTaskId)) {
394
-                // emit event to js context
395
-                RNFetchBlob.RCTContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
396
-                        .emit(RNFetchBlobConst.EVENT_UPLOAD_PROGRESS, args);
397
-            }
398
-        }
399
-    }
400 377
 }