永远在后台运行 iOS 应用程序

Posted

技术标签:

【中文标题】永远在后台运行 iOS 应用程序【英文标题】:Running iOS app in the background forever 【发布时间】:2013-09-18 11:55:55 【问题描述】:

我的应用需要连接到国家/地区频道(美国)并开始播放该频道的记录。这基本上是一个由用户运营的频道,用户将他们的记录上传到频道并逐一播放。连接到频道的用户开始收听频道。

服务器向 ios 应用发送需要通过套接字播放的记录的 URL,iOS 应用创建 AVQueuePlayer 以一一播放 URL(使用 AVPlayerItems)。

如果我在频道充满记录近 1 天左右时将应用程序置于后台,则应用程序会继续运行并继续播放所有记录。我知道AVQueuePlayer 会一直负责运行应用程序,而不会因为它接收到新的播放器项目而被杀死。

但是,如果频道中没有记录,并且如果用户连接到频道,则如果应用的空闲时间超过 10 分钟,则应用不会在后台播放记录。

我编写了带有后台任务标识符的代码,它使我的套接字连接保持打开状态,以便可以一直接收新的记录 URL。

我在我的设备中看到了一些崩溃报告,上面写着"AppName(my app) has active assertions beyond permitted time"

所以我能知道这里出了什么问题吗?

我也在贴后台任务代码

- (void)keepBroadcastPersistentConnection 

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^

    if(self._bgTaskIdentifier)
        self._bgTaskIdentifier = UIBackgroundTaskInvalid;
    self._bgTaskIdentifier = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler: ^

        [[UIApplication sharedApplication] endBackgroundTask:self._bgTaskIdentifier];
        self._bgTaskIdentifier = UIBackgroundTaskInvalid;
        CGLog(@"========================================end bg task at time %@", [NSDate date]);
        CGLog(@"Time taken by app to run in bg is %f seconds", [[NSDate date] timeIntervalSinceDate:self.date]);
    ];

    [[BroadcastSocketConnecter sharedSocketConnecter].socketIO sendHeartbeat]; // this keep the socket alive
    self.date = [NSDate date];
    CGLog(@"========================================begin bg task at time %@", self.date);
);

谢谢

【问题讨论】:

*** 上有很多帖子告诉你为什么不应该这样做以及什么是可能的。尝试搜索,不要让您的应用永远在后台运行。 请解释:但是如果频道中没有记录,如果用户连接到频道,那么如果应用程序的空闲时间超过10分钟,应用程序不会在后台播放记录. 我不明白发生了什么。另一方面,如果应用程序不执行某些允许的后台任务,您的应用程序不能在后台运行超过 10 分钟左右。但是你已经描述了这一点,所以我不明白你的问题是什么。 @allprog :这意味着如果应用程序连接到某个频道并且频道中没有播放任何内容,并且如果用户此时将应用程序作为后台,则应用程序将保持 sokcet 连接仅 10 分钟,然后断开连接。此时,如果有人将记录上传到频道,则不会在设备中播放。 数据是否被receiver socket消费,新item是否成功加入队列? @allprog:是的,它已被消耗,项目被创建并添加到队列播放器中。没有问题。我测试了在后台运行的应用程序,它连接到包含大约 10 小时记录的某个频道,套接字继续运行,应用程序继续播放记录 10 小时。 【参考方案1】:

来自音频会话编程指南:

Why a Default Audio Session Usually Isn’t What You Want

场景 3。您编写了一个使用音频的流式广播应用程序 用于播放的队列服务。当用户正在收听时,一个电话 正如预期的那样到达并停止您的声音。用户选择忽略 呼叫并解除警报。用户再次点击播放以恢复 音乐流,但没有任何反应。要恢复播放,用户 必须退出您的应用程序并重新启动它。

要优雅地处理音频队列的中断,请实现 委托方法或编写音频会话回调函数以允许 您的应用程序继续自动播放或允许 用户手动恢复播放。请参阅“Responding to Audio Session Interruptions”。

简而言之,解决方案是实现 AVAudioSessionDelegate 协议'a beginInterruptionendInterruption 方法。但是,AvAudioSession 类的 delegate 属性在 iOS6 中已弃用,而应使用 Notifications。即你对AVAudioSessionInterruptionNotification感兴趣

解决方案。根据这个故事,如果播放停止,那么您应该再次显式激活音频会话以防止您的应用程序被终止。

以下是委托实现的源代码,但通知的逻辑并没有太大变化,所以我觉得它仍然是一个很好的信息源。

- (void) beginInterruption 
    if (playing) 
        playing = NO;
        interruptedWhilePlaying = YES;
        [self updateUserInterface];
    


NSError *activationError = nil;
- (void) endInterruption 
    if (interruptedWhilePlaying) 
        BOOL success = [[AVAudioSession sharedInstance] setActive: YES error: &activationError];
        if (!success)  /* handle the error in activationError */ 
        [player play];
        playing = YES;
        interruptedWhilePlaying = NO;
        [self updateUserInterface];
    

仍然有效但不是优雅解决方案的旧响应

您无法在后台开始播放音频。这个答案解释了我在上面的评论中提到的内容:https://***.com/a/16568437/768935 用AudioSession 搞恶作剧似乎对这项政策没有影响。

作为一种解决方案,您需要继续播放音频。如果队列中没有项目,则插入“静音”音轨。但是,我怀疑具有此技巧的应用程序是否会在 App Store 中被接纳。如果再次启动应用程序,最好通知用户将恢复音频播放。

【讨论】:

以上是关于永远在后台运行 iOS 应用程序的主要内容,如果未能解决你的问题,请参考以下文章

如何在 ios 中永远运行后台服务以同步数据

如果没有 IOS 中的 VOIP,我如何让我的应用程序永远活着?

后台任务永远运行?

如何永远在后台运行需要蓝牙的应用程序?

ios 8后台获取永远不会在设备上多次调用

如何永远在后台模式下运行应用程序?