zoukankan      html  css  js  c++  java
  • 三种方式使得iOS应用能够在后台进行数据更新和下载

    三种方式使得iOS程序即使在关闭或崩溃的情况下也能够在后台持续进行一些任务,比如更新程序界面快照,下载文件等。这三个方法分别是Background Fetch,Remote Notification和NSURLSession的backgroundSessionConfiguration

    Background Fetch

    开启

    首先在info plist文件中开启UIBackgroundModes的Background fetch。或者手动编辑这个值

    <key>UIBackgroundModes</key>
    <array>
         <string>fetch</string>
    </array>

    iOS默认不进行background fetch,需要设置一个时间的间隔

    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
    {
         //UIApplicationBackgroundFetchIntervalMinimum表示尽可能频繁去获取,如果需要指定至少多少时间更新一次就需要给定一个时间值
         [application setMinimumBackgroundFetchInterval:UIApplicationBackgroundFetchIntervalMinimum];
         return YES;
    }

    最后在App Delegate里实现下面的方法,这个方法只能在30秒内完成。

    - (void) application:(UIApplication *)application
    performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
    {
         NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration];
         NSURLSession *session = [NSURLSession sessionWithConfiguration:sessionConfiguration];
    
         NSURL *url = [[NSURL alloc] initWithString:@"http://yourserver.com/data.json"];
         NSURLSessionDataTask *task = [session dataTaskWithURL:url
                   completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
    
              if (error) {
                   completionHandler(UIBackgroundFetchResultFailed);
                   return;
              }
    
              // 解析响应/数据以决定新内容是否可用
              BOOL hasNewData = ...
              if (hasNewData) {
                   completionHandler(UIBackgroundFetchResultNewData);
              } else {
                   completionHandler(UIBackgroundFetchResultNoData);
              }
         }];
    
         // 开始任务
         [task resume];
    }

    测试

    • 通过查看UIApplication的applicationState
    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
    {
         NSLog(@"Launched in background %d", UIApplicationStateBackground == application.applicationState);
    
         return YES;
    }

    Remote Notification

    在普通的远程通知里带上content-available标志就可以在通知用户同时在后台进行更新。通知结构如下

    {
         "aps" : {
              "content-available" : 1
         },
         "content-id" : 42
    }

    接收一条带有content-available的通知会调用下面的方法

    - (void)application:(UIApplication *)application
              didReceiveRemoteNotification:(NSDictionary *)userInfo
              fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
    {
         NSLog(@"Remote Notification userInfo is %@", userInfo);
    
         NSNumber *contentID = userInfo[@"content-id"];
         // 根据 content ID 进行操作
         completionHandler(UIBackgroundFetchResultNewData);
    }

    利用NSURLSession进行background transfer task

    使用[NSURLSessionConfiguration backgroundSessionConfiguration]创建一个后台任务,当应用退出后,崩溃或进程被关掉都还是会运行。

    范例,先处理一条远程通知,并将NSURLSessionDownloadTask添加到后台传输服务队列。

    - (NSURLSession *)backgroundURLSession
    {
         static NSURLSession *session = nil;
         static dispatch_once_t onceToken;
         dispatch_once(&onceToken, ^{
              NSString *identifier = @"io.objc.backgroundTransferExample";
              NSURLSessionConfiguration* sessionConfig = [NSURLSessionConfiguration backgroundSessionConfiguration:identifier];
              session = [NSURLSession sessionWithConfiguration:sessionConfig
                   delegate:self
                   delegateQueue:[NSOperationQueue mainQueue]];
         });
    
         return session;
    }
    
    - (void) application:(UIApplication *)application
         didReceiveRemoteNotification:(NSDictionary *)userInfo
         fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
    {
         NSLog(@"Received remote notification with userInfo %@", userInfo);
    
         NSNumber *contentID = userInfo[@"content-id"];
         NSString *downloadURLString = [NSString stringWithFormat:@"http://yourserver.com/downloads/%d.mp3", [contentID intValue]];
         NSURL* downloadURL = [NSURL URLWithString:downloadURLString];
    
         NSURLRequest *request = [NSURLRequest requestWithURL:downloadURL];
         NSURLSessionDownloadTask *task = [[self backgroundURLSession] downloadTaskWithRequest:request];
         task.taskDescription = [NSString stringWithFormat:@"Podcast Episode %d", [contentID intValue]];
         //执行resume保证开始了任务
         [task resume];
    
         completionHandler(UIBackgroundFetchResultNewData);
    }

    下载完成后调用NSURLSessionDownloadDelegate的委托方法,这些委托方法全部是必须实现的。了解所有类型session task的生命周期可以参考官方文档:https://developer.apple.com/library/ios/documentation/cocoa/Conceptual/URLLoadingSystem/NSURLSessionConcepts/NSURLSessionConcepts.html#//apple_ref/doc/uid/10000165i-CH2-SW42

    #Pragma Mark - NSURLSessionDownloadDelegate
    
    - (void) URLSession:(NSURLSession *)session
         downloadTask:(NSURLSessionDownloadTask *)downloadTask
         didFinishDownloadingToURL:(NSURL *)location
    {
         NSLog(@"downloadTask:%@ didFinishDownloadingToURL:%@", downloadTask.taskDescription, location);
    
         // 必须用 NSFileManager 将文件复制到应用的存储中,因为临时文件在方法返回后会被删除
         // ...
    
         // 通知 UI 刷新
    }
    
    - (void) URLSession:(NSURLSession *)session
         downloadTask:(NSURLSessionDownloadTask *)downloadTask
    didResumeAtOffset:(int64_t)fileOffset
         expectedTotalBytes:(int64_t)expectedTotalBytes
    {
    }
    
    - (void) URLSession:(NSURLSession *)session
         downloadTask:(NSURLSessionDownloadTask *)downloadTask
         didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten
         totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
    {
    }

    后台的任务完成后如果应用没有在前台运行,需要实现UIApplication的两个delegate让系统唤醒应用

    - (void) application:(UIApplication *)application
         handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)())completionHandler
    {
         // 你必须重新建立一个后台 seesiong 的参照
         // 否则 NSURLSessionDownloadDelegate 和 NSURLSessionDelegate 方法会因为
         // 没有 对 session 的 delegate 设定而不会被调用。参见上面的 backgroundURLSession
         NSURLSession *backgroundSession = [self backgroundURLSession];
    
         NSLog(@"Rejoining session with identifier %@ %@", identifier, backgroundSession);
    
         // 保存 completion handler 以在处理 session 事件后更新 UI
         [self addCompletionHandler:completionHandler forSession:identifier];
    }
    
    - (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session
    {
         NSLog(@"Background URL session %@ finished events.
    ", session);
    
         if (session.configuration.identifier) {
              // 调用在 -application:handleEventsForBackgroundURLSession: 中保存的 handler
              [self callCompletionHandlerForSession:session.configuration.identifier];
         }
    }
    
    - (void)addCompletionHandler:(CompletionHandlerType)handler forSession:(NSString *)identifier
    {
         if ([self.completionHandlerDictionary objectForKey:identifier]) {
              NSLog(@"Error: Got multiple handlers for a single session identifier. This should not happen.
    ");
         }
    
         [self.completionHandlerDictionary setObject:handler forKey:identifier];
    }
    
    - (void)callCompletionHandlerForSession: (NSString *)identifier
    {
         CompletionHandlerType handler = [self.completionHandlerDictionary objectForKey: identifier];
    
         if (handler) {
              [self.completionHandlerDictionary removeObjectForKey: identifier];
              NSLog(@"Calling completion handler for session %@", identifier);
    
              handler();
         }
    }

    原文地址
  • 相关阅读:
    toj 2819 Travel
    toj 2807 Number Sort
    zoj 2818 Prairie dogs IV
    zoj 1276 Optimal Array Multiplication Sequence
    toj 2802 Tom's Game
    toj 2798 Farey Sequence
    toj 2815 Searching Problem
    toj 2806 Replace Words
    toj 2794 Bus
    css截取字符
  • 原文地址:https://www.cnblogs.com/pandas/p/4334871.html
Copyright © 2011-2022 走看看