最近新開一個項目,要使用UDP通訊來和智能設備進行數據傳輸。大家都知道,在iOS平台上,由於蘋果的后台機制,會有以下問題:
- 當程序退到后台的時候,一段時間后(大概300s)所有線程被掛起。
- 線程掛起后,系統就會回收所有的socket資源,那么socket連接就會被關閉,因此無法再進行數據的傳輸。
解決方案:
1.
2.在AppDelegate中:
1 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 2 { 3 //socket心跳包 4 NSTimer *socketTimer = [NSTimer scheduledTimerWithTimeInterval:10.0 target:self selector:@selector(socketTimer) userInfo:nil repeats:YES]; 5 [[NSRunLoop mainRunLoop] addTimer:socketTimer forMode:NSRunLoopCommonModes]; 6 return YES; 7 }
1 //socket心跳包 2 - (void)socketTimer 3 { 4 [[NSNotificationCenter defaultCenter] postNotificationName:@"SOCKETTIMER" object:nil];//計時器內周期性去調用socket心跳包,保持連接。 5 }
1 - (void)applicationDidEnterBackground:(UIApplication *)application 2 { 3 // 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. 4 // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 5 6 [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:nil];//開啟后台任務 7 8 } 9 10 11 - (void)applicationWillEnterForeground:(UIApplication *)application 12 { 13 // 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. 14 [[UIApplication sharedApplication] endBackgroundTask:UIBackgroundTaskInvalid];//結束后台任務 15 }
注意:經測試使用以上方法在App上架時會被蘋果審核組拒絕。
2019年8月22日加入以上代碼段發布,依舊被拒絕。
修改方案(換一種后台運行方法:)【可以審核通過✅】
AppDelegate.m
@interface AppDelegate () { UIBackgroundTaskIdentifier _backIden; } @property (nonatomic, assign) NSInteger number; @property (nonatomic, strong) NSTimer *timer; @end
/// 退到后台 - (void)applicationDidEnterBackground:(UIApplication *)application { [self beginTask]; [UIApplication sharedApplication].applicationIconBadgeNumber = 0; self.number = 0; if (@available(iOS 10.0, *)) { self.timer = [NSTimer scheduledTimerWithTimeInterval:1.f repeats:YES block:^(NSTimer * _Nonnull timer) { self.number++; [UIApplication sharedApplication].applicationIconBadgeNumber = self.number; if (self.number == 9) { [self.timer invalidate]; } NSLog(@"%@==%ld ",[NSDate date],(long)self.number); }]; } else { // Fallback on earlier versions } } /// app進入后台后保持運行 - (void)beginTask { _backIden = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{ //如果在系統規定時間3分鍾內任務還沒有完成,在時間到之前會調用到這個方法 [self endBack]; }]; } /// 結束后台運行,讓app掛起 - (void)endBack { //切記endBackgroundTask要和beginBackgroundTaskWithExpirationHandler成對出現 [[UIApplication sharedApplication] endBackgroundTask:_backIden]; _backIden = UIBackgroundTaskInvalid; }