代码之家  ›  专栏  ›  技术社区  ›  UglyBlueCat

NSURLSessionDownloadTask在wifi上工作,而不是在4G上工作

  •  0
  • UglyBlueCat  · 技术社区  · 7 年前

    我正在开发一个需要定期下载数据的应用程序,该应用程序位于前台或后台。

    我使用NSURLSessionDownloadTask建立了网络,这样它在除一种情况外的所有情况下都可以正常工作。

    当应用程序在物理设备上运行时,在前台,网络连接在移动数据上,任务将恢复到运行状态,但不会下载任何数据,不会取得任何进展,也不会暂停。

    如果我打开wifi,从Xcode(调试或发布)运行,或者在模拟器上运行,效果会很好。

    我还应该提到,它是间歇性的;我可以在昨天复制,但今天不行,所以后台网络可能会受到影响。

    编辑 -示例代码

    由于应用程序的复杂性和我所能提供的时间有限,我不能给出整个应用程序,但我已经包含了来自AppDelegate和JobsManager类以及整个BackgroundJobFetcher类的相关方法。

    AppDelegate方法:

    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    
    // other stuff
    
        [BackgroundJobFetcher sharedInstance];
    }
    
    -(void)application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
        [[BackgroundJobFetcher sharedInstance] setFetchCompletionHandler:completionHandler];
        [[JobsManager sharedInstance] fetchAllJobs];
    }
    
    - (void) application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)(void))completionHandler {
        [[BackgroundJobFetcher sharedInstance] setSavedCompletionHandler:completionHandler];
    }
    

    JobsManager方法:

    - (void) initiateProcesses {
        self.updateTimer = [NSTimer scheduledTimerWithTimeInterval:30 repeats:YES block:^(NSTimer * _Nonnull timer) {
            [self fetchAllJobs];
        }];
    }
    - (void) fetchAllJobs {
        DefaultsManager *dManager = [DefaultsManager sharedDefaultsManager];
        NSString *apiFunction = @"getAllJobs";
        NSArray* optionsList = @[dManager.CustomerID, dManager.UserID];
    
        [self callAPIFunction:apiFunction options:optionsList];
    }
    
    - (void) callAPIFunction:(NSString*)apiFunction options:(NSArray*)options {
        NSString *apiBaseURL = @"https://www.*****.com/rest";
        NSString *urlComplete = [NSString stringWithFormat:@"%@/%@",
                                 apiBaseURL,
                                 apiFunction];
    
        for (NSString* option in options) {
            urlComplete = [NSString stringWithFormat:@"%@/%@", urlComplete, option];
        }
    
        NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:urlComplete]
                                                 cachePolicy:NSURLRequestReloadIgnoringCacheData
                                             timeoutInterval:30.0];
    
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            [[BackgroundJobFetcher sharedInstance] handleRequest:request];
        });
    }
    

    BackgroundJobFetcher。h:

    #import <Foundation/Foundation.h>
    
    @interface BackgroundJobFetcher : NSObject
    
    @property (nonatomic, copy) void (^ _Nullable savedCompletionHandler)();
    @property (nonatomic, copy) void (^ _Nullable fetchCompletionHandler)(UIBackgroundFetchResult);
    
    + (BackgroundJobFetcher*_Nonnull)sharedInstance;
    - (void) handleRequest:(NSURLRequest*_Nonnull)request;
    - (void) getAllTasksWithCompletionHandler:(void(^_Nonnull)(NSArray<__kindof NSURLSessionTask *> * _Nonnull tasks))completionHandler;
    - (void) stopAllTasks;
    
    @end
    

    BackgroundJobFetcher。m:

    #import "BackgroundJobFetcher.h"
    #import "JobsManager.h"
    #import "DefaultsManager.h"
    #import "AppDelegate.h"
    
    @interface BackgroundJobFetcher() <NSURLSessionDelegate, NSURLSessionTaskDelegate, NSURLSessionDownloadDelegate>
    
    @property (nonatomic, strong) NSMutableData* responseData;
    @property (nonatomic, retain) NSURLSession *defaultSession;
    
    @end
    
    @implementation BackgroundJobFetcher
    
    + (BackgroundJobFetcher*)sharedInstance {
        static BackgroundJobFetcher* _sharedInstance = nil;
        static dispatch_once_t oncePredicate;
        dispatch_once(&oncePredicate, ^{
            _sharedInstance = [BackgroundJobFetcher new];
            NSURLSessionConfiguration* sessionConfiguration = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:@"MonitorJobFetcher"];
            sessionConfiguration.sessionSendsLaunchEvents = YES;
            sessionConfiguration.discretionary = YES;
            _sharedInstance.defaultSession = [NSURLSession sessionWithConfiguration:sessionConfiguration
                                                                           delegate:_sharedInstance
                                                                      delegateQueue:nil];
        });
        return _sharedInstance;
    }
    
    - (void) handleRequest:(NSURLRequest*)request {
        NSURLSessionDownloadTask* downloadTask = [self.defaultSession downloadTaskWithRequest:request];
        [downloadTask resume];
    }
    
    - (void) getAllTasksWithCompletionHandler:(void(^)(NSArray<__kindof NSURLSessionTask *> * _Nonnull tasks))completionHandler {
        [self.defaultSession getAllTasksWithCompletionHandler:completionHandler];
    }
    
    - (void) stopAllTasks {
        [self.defaultSession getAllTasksWithCompletionHandler:^(NSArray<__kindof NSURLSessionTask *> * _Nonnull tasks) {
            for (NSURLSessionTask* task in tasks) {
                [task cancel];
            }
        }];
    }
    
    #pragma mark NSURLSessionDelegate methods
    
    - (void)URLSession:(NSURLSession *)session didBecomeInvalidWithError:(NSError *)error {
        DLog(@"%@", error.localizedDescription);
    }
    
    - (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session {
        if (self.savedCompletionHandler) {
            self.savedCompletionHandler();
            self.savedCompletionHandler = nil;
        }
    }
    
    - (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler {
        DefaultsManager* dManager = [DefaultsManager sharedDefaultsManager];
        NSURLCredential *credential = [NSURLCredential credentialWithUser:dManager.Email
                                                                 password:dManager.Password
                                                              persistence:NSURLCredentialPersistenceForSession];
        completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, credential);
    }
    
    #pragma mark NSURLSessionTaskDelegate methods
    
    - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data {
        if (!self.responseData) {
            self.responseData = [NSMutableData dataWithData:data];
        } else {
            [self.responseData appendData:data];
        }
    }
    
    - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error {
        NSString* urlString = task.originalRequest.URL.absoluteString;
        if (error) {
            DLog(@"error: %@", error.localizedDescription);
            [[JobsManager sharedInstance] requestFailedWithError:error fromURL:urlString];
        } else {
            [[JobsManager sharedInstance] jobsFetched:self.responseData];
        }
    
        self.responseData = nil;
    
        if (self.fetchCompletionHandler) {
            self.fetchCompletionHandler(UIBackgroundFetchResultNewData);
            self.fetchCompletionHandler = nil;
        }
    }
    
    - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler {
        DefaultsManager* dManager = [DefaultsManager sharedDefaultsManager];
        NSURLCredential *credential = [NSURLCredential credentialWithUser:dManager.Email
                                                                 password:dManager.Password
                                                              persistence:NSURLCredentialPersistenceForSession];
        completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, credential);
    }
    
    - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task willPerformHTTPRedirection:(NSHTTPURLResponse *)response newRequest:(NSURLRequest *)request completionHandler:(void (^)(NSURLRequest *))completionHandler {
        completionHandler(request);
    }
    
    - (void)URLSession:(NSURLSession *)session taskIsWaitingForConnectivity:(NSURLSessionTask *)task {
        DLog(@"URL: %@", task.originalRequest.URL.absoluteString);
        DLog(@"task.taskIdentifier: %lu", (unsigned long)task.taskIdentifier);
    }
    
    - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didBecomeDownloadTask:(NSURLSessionDownloadTask *)downloadTask
    {
        [downloadTask resume];
    }
    
    - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didFinishCollectingMetrics:(NSURLSessionTaskMetrics *)metrics {
        DLog(@"URL: %@", task.originalRequest.URL.absoluteString);
        DLog(@"task.taskIdentifier: %lu", (unsigned long)task.taskIdentifier);
        DLog(@"metrics: %@", metrics);
    }
    
    #pragma mark NSURLSessionDownloadDelegate methods
    
    - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location {
        self.responseData = [[NSData dataWithContentsOfURL:location] mutableCopy];
    }
    
    - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didResumeAtOffset:(int64_t)fileOffset expectedTotalBytes:(int64_t)expectedTotalBytes
    {
        DLog(@"downloadTask.taskIdentifier: %lu", (unsigned long)downloadTask.taskIdentifier);
        DLog(@"fileOffset: %lld", fileOffset);
        DLog(@"expectedTotalBytes: %lld", expectedTotalBytes);
    }
    
    - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
    {
        DLog(@"downloadTask.taskIdentifier: %lu", (unsigned long)downloadTask.taskIdentifier);
        DLog(@"bytesWritten: %lld", bytesWritten);
        DLog(@"totalBytesWritten: %lld", totalBytesWritten);
    }
    
    @end
    
    1 回复  |  直到 7 年前
        1
  •  1
  •   UglyBlueCat    7 年前

    我相信我已经找到了答案 this so post .

    我已删除设置

    sessionConfiguration.discretionary = YES;
    

    虽然仍在测试中,但它现在似乎正在工作。

    编辑: 测试表明,这确实正在发挥作用:)

    推荐文章