奇怪的NSURLSessionDownloadTask行为通过蜂窝(不是wifi)
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了奇怪的NSURLSessionDownloadTask行为通过蜂窝(不是wifi)相关的知识,希望对你有一定的参考价值。
我已启用具有远程通知任务的后台模式,以便在应用程序收到推送通知时在后台下载小文件(100kb)。我已经使用配置了下载会话
NSURLSessionConfiguration *backgroundConfiguration = [NSURLSessionConfiguration backgroundSessionConfiguration:sessionIdentifier];
[backgroundConfiguration setAllowsCellularAccess:YES];
self.backgroundSession = [NSURLSession sessionWithConfiguration:backgroundConfiguration
delegate:self
delegateQueue:[NSOperationQueue mainQueue]];
并使用激活它
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[hostComponents URL]];
[request setAllowsCellularAccess:YES];
NSMutableData *bodyMutableData = [NSMutableData data];
[bodyMutableData appendData:[params dataUsingEncoding:NSUTF8StringEncoding]];
[request setHTTPMethod:@"POST"];
[request setHTTPBody:[bodyMutableData copy]];
_downloadTask = [self.backgroundSession downloadTaskWithRequest:request];
[self.downloadTask resume];
现在一切正常,只有当我通过Wifi或通过Cellular连接但iPhone连接到xCode的电缆时,如果我断开iPhone并通过蜂窝接收推送通知,代码停在[self.downloadTask resume];
线而不调用URL。
处理这些操作的类是NSURLSessionDataDelegate,NSURLSessionDownloadDelegate,NSURLSessionTaskDelegate,因此实现:
- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential *))completionHandler
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didResumeAtOffset:(int64_t)fileOffset expectedTotalBytes:(int64_t)expectedTotalBytes
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location
我试图在UILocalNotification
之后插入一个带有[self.downloadTask resume]
(现在'现在')的调试行,但在5分钟后被调用并且说self.downloadTask.state
被“暂停”
是什么导致这种奇怪的行为?
NSURLSessionConfiguration类参考的文档在这里:
说:对于自由选择的财产:
讨论
设置此标志后,插入电源和Wi-Fi时更有可能发生传输。默认情况下,此值为false。
仅当最初通过调用backgroundSessionConfiguration:方法构造会话的配置对象时才使用此属性,并且仅在应用程序位于前台时启动的任务中使用此属性。如果在应用程序处于后台时启动任务,则无论此属性的实际值如何,该任务都将被视为自由裁量。对于基于其他配置创建的会话,将忽略此属性。
这似乎意味着如果在后台启动下载,操作系统始终可以自行决定是否以及何时继续下载。在完成这些任务之前,操作系统似乎总是在等待wifi连接。
我的经验支持这个猜想。我发现当设备处于蜂窝状态时,我可以发送几个下载通知。他们仍然卡住了。当我将设备切换到wifi时,它们都会通过。
我遇到了同样的问题,最后我确定了
configuration.discretionary = NO;
一切正常,对于backgroundConfiguration
,discretionary = YES
默认,似乎任务开始与WIFI
和电池两者。希望有帮助
你在做什么
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void(^)(UIBackgroundFetchResult))completionHandler {}
您是否在下载完成之前立即调用completionHandler?我相信这样做不会影响Wifi模式或连接到Xcode时的操作。但不知何故,当在Cellular的背景下,它会使下载停止,直到你去Wifi。
唯一真正的解决方法是在应用程序在后台并使用CF套接字时转储NSURLSession。如果我使用CFStreamCreatePairWithSocketToHost
打开CFStream,我可以在应用程序处于后台时通过蜂窝成功执行HTTP请求
#import "Communicator.h"
@implementation Communicator {
CFReadStreamRef readStream;
CFWriteStreamRef writeStream;
NSInputStream *inputStream;
NSOutputStream *outputStream;
CompletionBlock _complete;
}
- (void)setupWithCallBack:(CompletionBlock) completionBlock {
_complete = completionBlock;
NSURL *url = [NSURL URLWithString:_host];
//NSLog(@"Setting up connection to %@ : %i", [url absoluteString], _port);
CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault, (__bridge CFStringRef)[url host], _port, &readStream, &writeStream);
if(!CFWriteStreamOpen(writeStream)) {
NSLog(@"Error, writeStream not open");
return;
}
[self open];
//NSLog(@"Status of outputStream: %lu", (unsigned long)[outputStream streamStatus]);
return;
}
- (void)open {
//NSLog(@"Opening streams.");
inputStream = (__bridge NSInputStream *)readStream;
outputStream = (__bridge NSOutputStream *)writeStream;
[inputStream setDelegate:self];
[outputStream setDelegate:self];
[inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[inputStream open];
[outputStream open];
}
- (void)close {
//NSLog(@"Closing streams.");
[inputStream close];
[outputStream close];
[inputStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[outputStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[inputStream setDelegate:nil];
[outputStream setDelegate:nil];
inputStream = nil;
outputStream = nil;
}
- (void)stream:(NSStream *)stream handleEvent:(NSStreamEvent)event {
//NSLog(@"Stream triggered.");
switch(event) {
case NSStreamEventHasSpaceAvailable: {
if(stream == outputStream) {
if (_complete) {
CompletionBlock copyComplete = [_complete copy];
_complete = nil;
copyComplete();
}
}
break;
}
case NSStreamEventHasBytesAvailable: {
if(stream == inputStream) {
//NSLog(@"inputStream is ready.");
uint8_t buf[1024];
NSInteger len = 0;
len = [inputStream read:buf maxLength:1024];
if(len > 0) {
NSMutableData* data=[[NSMutableData alloc] initWithLength:0];
[data appendBytes: (const void *)buf length:len];
NSString *s = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];
[self readIn:s];
}
}
break;
}
default: {
//NSLog(@"Stream is sending an Event: %lu", (unsigned long)event);
break;
}
}
}
- (void)readIn:(NSString *)s {
//NSLog(@"reading : %@",s);
}
- (void)writeOut:(NSString *)s{
uint8_t *buf = (uint8_t *)[s UTF8String];
[outputStream write:buf maxLength:strlen((char *)buf)];
NSLog(@"Writing out the following:");
NSLog(@"%@", s);
}
@end
以上是关于奇怪的NSURLSessionDownloadTask行为通过蜂窝(不是wifi)的主要内容,如果未能解决你的问题,请参考以下文章