由于项目需要,app与服务器之间需要保持一个常交互的关系。最好是app打开一次之后,在不主动杀死app的情况下,依然能与服务器交互数据。有以下几个方案:
1、GPS定位:通过一直获取地理信息,类似于百度地图的导航功能,该方法基本可以达到目的。但是受限于很多人不一定开启位置服务,而且该方法会导致耗电很快,最终没有采用。
2、音乐播放:这个就比较简单了,app中循环播放一段无声的音频,但是在锁屏状态下时会显示player界面,而且无法通过自定义移除这个界面。肯定不行也是没有采用。
3、VOIP:钉钉、QQ、微信的语音通话就是通过这个来达到不开启app情况下,唤醒接电话界面。原理就是通过voip提供的推送协议,在每次静默推送的情况下app内接受到推送消息,会给出大概10秒钟时间处理事件。通过此10s时间可以对数据进行处理和服务器交互。而且该方法可以在app杀掉进程,手机重启之后唤醒app。最后服务器可以定时几分钟给每个用户推送一次,定时唤醒app,达到心跳机制。这就是我们想要的方法。
开源代码:下载代码
源码里是第三种实现方案,如果有朋友需要前面2种的实现代码。可以在github上issues我,或者在文章后面评论,后续再补上。
补上另外2种方式的大概代码:
1:音乐播放
#import <MediaPlayer/MPNowPlayingInfoCenter.h>
@interface AppDelegate ()<AVAudioPlayerDelegate>
{
UIBackgroundTaskIdentifier _bgTaskId;
AVAudioPlayer *avAudioPlayer;
}
@property (assign, nonatomic) UIBackgroundTaskIdentifier bgTask;
@property (assign, nonatomic) BOOL played;
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleInterreption:) name:AVAudioSessionInterruptionNotification object:[AVAudioSession sharedInstance]];
//开启后台处理多媒体事件
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
AVAudioSession *session = [AVAudioSession sharedInstance];
[session setActive:YES error:nil];
//后台播放
[session setCategory:AVAudioSessionCategoryPlayback error:nil];
_bgTaskId = [AppDelegate backgroundPlayerID:_bgTaskId];
[self playmusic];
[self configNowPlayingCenter];
+(UIBackgroundTaskIdentifier)backgroundPlayerID:(UIBackgroundTaskIdentifier)backTaskId
{
//设置并激活音频会话类别
AVAudioSession *session=[AVAudioSession sharedInstance];
[session setCategory:AVAudioSessionCategoryPlayback error:nil];
[session setActive:YES error:nil];
//允许应用程序接收远程控制
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
//设置后台任务ID
UIBackgroundTaskIdentifier newTaskId = UIBackgroundTaskInvalid;
newTaskId = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:nil];
if(newTaskId != UIBackgroundTaskInvalid && backTaskId != UIBackgroundTaskInvalid)
{
[[UIApplication sharedApplication] endBackgroundTask:backTaskId];
}
return newTaskId;
}
//处理中断事件
-(void)handleInterreption:(NSNotification *)sender
{
if(_played)
{
[avAudioPlayer pause];
_played = NO;
}
else
{
[avAudioPlayer play];
_played = YES;
}
}
-(void)playmusic
{
//从budle路径下读取音频文件 这个文件名是你的歌曲名字,mp3是你的音频格式
NSString *string = [[NSBundle mainBundle] pathForResource:@"李玉刚 - 刚好遇见你" ofType:@"mp3"];
//把音频文件转换成url格式
NSURL *url = [NSURL fileURLWithPath:string];
//初始化音频类 并且添加播放文件
avAudioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil];
//设置代理
avAudioPlayer.delegate = self;
//设置初始音量大小
avAudioPlayer.volume = 1;
//设置音乐播放次数 -1为一直循环
avAudioPlayer.numberOfLoops = -1;
//预播放
// [avAudioPlayer play];
}
-(void)configNowPlayingCenter {
[[MPNowPlayingInfoCenter defaultCenter] setNowPlayingInfo:nil];
}
2:GPS定位
@property (strong, nonatomic) NSTimer *timer;
LocationManager *locationManager;
- (void)initLocation
{
locationManager = [LocationManager shareInstance];
if (![CLLocationManager locationServicesEnabled]) {
NSLog(@"定位服务当前可能尚未打开,请设置打开!");
return;
}
//如果没有授权则请求用户授权
if ([CLLocationManager authorizationStatus]==kCLAuthorizationStatusNotDetermined){
[locationManager._locationManager requestAlwaysAuthorization];
}else if([CLLocationManager authorizationStatus]==kCLAuthorizationStatusAuthorizedAlways){
//设置代理
locationManager._locationManager.delegate = self;
// //设置定位精度
// _locationManager.desiredAccuracy=kCLLocationAccuracyBest;
// //定位频率,每隔多少米定位一次
// CLLocationDistance distance= 0;//十米定位一次
// _locationManager.distanceFilter=distance;
//启动跟踪定位
[locationManager._locationManager startUpdatingLocation];
}
}
#pragma mark CLLocationManagerDelegate
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations{
CLLocation *location=[locations firstObject];//取出第一个位置
CLLocationCoordinate2D coordinate=location.coordinate;//位置坐标
NSLog(@"经度:%f,纬度:%f,海拔:%f,航向:%f,行走速度:%f",coordinate.longitude,coordinate.latitude,location.altitude,location.course,location.speed);
if (_timer == nil) {
_timer = [NSTimer scheduledTimerWithTimeInterval:60.0f target:self selector:@selector(activeLog) userInfo:nil repeats:YES];
}
}
复制代码