Как использовать BGTask в objective- c с iOS 13 (фоновая выборка) - PullRequest
2 голосов
/ 26 мая 2020

Итак, я хочу создать iOS, я новичок в мире объективных c, и одна функция, которую я хочу реализовать, - это возможность отправлять запросы API и выполнять небольшую фоновую обработку, пока приложение не находится «в фокусе / в фоновом режиме». В течение пары дней я исследовал этот BGTask API для iOS 13 и создал проект, чтобы увидеть, могу ли я получить «фоновую выборку». Я не могу. Я почти уверен, что все настроено правильно, но я не могу запустить функцию фоновой выборки на моем iPhone, ни разу за последние пару дней.

  • Я использую фактический iOS устройство, чтобы проверить это с помощью iOS 13.4.1
  • «Разрешенные идентификаторы планировщика фоновых задач» правильно настроены в Info.plist
  • Приложение подписано
  • Фоновая обработка и фон выборка проверяется в Фоновых режимах
  • Я ждал 15-минутный интервал согласно документации Apple

Вот мой код. Все это просто пустой проект iOS с использованием objective- c. Я редактировал только 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? Даже нажатие на «Simulate background fetch» ​​в меню отладки Xcode не работает. Приложение просто закрывается, и ничего не происходит. Кто-нибудь может помочь / дать совет?

1 Ответ

0 голосов
/ 29 мая 2020

Несколько наблюдений:

  1. setTaskCompletedWithSuccess должен находиться внутри обработчика завершения сетевого запроса. Вы не хотите отмечать задачу как выполненную до тех пор, пока запрос не будет выполнен и вы не обработали результат.

  2. Вы вызываете 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);
    }
    

    Если в вашем коде произойдет сбой, вы никогда не узнаете.

  3. Вы поместили этот код в applicationDidEnterBackground. Т.е. вы вообще видите это сообщение «Вход в фоновый режим»? Причина, по которой я спрашиваю, заключается в том, что если вы предоставили делегат сцены (обычно, если вы только что создали новое приложение iOS 13), этот метод не будет вызываться, тогда как sceneDidEnterBackground будет.

  4. Вы сказали, что пробовали «Имитировать фоновую выборку». Но вы не создали запрос фоновой выборки (BGAppRefreshTask). Вы создали фоновую задачу (BGProcessingTask), а это совсем другое дело. Чтобы проверить запросы фоновой обработки, обратитесь к Запуск и завершение задач во время разработки .

  5. Возникает интересный вопрос, как вы знаете, что запрос на выборку был обработан. Вы просто используете NSLog (что предполагает, что ваше приложение прикреплено к отладчику Xcode). Я бы посоветовал протестировать это без привязки приложения к Xcode. Есть несколько вариантов:

    • Если вы можете посмотреть журналы вашего сервера на предмет запросов, это работает.

    • Я лично часто вставляю UserNotifications (и убедитесь, что go в настройках и включите постоянные уведомления, чтобы я не пропустил их).

    • Другой подход, который я сделал, - чтобы зарегистрировать эти события в некоторой таблице в постоянном хранилище моего приложения, а затем иметь некоторый пользовательский интерфейс в приложении для извлечения этих данных, чтобы я мог подтвердить, что произошло.

    • Я часто использую Унифицированное ведение журнала , чтобы я мог смотреть операторы os_log, выдаваемые моим устройством, из консоли macOS, даже когда Xcode не запущен. Это очень полезно при регистрации методов приложения / сцены. См. WWD C 2016 Единое ведение журнала и отслеживание активности

    Что бы вы ни делали, для таких вещей, как фоновая обработка, обновление фонового приложения sh, и c., Я запрограммирую некоторый механизм, чтобы я мог проверить, есть ли запросы / tasks выполнялись, даже если не были прикреплены к Xcode. В некоторых случаях подключение к отладчику может повлиять на жизненный цикл приложения, и я хочу убедиться, что у меня есть способ подтвердить, что происходит без использования консоли.

  6. Вероятно, очевидно, но убедитесь, что вы никогда не «принудительно закрываете» приложение, так как это остановит выполнение фоновых процессов.

Для получения дополнительной информации см. WWD C 2019 видео Достижения в фоновом исполнении приложения .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...