Browse Source

Fix NSURLSession progress report issue #37

Ben Hsieh 8 years ago
parent
commit
06949df4e7
2 changed files with 93 additions and 90 deletions
  1. 3
    3
      src/ios/RNFetchBlobNetwork.h
  2. 90
    87
      src/ios/RNFetchBlobNetwork.m

+ 3
- 3
src/ios/RNFetchBlobNetwork.h View File

15
 typedef void(^CompletionHander)(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error);
15
 typedef void(^CompletionHander)(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error);
16
 typedef void(^DataTaskCompletionHander) (NSData * _Nullable resp, NSURLResponse * _Nullable response, NSError * _Nullable error);
16
 typedef void(^DataTaskCompletionHander) (NSData * _Nullable resp, NSURLResponse * _Nullable response, NSError * _Nullable error);
17
 
17
 
18
-@interface RNFetchBlobNetwork : NSObject  <NSURLSessionDelegate, NSURLSessionTaskDelegate, NSURLSessionDataDelegate, UIApplicationDelegate>
18
+@interface RNFetchBlobNetwork : NSObject  <NSURLSessionDelegate, NSURLSessionTaskDelegate, NSURLSessionDataDelegate>
19
 
19
 
20
 @property (nullable, nonatomic) NSString * taskId;
20
 @property (nullable, nonatomic) NSString * taskId;
21
 @property (nonatomic) int expectedBytes;
21
 @property (nonatomic) int expectedBytes;
25
 @property (nullable, nonatomic) RCTBridge * bridge;
25
 @property (nullable, nonatomic) RCTBridge * bridge;
26
 @property (nullable, nonatomic) NSDictionary * options;
26
 @property (nullable, nonatomic) NSDictionary * options;
27
 @property (nullable, nonatomic) RNFetchBlobFS * fileStream;
27
 @property (nullable, nonatomic) RNFetchBlobFS * fileStream;
28
-//@property (strong, nonatomic) CompletionHander fileTaskCompletionHandler;
29
-//@property (strong, nonatomic) DataTaskCompletionHander dataTaskCompletionHandler;
28
+@property (strong, nonatomic) CompletionHander fileTaskCompletionHandler;
29
+@property (strong, nonatomic) DataTaskCompletionHander dataTaskCompletionHandler;
30
 @property (nullable, nonatomic) NSError * error;
30
 @property (nullable, nonatomic) NSError * error;
31
 
31
 
32
 
32
 

+ 90
- 87
src/ios/RNFetchBlobNetwork.m View File

21
 //
21
 //
22
 ////////////////////////////////////////
22
 ////////////////////////////////////////
23
 
23
 
24
+@interface RNFetchBlobNetwork ()
25
+{
26
+    BOOL * respFile;
27
+    NSString * destPath;
28
+    NSOutputStream * writeStream;
29
+    long bodyLength;
30
+}
31
+
32
+@end
33
+
24
 @implementation RNFetchBlobNetwork
34
 @implementation RNFetchBlobNetwork
25
 
35
 
26
 NSOperationQueue *taskQueue;
36
 NSOperationQueue *taskQueue;
32
 @synthesize callback;
42
 @synthesize callback;
33
 @synthesize bridge;
43
 @synthesize bridge;
34
 @synthesize options;
44
 @synthesize options;
35
-//@synthesize fileTaskCompletionHandler;
36
-//@synthesize dataTaskCompletionHandler;
45
+@synthesize fileTaskCompletionHandler;
46
+@synthesize dataTaskCompletionHandler;
37
 @synthesize error;
47
 @synthesize error;
38
 
48
 
39
 
49
 
73
     NSString * ext = [self.options valueForKey:CONFIG_FILE_EXT];
83
     NSString * ext = [self.options valueForKey:CONFIG_FILE_EXT];
74
     NSURLSession * session;
84
     NSURLSession * session;
75
     
85
     
86
+    bodyLength = [[req HTTPBody] length];
87
+    
76
     // the session trust any SSL certification
88
     // the session trust any SSL certification
77
-    if([options valueForKey:CONFIG_TRUSTY] != nil)
89
+
90
+    NSURLSessionConfiguration *defaultConfigObject = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:taskId];
91
+    session = [NSURLSession sessionWithConfiguration:defaultConfigObject delegate:self delegateQueue:[NSOperationQueue mainQueue]];
92
+    
93
+    if(path != nil || [self.options valueForKey:CONFIG_USE_TEMP]!= nil)
78
     {
94
     {
79
-        NSURLSessionConfiguration *defaultConfigObject = [NSURLSessionConfiguration defaultSessionConfiguration];
80
-        session = [NSURLSession sessionWithConfiguration:defaultConfigObject delegate:self delegateQueue:[NSOperationQueue mainQueue]];
95
+        respFile = YES;
96
+        if(path != nil)
97
+            destPath = path;
98
+        else
99
+            destPath = [RNFetchBlobFS getTempPath:taskId withExtension:[self.options valueForKey:CONFIG_FILE_EXT]];
81
     }
100
     }
82
-    // the session validates SSL certification, self-signed certification will be aborted
83
     else
101
     else
84
     {
102
     {
85
-        session = [NSURLSession sharedSession];
86
-    }
87
-    
88
-    // file will be stored at a specific path
89
-    if( path != nil) {
90
-        
91
-//        self.fileTaskCompletionHandler = ;
92
-        NSURLSessionDownloadTask * task = [session downloadTaskWithRequest:req completionHandler:^(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error) {
93
-            if(error != nil) {
94
-                callback(@[[error localizedDescription]]);
95
-                return;
96
-            }
97
-            NSError * taskErr;
98
-            NSFileManager * fm = [NSFileManager defaultManager];
99
-            // move temp file to desination
100
-            [fm moveItemAtURL:location toURL:[NSURL fileURLWithPath:path] error:&taskErr];
101
-            if(taskErr != nil) {
102
-                callback(@[[taskErr localizedDescription]]);
103
-                return;
104
-            }
105
-            callback(@[[NSNull null], path]);
106
-            // prevent memory leaks
107
-            self.respData = nil;
108
-            [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
109
-        }];
110
-        [task resume];
111
-    }
112
-    // file will be stored at tmp path
113
-    else if ( [self.options valueForKey:CONFIG_USE_TEMP]!= nil ) {
114
-        
115
-//        self.fileTaskCompletionHandler;
116
-        NSURLSessionDownloadTask * task = [session downloadTaskWithRequest:req completionHandler:^(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error) {
117
-            if(error != nil) {
118
-                callback(@[[error localizedDescription]]);
119
-                return;
120
-            }
121
-            NSError * taskErr;
122
-            NSFileManager * fm = [NSFileManager defaultManager];
123
-            NSString * tmpPath = [RNFetchBlobFS getTempPath:self.taskId withExtension:[self.options valueForKey:CONFIG_FILE_EXT]];
124
-            // move temp file to desination
125
-            [fm moveItemAtURL:location toURL:[NSURL fileURLWithPath:tmpPath] error:&taskErr];
126
-            if(taskErr != nil) {
127
-                callback(@[[taskErr localizedDescription]]);
128
-                return;
129
-            }
130
-            callback(@[[NSNull null], tmpPath]);
131
-            [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
132
-            // prevent memory leaks
133
-            self.respData = nil;
134
-        }];
135
-        [task resume];
136
-    }
137
-    // base64 response
138
-    else {
139
-//        self.dataTaskCompletionHandler = ;
140
-        NSURLSessionDataTask * task = [session dataTaskWithRequest:req completionHandler:^(NSData * _Nullable resp, NSURLResponse * _Nullable response, NSError * _Nullable error) {
141
-            if(error != nil) {
142
-                callback(@[[error localizedDescription]]);
143
-                return;
144
-            }
145
-            else {
146
-                callback(@[[NSNull null], [resp base64EncodedStringWithOptions:0]]);
147
-            }
148
-            self.respData = nil;
149
-            [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
150
-        }];
151
-        [task resume];
103
+        respData = [[NSMutableData alloc] init];
104
+        respFile = NO;
152
     }
105
     }
106
+    NSURLSessionDataTask * task = [session dataTaskWithRequest:req];
107
+    [task resume];
153
     
108
     
154
     // network status indicator
109
     // network status indicator
155
     if([[options objectForKey:CONFIG_INDICATOR] boolValue] == YES)
110
     if([[options objectForKey:CONFIG_INDICATOR] boolValue] == YES)
169
 - (void) URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler
124
 - (void) URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler
170
 {
125
 {
171
     expectedBytes = [response expectedContentLength];
126
     expectedBytes = [response expectedContentLength];
127
+    
128
+    if(respFile == YES)
129
+    {
130
+        NSFileManager * fm = [NSFileManager defaultManager];
131
+        NSString * folder = [destPath stringByDeletingLastPathComponent];
132
+        if(![fm fileExistsAtPath:folder]) {
133
+            [fm createDirectoryAtPath:folder withIntermediateDirectories:YES attributes:NULL error:nil];
134
+        }
135
+        [fm createFileAtPath:destPath contents:[[NSData alloc] init] attributes:nil];
136
+        writeStream = [[NSOutputStream alloc] initToFileAtPath:destPath append:YES];
137
+        [writeStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
138
+        [writeStream open];
139
+    }
140
+    completionHandler(NSURLSessionResponseAllow);
172
 }
141
 }
173
 
142
 
174
 // download progress handler
143
 // download progress handler
175
 - (void) URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data
144
 - (void) URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data
176
 {
145
 {
177
     receivedBytes += [data length];
146
     receivedBytes += [data length];
178
-    
179
-    Boolean fileCache = [self.options valueForKey:CONFIG_USE_TEMP];
180
-    NSString * path = [self.options valueForKey:CONFIG_FILE_PATH];
181
-    // cache data in memory
182
-    if(path == nil && fileCache == nil) {
147
+    if(respFile == NO)
148
+    {
183
         [respData appendData:data];
149
         [respData appendData:data];
184
     }
150
     }
151
+    else
152
+    {
153
+        [writeStream write:[data bytes] maxLength:[data length]];
154
+    }
185
     
155
     
186
     [self.bridge.eventDispatcher
156
     [self.bridge.eventDispatcher
187
      sendDeviceEventWithName:@"RNFetchBlobProgress"
157
      sendDeviceEventWithName:@"RNFetchBlobProgress"
191
             @"total": [NSString stringWithFormat:@"%d", expectedBytes]
161
             @"total": [NSString stringWithFormat:@"%d", expectedBytes]
192
             }
162
             }
193
      ];
163
      ];
164
+    
165
+    if(receivedBytes >= expectedBytes)
166
+    {
167
+        if(respFile == YES)
168
+        {
169
+            [writeStream close];
170
+            callback(@[[NSNull null], destPath]);
171
+        }
172
+        // base64 response
173
+        else {
174
+            callback(@[[NSNull null], [respData base64EncodedStringWithOptions:0]]);
175
+        }
176
+        [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
177
+    }
194
 }
178
 }
195
 
179
 
196
 - (void) URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error {
180
 - (void) URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error {
202
 // upload progress handler
186
 // upload progress handler
203
 - (void) URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didSendBodyData:(int64_t)bytesSent totalBytesSent:(int64_t)totalBytesWritten totalBytesExpectedToSend:(int64_t)totalBytesExpectedToWrite
187
 - (void) URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didSendBodyData:(int64_t)bytesSent totalBytesSent:(int64_t)totalBytesWritten totalBytesExpectedToSend:(int64_t)totalBytesExpectedToWrite
204
 {
188
 {
205
-    expectedBytes = totalBytesExpectedToWrite;
206
-    receivedBytes += totalBytesWritten;
207
     [self.bridge.eventDispatcher
189
     [self.bridge.eventDispatcher
208
      sendDeviceEventWithName:@"RNFetchBlobProgress"
190
      sendDeviceEventWithName:@"RNFetchBlobProgress"
209
      body:@{
191
      body:@{
210
             @"taskId": taskId,
192
             @"taskId": taskId,
211
-            @"written": [NSString stringWithFormat:@"%d", receivedBytes],
212
-            @"total": [NSString stringWithFormat:@"%d", expectedBytes]
193
+            @"written": [NSString stringWithFormat:@"%d", totalBytesWritten],
194
+            @"total": [NSString stringWithFormat:@"%d", totalBytesExpectedToWrite]
213
             }
195
             }
214
      ];
196
      ];
215
 }
197
 }
230
 //    }
212
 //    }
231
 //}
213
 //}
232
 
214
 
233
-- (void) URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential * _Nullable))completionHandler
215
+- (void) URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential * _Nullable credantial))completionHandler
234
 {
216
 {
235
     if([options valueForKey:CONFIG_TRUSTY] != nil)
217
     if([options valueForKey:CONFIG_TRUSTY] != nil)
236
-        completionHandler(NSURLSessionAuthChallengeUseCredential, [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]);
237
-    else {
238
-        RCTLogWarn(@"counld not create connection with an unstrusted SSL certification, if you're going to create connection anyway, add `trusty:true` to RNFetchBlob.config");
239
-        [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
218
+    {
219
+        completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]);
220
+    }
221
+    else
222
+    {
223
+        NSURLSessionAuthChallengeDisposition disposition = NSURLSessionAuthChallengePerformDefaultHandling;
224
+        __block NSURLCredential *credential = nil;
225
+        if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust])
226
+        {
227
+            credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
228
+            if (credential) {
229
+                disposition = NSURLSessionAuthChallengeUseCredential;
230
+            } else {
231
+                disposition = NSURLSessionAuthChallengePerformDefaultHandling;
232
+            }
233
+        }
234
+        else
235
+        {
236
+            disposition = NSURLSessionAuthChallengeCancelAuthenticationChallenge;
237
+            RCTLogWarn(@"counld not create connection with an unstrusted SSL certification, if you're going to create connection anyway, add `trusty:true` to RNFetchBlob.config");
238
+            [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
239
+        }
240
+        if (completionHandler) {
241
+            completionHandler(disposition, credential);
242
+        }
240
     }
243
     }
241
 }
244
 }
242
 
245