前言

一般APP在按下Home键被挂起后,这时APP的 backgroundTimeRemaining 也就是后台运行时间大约只有3分钟,如果在退出APP后,过十几二十二分钟或者更长时间再回到APP,APP就会回到刚打开时的状态,也就是首页;有的项目在被挂起后需要在后台运行一段时间,使有足够的时间来完成与服务器对接的操作,或者需要一直运行的需求;如果需要,则在APP被挂起后,申请后台,来延长后台运行时间。

APP申请后台运行的方式有几种:

播放音乐

定位 

Newsstand downloads

fetch 等;

这里主要说下后台播放无声音乐(其实是不播放),采用哪种方式,对应勾选上图;我的项目中有音频播放需求,如果没有,那就找一个播放音频的理由,或者用其他方式实现。

实现

这里采用了两个单例:电话监控(XKTelManager)、后台运行(XKBGRunManager),电话监控可以忽略,视情况而用;采用单例是为了方便管理;

XKTelManager.h

#import <Foundation/Foundation.h>

@interface XKTelManager : NSObject
///是否在后台运行
@property (nonatomic,assign) BOOL inBackgroundRun;
+ (XKTelManager *)sharedManager;
/**
来电监听
*/
- (void)startMonitor;
@end

XKTelManager.m

#import "XKTelManager.h"
#import "XKBGRunManager.h"
#import <CoreTelephony/CTCallCenter.h>
#import <CoreTelephony/CTCall.h> static XKTelManager *_sharedManger;
@interface XKTelManager()
@property (nonatomic, strong) CTCallCenter *callCenter;
@end
@implementation XKTelManager
+ (XKTelManager *)sharedManager{
static dispatch_once_t onceTelSingle;
dispatch_once(&onceTelSingle, ^{
if (!_sharedManger) {
_sharedManger = [[XKTelManager alloc]init];
}
});
return _sharedManger;
}
- (instancetype)init{
self = [super init];
if (self) {
_inBackgroundRun = NO;
}
return self;
}
#pragma mark -********* 监听电话相关
- (void)startMonitor {
__weak typeof(self) weakSelf = self;
_callCenter = [[CTCallCenter alloc] init];
_callCenter.callEventHandler = ^(CTCall * call) {
///如果已经进入后台了,不做任何操作
if (weakSelf.inBackgroundRun) {
return;
}
///APP未进入后台
if ([call.callState isEqualToString:CTCallStateDisconnected]){
NSLog(@"电话 --- 断开连接");
[[XKBGRunManager sharedManager] stopBGRun];
}
else if ([call.callState isEqualToString:CTCallStateConnected]){
NSLog(@"电话 --- 接通");
}
else if ([call.callState isEqualToString:CTCallStateIncoming]){
NSLog(@"电话 --- 待接通");
[[XKBGRunManager sharedManager] startBGRun];
}
else if ([call.callState isEqualToString:CTCallStateDialing]){
NSLog(@"电话 --- 拨号中");
[[XKBGRunManager sharedManager] startBGRun];
}
else {
NSLog(@"电话 --- 无操作");
} };
}
@end

XKBGRunManager.h

#import <Foundation/Foundation.h>

@interface XKBGRunManager : NSObject
+ (XKBGRunManager *)sharedManager; /**
开启后台运行
*/
- (void)startBGRun; /**
关闭后台运行
*/
- (void)stopBGRun;
@end

XKBGRunManager.m

#import "XKBGRunManager.h"
///循环时间
static NSInteger _circulaDuration = ;
static XKBGRunManager *_sharedManger;
@interface XKBGRunManager()
@property (nonatomic,assign) UIBackgroundTaskIdentifier task;
///后台播放
@property (nonatomic,strong) AVAudioPlayer *playerBack;
@property (nonatomic, strong) NSTimer *timerAD;
///用来打印测试
@property (nonatomic, strong) NSTimer *timerLog;
@property (nonatomic,assign) NSInteger count;
@end
@implementation XKBGRunManager{
CFRunLoopRef _runloopRef;
dispatch_queue_t _queue;
}
+ (XKBGRunManager *)sharedManager{
static dispatch_once_t onceRunSingle;
dispatch_once(&onceRunSingle, ^{
if (!_sharedManger) {
_sharedManger = [[XKBGRunManager alloc]init];
}
});
return _sharedManger;
}
/// 重写init方法,初始化音乐文件
- (instancetype)init {
if (self = [super init]) {
[self setupAudioSession];
_queue = dispatch_queue_create("com.audio.inBackground", NULL);
//静音文件
NSString *filePath = [[NSBundle mainBundle] pathForResource:@"****" ofType:@"mp3"];
NSURL *fileURL = [[NSURL alloc] initFileURLWithPath:filePath];
self.playerBack = [[AVAudioPlayer alloc] initWithContentsOfURL:fileURL error:nil];
[self.playerBack prepareToPlay];
// 0.0~1.0,默认为1.0
self.playerBack.volume = 0.01;
// 循环播放
self.playerBack.numberOfLoops = -;
}
return self;
} - (void)setupAudioSession {
// 新建AudioSession会话
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
// 设置后台播放
NSError *error = nil;
[audioSession setCategory:AVAudioSessionCategoryPlayback withOptions:AVAudioSessionCategoryOptionMixWithOthers error:&error];
if (error) {
NSLog(@"Error setCategory AVAudioSession: %@", error);
}
NSLog(@"%d", audioSession.isOtherAudioPlaying);
NSError *activeSetError = nil;
// 启动AudioSession,如果一个前台app正在播放音频则可能会启动失败
[audioSession setActive:YES error:&activeSetError];
if (activeSetError) {
NSLog(@"Error activating AVAudioSession: %@", activeSetError);
}
} /**
启动后台运行
*/
- (void)startBGRun{
[self.playerBack play];
[self applyforBackgroundTask];
///确保两个定时器同时进行
dispatch_async(_queue, ^{
self.timerLog = [[NSTimer alloc] initWithFireDate:[NSDate date] interval: target:self selector:@selector(log) userInfo:nil repeats:YES];
self.timerAD = [[NSTimer alloc] initWithFireDate:[NSDate date] interval:_circulaDuration target:self selector:@selector(startAudioPlay) userInfo:nil repeats:YES];
_runloopRef = CFRunLoopGetCurrent();
[[NSRunLoop currentRunLoop] addTimer:self.timerAD forMode:NSDefaultRunLoopMode];
[[NSRunLoop currentRunLoop] addTimer:self.timerLog forMode:NSDefaultRunLoopMode];
CFRunLoopRun();
});
} /**
申请后台
*/
- (void)applyforBackgroundTask{
_task =[[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
dispatch_async(dispatch_get_main_queue(), ^{
[[UIApplication sharedApplication] endBackgroundTask:_task];
_task = UIBackgroundTaskInvalid;
});
}];
} /**
打印
*/
- (void)log{
_count = _count + ;
NSLog(@"_count = %ld",_count)
} /**
检测后台运行时间
*/
- (void)startAudioPlay{
_count = ;
dispatch_async(dispatch_get_main_queue(), ^{
if ([[UIApplication sharedApplication] backgroundTimeRemaining] < 61.0) {
NSLog(@"后台快被杀死了");
[self.playerBack play];
[self applyforBackgroundTask];
}
else{
NSLog(@"后台继续活跃呢");
}///再次执行播放器停止,后台一直不会播放音乐文件
[self.playerBack stop];
});
} /**
停止后台运行
*/
- (void)stopBGRun{
if (self.timerAD) {
CFRunLoopStop(_runloopRef);
[self.timerLog invalidate];
self.timerLog = nil;
// 关闭定时器即可
[self.timerAD invalidate];
self.timerAD = nil;
[self.playerBack stop];
}
if (_task) {
[[UIApplication sharedApplication] endBackgroundTask:_task];
_task = UIBackgroundTaskInvalid;
}
} @end

最后在 AppDelegate.m 对应的方法中,实现开启和停止后台运行即可!

iOS-实现后台长时间运行的更多相关文章

  1. iOS开发:保持程序在后台长时间运行

    iOS开发:保持程序在后台长时间运行 2014 年 5 月 26 日 / NIVALXER / 0 COMMENTS iOS为了让设备尽量省电,减少不必要的开销,保持系统流畅,因而对后台机制采用墓碑式 ...

  2. iOS开发:后台运行以及保持程序在后台长时间运行

    第一部分 1.先说说iOS 应用程序5个状态: 停止运行-应用程序已经终止,或者还未启动. 不活动-应用程序处于前台但不再接收事件(例如,用户在app处于活动时锁住了设备). 活动-app处于“使用中 ...

  3. 保持程序在后台长时间运行-b

    iOS为了让设备尽量省电,减少不必要的开销,保持系统流畅,因而对后台机制采用墓碑式的“假后台”.除了系统官方极少数程序可以真后台,一般开发者开发出来的应用程序后台受到以下限制:1.用户按Home之后, ...

  4. iOS保持App真后台运行

    https://www.jianshu.com/p/d466f2da0d33 在我看来,苹果系统与安卓系统最直观的区别就是后台处理方式了吧,安卓手机一旦开启了很多app放到后台,即使前台什么也不做,就 ...

  5. [ASP.NET Core 3框架揭秘] 服务承载系统[1]: 承载长时间运行的服务[上篇]

    借助.NET Core提供的承载(Hosting)系统,我们可以将任意一个或者多个长时间运行(Long-Running)的服务寄宿或者承载于托管进程中.ASP.NET Core应用仅仅是该承载系统的一 ...

  6. phonegap ios插件开发及无限后台运行解决

    1.首先开发插件:因为我的项目前需要所以要做(根据情况) 在项目的plugins文件中新建obj c文件.如 Demo,此时会产生出Demo.h和Demo.m两个文件. .h文件主要就是定义一些方法, ...

  7. 定时器解决js长时间运行脚本问题

    一般地,单个js操作的运行时间不应超过100毫秒,否则的话,会影响用户体验,用户会认为自己与界面失去联系.而对于一些复杂的任务,可能无法在100ms内完成,甚至会突破浏览器限制(调用栈大小限制和长时间 ...

  8. ASP.NET 工作流:支持长时间运行操作的 Web 应用程序

    ASP.NET 工作流 支持长时间运行操作的 Web 应用程序 Michael Kennedy   代码下载位置:MSDN 代码库 在线浏览代码 本文将介绍以下内容: 独立于进程的工作流 同步和异步活 ...

  9. android studio从1.5更新到2.0后terminal无法运行gradle命令,提示无法找到gradle命令

    android studio从1.5更新到2.0后terminal无法运行gradle命令,提示无法找到gradle命令. 'gradle' 不是内部或外部命令,也不是可运行的程序 或批处理文件. 设 ...

随机推荐

  1. 简单实用的分页类-python

    django自带的分页虽然挺好,但是就想自己弄个通用的 自己写了个分页的类,用的是python,   其他语言改下语法就能用了. #定义好类.class pagemanage: def __init_ ...

  2. 定时任务APScheduler

    安装 APScheduler $ pip install apscheduler 快速开始 from apscheduler.schedulers.blocking import BlockingSc ...

  3. python的魔术方法

    什么叫魔术方法: 在python中定义以双下划线开头,有一些python自定义的函数,并且以双下划线为结尾的函数叫做魔法函数 class Company(object): def __init__(s ...

  4. Web前端(整理不好,自己未学)

    1.公司招聘信息 (1)小公司 (2)腾讯 ①社会招聘 ②校园招聘 (3)百度 ①社会招聘 ②实习 ③校园招聘 2.岗位要求 开发经验,良好的编程习惯,学习能力,至少二个项目开发设计,具备需求功能模块 ...

  5. linux主机名设置

    有时会报错: 代理抛出异常错误: java.net.MalformedURLException: Local host name unknown: java.net.UnknownHostExcept ...

  6. message [Failed to convert property value of type [java.lang.String] to required type [java.util.Date] for property

    springmvc前台字符串,后台Date类型字段.时间强转失败 数值:18年12月31日 15:43:21 解决方法,给时间字段加注释 @DateTimeFormat(pattern = " ...

  7. linux下sort命令使用详解---linux将文本文件内容加以排序命令

    转载自:http://www.cnblogs.com/hitwtx/archive/2011/12/03/2274592.html linux下sort命令使用详解---linux将文本文件内容加以排 ...

  8. win10下使用wget

    一.下载 官网:http://gnuwin32.sourceforge.net/packages/wget.htm 下载地址:http://downloads.sourceforge.net/gnuw ...

  9. Python之路(第三十篇) 网络编程:socket、tcp/ip协议

    一.客户端/服务器架构 1.硬件C/S架构(打印机) 打印机作为一个服务端,电脑连接打印机进行打印 2.软件C/S架构 互联网中处处是C/S架构 如谷歌网站是服务端,你的浏览器是客户端(B/S架构也是 ...

  10. win10自带输入法的标点符号切换

    快捷键是ctrl+句号 然后开启设置,把中文也用英文标点也选上.