Kaynağa Gözat

Fix NSURLSession progress report issue #37

Ben Hsieh 8 yıl önce
ebeveyn
işleme
1b2d9a7bf4
2 değiştirilmiş dosya ile 93 ekleme ve 90 silme
  1. 3
    3
      src/ios/RNFetchBlobNetwork.h
  2. 90
    87
      src/ios/RNFetchBlobNetwork.m

+ 3
- 3
src/ios/RNFetchBlobNetwork.h Dosyayı Görüntüle

@@ -15,7 +15,7 @@
15 15
 typedef void(^CompletionHander)(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error);
16 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 20
 @property (nullable, nonatomic) NSString * taskId;
21 21
 @property (nonatomic) int expectedBytes;
@@ -25,8 +25,8 @@ typedef void(^DataTaskCompletionHander) (NSData * _Nullable resp, NSURLResponse
25 25
 @property (nullable, nonatomic) RCTBridge * bridge;
26 26
 @property (nullable, nonatomic) NSDictionary * options;
27 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 30
 @property (nullable, nonatomic) NSError * error;
31 31
 
32 32
 

+ 90
- 87
src/ios/RNFetchBlobNetwork.m Dosyayı Görüntüle

@@ -21,6 +21,16 @@
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 34
 @implementation RNFetchBlobNetwork
25 35
 
26 36
 NSOperationQueue *taskQueue;
@@ -32,8 +42,8 @@ NSOperationQueue *taskQueue;
32 42
 @synthesize callback;
33 43
 @synthesize bridge;
34 44
 @synthesize options;
35
-//@synthesize fileTaskCompletionHandler;
36
-//@synthesize dataTaskCompletionHandler;
45
+@synthesize fileTaskCompletionHandler;
46
+@synthesize dataTaskCompletionHandler;
37 47
 @synthesize error;
38 48
 
39 49
 
@@ -73,83 +83,28 @@ NSOperationQueue *taskQueue;
73 83
     NSString * ext = [self.options valueForKey:CONFIG_FILE_EXT];
74 84
     NSURLSession * session;
75 85
     
86
+    bodyLength = [[req HTTPBody] length];
87
+    
76 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 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 109
     // network status indicator
155 110
     if([[options objectForKey:CONFIG_INDICATOR] boolValue] == YES)
@@ -169,19 +124,34 @@ NSOperationQueue *taskQueue;
169 124
 - (void) URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler
170 125
 {
171 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 143
 // download progress handler
175 144
 - (void) URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data
176 145
 {
177 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 149
         [respData appendData:data];
184 150
     }
151
+    else
152
+    {
153
+        [writeStream write:[data bytes] maxLength:[data length]];
154
+    }
185 155
     
186 156
     [self.bridge.eventDispatcher
187 157
      sendDeviceEventWithName:@"RNFetchBlobProgress"
@@ -191,6 +161,20 @@ NSOperationQueue *taskQueue;
191 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 180
 - (void) URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error {
@@ -202,14 +186,12 @@ NSOperationQueue *taskQueue;
202 186
 // upload progress handler
203 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 189
     [self.bridge.eventDispatcher
208 190
      sendDeviceEventWithName:@"RNFetchBlobProgress"
209 191
      body:@{
210 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,13 +212,34 @@ NSOperationQueue *taskQueue;
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 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