如何在 React Native 应用程序上使用 beginBackgroundTask 向 iOS 请求更多后台执行时间

piu*_*olo 6 objective-c ios react-native

当应用程序不在前台/活动状态时,我需要 iOS 可以为应用程序提供的所有执行时间。大多数应用程序一旦进入后台状态就会被挂起,但可以使用beginBackgroundTaskWithName:expirationHandler:或 请求更多的后台执行时间 beginBackgroundTaskWithExpirationHandler:。即使系统可能会在需要时暂停或终止应用程序,此额外的后台执行时间可能会延长至三分钟。

这个过程在原生 iOS 应用程序上看起来很简单,但是我在为 React Native 应用程序制作一个可以启动/完成这些后台任务的原生模块时遇到了问题。

本文解释了非常相似的情况,即系统被要求提供更多的后台执行时间来测距信标。

我的目标是通过使用适用于 iOS 的本机模块,以类似的方式在 React Native 中的 Javascript 代码上请求执行时间。

通过使用文档中描述的方法,我能够让更简单的本机模块与 React Native 一起工作。

我无法获取到的UIApplication来电beginBackgroundTaskWithName或endBackgroundTask与RCT_EXPORT_METHOD()二人的引用有问题的后台任务。

我也试过把上面文章中代码的方法直接导出就是这种方式,但是显然不行。

#import <CoreLocation/CoreLocation.h>
#import "BackgroundIOS.h"
#import <React/RCTLog.h>
#import <UIKit/UIKit.h>

@implementation BackgroundIOS

RCT_EXPORT_MODULE();

static BOOL _inBackground;
static _backgroundTask = nil;


RCT_EXPORT_METHOD(locationManager:(CLLocationManager *)manager didDetermineState:(CLRegionState)state forRegion:(CLRegion *)region)
{
  if (_inBackground) {
    [self extendBackgroundRunningTime];
  }
}

RCT_EXPORT_METHOD(applicationDidEnterBackground:(UIApplication *)application)
{
  [self extendBackgroundRunningTime];
  _inBackground = YES;
}

RCT_EXPORT_METHOD(applicationDidBecomeActive:(UIApplication *)application)
{
  _inBackground = NO;
}

RCT_EXPORT_METHOD(extendBackgroundRunningTime) {
  if (_backgroundTask != UIBackgroundTaskInvalid) {
    // if we are in here, that means the background task is already running.
    // don't restart it.
    return;
  }
  NSLog(@"Attempting to extend background running time");

  __block Boolean self_terminate = YES;

  _backgroundTask = [[UIApplication sharedApplication] beginBackgroundTaskWithName:@"DummyTask" expirationHandler:^{
    NSLog(@"Background task expired by iOS");
    if (self_terminate) {
      [[UIApplication sharedApplication] endBackgroundTask:_backgroundTask];
      _backgroundTask = UIBackgroundTaskInvalid;
    }
  }];

  dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    NSLog(@"Background task started");

    while (true) {
      NSLog(@"background time remaining: %8.2f", [UIApplication sharedApplication].backgroundTimeRemaining);
      [NSThread sleepForTimeInterval:1];
    }

  });
}

@end
Run Code Online (Sandbox Code Playgroud)

编辑:

设置这样的方法似乎可以与来自 JS 的调用一起使用:

背景IOS.h:

#import <React/RCTBridgeModule.h>
#import <UIKit/UIKit.h>


@interface BackgroundIOS : NSObject <RCTBridgeModule>

@property UIBackgroundTaskIdentifier backgroundUpdateTask;

@end
Run Code Online (Sandbox Code Playgroud)

背景IOS.m:

#import "BackgroundIOS.h"
#import <React/RCTLog.h>

@implementation BackgroundIOS

RCT_EXPORT_MODULE();

RCT_EXPORT_METHOD(beginBackgroundTask){
  NSLog(@"Background time in total: %f",[[UIApplication sharedApplication] backgroundTimeRemaining]);
  [self beginBackgroundUpdateTask];
}

RCT_EXPORT_METHOD(endBackgroundTask){
  [self endBackgroundUpdateTask];
  NSLog(@"Background task ended.");
}

- (void) beginBackgroundUpdateTask
{
  self.backgroundUpdateTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
    [self endBackgroundUpdateTask];
  }];
}

- (void) endBackgroundUpdateTask
{
  [[UIApplication sharedApplication] endBackgroundTask: self.backgroundUpdateTask];
  self.backgroundUpdateTask = UIBackgroundTaskInvalid;
}

@end
Run Code Online (Sandbox Code Playgroud)