React-native 应用程序永远不会重新启动以处理 iOS 中的位置更新
Posted
技术标签:
【中文标题】React-native 应用程序永远不会重新启动以处理 iOS 中的位置更新【英文标题】:React-native app is never relaunched to handle location updates in iOS 【发布时间】:2017-10-30 19:59:22 【问题描述】:我正在尝试在应用终止时在 react-native 应用中处理位置更新。经过几天未能让react-native-background-geolocation 或 CLLocationManager 始终如一地工作,我现在尝试使用intuit/LocationManager pod,但我的应用程序没有重新启动以响应位置更新(或者它只是没有记录它们? )
这是 Intuit 处理基于位置的启动的示例:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
// If you start monitoring significant location changes and your app is subsequently terminated, the system automatically relaunches the app into the background if a new event arrives.
// Upon relaunch, you must still subscribe to significant location changes to continue receiving location events.
if ([launchOptions objectForKey:UIApplicationLaunchOptionsLocationKey])
INTULocationManager *locMgr = [INTULocationManager sharedInstance];
[locMgr subscribeToSignificantLocationChangesWithBlock:^(CLLocation *currentLocation, INTULocationAccuracy achievedAccuracy, INTULocationStatus status)
// This block will be executed with the details of the significant location change that triggered the background app launch,
// and will continue to execute for any future significant location change events as well (unless canceled).
];
return YES;
这是我的代码:
- (BOOL) application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
NSLog(@"--- Initializing application");
INTULocationManager *locMgr = [INTULocationManager sharedInstance];
[locMgr subscribeToSignificantLocationChangesWithBlock:^(CLLocation *currentLocation, INTULocationAccuracy achievedAccuracy, INTULocationStatus status)
// This block will be executed with the details of the significant location change that triggered the background app launch,
// and will continue to execute for any future significant location change events as well (unless canceled).
NSLog(@"--- location update");
];
_app = application;
id<RCTBridgeDelegate> moduleInitialiser = self;
RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:moduleInitialiser launchOptions:launchOptions];
RCTRootView *rootView = [[RCTRootView alloc]
initWithBridge:bridge
moduleName:@"GoNote"
initialProperties:nil
];
rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1];
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
UIViewController *rootViewController = [UIViewController new];
rootViewController.view = rootView;
self.window.rootViewController = rootViewController;
[self.window makeKeyAndVisible];
[FIRApp configure];
[[UNUserNotificationCenter currentNotificationCenter] setDelegate:self];
return YES;
为了测试这一点,我在模拟器中打开应用程序,等待位置更新(应用程序记录“位置更新”),然后关闭应用程序(双击 command-shift-h 并滑开应用程序)。然后我等待模拟器的调试位置设置为“高速公路驱动器”。
据我了解,应用程序应该在后台启动,我应该看到日志“正在初始化应用程序”和“位置更新”,但这从未发生过。
我的info.plist
文件中有这些条目:
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>CHANGEME: NSLocationAlwaysAndWhenInUseUsageDescription</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>CHANGEME: NSLocationAlwaysUsageDescription</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>CHANGEME: NSLocationWhenInUseUsageDescription</string>
<key>NSMotionUsageDescription</key>
<string>CHANGEME: NSMotionUsageDescription</string>
<key>UIBackgroundModes</key>
<array>
<string>fetch</string>
<string>remote-notification</string>
<string>location</string>
</array>
为什么我的应用不处理位置更新?
【问题讨论】:
你能得到这个工作吗?我将时间花在完全相同的场景中。 【参考方案1】:ios 有几个选项可以在后台正确运行应用程序。这些方法在 iOS 中启用。我们将使用您的应用程序将使用且我们需要的那个。我们可以在 UIBackgroundModes 数组中看到的所有服务:
点击此链接:- https://developer.apple.com/documentation/corelocation/cllocationmanager/1620568-allowsbackgroundlocationupdates?language=objc
如果应用程序在前台,我们可以简单地停止监视并在间隔后重新启动它,例如使用 NSTimer。在这种情况下,我们必须考虑应用程序的生命周期。应用程序在后台运行,空闲时停止工作。
在 iOS 原生中,我们无法更改系统更新用户位置的时间间隔。如果有 GPS 信号,IOS 会每秒定期更新位置。
应用程序每 5 分钟更新一次后台位置,请执行以下操作:
转到您的项目“目标”-> 功能-> 后台模式-> 选择位置更新
我的最后一个过程是在后台使用 NSTimer,方法是使用 UIApplication:beginBackgroundTaskWithExpirationHandler:。此计时器会在应用程序在后台运行时定期触发。
现在,当您的应用在后台时,让定位工作,并将坐标发送到网络服务或每 5 分钟对它们执行任何操作,如下面的代码所示。
AppDelegate.m
//update location
-(void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
NSLog(@"Location: %f, %f", newLocation.coordinates.longtitude, newLocation.coordinates.latitude);
//run background task
-(voud)runBackgroundTask: (int) time
//check if application is in background mode
if ([UIApplication sharedApplication].applicationState == UIApplicationStateBackground)
//create UIBackgroundTaskIdentifier and create tackground task, which starts after time
__block UIBackgroundTaskIdentifier bgTask = [app beginBackgroundTaskWithExpirationHandler:^
[app endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
];
dispatch_async(dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^
NSTimer* t = [NSTimer scheduledTimerWithTimeInterval:time target:self selector:@selector(startTrackingBg) userInfo:nil repeats:NO];
[[NSRunLoop currentRunLoop] addTimer:t forMode:NSDefaultRunLoopMode];
[[NSRunLoop currentRunLoop] run];
);
//starts when application switchs into backghround
- (void)applicationDidEnterBackground:(UIApplication *)application
//check if application status is in background
if ([UIApplication sharedApplication].applicationState == UIApplicationStateBackground)
NSLog(@"start backgroun tracking from appdelegate");
//start updating location with location manager
[locationManager startUpdatingLocation];
//change locationManager status after time
[self runBackgroundTask:20];
//starts with background task
-(void)startTrackingBg
//write background time remaining
NSLog(@"backgroundTimeRemaining: %.0f", [[UIApplication sharedApplication] backgroundTimeRemaining]);
//set default time
int time = 60;
//if locationManager is ON
if (locationStarted == TRUE )
//stop update location
[locationManager stopUpdatingLocation];
locationStarted = FALSE;
else
//start updating location
[locationManager startUpdatingLocation];
locationStarted = TRUE;
//ime how long the application will update your location
time = 5;
[self runBackgroundTask:time];
//application switchs back from background
- (void)applicationWillEnterForeground:(UIApplication *)application
locationStarted = FALSE;
//stop updating
[locationManager stopUpdatingLocation];
【讨论】:
为什么这么复杂?为什么必须在 didEnterBackground 生命周期方法中检查应用是否在后台?当应用程序在前台时,applicationDidEnterBackground
会被调用吗?为什么在applicationDidEnterBackground
中调用startUpdatingLocation
,然后在20 秒后在startTrackingBg
中再次调用它?为什么停止startTrackingBg
中的位置更新?当您提到“背景”时,是否包括应用程序终止的时间?以上是关于React-native 应用程序永远不会重新启动以处理 iOS 中的位置更新的主要内容,如果未能解决你的问题,请参考以下文章
与本机应用程序集成时,React-native 应用程序在每次导航时都会重新启动