iOS系統在後臺執行程式時,有嚴格的限制,為了更好地管理資源和電池壽命,iOS會限制應用程式在後臺的執行時間。然而,iOS提供了一些特定的策略和技術,使得應用程式可以在特定場景下保持後臺執行(即“後臺保活”)。以下是iOS中幾種常見的後臺保活方案,並附上示例程式碼:
一、後臺任務
利用beginBackgroundTask
和endBackgroundTask
來執行後臺任務。後臺任務將在應用程式進入後臺時仍能保持有限的時間執行任務。
#import <UIKit/UIKit.h>
@interface AppDelegate : UIResponder <UIApplicationDelegate>
@property (strong, nonatomic) UIWindow *window;
@property (assign, nonatomic) UIBackgroundTaskIdentifier bgTask;
@end
@implementation AppDelegate
- (void)applicationDidEnterBackground:(UIApplication *)application {
self.bgTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
[[UIApplication sharedApplication] endBackgroundTask:self.bgTask];
self.bgTask = UIBackgroundTaskInvalid;
}];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// 在這裡執行你的後臺任務
for (int i = 0; i < 100; i++) {
NSLog(@"Background task running %d", i);
[NSThread sleepForTimeInterval:1];
}
[[UIApplication sharedApplication] endBackgroundTask:self.bgTask];
self.bgTask = UIBackgroundTaskInvalid;
});
}
@end
二、使用Background Fetch
利用Background Fetch,系統會間歇性地喚醒應用程式,以便它可以執行任務或獲取資料。需要在Xcode的“Capabilities”中開啟Background Modes,並勾選“Background fetch”。
#import <UIKit/UIKit.h>
@interface AppDelegate : UIResponder <UIApplicationDelegate>
@property (strong, nonatomic) UIWindow *window;
@end
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[application setMinimumBackgroundFetchInterval:UIApplicationBackgroundFetchIntervalMinimum];
return YES;
}
- (void)application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
// 在這裡執行你的後臺資料獲取任務
NSLog(@"Background fetch started");
// 模擬資料獲取
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"Background fetch completed");
completionHandler(UIBackgroundFetchResultNewData);
});
}
@end
三、使用遠端通知(Silent Push Notification)
利用遠端通知,在接收到通知時,系統會喚醒應用程式執行指定的任務。需要開啟Remote notifications,在Application Capabilities中勾選“Remote notifications”。
#import <UIKit/UIKit.h>
#import <UserNotifications/UserNotifications.h>
@interface AppDelegate : UIResponder <UIApplicationDelegate, UNUserNotificationCenterDelegate>
@property (strong, nonatomic) UIWindow *window;
@end
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[UNUserNotificationCenter currentNotificationCenter].delegate = self;
[[UNUserNotificationCenter currentNotificationCenter] requestAuthorizationWithOptions:(UNAuthorizationOptionAlert | UNAuthorizationOptionSound | UNAuthorizationOptionBadge) completionHandler:^(BOOL granted, NSError * _Nullable error) {
if (granted) {
[[UIApplication sharedApplication] registerForRemoteNotifications];
}
}];
return YES;
}
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
// 在這裡處理收到的遠端通知
NSLog(@"Received remote notification");
// 模擬處理任務
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"Handled remote notification");
completionHandler(UIBackgroundFetchResultNewData);
});
}
@end
四、使用特定的後臺模式(Background Modes)
iOS提供了一些特定的後臺模式,允許程式在後臺持續執行。常見的後臺模式包括:
- Audio: 允許應用程式在後臺播放音訊。
- Location: 允許應用程式在後臺持續獲取位置更新。
- VoIP: 允許應用程式在後臺偵聽VoIP事件。
- Bluetooth: 允許應用程式與藍芽裝置通訊。
1. Audio後臺模式
需要在Xcode的“Capabilities”中開啟Background Modes,並勾選“Audio, AirPlay, and Picture in Picture”。
#import <AVFoundation/AVFoundation.h>
@interface AppDelegate ()
@property (nonatomic, strong) AVAudioPlayer *audioPlayer;
@end
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
NSError *error = nil;
NSURL *audioURL = [[NSBundle mainBundle] URLForResource:@"audioFileName" withExtension:@"mp3"];
self.audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:audioURL error:&error];
[self.audioPlayer prepareToPlay];
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
[audioSession setCategory:AVAudioSessionCategoryPlayback error:&error];
[audioSession setActive:YES error:&error];
return YES;
}
- (void)applicationDidEnterBackground:(UIApplication *)application {
[self.audioPlayer play];
}
@end
2. Location後臺模式
需要在Xcode的“Capabilities”中開啟Background Modes,並勾選“Location updates”。
#import <CoreLocation/CoreLocation.h>
@interface AppDelegate () <CLLocationManagerDelegate>
@property (nonatomic, strong) CLLocationManager *locationManager;
@end
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
[self.locationManager requestAlwaysAuthorization];
return YES;
}
- (void)applicationDidEnterBackground:(UIApplication *)application {
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
[self.locationManager startUpdatingLocation];
}
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations {
CLLocation *location = [locations lastObject];
NSLog(@"Background location: %@", location);
}
@end
五、使用後臺URLSession
使用NSURLSession
來執行後臺下載和上傳任務。需要在後臺配置中開啟Background Modes,並勾選“Background fetch”和“Remote notifications”。
#import <UIKit/UIKit.h>
@interface AppDelegate : UIResponder <UIApplicationDelegate, NSURLSessionDelegate, NSURLSessionDownloadDelegate>
@property (strong, nonatomic) UIWindow *window;
@property (nonatomic, strong) NSURLSession *backgroundSession;
@end
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
NSURLSessionConfiguration *config = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:@"com.example.background"];
self.backgroundSession = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:nil];
return YES;
}
- (void)applicationDidEnterBackground:(UIApplication *)application {
NSURL *url = [NSURL URLWithString:@"http://example.com/largefile.zip"];
NSURLSessionDownloadTask *downloadTask = [self.backgroundSession downloadTaskWithURL:url];
[downloadTask resume];
}
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location {
NSLog(@"Download completed: %@", location);
// 處理下載結果,比如儲存檔案
}
@end
透過上述幾種方案,我們可以在iOS應用程式中實現各種場景下的後臺保活。每種方案都有其適用的場景和限制,開發者需要根據應用的實際需求和系統提供的特性,選擇合適的後臺保活方案。