溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶(hù)服務(wù)條款》

如何解決iOS應(yīng)用進(jìn)入后臺(tái)后計(jì)時(shí)器和位置更新停止問(wèn)題

發(fā)布時(shí)間:2021-07-21 09:49:04 來(lái)源:億速云 閱讀:375 作者:小新 欄目:移動(dòng)開(kāi)發(fā)

這篇文章主要介紹如何解決iOS應(yīng)用進(jìn)入后臺(tái)后計(jì)時(shí)器和位置更新停止問(wèn)題,文中介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們一定要看完!

由于iOS系統(tǒng)為“偽后臺(tái)”運(yùn)行模式,當(dāng)按下HOME鍵時(shí),如程序不做任何操作,應(yīng)用會(huì)有5秒的執(zhí)行緩沖時(shí)間,隨機(jī)程序被掛起,所有任務(wù)終端,包括計(jì)時(shí)器和位置更新等操作,但程序打開(kāi)后臺(tái)模式開(kāi)關(guān)后,部分任務(wù)可以再后臺(tái)執(zhí)行,如音頻,定位,藍(lán)牙,下載,VOIP,即便如此,程序的后臺(tái)運(yùn)行最多可以延長(zhǎng)594秒(大概是10分鐘)。不幸的是,程序在聲明后臺(tái)模式后很有可能在app上架時(shí)被拒?;诖?,我研究出了不用申明后臺(tái)模式就能讓計(jì)時(shí)器和定位在app進(jìn)入前臺(tái)時(shí)繼續(xù)運(yùn)行的方法。

  實(shí)現(xiàn)原理如下:

  利用iOS的通知機(jī)制,在程序進(jìn)入后臺(tái)和再次回到前臺(tái)時(shí)發(fā)送通知,并記錄進(jìn)入后臺(tái)的當(dāng)前時(shí)間和再次回到前臺(tái)的當(dāng)前時(shí)間,算出兩者的時(shí)間間隔,在程序任何需要的地方添加通知監(jiān)聽(tīng)者,在監(jiān)聽(tīng)方法中執(zhí)行代碼塊,代碼塊內(nèi)參數(shù)為通知對(duì)象和計(jì)算出的時(shí)間間隔。以計(jì)時(shí)器為例,程序再進(jìn)入后臺(tái)后,計(jì)時(shí)器停止運(yùn)行,此時(shí)運(yùn)用上述方法,在程序再次回到前臺(tái)時(shí)執(zhí)行代碼塊中內(nèi)容,將程序進(jìn)入后臺(tái)時(shí)計(jì)時(shí)器的當(dāng)前時(shí)間間隔加上代碼塊的時(shí)間間隔參數(shù)就能使計(jì)時(shí)器準(zhǔn)確無(wú)誤地計(jì)時(shí)。廢話不多說(shuō),上代碼:

在AppDelegate.m實(shí)現(xiàn)文件中:

- (void)applicationDidEnterBackground:(UIApplication *)application {
  // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
  // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
  [[NSNotificationCenter defaultCenter]postNotificationName:UIApplicationDidEnterBackgroundNotification object:nil];
}
- (void)applicationWillEnterForeground:(UIApplication *)application {
  // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
  [[NSNotificationCenter defaultCenter]postNotificationName:UIApplicationWillEnterForegroundNotification object:nil];
}

代碼說(shuō)明:程序進(jìn)入后臺(tái)后,利用系統(tǒng)通知機(jī)制通知程序進(jìn)入后臺(tái)和再次回到前臺(tái),監(jiān)聽(tīng)對(duì)象為所有對(duì)象。

之后定義一個(gè)處理程序進(jìn)入后臺(tái)的類(lèi)YTHandlerEnterBackground

//
// YTHandlerEnterBackground.h
// 分時(shí)租賃
//
// Created by 柯其譜 on 17/2/24.
// Copyright © 2017年 柯其譜. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
/** 進(jìn)入后臺(tái)block typedef */
typedef void(^YTHandlerEnterBackgroundBlock)(NSNotification * _Nonnull note, NSTimeInterval stayBackgroundTime);
/** 處理進(jìn)入后臺(tái)并計(jì)算留在后臺(tái)時(shí)間間隔類(lèi) */
@interface YTHandlerEnterBackground : NSObject
/** 添加觀察者并處理后臺(tái) */
+ (void)addObserverUsingBlock:(nullable YTHandlerEnterBackgroundBlock)block;
/** 移除后臺(tái)觀察者 */
+ (void)removeNotificationObserver:(nullable id)observer;
@end

在YTHandlerEnterBackground.m實(shí)現(xiàn)文件中:

//
// YTHandlerEnterBackground.m
// 分時(shí)租賃
//
// Created by 柯其譜 on 17/2/24.
// Copyright &copy; 2017年 柯其譜. All rights reserved.
//
#import "YTHandlerEnterBackground.h"
@implementation YTHandlerEnterBackground
+ (void)addObserverUsingBlock:(YTHandlerEnterBackgroundBlock)block {
  __block CFAbsoluteTime enterBackgroundTime;
  [[NSNotificationCenter defaultCenter]addObserverForName:UIApplicationDidEnterBackgroundNotification object:nil queue:nil usingBlock:^(NSNotification * _Nonnull note) {
    if (![note.object isKindOfClass:[UIApplication class]]) {
      enterBackgroundTime = CFAbsoluteTimeGetCurrent();
    }
  }];
  __block CFAbsoluteTime enterForegroundTime;
  [[NSNotificationCenter defaultCenter]addObserverForName:UIApplicationWillEnterForegroundNotification object:nil queue:nil usingBlock:^(NSNotification * _Nonnull note) {
    if (![note.object isKindOfClass:[UIApplication class]]) {
      enterForegroundTime = CFAbsoluteTimeGetCurrent();
      CFAbsoluteTime timeInterval = enterForegroundTime-enterBackgroundTime;
      block? block(note, timeInterval): nil;
    }
  }];
}
+ (void)removeNotificationObserver:(id)observer {
  if (!observer) {
    return;
  }
  [[NSNotificationCenter defaultCenter]removeObserver:observer name:UIApplicationDidEnterBackgroundNotification object:nil];
  [[NSNotificationCenter defaultCenter]removeObserver:observer name:UIApplicationWillEnterForegroundNotification object:nil];
}
@end

該類(lèi)實(shí)現(xiàn)了用來(lái)添加通知監(jiān)聽(tīng)者并處理后臺(tái)和移除通知監(jiān)聽(tīng)者的方法,需要注意的是,在addObserverUsingBlock方法中,必須有if (![note.object isKindOfClass:[UIApplication class]])的判斷,否則addObserverForName方法中的代碼塊會(huì)執(zhí)行多次,此代碼執(zhí)行了兩次。addObserverUsingBlock方法是在viewWillAppear方法中調(diào)用添加通知監(jiān)聽(tīng)者,在viewWillDisappear方法中調(diào)用移除通知監(jiān)聽(tīng)者。

例如,在使用了計(jì)時(shí)器NSTimer控制器中:

- (void)viewWillAppear:(BOOL)animated {
  [super viewWillAppear:animated];
  [YTHandlerEnterBackground addObserverUsingBlock:^(NSNotification * _Nonnull note, NSTimeInterval stayBackgroundTime) {
    self.rentTimerInterval = self.rentTimerInterval-stayBackgroundTime;
  }];
}
- (void)viewWillDisappear:(BOOL)animated {
  [super viewWillDisappear:animated];
  [self.timer invalidate];
  [YTHandlerEnterBackground removeNotificationObserver:self];
}

我定義了一個(gè)倒計(jì)時(shí)5分鐘的計(jì)時(shí)器對(duì)象timer屬性,并定義了一個(gè)計(jì)時(shí)器當(dāng)前倒計(jì)時(shí)時(shí)間間隔rentTimerInterval屬性,在添加通知監(jiān)聽(tīng)者代碼塊中,rentTimerInterval等于進(jìn)入后臺(tái)時(shí)的倒計(jì)時(shí)時(shí)間間隔減去程序停留在后臺(tái)的時(shí)間間隔,當(dāng)計(jì)時(shí)器再次回到前臺(tái)時(shí),計(jì)時(shí)器此時(shí)的時(shí)間間隔是持續(xù)的。雖然計(jì)時(shí)器并未在后臺(tái)持續(xù)運(yùn)行,但是使用了此方法,同樣實(shí)現(xiàn)了計(jì)時(shí)器的正確即時(shí)。

同樣的,當(dāng)程序存在位置更新功能時(shí),當(dāng)程序進(jìn)入后臺(tái),位置服務(wù)對(duì)象會(huì)自動(dòng)停止更新,此時(shí)的作法依然是調(diào)用上述兩個(gè)處理進(jìn)入后臺(tái)的方法,使得程序進(jìn)入后臺(tái)后,再次開(kāi)始定位:

在需要位置更新的類(lèi)中:

- (void)viewWillAppear:(BOOL)animated {
  [super viewWillAppear:animated];
  self.locService.delegate = self;
  [self.locService startUserLocationService];
  //進(jìn)入后臺(tái)再進(jìn)入前臺(tái)重新開(kāi)始定位
  [YTHandlerEnterBackground addObserverUsingBlock:^(NSNotification * _Nonnull note, NSTimeInterval stayBackgroundTime) {
    [self.locService startUserLocationService];
  }];
}
- (void)viewWillDisappear:(BOOL)animated {
  [super viewWillDisappear:animated];
  //停止定位
  self.locService.delegate = nil;
  [self.locService stopUserLocationService];
  //移除后臺(tái)監(jiān)聽(tīng)
  [YTHandlerEnterBackground removeNotificationObserver:self];
}

此處使用的是百度地圖SDK

利用這種方法,像是計(jì)時(shí)器和位置更新等需要在后臺(tái)運(yùn)行的任務(wù)都可以實(shí)現(xiàn)相應(yīng)的需求,只是麻煩的是,在任何需要的類(lèi)中都要調(diào)用這兩種方法,你可以根據(jù)自己的需求,在程序進(jìn)入后臺(tái)和再次回到前臺(tái)時(shí)添加別的參數(shù)(通知對(duì)象參數(shù)是必須的),例如保存進(jìn)入后臺(tái)前的操作等等?;蚴嵌x不同的添加通知監(jiān)聽(tīng)者的方法以實(shí)現(xiàn)不同的需求。

以上是“如何解決iOS應(yīng)用進(jìn)入后臺(tái)后計(jì)時(shí)器和位置更新停止問(wèn)題”這篇文章的所有內(nèi)容,感謝各位的閱讀!希望分享的內(nèi)容對(duì)大家有幫助,更多相關(guān)知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

ios
AI