Selaa lähdekoodia

Add progress report support for IOS #1

Ben Hsieh 8 vuotta sitten
vanhempi
commit
5b04a2a250

+ 10
- 5
src/index.js Näytä tiedosto

@@ -3,10 +3,15 @@
3 3
  * @version 0.3.3
4 4
  */
5 5
 
6
-import { NativeModules } from 'react-native'
7
-import { DeviceEventEmitter } from 'react-native';
8
-import base64 from 'base-64'
6
+import {
7
+  NativeModules,
8
+  DeviceEventEmitter,
9
+  NativeAppEventEmitter,
10
+  Platform,
11
+} from 'react-native'
9 12
 
13
+import base64 from 'base-64'
14
+const emitter = (Platform.OS === 'android' ? DeviceEventEmitter : NativeAppEventEmitter)
10 15
 const RNFetchBlob = NativeModules.RNFetchBlob
11 16
 
12 17
 // Show warning if native module not detected
@@ -27,7 +32,7 @@ const fetch = (...args) => {
27 32
 
28 33
     let [method, url, headers, body] = [...args]
29 34
     let nativeMethodName = Array.isArray(body) ? 'fetchBlobForm' : 'fetchBlob'
30
-    let handle = DeviceEventEmitter.addListener('RNFetchBlobProgress', (e) => {
35
+    let subscription = emitter.addListener('RNFetchBlobProgress', (e) => {
31 36
       if(e.taskId === taskId && promise.onProgress) {
32 37
         promise.onProgress(e.written, e.total)
33 38
       }
@@ -36,7 +41,7 @@ const fetch = (...args) => {
36 41
     RNFetchBlob[nativeMethodName](taskId, method, url, headers || {}, body, (err, ...data) => {
37 42
 
38 43
       // task done, remove event listener
39
-      handle.remove()
44
+      subscription.remove()
40 45
 
41 46
       if(err)
42 47
         reject(new Error(err, ...data))

+ 41
- 5
src/ios/RNFetchBlob.xcodeproj/project.pbxproj Näytä tiedosto

@@ -5,11 +5,22 @@
5 5
 	};
6 6
 	objectVersion = 46;
7 7
 	objects = {
8
+
8 9
 /* Begin PBXBuildFile section */
9 10
 		A15C30141CD25C330074CB35 /* RNFetchBlob.m in Sources */ = {isa = PBXBuildFile; fileRef = A15C30131CD25C330074CB35 /* RNFetchBlob.m */; };
10 11
 		A166D1AA1CE0647A00273590 /* RNFetchBlob.h in Sources */ = {isa = PBXBuildFile; fileRef = A15C30111CD25C330074CB35 /* RNFetchBlob.h */; };
11 12
 /* End PBXBuildFile section */
12 13
 
14
+/* Begin PBXContainerItemProxy section */
15
+		A1BAA89E1CF415DF003A9374 /* PBXContainerItemProxy */ = {
16
+			isa = PBXContainerItemProxy;
17
+			containerPortal = ADC1D945EE804D3DA47CF622 /* RNFetchBlob.xcodeproj */;
18
+			proxyType = 2;
19
+			remoteGlobalIDString = A15C300E1CD25C330074CB35;
20
+			remoteInfo = RNFetchBlob;
21
+		};
22
+/* End PBXContainerItemProxy section */
23
+
13 24
 /* Begin PBXCopyFilesBuildPhase section */
14 25
 		A15C300C1CD25C330074CB35 /* CopyFiles */ = {
15 26
 			isa = PBXCopyFilesBuildPhase;
@@ -26,7 +37,7 @@
26 37
 		A15C300E1CD25C330074CB35 /* libRNFetchBlob.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRNFetchBlob.a; sourceTree = BUILT_PRODUCTS_DIR; };
27 38
 		A15C30111CD25C330074CB35 /* RNFetchBlob.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = RNFetchBlob.h; path = RNFetchBlob/RNFetchBlob.h; sourceTree = "<group>"; };
28 39
 		A15C30131CD25C330074CB35 /* RNFetchBlob.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = RNFetchBlob.m; path = RNFetchBlob/RNFetchBlob.m; sourceTree = "<group>"; };
29
-		ADC1D945EE804D3DA47CF622 /* RNFetchBlob.xcodeproj */ = {isa = PBXFileReference; name = "RNFetchBlob.xcodeproj"; path = "../../node_modules/react-native-fetch-blob/ios/RNFetchBlob.xcodeproj"; sourceTree = "<group>"; fileEncoding = undefined; lastKnownFileType = wrapper.pb-project; explicitFileType = undefined; includeInIndex = 0; };
40
+		ADC1D945EE804D3DA47CF622 /* RNFetchBlob.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = RNFetchBlob.xcodeproj; path = "../../node_modules/react-native-fetch-blob/ios/RNFetchBlob.xcodeproj"; sourceTree = "<group>"; };
30 41
 /* End PBXFileReference section */
31 42
 
32 43
 /* Begin PBXFrameworksBuildPhase section */
@@ -40,6 +51,14 @@
40 51
 /* End PBXFrameworksBuildPhase section */
41 52
 
42 53
 /* Begin PBXGroup section */
54
+		8BD9ABDFAF76406291A798F2 /* Libraries */ = {
55
+			isa = PBXGroup;
56
+			children = (
57
+				ADC1D945EE804D3DA47CF622 /* RNFetchBlob.xcodeproj */,
58
+			);
59
+			name = Libraries;
60
+			sourceTree = "<group>";
61
+		};
43 62
 		A15C30051CD25C330074CB35 = {
44 63
 			isa = PBXGroup;
45 64
 			children = (
@@ -58,13 +77,12 @@
58 77
 			name = Products;
59 78
 			sourceTree = "<group>";
60 79
 		};
61
-		8BD9ABDFAF76406291A798F2 /* Libraries */ = {
80
+		A1BAA8981CF415DF003A9374 /* Products */ = {
62 81
 			isa = PBXGroup;
63 82
 			children = (
64
-				ADC1D945EE804D3DA47CF622 /* RNFetchBlob.xcodeproj */,
83
+				A1BAA89F1CF415DF003A9374 /* libRNFetchBlob.a */,
65 84
 			);
66
-			name = Libraries;
67
-			path = "";
85
+			name = Products;
68 86
 			sourceTree = "<group>";
69 87
 		};
70 88
 /* End PBXGroup section */
@@ -111,6 +129,12 @@
111 129
 			mainGroup = A15C30051CD25C330074CB35;
112 130
 			productRefGroup = A15C300F1CD25C330074CB35 /* Products */;
113 131
 			projectDirPath = "";
132
+			projectReferences = (
133
+				{
134
+					ProductGroup = A1BAA8981CF415DF003A9374 /* Products */;
135
+					ProjectRef = ADC1D945EE804D3DA47CF622 /* RNFetchBlob.xcodeproj */;
136
+				},
137
+			);
114 138
 			projectRoot = "";
115 139
 			targets = (
116 140
 				A15C300D1CD25C330074CB35 /* RNFetchBlob */,
@@ -118,6 +142,16 @@
118 142
 		};
119 143
 /* End PBXProject section */
120 144
 
145
+/* Begin PBXReferenceProxy section */
146
+		A1BAA89F1CF415DF003A9374 /* libRNFetchBlob.a */ = {
147
+			isa = PBXReferenceProxy;
148
+			fileType = archive.ar;
149
+			path = libRNFetchBlob.a;
150
+			remoteRef = A1BAA89E1CF415DF003A9374 /* PBXContainerItemProxy */;
151
+			sourceTree = BUILT_PRODUCTS_DIR;
152
+		};
153
+/* End PBXReferenceProxy section */
154
+
121 155
 /* Begin PBXSourcesBuildPhase section */
122 156
 		A15C300A1CD25C330074CB35 /* Sources */ = {
123 157
 			isa = PBXSourcesBuildPhase;
@@ -225,6 +259,7 @@
225 259
 					"$(SRCROOT)/../../react-native/React/**",
226 260
 					"$(SRCROOT)/../../node_modules/react-native/React/**",
227 261
 					"$(SRCROOT)/../../node_modules/react-native-fetch-blob/ios/RNFetchBlob",
262
+					"$(SRCROOT)/../../RNFetchBlobTest/node_modules/react-native/**",
228 263
 				);
229 264
 				OTHER_LDFLAGS = "-ObjC";
230 265
 				PRODUCT_NAME = "$(TARGET_NAME)";
@@ -244,6 +279,7 @@
244 279
 					"$(SRCROOT)/../../react-native/React/**",
245 280
 					"$(SRCROOT)/../../node_modules/react-native/React/**",
246 281
 					"$(SRCROOT)/../../node_modules/react-native-fetch-blob/ios/RNFetchBlob",
282
+					"$(SRCROOT)/../../RNFetchBlobTest/node_modules/react-native/**",
247 283
 				);
248 284
 				OTHER_LDFLAGS = "-ObjC";
249 285
 				PRODUCT_NAME = "$(TARGET_NAME)";

+ 23
- 5
src/ios/RNFetchBlob/RNFetchBlob.h Näytä tiedosto

@@ -1,24 +1,42 @@
1 1
 //
2 2
 //  RNFetchBlob.h
3 3
 //
4
-//  Created by suzuri04x2 on 2016/4/28.
5
-//  Copyright © 2016年 Facebook. All rights reserved.
4
+//  Created by wkh237 on 2016/4/28.
6 5
 //
7 6
 
8 7
 #ifndef RNFetchBlob_h
9 8
 #define RNFetchBlob_h
10
-
9
+#import <Foundation/Foundation.h>
11 10
 #import "RCTBridgeModule.h"
12 11
 
13 12
 @interface RNFetchBlob : NSObject <RCTBridgeModule> 
14 13
 
15 14
 @end
16 15
 
17
-@interface FetchBlobUtils : NSObject
16
+@interface FetchBlobUtils : NSObject  <NSURLConnectionDelegate, NSURLConnectionDataDelegate> {
17
+
18
+    NSString * taskId;
19
+    int expectedBytes;
20
+    int receivedBytes;
21
+    NSMutableData * respData;
22
+    RCTResponseSenderBlock callback;
23
+    RCTBridge * bridge;
24
+}
25
+@property (nonatomic) NSString * taskId;
26
+@property (nonatomic) int expectedBytes;
27
+@property (nonatomic) int receivedBytes;
28
+@property (nonatomic) NSMutableData * respData;
29
+@property (nonatomic) RCTResponseSenderBlock callback;
30
+@property (nonatomic) RCTBridge * bridge;
31
+
32
+
33
+- (id) init;
34
+- (id) delegate;
35
+- (void) sendRequest;
18 36
 
19
-+ (void) onBlobResponse;
20 37
 + (NSMutableDictionary *) normalizeHeaders;
21 38
 
39
+
22 40
 @end
23 41
 
24 42
 

+ 118
- 34
src/ios/RNFetchBlob/RNFetchBlob.m Näytä tiedosto

@@ -2,13 +2,14 @@
2 2
 //  RNFetchBlob.m
3 3
 //
4 4
 //  Created by suzuri04x2 on 2016/4/28.
5
-//  Copyright © 2016年 Facebook. All rights reserved.
6 5
 //
7 6
 
8 7
 #import "RNFetchBlob.h"
9 8
 #import "RCTConvert.h"
10 9
 #import "RCTLog.h"
11 10
 #import <Foundation/Foundation.h>
11
+#import "RCTBridge.h"
12
+#import "RCTEventDispatcher.h"
12 13
 
13 14
 
14 15
 ////////////////////////////////////////
@@ -19,24 +20,14 @@
19 20
 
20 21
 @implementation FetchBlobUtils
21 22
 
22
-// callback class method to handle request
23
-+ (void) onBlobResponse:(NSURLResponse * _Nullable)response withData:(NSData * _Nullable)data withError:(NSError * _Nullable)connectionError withCallback:(RCTResponseSenderBlock)callback{
24
-    
25
-    NSHTTPURLResponse* resp = (NSHTTPURLResponse *) response;
26
-    NSString* status = [NSString stringWithFormat:@"%d", resp.statusCode];
27
-    
28
-    if(connectionError)
29
-    {
30
-        callback(@[[connectionError localizedDescription], [NSNull null]]);
31
-    }
32
-    else if(![status isEqualToString:@"200"]) {
33
-        callback(@[status, [NSNull null]]);
34
-    }
35
-    else {
36
-        callback(@[[NSNull null], [data base64EncodedStringWithOptions:0]]);
37
-    }
38
-    
39
-}
23
+
24
+@synthesize taskId;
25
+@synthesize expectedBytes;
26
+@synthesize receivedBytes;
27
+@synthesize respData;
28
+@synthesize callback;
29
+@synthesize bridge;
30
+
40 31
 
41 32
 // removing case of headers
42 33
 + (NSMutableDictionary *) normalizeHeaders:(NSDictionary *)headers {
@@ -49,6 +40,90 @@
49 40
     return mheaders;
50 41
 }
51 42
 
43
+- (id)init {
44
+    self = [super init];
45
+    return self;
46
+}
47
+
48
+- (id)delegate:(id)delegate {
49
+    return delegate;
50
+}
51
+
52
+- (void) sendRequest:(RCTBridge *)bridgeRef taskId:(NSString *)taskId withRequest:(NSURLRequest *)req callback:(RCTResponseSenderBlock) callback {
53
+    self.taskId = taskId;
54
+    self.respData = [[NSMutableData alloc] initWithLength:0];
55
+    self.callback = callback;
56
+    self.bridge = bridgeRef;
57
+    // Call long-running code on background thread
58
+    NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:req delegate:self startImmediately:NO];
59
+    [conn scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
60
+    [conn start];
61
+    
62
+    if(!conn) {
63
+        callback(@[[NSString stringWithFormat:@"RNFetchBlob could not initialize connection"], [NSNull null]]);
64
+    }
65
+}
66
+
67
+
68
+#pragma mark NSURLConnection delegate methods
69
+
70
+
71
+- (void) connection:(NSURLConnection *)connection didReceiveResponse:(nonnull NSURLResponse *)response {
72
+    [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
73
+    expectedBytes = [response expectedContentLength];
74
+}
75
+
76
+- (void) connection:(NSURLConnection *)connection didReceiveData:(nonnull NSData *)data {
77
+    receivedBytes = data.length;
78
+    [respData appendData:data];
79
+    
80
+    [self.bridge.eventDispatcher
81
+        sendAppEventWithName:@"RNFetchBlobProgress"
82
+        body:@{
83
+            @"taskId": taskId,
84
+            @"written": [NSString stringWithFormat:@"%d", receivedBytes],
85
+            @"total": [NSString stringWithFormat:@"%d", expectedBytes]
86
+        }
87
+     ];
88
+}
89
+
90
+- (void) connection:(NSURLConnection *)connection didSendBodyData:(NSInteger)bytesWritten totalBytesWritten:(NSInteger)totalBytesWritten totalBytesExpectedToWrite:(NSInteger)totalBytesExpectedToWrite {
91
+    
92
+    expectedBytes = totalBytesExpectedToWrite;
93
+    receivedBytes = totalBytesWritten;
94
+    [self.bridge.eventDispatcher
95
+        sendAppEventWithName:@"RNFetchBlobProgress"
96
+            body:@{
97
+                    @"taskId": taskId,
98
+                    @"written": [NSString stringWithFormat:@"%d", receivedBytes],
99
+                    @"total": [NSString stringWithFormat:@"%d", expectedBytes]
100
+                }
101
+     ];
102
+    
103
+}
104
+
105
+- (void) connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
106
+    [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
107
+    callback(@[[error localizedDescription], [NSNull null]]);
108
+}
109
+
110
+- (NSCachedURLResponse *) connection:(NSURLConnection *)connection willCacheResponse: (NSCachedURLResponse *)cachedResponse {
111
+    return nil;
112
+}
113
+
114
+
115
+// handle 301 and 302 responses
116
+- (NSURLRequest *)connection:(NSURLConnection *)connection willSendRequest:(NSURLRequest *)request redirectResponse:response {
117
+    
118
+    return request;
119
+}
120
+
121
+// request complete
122
+- (void) connectionDidFinishLoading:(NSURLConnection *)connection {
123
+    NSData * data = [NSData dataWithData:respData];
124
+    callback(@[[NSNull null], [data base64EncodedStringWithOptions:0]]);
125
+}
126
+
52 127
 @end
53 128
 
54 129
 
@@ -60,16 +135,19 @@
60 135
 
61 136
 @implementation RNFetchBlob
62 137
 
138
+@synthesize bridge = _bridge;
139
+
63 140
 RCT_EXPORT_MODULE();
64 141
 
65 142
 // Fetch blob data request
66
-RCT_EXPORT_METHOD(fetchBlobForm:(NSString *)method url:(NSString *)url headers:(NSDictionary *)headers form:(NSArray *)form callback:(RCTResponseSenderBlock)callback)
143
+RCT_EXPORT_METHOD(fetchBlobForm:(NSString *)taskId method:(NSString *)method url:(NSString *)url headers:(NSDictionary *)headers form:(NSArray *)form callback:(RCTResponseSenderBlock)callback)
67 144
 {
68 145
     
69 146
     // send request
70 147
     NSMutableURLRequest *request = [[NSMutableURLRequest alloc]
71 148
                                     initWithURL:[NSURL
72 149
                                                  URLWithString: url]];
150
+    
73 151
     NSMutableDictionary *mheaders = [[NSMutableDictionary alloc] initWithDictionary:[ FetchBlobUtils normalizeHeaders:headers]];
74 152
     
75 153
     
@@ -120,18 +198,20 @@ RCT_EXPORT_METHOD(fetchBlobForm:(NSString *)method url:(NSString *)url headers:(
120 198
     [request setHTTPMethod: method];
121 199
     [request setAllHTTPHeaderFields:mheaders];
122 200
     
201
+    [[[FetchBlobUtils alloc] init] sendRequest:self.bridge taskId:taskId withRequest:request callback:callback];
202
+    
123 203
     // create thread for http request
124
-    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
125
-    [NSURLConnection sendAsynchronousRequest:request queue:queue completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) {
126
-        
127
-        [FetchBlobUtils onBlobResponse:response withData:data withError: connectionError withCallback: callback];
128
-        
129
-    }];
204
+//    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
205
+//    [NSURLConnection sendAsynchronousRequest:request queue:queue completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) {
206
+//        
207
+//        [FetchBlobUtils onBlobResponse:response withData:data withError: connectionError withCallback: callback];
208
+//        
209
+//    }];
130 210
     
131 211
 }
132 212
 
133 213
 // Fetch blob data request
134
-RCT_EXPORT_METHOD(fetchBlob:(NSString *)method url:(NSString *)url headers:(NSDictionary *)headers body:(NSString *)body callback:(RCTResponseSenderBlock)callback)
214
+RCT_EXPORT_METHOD(fetchBlob:(NSString *)taskId method:(NSString *)method url:(NSString *)url headers:(NSDictionary *)headers body:(NSString *)body callback:(RCTResponseSenderBlock)callback)
135 215
 {
136 216
     // send request
137 217
     NSMutableURLRequest *request = [[NSMutableURLRequest alloc]
@@ -155,14 +235,18 @@ RCT_EXPORT_METHOD(fetchBlob:(NSString *)method url:(NSString *)url headers:(NSDi
155 235
     [request setHTTPMethod: method];
156 236
     [request setAllHTTPHeaderFields:mheaders];
157 237
     
238
+    [[[FetchBlobUtils alloc] init] sendRequest:self.bridge taskId:taskId withRequest:request callback:callback];
239
+    
158 240
     // create thread for http request
159
-    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
160
-    [NSURLConnection sendAsynchronousRequest:request queue:queue completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) {
161
-        
162
-        [FetchBlobUtils onBlobResponse:response withData:data withError: connectionError withCallback: callback];
163
-        
164
-    }];
241
+//    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
242
+//    
243
+//    
244
+//    [NSURLConnection sendAsynchronousRequest:request queue:queue completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) {
245
+//        
246
+//        [FetchBlobUtils onBlobResponse:response withData:data withError: connectionError withCallback: callback];
247
+//        
248
+//    }];
165 249
     
166 250
 }
167
-@end
168 251
 
252
+@end

+ 44
- 0
src/ios/RNFetchBlobUtil.h Näytä tiedosto

@@ -0,0 +1,44 @@
1
+//
2
+//  RNFetchBlobUtil.h
3
+//  RNFetchBlob
4
+//
5
+//  Created by Ben Hsieh on 2016/5/24.
6
+//  Copyright © 2016年 suzuri04x2. All rights reserved.
7
+//
8
+
9
+#import <Foundation/Foundation.h>
10
+#import "RCTBridgeModule.h"
11
+
12
+#ifndef RNFetchBlobUtil_h
13
+#define RNFetchBlobUtil_h
14
+
15
+@class FetchBlobUtils;
16
+
17
+
18
+@interface FetchBlobUtils : NSObject  <RCTBridgeModule, NSURLConnectionDelegate, NSURLConnectionDataDelegate> {
19
+    
20
+    NSString * taskId;
21
+    int expectedBytes;
22
+    int receivedBytes;
23
+    NSMutableData * respData;
24
+    RCTResponseSenderBlock callback;
25
+}
26
+@property (nonatomic) NSString * taskId;
27
+@property (nonatomic) int expectedBytes;
28
+@property (nonatomic) int receivedBytes;
29
+@property (nonatomic) NSMutableData * respData;
30
+@property (nonatomic) RCTResponseSenderBlock callback;
31
+
32
+
33
+- (id) init;
34
+- (id) delegate;
35
+- (void) sendRequest;
36
+
37
++ (NSMutableDictionary *) normalizeHeaders;
38
+
39
+
40
+@end
41
+
42
+
43
+
44
+#endif /* RNFetchBlobUtil_h */

+ 140
- 0
src/ios/RNFetchBlobUtil.m Näytä tiedosto

@@ -0,0 +1,140 @@
1
+//
2
+//  RNFetchBlobUtil.m
3
+//  RNFetchBlob
4
+//
5
+//  Created by Ben Hsieh on 2016/5/24.
6
+//  Copyright © 2016年 suzuri04x2. All rights reserved.
7
+//
8
+
9
+#import <Foundation/Foundation.h>
10
+#import "RNFetchBlobUtil.h"
11
+
12
+
13
+////////////////////////////////////////
14
+//
15
+//  Util functions
16
+//
17
+////////////////////////////////////////
18
+
19
+@implementation FetchBlobUtils
20
+
21
+
22
+@synthesize taskId;
23
+@synthesize expectedBytes;
24
+@synthesize receivedBytes;
25
+@synthesize respData;
26
+@synthesize callback;
27
+
28
+RCT_EXPORT_MODULE();
29
+
30
+// callback class method to handle request
31
+//+ (void) onBlobResponse:(NSURLResponse * _Nullable)response withData:(NSData * _Nullable)data withError:(NSError * _Nullable)connectionError withCallback:(RCTResponseSenderBlock) callback{
32
+//
33
+//    NSHTTPURLResponse* resp = (NSHTTPURLResponse *) response;
34
+//    NSString* status = [NSString stringWithFormat:@"%d", resp.statusCode];
35
+//
36
+//    if(connectionError)
37
+//    {
38
+//        callback(@[[connectionError localizedDescription], [NSNull null]]);
39
+//    }
40
+//    else if(![status isEqualToString:@"200"]) {
41
+//        callback(@[status, [NSNull null]]);
42
+//    }
43
+//    else {
44
+//        callback(@[[NSNull null], [data base64EncodedStringWithOptions:0]]);
45
+//    }
46
+//
47
+//}
48
+
49
+// removing case of headers
50
++ (NSMutableDictionary *) normalizeHeaders:(NSDictionary *)headers {
51
+    
52
+    NSMutableDictionary * mheaders = [[NSMutableDictionary alloc]init];
53
+    for(NSString * key in headers) {
54
+        [mheaders setValue:[headers valueForKey:key] forKey:[key lowercaseString]];
55
+    }
56
+    
57
+    return mheaders;
58
+}
59
+
60
+- (id)init {
61
+    self = [super init];
62
+    return self;
63
+}
64
+
65
+- (id)delegate:(id)delegate {
66
+    return delegate;
67
+}
68
+
69
+- (void) sendRequest:(NSString *)taskId withRequest:(NSURLRequest *)req callback:(RCTResponseSenderBlock) callback {
70
+    self.taskId = taskId;
71
+    self.respData = [[NSMutableData alloc] initWithLength:0];
72
+    // Call long-running code on background thread
73
+    NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:req delegate:self startImmediately:NO];
74
+    [conn scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
75
+    [conn start];
76
+    
77
+    if(!conn) {
78
+        callback(@[[NSString stringWithFormat:@"RNFetchBlob could not initialize connection"], [NSNull null]]);
79
+    }
80
+}
81
+
82
+
83
+#pragma mark NSURLConnection delegate methods
84
+
85
+
86
+- (void) connection:(NSURLConnection *)connection didReceiveResponse:(nonnull NSURLResponse *)response {
87
+    [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
88
+    expectedBytes = [response expectedContentLength];
89
+}
90
+
91
+- (void) connection:(NSURLConnection *)connection didReceiveData:(nonnull NSData *)data {
92
+    receivedBytes = data.length;
93
+    [respData appendData:data];
94
+    [self.bridge.eventDispatcher
95
+     sendAppEventWithName:@"RNFetchBlobProgress"
96
+     body:@{
97
+            @"taskId": taskId,
98
+            @"written": [NSString stringWithFormat:@"%@", receivedBytes],
99
+            @"total": [NSString stringWithFormat:@"%@", expectedBytes]
100
+            }
101
+     ];
102
+}
103
+
104
+- (void) connection:(NSURLConnection *)connection didSendBodyData:(NSInteger)bytesWritten totalBytesWritten:(NSInteger)totalBytesWritten totalBytesExpectedToWrite:(NSInteger)totalBytesExpectedToWrite {
105
+    
106
+    expectedBytes = totalBytesExpectedToWrite;
107
+    receivedBytes = totalBytesWritten;
108
+    [self.bridge.eventDispatcher
109
+     sendAppEventWithName:@"RNFetchBlobProgress"
110
+     body:@{
111
+            @"taskId": taskId,
112
+            @"written": [NSString stringWithFormat:@"%@", receivedBytes],
113
+            @"total": [NSString stringWithFormat:@"%@", expectedBytes]
114
+            }
115
+     ];
116
+    
117
+}
118
+
119
+- (void) connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
120
+    [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
121
+    callback(@[[error localizedDescription], [NSNull null]]);
122
+}
123
+
124
+- (NSCachedURLResponse *) connection:(NSURLConnection *)connection willCacheResponse: (NSCachedURLResponse *)cachedResponse {
125
+    return nil;
126
+}
127
+
128
+
129
+// handle 301 and 302 responses
130
+- (NSURLRequest *)connection:(NSURLConnection *)connection willSendRequest:(NSURLRequest *)request redirectResponse:response {
131
+    
132
+    return request;
133
+}
134
+
135
+// request complete
136
+- (void) connectionDidFinishLoading:(NSURLConnection *)connection {
137
+    callback(@[[NSNull null], [respData base64EncodedStringWithOptions:0]]);
138
+}
139
+
140
+@end