美文网首页
ios后台保活

ios后台保活

作者: zxh123456 | 来源:发表于2022-08-17 17:01 被阅读0次

    原理:
    1.开启后台任务权限,播放音乐


    image.png

    2.app后台后,开启后台任务,定时轮询后台剩余时间,低于20秒时候再申请新的后台任务
    3.app回前台后,结束后台任务

    -(void)applicationDidEnterBackground:(UIApplication *)application{
        [[BackgroundTaskTool shareTool] startBackgroundTask];
    }
    
    -(void)applicationWillEnterForeground:(UIApplication *)application{
        [[BackgroundTaskTool shareTool] stopBackgroundTask];
    }
    

    .h

    #import <Foundation/Foundation.h>
    
    NS_ASSUME_NONNULL_BEGIN
    
    @interface BackgroundTaskTool : NSObject
    
    +(instancetype)shareTool;
    
    -(void)startBackgroundTask;
    
    -(void)stopBackgroundTask;
    
    @end
     
    
    NS_ASSUME_NONNULL_END
    

    .m

    #import "BackgroundTaskTool.h"
    #import <AVFoundation/AVFoundation.h>
    
    ///循环时间5秒查一次是否需要再次申请后台任务
    static NSInteger _circulaDuration = 5;
    static BackgroundTaskTool *_sharedTool;
    
    @interface BackgroundTaskTool()
    
    @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 BackgroundTaskTool{
        CFRunLoopRef _runloopRef;
        dispatch_queue_t _queue;
    }
    
    + (instancetype)shareTool
    {
        static BackgroundTaskTool *tool = nil;
        static dispatch_once_t predicate;
        dispatch_once(&predicate, ^{
            tool = [[self alloc] init];
        });
        return tool;
    }
    
    
    /// 重写init方法,初始化音乐文件
    - (instancetype)init {
        if (self = [super init]) {
            [self setupAudioSession];
            _queue = dispatch_queue_create("com.audio.inBackground", NULL);
            //静音文件
            NSString *filePath = [[NSBundle mainBundle] pathForResource:@"Silence" ofType:@"wav"];
            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 = -1;
        }
        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)startBackgroundTask{
        [self.playerBack play];
        [self applyforBackgroundTask];
        ///确保两个定时器同时进行
        dispatch_async(_queue, ^{
            self.timerLog = [[NSTimer alloc] initWithFireDate:[NSDate date] interval:1 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];
            self->_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:self->_task];
                self->_task = UIBackgroundTaskInvalid;
            });
        }];
    }
    
    /**
     打印
     */
    - (void)log{
        _count = _count + 1;
        NSLog(@"_count = %ld",_count);
    }
    
    /**
     检测后台运行时间
     */
    - (void)startAudioPlay{
        _count = 0;
        dispatch_async(dispatch_get_main_queue(), ^{
            if ([[UIApplication sharedApplication] backgroundTimeRemaining] < 20.0) {
                NSLog(@"后台快被杀死了");
                [self.playerBack play];
                dispatch_async(dispatch_get_main_queue(), ^{
                    [[UIApplication sharedApplication] endBackgroundTask:self->_task];
                    self->_task = UIBackgroundTaskInvalid;
                });
                dispatch_after(0.1, dispatch_get_main_queue(), ^{
                    [self applyforBackgroundTask];
                });
            }
            else{
                NSLog(@"后台继续活跃呢");
            }///再次执行播放器停止,后台一直不会播放音乐文件
            [self.playerBack stop];
        });
    }
    
    /**
     停止后台运行
     */
    - (void)stopBackgroundTask{
        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
    

    相关文章

      网友评论

          本文标题:ios后台保活

          本文链接:https://www.haomeiwen.com/subject/hdzjgrtx.html