iOS之退出到后台

iOS为了让设备尽量省电,减少不必要的开销,保持系统流畅,因而对后台机制采用墓碑式的“假后台”(按下Home键至主界面后,应用随即进入后台,但其被冻结,并不能进行任何操作。用户按Home之后,App转入后台进行运行,此时拥有180s后台时间(iOS7)或者600s(iOS6)运行时间可以处理后台操作。一般开发者开发出来的应用程序后台受到限制。

关于墓碑机制,有人这样形象描述:

说简单点,就是手机上一个任务被迫中断时(如有电话打入),系统记录下当前应用程序的状态后,(像把事件记录在墓碑上一样),然后中止程序。当需要恢复时,根据“墓碑”上的内容,将程序恢复到中断之前的状态。这样的一种机制就是“墓碑机制”

官方对其描述如下:


当有内存压力时,会终止app;所以我们会经常发现,一个app退出到后台后,隔了一段时间再次打开,app会重新登录。



当然iOS为了特殊应用也保留了一些可以实现“真后台”的方法,摘取比较常用的:

1、Background Audio,这是后台的音频,这个很早之前便有,也是iOS设备中用得最多的后台应用,调用这个接口可以实现后台的音乐播放

2、Location Services,这是后台的定位,系统会拥有统一页面进行管理。

3、VoIP,后台语音服务,类似Skype通话应用需要调用,可进行后台的语音通话

4、Newsstand,报刊杂志后台自动下载更新,其能够自动实时更新。

5、Background Task  Completion,这个接口早在iOS 4时候便拥有,其可以供任意类型的APP使用,不过在旧系统中,这个接口的后台限制运行时间仅为10分钟,意味着当应用退至后台,其后台运行仅能持续10分钟便会转至休眠状态。iOS 7中对这个接口作出了改变,原来的为连续10分钟,即不论你这10分钟内用户是否关闭屏幕进入休眠状态,应用仍然会在后台等待10分钟完结后推出,而新的改进为假如遇到关闭屏幕休眠的情况,这后台运行的10分钟便会跟随一同休眠,剩余的后台时间将会留待用户再一次唤醒设备才计算。这样后台运行的时间仍然为10分钟,但并不连续,这样做的优点为省电。

如现在有一些词典应用带有后台复制选词功能,实际上其是利用了这个接口,如果用户开启词典后并推出,即使屏幕关闭,但词典仍然在后台运行,电量消耗还是比较大的,在iOS 7上,这个问题可以得到解决。

6、 Remote Notification,这是本次较大的一个改进接口,以往聊天类应用接受推送后点进去需要再收一次信息,这情况在QQ、微信等应用上最为明显。不过拥有了这个接口后,这情况将不复存在,以后推送将能够直接启动后台任务。值得注意的是remote notification支持silent notification(静默推送),这样dropbox这类同步应用可以在后台以最节能的模式实时静默同步了,类似布卡漫画这种也可以推送正在追的漫画的新章节并在后台静默下载,待到下载好再给用户发送一个本地推送,用户点开即看无需再联网。

7、Background Transfer Service,后台上传下载。iOS最接近传统多任务的后台接口,可供任意类型的app调用,无时间限制。应用场景包括后台上传和下载数据,这使得游戏后台更新数据包,后台上传视频等等都成为可能,但是正如其名字,它只能用于处理上传下载这种传输类的任务,类似后台剪切板监控这种它就无能为力了。

iOS 7新增的background fetch,这个后台接口在苹果WWDC 2013上有提及,其会根据用户行为自动调整达到效率最优的后台模式,能够处理不是很有时效性的信息获取。例如一些社交、新闻类的应用的后台信息更新,iOS系统便会根据应用启动频率、时间和当前网络和电量的状况来智能分配每个应用的后台获取频率和启动时长。



当前社交项目,如何使用ios后台

1.当前项目特点:

a. 在保存长连接的情况下,用户一直在线,才能即时接收到消息;

b. 在初始化连接的时候,需要做很多处理,如果经常连接,必然很耗电, 所以尽力在后台的时候,不是时常断开后又连接;

2. 通过以上分析,改选用何种方式来保存app后台运行

voip不行;

静音播放,不清除这种方式,是否可以通过审核

vpns推送,可取的方式,(具体方法: 用户在登录后,发送一个设备的tokenid; 在发送消息时,平台根据对方是离线还是在线,来判断要不要发推送消息)

3.background fetch在该项目中的应用

由于该app在初始化时,需要耗点时间,最好的方式就是通过  后台获取  来处理该工作,这样能保证用户的流畅体验


当一个 iOS 应用被送到后台,它的主线程会被暂停。你用 NSThread detachNewThreadSelector:toTar get:withObject:类方法创建的线程也被挂起了。


我们假设有这么一种情况:

当我们的应用程序从前台被送到了后台。
这时候,我们的程序将执行委托方法 applicationDidEnterBackground。但是,这时候,应用程序只给了我们可怜的一点点时间(也就是秒级别的)来处理东西,然后,所有的线程都被挂起了。
而实际中,我们可能需要更长的时间来完成我们的需要的必要操作:

1.我们需要在应用程序推到后台时,能够有足够的时间来完成将数据保存到远程服务器的操作。

2.有足够的时间记录一些需要的信息操作。

怎么办?!因为我们需要的时间可能会有点长,而默认情况下,iOS没有留给我们足够的时间。
悲剧了……

总需要有一个办法来解决~~~~

向iOS申请,在后台完成一个Long-Running Task任务

想在后台完成一个长期任务,就必须调用 UIApplication  beginBackgroundTaskWithExpirationHandler:实例方法,来向 iOS 借点时间。

//
//  AppDelegate.m
//  Test
//
//  Created by lvxiangan on 4/21/16.
//  Copyright © 2016 lvxiangan. All rights reserved.
//

#import "AppDelegate.h"

@interface AppDelegate ()


@property (assign, nonatomic) UIBackgroundTaskIdentifier bgTaskId;            // 后台任务标记
@property (strong, nonatomic) dispatch_block_t expirationHandler;
@property (assign, nonatomic) BOOL background;
@property (assign, nonatomic) BOOL isLogined;


@end

@implementation AppDelegate


- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    
    UIApplication* app = [UIApplication sharedApplication];
    
    self.isLogined = YES;
    
    __weak AppDelegate* weakSelf = self;
    
    // 创建后台自唤醒,当180s时间结束的时候系统会调用这里面的方法
    self.expirationHandler = ^{
        
        // 每个对 beginBackgroundTaskWithExpirationHandler:方法的调用,必须要相应的调用 endBackgroundTask:方法。来告诉应用程序你已经执行完成了。
        // // 标记指定的后台任务完成
        [app endBackgroundTask:weakSelf.bgTaskId];
        // 销毁后台任务标识符
        weakSelf.bgTaskId = UIBackgroundTaskInvalid;
        
        
//        weakSelf.bgTaskId = [app beginBackgroundTaskWithExpirationHandler:weakSelf.expirationHandler];
        NSLog(@"Expired");
        
//        // Restart the background task so we can run forever.
//        [weakSelf runBackgroundTask];
        
    };
    
    return YES;
}

- (void)applicationDidBecomeActive:(UIApplication *)application
{
    self.background = NO;
}

- (void)applicationDidEnterBackground:(UIApplication *)application
{
    // 当登陆状态才启动后台操作
    if (self.isLogined)
    {
        NSLog(@"Entered background");
        
        self.bgTaskId = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:self.expirationHandler];
        self.background = YES;
//        [self runBackgroundTask];
        
    }
}


- (void)runBackgroundTask
{
    
    // 当登陆状态才进入后台循环
    if (self.isLogined)
    {
        NSLog(@"状态:已登录,开启后台进程");
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            
            NSInteger count = 0;
            while (self.background)
            {
                NSLog(@"进入后台进程循环");
                [NSThread sleepForTimeInterval:1];
                count++;
                
                // 每60s进行一次开启定位,刷新后台时间
                if (count > 60)
                {
                    count = 0;
//                    [locationManager startUpdatingLocation];
                    NSLog(@"开始请求--位置服务");
                    [NSThread sleepForTimeInterval:1];
//                    [locationManager stopUpdatingLocation];
                    NSLog(@"停止位置服务");
                }
                
                
                if (!self.isLogined)
                {
                    NSLog(@"未登录或者掉线状态下,退出");
                    [[UIApplication sharedApplication] endBackgroundTask:self.bgTaskId];
                    return;
                }
                
                
                NSTimeInterval backgroundTimeRemaining = [[UIApplication sharedApplication] backgroundTimeRemaining];
                NSLog(@"Background Time Remaining = %.02f Seconds",backgroundTimeRemaining);
                
                
                if (backgroundTimeRemaining < 10)
                {
                    NSLog(@"请结束客户端重新登录");
                    [[NSNotificationCenter defaultCenter] postNotificationName:@"MessageUpdate" object:@"请结束客户端重新登录"];
                }

            }
            
        });
    }
}

@end




向iOS申请,在后台无限时间

经过证明,即使时执行Long-Running Task 任务,当程序被调到后台后,也是有时间限制的。一般为10分总(600s)。如何向程序申请无限时间呢?!

那就欺骗iOS系统吧。让它感觉你的程序还是在运行。
那就在后台用 AVAudioPlayer无限循环播放一个音频文件。
呵呵,如果播放一个无声音的音频文件呢?!! 当程序到后台后,继续完成Long-Running <wbr>Task <wbr>任务够淫荡的啊!!!
步骤:
1.在plist文件中加入背景播放的支持。
加入项:Required background modes。并设置为:audio

2.初始化一个AVAudioPlayer音频,并且无限制的播放下去。

- (void)viewDidLoad

{

    [super viewDidLoad];

    

    dispatch_queue_t dispatchQueue =dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

    dispatch_async(dispatchQueue, ^(void) {

        NSError *audioSessionError = nil;

        AVAudioSession *audioSession = [AVAudioSession sharedInstance];

        if ([audioSession setCategory:AVAudioSessionCategoryPlaybackerror:&audioSessionError]){

            NSLog(@"Successfully set the audio session.");

        } else {

            NSLog(@"Could not set the audio session");

        }

        

         

        NSBundle *mainBundle = [NSBundle mainBundle];

        NSString *filePath = [mainBundle pathForResource:@"mySong" ofType:@"mp3"];

        NSData *fileData = [NSData dataWithContentsOfFile:filePath];

        NSError *error = nil;

      

        self.audioPlayer = [[AVAudioPlayer allocinitWithData:fileData error:&error];

        

        if (self.audioPlayer != nil){

            self.audioPlayer.delegate = self;


            [self.audioPlayer setNumberOfLoops:-1];

             if ([self.audioPlayer prepareToPlay] && [self.audioPlayer play]){

                 NSLog(@"Successfully started playing...");

             } else {

                 NSLog(@"Failed to play.");

             }

         } else {

            

         }

    });

}



所有参考资料源自互联网




  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值