尝试在应用在后台时播放声音。如果我用以下方法启动声音,我的代码会正确播放声音。背景我的意思是当手机屏幕关闭时(例如,当你把它放在口袋里时)。
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[self startSilentBackgroundSound]; // works fine
}
如果我删除上面的代码并在此处执行,则在应用程序处于后台时, NOT 播放声音。
- (void)applicationDidEnterBackground:(UIApplication *)application {
self.newTaskId = UIBackgroundTaskInvalid;
self.newTaskId = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:NULL];
[self startSilentBackgroundSound]; // does NOT work
}
在所需的背景模式中,我有以下内容:
App plays audio or streams audio/video using AirPlay
App downloads content from the network
App registers for location updates
App provides Voice over IP services
App downloads content in response to push notifications
如果有人知道GitHub项目,我会非常感谢!!!
////我的APP代码中的代码////////
-(void)startSilentBackgroundSound {
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
NSError *error = nil;
NSLog(@"Activating audio session");
if (![audioSession setCategory:AVAudioSessionCategoryPlayback withOptions:AVAudioSessionCategoryOptionDuckOthers error:&error]) {
NSLog(@"Unable to set audio session category: %@", error);
}
BOOL result = [audioSession setActive:YES error:&error];
if (!result) {
NSLog(@"Error activating audio session: %@", error);
}
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
[self startAlarmSound];
}
-(void)stopSilentBackgroundSound {
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
NSError *error = nil;
NSLog(@"Deactivating audio session");
BOOL result = [audioSession setActive:NO error:&error];
if (!result) {
NSLog(@"Error deactivating audio session: %@", error);
}
[self stopSounds];
}
-(void)startAlarmSound {
self.silentAudioController = [[SilentAudioController alloc] init];
[self.silentAudioController tryPlayMusic];
}
-(void)stopSounds {
[self.silentAudioController tryStopMusic];
self.silentAudioController = nil;
}
///这是我处理所有声音的文件
#import "SilentAudioController.h"
@import AVFoundation;
@interface SilentAudioController () <AVAudioPlayerDelegate>
@property (strong, nonatomic) AVAudioSession *audioSession;
@property (strong, nonatomic) AVAudioPlayer *backgroundMusicPlayer;
@property (assign) BOOL backgroundMusicPlaying;
@property (assign) BOOL backgroundMusicInterrupted;
@property (assign) SystemSoundID pewPewSound;
@end
@implementation SilentAudioController
#pragma mark - Public
- (instancetype)init
{
self = [super init];
if (self) {
[self configureAudioSession];
[self configureAudioPlayer];
[self configureSystemSound];
}
return self;
}
- (void)tryPlayMusic {
// If background music or other music is already playing, nothing more to do here
if (self.backgroundMusicPlaying || [self.audioSession isOtherAudioPlaying]) {
return;
}
// Play background music if no other music is playing and we aren't playing already
//Note: prepareToPlay preloads the music file and can help avoid latency. If you don't
//call it, then it is called anyway implicitly as a result of [self.backgroundMusicPlayer play];
//It can be worthwhile to call prepareToPlay as soon as possible so as to avoid needless
//delay when playing a sound later on.
[self.backgroundMusicPlayer prepareToPlay];
[self.backgroundMusicPlayer play];
self.backgroundMusicPlaying = YES;
}
- (void)tryStopMusic {
[self.backgroundMusicPlayer stop];
self.backgroundMusicPlaying = NO;
}
- (void)playSystemSound {
AudioServicesPlaySystemSound(self.pewPewSound);
}
#pragma mark - Private
- (void) configureAudioSession {
// Implicit initialization of audio session
self.audioSession = [AVAudioSession sharedInstance];
// Set category of audio session
// See handy chart on pg. 46 of the Audio Session Programming Guide for what the categories mean
// Not absolutely required in this example, but good to get into the habit of doing
// See pg. 10 of Audio Session Programming Guide for "Why a Default Session Usually Isn't What You Want"
NSError *setCategoryError = nil;
if ([self.audioSession isOtherAudioPlaying]) { // mix sound effects with music already playing
[self.audioSession setCategory:AVAudioSessionCategorySoloAmbient error:&setCategoryError];
self.backgroundMusicPlaying = NO;
} else {
[self.audioSession setCategory:AVAudioSessionCategoryAmbient error:&setCategoryError];
}
if (setCategoryError) {
NSLog(@"Error setting category! %ld", (long)[setCategoryError code]);
}
}
- (void)configureAudioPlayer {
// Create audio player with background music
NSString *backgroundMusicPath = [[NSBundle mainBundle] pathForResource:@"background-music-aac" ofType:@"caf"];
NSURL *backgroundMusicURL = [NSURL fileURLWithPath:backgroundMusicPath];
self.backgroundMusicPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:backgroundMusicURL error:nil];
self.backgroundMusicPlayer.delegate = self; // We need this so we can restart after interruptions
self.backgroundMusicPlayer.numberOfLoops = -1; // Negative number means loop forever
}
- (void)configureSystemSound {
// This is the simplest way to play a sound.
// But note with System Sound services you can only use:
// File Formats (a.k.a. audio containers or extensions): CAF, AIF, WAV
// Data Formats (a.k.a. audio encoding): linear PCM (such as LEI16) or IMA4
// Sounds must be 30 sec or less
// And only one sound plays at a time!
NSString *pewPewPath = [[NSBundle mainBundle] pathForResource:@"pew-pew-lei" ofType:@"caf"];
NSURL *pewPewURL = [NSURL fileURLWithPath:pewPewPath];
AudioServicesCreateSystemSoundID((__bridge CFURLRef)pewPewURL, &_pewPewSound);
}
#pragma mark - AVAudioPlayerDelegate methods
- (void) audioPlayerBeginInterruption: (AVAudioPlayer *) player {
//It is often not necessary to implement this method since by the time
//this method is called, the sound has already stopped. You don't need to
//stop it yourself.
//In this case the backgroundMusicPlaying flag could be used in any
//other portion of the code that needs to know if your music is playing.
self.backgroundMusicInterrupted = YES;
self.backgroundMusicPlaying = NO;
}
- (void) audioPlayerEndInterruption: (AVAudioPlayer *) player withOptions:(NSUInteger) flags{
//Since this method is only called if music was previously interrupted
//you know that the music has stopped playing and can now be resumed.
[self tryPlayMusic];
self.backgroundMusicInterrupted = NO;
}
@end
//更新//////////////
我已经实现了这个(hayageek.com/ios-long-running-background-task)长时间运行的任务,就像这个例子一样。现在声音文件在后台播放,但仅在模拟器上播放。在ios7手机和ios8手机上试过并且都没有播放声音文件?
答案 0 :(得分:0)
你看过这个Apple Documentation了吗?您必须按照文档中的规定实施长时间运行的任务。
答案 1 :(得分:0)
解决方案就是这个
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];