ios - 如何在 iOS 13 中使用 Objective-c 中的 BGTask(后台获取)

标签 ios objective-c

所以我想构建一个iOS,我对objective-c的世界很陌生,我想要实现的一个功能是能够发送API请求并在应用程序不是“焦点/焦点”时进行一些后台处理在后台”。我已经研究了几天关于这个 BG任务适用于 iOS 13 的 API 并创建了一个项目,以查看我是否可以让“后台获取”正常工作。我已经不能了。我很确定我的所有设置都正确,但我无法在我的 iPhone 上触发后台获取功能,在过去几天甚至一次都没有。

  • 我正在使用实际的 iOS 设备在 iOS 13.4.1
  • 上进行测试
  • 在 Info.plist
  • 中正确设置了“允许的后台任务调度程序标识符”
  • 应用签名
  • 中检查后台处理和后台提取背景模式
  • 根据 Apple 文档
  • ,我等待了 15 分钟的间隔。

    这是我的代码。这一切只是一个使用objective-c的空白iOS项目。我只编辑了 AppDelegate.m Info.plist

    AppDelegate.m
    #import "AppDelegate.h"
    #import <BackgroundTasks/BackgroundTasks.h>
    
    
    static NSString* TaskID = @"com.myapp.task";
    
    @interface AppDelegate ()
    
    @end
    
    @implementation AppDelegate
    
    
    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
        // Override point for customization after application launch.
    
    
        [[BGTaskScheduler sharedScheduler] registerForTaskWithIdentifier:TaskID
                                                              usingQueue:nil
                                                           launchHandler:^(BGProcessingTask *task) {
    
            [self handleAppRefreshTask:task];
        }];
    
        return YES;
    }
    
    
    #pragma mark - UISceneSession lifecycle
    
    
    - (UISceneConfiguration *)application:(UIApplication *)application configurationForConnectingSceneSession:(UISceneSession *)connectingSceneSession options:(UISceneConnectionOptions *)options {
        // Called when a new scene session is being created.
        // Use this method to select a configuration to create the new scene with.
        return [[UISceneConfiguration alloc] initWithName:@"Default Configuration" sessionRole:connectingSceneSession.role];
    }
    
    
    - (void)application:(UIApplication *)application didDiscardSceneSessions:(NSSet<UISceneSession *> *)sceneSessions {
        // Called when the user discards a scene session.
        // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
        // Use this method to release any resources that were specific to the discarded scenes, as they will not return.
    }
    
    
    -(void)handleAppRefreshTask:(BGProcessingTask *)task {
        //do things with task
      NSLog(@"Process started!");
      task.expirationHandler = ^{
        NSLog(@"WARNING: expired before finish was executed.");
    
      };
    
      NSString *targetUrl = @"https://webhook.site/1b274a6f-016f-4edf-8e31-4ed7058eaeac";
      NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
      [request setHTTPMethod:@"GET"];
      [request setURL:[NSURL URLWithString:targetUrl]];
    
      [[[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:
        ^(NSData * _Nullable data,
          NSURLResponse * _Nullable response,
          NSError * _Nullable error) {
    
            NSString *myString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
            NSLog(@"Data received: %@", myString);
      }] resume];
    
      task.expirationHandler = ^{
        NSLog(@"WARNING: expired before finish was executed.");
    
      };
    
      [task setTaskCompletedWithSuccess:YES];
    }
    
    - (void)applicationDidEnterBackground:(UIApplication *)application
    {
      NSLog(@"Entering background");
      BGProcessingTaskRequest *request = [[BGProcessingTaskRequest alloc] initWithIdentifier:TaskID];
      request.requiresNetworkConnectivity = true;
      request.requiresExternalPower = false;
      request.earliestBeginDate = [NSDate dateWithTimeIntervalSinceNow:60];
    
      @try {
        [[BGTaskScheduler sharedScheduler] submitTaskRequest:request error:nil];
      }
      @catch(NSException *e){
        NSLog(@" Unable to submit request");
      }
    
    
    }
    
    @end
    

    iOS 13 中的后台获取是否中断?即使在 Xcode 调试菜单中单击“模拟后台提取”也不起作用。它只是关闭了应用程序,没有任何 react 。任何人都可以帮助/提供任何建议吗?

    最佳答案

    几点观察:

  • setTaskCompletedWithSuccess应该在网络请求的完成处理程序中。在请求有机会运行并且您已处理结果之前,您不希望将任务标记为完成。
  • 您调用submitTaskRequest , 但通过 nil对于NSError引用。您还将其包装在异常处理程序中。但是这个 API 调用不会抛出异常,而只是将错误传回。但是您必须为其提供错误引用。例如。
    NSLog(@"Entering background");
    BGProcessingTaskRequest *request = [[BGProcessingTaskRequest alloc] initWithIdentifier:TaskID];
    request.requiresNetworkConnectivity = true;
    request.requiresExternalPower = false;
    request.earliestBeginDate = [NSDate dateWithTimeIntervalSinceNow:60];
    
    NSError *error;
    if (![[BGTaskScheduler sharedScheduler] submitTaskRequest:request error:&error]) {
        NSLog(@"BGTaskScheduler failed: %@", error);
    }
    

    在你的代码中,如果它失败了,你永远不会知道。
  • 您已将此代码放入 applicationDidEnterBackground .即,您是否看到此“进入后台”消息?我问的原因是如果你提供了一个场景委托(delegate)(如果你刚刚创建了一个新的 iOS 13 应用程序很常见),这个方法将不会被调用,而 sceneDidEnterBackground 将要。
  • 您说您尝试过“模拟后台获取”。但是您还没有创建后台获取请求(BGAppRefreshTask)。您创建了一个后台任务(BGProcessingTask),这是另一回事。要测试后台处理请求,请参阅 Starting and Terminating Tasks During Development .
  • 关于如何知道获取请求已被处理,有一个有趣的问题。您只是在使用 NSLog (假设您将应用程序附加到 Xcode 调试器)。我建议在不将应用程序附加到 Xcode 的情况下对此进行测试。有几个选项:
  • 如果您可以查看服务器日志中的请求,那就可以了。
  • 我个人会经常放UserNotifications (并确保进入设置并打开持久通知,这样我就不会错过它们)。
  • 我所做的另一种方法是将这些事件记录在我的应用程序持久存储中的某个表中,然后在应用程序中使用一些 UI 来获取这些数据,以便我可以确认发生了什么。
  • 我会经常使用Unified Logging让我看os_log即使 Xcode 未运行,我的设备也会从 macOS 控制台发出语句。这在记录应用程序/场景方法时非常有用。参见 WWDC 2016 Unified Logging and Activity Tracing

  • 无论你做什么,对于后台处理、后台应用程序刷新等,我都会编写一些机制,以便我可以检查请求/任务是否发生,即使没有附加到 Xcode。在某些情况下,附加到调试器会影响应用程序的生命周期,我想确保我有一些方法可以在没有控制台优势的情况下确认正在发生的事情。
  • 可能很明显,但请确保您永远不要“强制退出”应用程序,因为这将阻止后台进程的发生。

  • 有关更多信息,请参阅 WWDC 2019 视频 Advances in App Background Execution .

    关于ios - 如何在 iOS 13 中使用 Objective-c 中的 BGTask(后台获取),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62026107/

    相关文章:

    ios - UIsearchBar 输入键盘类型

    iphone - 托管对象之外的 NSManagedObject 子类作为普通对象

    objective-c - 堆栈跟踪中方法名称旁边的数字是什么?

    objective-c - 通过 SSH 读取实时日志

    ios - 打开 UISplitViewController 到 Master View 而不是 Detail

    ios - 检索核心数据数据库中最后保存的属性

    ios - 如何在UIView中制作可扩展的环形动画(类似海底声纳)?

    ios - UIGestureRecognizerStateEnded 的 Swift 等价物是什么?

    ios - 滚动时以曲线/圆弧路径移动 View

    iOS - 是否可以在不导入每次定义它的文件的情况下使宏全局可用?