I want to play an "audio" after 5 seconds when my app goes in background mode. The NSTimer triggered correctly. I am getting the NSLog(#"repeat"); after 5 seconds. But, some how the audio isn't playing. I enable Background Modes in my target. I try with many other solution, found here in stackoverflow, but no luck. Can any one provide me the right solution.
In my appdelegate.h file:
#import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>
#interface AppDelegate : UIResponder <UIApplicationDelegate>
{
NSTimer* timer;
}
#property (strong, nonatomic) UIWindow *window;
#property (nonatomic, strong) NSString *musicName;
#property (nonatomic, strong) AVAudioPlayer *audioPlayer;
In my appdelegate.m file:
#import "AppDelegate.h"
#interface AppDelegate ()
#end
#implementation AppDelegate
#synthesize
musicName,
audioPlayer;
-(void) playAlarmSound
{
musicName = #"note3BreakOf.mp3";
// Construct URL to sound file
NSString *path = [NSString stringWithFormat:#"%#/%#", [[NSBundle mainBundle] resourcePath], musicName];
NSURL *soundUrl = [NSURL fileURLWithPath:path];
// Create audio player object and initialize with URL to sound
audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:soundUrl error:nil];
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[self playAlarmSound];
return YES;
}
-(void)methodRunAfterBackground
{
[audioPlayer play];
[timer invalidate];
NSLog(#"repeat");
}
- (void)applicationDidEnterBackground:(UIApplication *)application
{
UIApplication *app = [UIApplication sharedApplication];
//create new uiBackgroundTask
__block UIBackgroundTaskIdentifier bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
[app endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}];
//and create new timer with async call:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//run function methodRunAfterBackground
timer = [NSTimer scheduledTimerWithTimeInterval:5 target:self selector:#selector(methodRunAfterBackground) userInfo:nil repeats:NO];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
[[NSRunLoop currentRunLoop] run];
});
}
You need to add "playsAudio" to your plist and set
AVAudioSession sharedInstance category to: AVAudioSessionCategoryPlayback
AVAudioSession sharedInstance
setActive: YES
UIApplication sharedApplication
beginReceivingRemoteControlEvents
Seems some of that might be deprecated, check here
In Objective-C:
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];
[[AVAudioSession sharedInstance] setActive: YES error: nil];
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
I want to play an "audio" after 5 seconds when my app goes in background mode
Well, you can't. If your app is not actively playing audio at the time it goes into the background, then when it goes into the background, it is suspended - regardless of your background settings. Your timer stops and the app sleeps.
(Many people solve this by playing a "silent" track as the app goes into the background, so that the app is playing something at that time, and can run in the background.)
You can do this by making the app active background. I am doing this in my app. I am using location manager api to make the app active in background. Then start playing a audio in background with the help of timer. You can use this link https://github.com/voyage11/Location to make the app active in background.Hope this will help.
Related
NSURLSession Delegate method
URLSessionDidFinishEventsForBackgroundURLSession is not Calling ?
I already enabled the Background Modes in project capabilities settings.
Here is the code
AppDelegate.h Method
#interface AppDelegate : UIResponder <UIApplicationDelegate>
#property (strong, nonatomic) UIWindow *window;
#property (nonatomic, copy) void(^backgroundTransferCompletionHandler)();
#end
AppDelegate.m Method
-(void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)())completionHandler{
self.backgroundTransferCompletionHandler = completionHandler;
}
ViewController.m Method
- (void)viewDidLoad
{
[super viewDidLoad];
//Urls
[self initializeFileDownloadDataArray];
NSArray *URLs = [[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask];
self.docDirectoryURL = [URLs objectAtIndex:0];
NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration backgroundSessionConfiguration:#"com.GACDemo"];
sessionConfiguration.HTTPMaximumConnectionsPerHost = 5;
self.session = [NSURLSession sessionWithConfiguration:sessionConfiguration
delegate:self
delegateQueue:nil];
}
NSUrlSession Method
-(void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session{
AppDelegate *appDelegate = [UIApplication sharedApplication].delegate;
// Check if all download tasks have been finished.
[self.session getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks) {
if ([downloadTasks count] == 0) {
if (appDelegate.backgroundTransferCompletionHandler != nil) {
// Copy locally the completion handler.
void(^completionHandler)() = appDelegate.backgroundTransferCompletionHandler;
// Make nil the backgroundTransferCompletionHandler.
appDelegate.backgroundTransferCompletionHandler = nil;
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
// Call the completion handler to tell the system that there are no other background transfers.
completionHandler();
// Show a local notification when all downloads are over.
UILocalNotification *localNotification = [[UILocalNotification alloc] init];
localNotification.alertBody = #"All files have been downloaded!";
[[UIApplication sharedApplication] presentLocalNotificationNow:localNotification];
}];
}
}
}];
}
I'm able to download all the files one by one but After downloading all the files, URLSessionDidFinishEventsForBackgroundURLSession method is not calling .
I have to perform some action method After Downloading all the files only.
These delegate methods won't get called if:
The app is already running when the tasks finish;
The app was terminated by double-tapping on the device's home button and manually killing it; or
If you fail to start a background NSURLSession with the same identifier.
So, the obvious questions are:
How was the app terminated? If not terminated, or if terminated incorrectly (e.g. you manually kill it by double-tapping on the home button), that will prevent these delegate methods from getting called.
Are you seeing handleEventsForBackgroundURLSession called at all?
Are you doing this on a physical device? This behaves differently on the simulator.
Bottom line, there's not enough here to diagnose the precise problem, but these are common reasons why that delegate method might not get called.
You later said:
Actually this is the first time I'm using NSURLSession class. My actual requirement is once the download (all the images) is completed then only I can retrieve the images from document directory and I can show in UICollectionView.
I'm following this tutorial from APPCODA. Here is the link http://appcoda.com/background-transfer-service-ios7
If that's your requirement, then background NSURLSession might be overkill. It's slower than standard NSURLSession, and more complicated. Only use background sessions if you really need large downloads to continue in the background after the app is suspended/terminated.
That tutorial you reference seems like a passable introduction to a pretty complicated topic (though I disagree with the URLSessionDidFinish... implementation, as discussed in comments). I would do something like:
- (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session {
// log message so we can see completion in device log; remove this once you're done testing the app
NSLog(#"%s", __FUNCTION__);
// Since you may be testing whether the terminated app is awaken when the
// downloads are done, you might want to post local notification.
// (Otherwise, since you cannot use the debugger, you're just staring
// at the device console hoping you see your log messages.) Local notifications
// are very useful in testing this, so you can see when this method is
// called, even if the app wasn't running. Obviously, you have to register
// for local notifications for this to work.
//
// UILocalNotification *notification = [[UILocalNotification alloc] init];
// notification.fireDate = [NSDate date];
// notification.alertBody = [NSString stringWithFormat:NSLocalizedString(#"Downloads done", nil. nil)];
//
// [[UIApplication sharedApplication] scheduleLocalNotification:notification];
// finally, in `handleEventsForBackgroundURLSession` you presumably
// captured the `completionHandler` (but did not call it). So this
// is where you'd call it on the main queue. I just have a property
// of this class in which I saved the completion handler.
dispatch_async(dispatch_get_main_queue(), ^{
if (self.savedCompletionHandler) {
self.savedCompletionHandler();
self.savedCompletionHandler = nil;
}
});
}
The question in my mind is whether you really want background session at all if you're just downloading images for collection view. I'd only do that if there were so many images (or they were so large) that they couldn't be reasonably downloaded while the app was still running.
For the sake of completeness, I'll share a full demonstration of background downloads below:
// AppDelegate.m
#import "AppDelegate.h"
#import "SessionManager.h"
#interface AppDelegate ()
#end
#implementation AppDelegate
// other app delegate methods implemented here
// handle background task, starting session and saving
// completion handler
- (void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)())completionHandler {
[SessionManager sharedSession].savedCompletionHandler = completionHandler;
}
#end
And
// SessionManager.h
#import UIKit;
#interface SessionManager : NSObject
#property (nonatomic, copy) void (^savedCompletionHandler)();
+ (instancetype)sharedSession;
- (void)startDownload:(NSURL *)url;
#end
and
// SessionManager.m
#import "SessionManager.h"
#interface SessionManager () <NSURLSessionDownloadDelegate, NSURLSessionDelegate>
#property (nonatomic, strong) NSURLSession *session;
#end
#implementation SessionManager
+ (instancetype)sharedSession {
static id sharedMyManager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedMyManager = [[self alloc] init];
});
return sharedMyManager;
}
- (instancetype)init {
self = [super init];
if (self) {
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:#"foo"];
self.session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:nil];
}
return self;
}
- (void)startDownload:(NSURL *)url {
[self.session downloadTaskWithURL:url];
}
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location {
NSLog(#"%s: %#", __FUNCTION__, downloadTask.originalRequest.URL.lastPathComponent);
NSError *error;
NSURL *documents = [[NSFileManager defaultManager] URLForDirectory:NSDocumentDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:false error:&error];
NSAssert(!error, #"Docs failed %#", error);
NSURL *localPath = [documents URLByAppendingPathComponent:downloadTask.originalRequest.URL.lastPathComponent];
if (![[NSFileManager defaultManager] moveItemAtURL:location toURL:localPath error:&error]) {
NSLog(#"move failed: %#", error);
}
}
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error {
NSLog(#"%s: %# %#", __FUNCTION__, error, task.originalRequest.URL.lastPathComponent);
}
- (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session {
NSLog(#"%s", __FUNCTION__);
// UILocalNotification *notification = [[UILocalNotification alloc] init];
// notification.fireDate = [NSDate date];
// notification.alertBody = [NSString stringWithFormat:NSLocalizedString(#"Downloads done", nil. nil)];
//
// [[UIApplication sharedApplication] scheduleLocalNotification:notification];
if (self.savedCompletionHandler) {
self.savedCompletionHandler();
self.savedCompletionHandler = nil;
}
}
#end
And, finally, the view controller code that initiates the request:
// ViewController.m
#import "ViewController.h"
#import "SessionManager.h"
#implementation ViewController
- (IBAction)didTapButton:(id)sender {
NSArray *urlStrings = #[#"http://spaceflight.nasa.gov/gallery/images/apollo/apollo17/hires/s72-55482.jpg",
#"http://spaceflight.nasa.gov/gallery/images/apollo/apollo10/hires/as10-34-5162.jpg",
#"http://spaceflight.nasa.gov/gallery/images/apollo-soyuz/apollo-soyuz/hires/s75-33375.jpg",
#"http://spaceflight.nasa.gov/gallery/images/apollo/apollo17/hires/as17-134-20380.jpg",
#"http://spaceflight.nasa.gov/gallery/images/apollo/apollo17/hires/as17-140-21497.jpg",
#"http://spaceflight.nasa.gov/gallery/images/apollo/apollo17/hires/as17-148-22727.jpg"];
for (NSString *urlString in urlStrings) {
NSURL *url = [NSURL URLWithString:urlString];
[[SessionManager sharedSession] startDownload:url];
}
// explicitly kill app if you want to test background operation
//
// exit(0);
}
- (void)viewDidLoad {
[super viewDidLoad];
// if you're going to use local notifications, you must request permission
UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert categories:nil];
[[UIApplication sharedApplication] registerUserNotificationSettings:settings];
}
#end
As stated by Apple:
If an iOS app is terminated by the system and relaunched, the app can use the same identifier to create a new configuration object and session and retrieve the status of transfers that were in progress at the time of termination. This behavior applies only for normal termination of the app by the system. If the user terminates the app from the multitasking screen, the system cancels all of the session’s background transfers. In addition, the system does not automatically relaunch apps that were force quit by the user. The user must explicitly relaunch the app before transfers can begin again.
I have backgroundmusic, declared in my app delegate for all my viewcontrollers.
appdelegate.h
#interface AppDelegate : UIResponder <UIApplicationDelegate, AVAudioPlayerDelegate>{
AVAudioPlayer *backgroundMusic;
}
appdelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
NSString *backgroundMusicString =[[NSBundle mainBundle]pathForResource:#"backgroundmusic" ofType:#"mp3"];
backgroundMusic = [[AVAudioPlayer alloc]initWithContentsOfURL:[NSURL fileURLWithPath:backgroundMusicString] error:nil];
backgroundMusic.delegate=self;
backgroundMusic.numberOfLoops=-1;
backgroundMusic.volume=0.2;
[backgroundMusic play];
return YES;
}
works fine. But how can i pause my background music in a viewcontroller?
i have a button to toggle it on off, but [backgroundMusic pause]; doesn't work.
- (IBAction)backgroundMusicOnOff:(id)sender {
}
I'm trying to play some music for my game in the background. The music will never stop unless the user turns it off in settings. The music will always play in the background for each view and doesn't pause or something.
For this reason I've made a singleton class for my background music. But when I press "Stop the music", the app breakpoints for an exception (I'm not seeing one, so I don't know what's wrong).
The music still stops, but there is something wrong and I don't know what. Is it right to make it in a singleton class, or do I need to solve this on an other way?
Here is a screenshot of when the exception happens:
Here is the code for my singleton class:
#import <Foundation/Foundation.h>
#import <AVFoundation/AVFoundation.h>
#interface Music : NSObject
#property AVAudioPlayer *player;
- (void)stop;
- (void)play;
+ (Music *)sharedInstance;
#end
#import "Music.h"
#implementation Music
+ (Music *)sharedInstance {
static Music *sharedInstance;
static dispatch_once_t onceToken;
dispatch_once(&onceToken,^{
sharedInstance = [[Music alloc] init];
});
return sharedInstance;
}
-(instancetype)init{
self = [super init];
if (self) {
NSURL *url = [NSURL fileURLWithPath:[[NSBundle mainBundle]
pathForResource:#"water_2"
ofType:#"wav"]];
self.player = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil];
self.player.numberOfLoops = -1;
}
return self;
}
- (void)stop{
[self.player stop];
}
- (void)play{
[self.player play];
}
I would switch up your code and I would use an IBAction instead of void stop and void play
-(IBAction)stop {
[player stop];
}
-(IBAction)play {
[player play];
}
I have an online music player. I want to add a feature to it that if the song is being played and a call (incoming or outgoing) is made, it should pause the music which call is going on and after the call is disconnected, the music should start again.
here is the code I have:
//
// FirstViewController.m
#import "FirstViewController.h"
CM_EXPORT const CMTime kCMTimeZero;
#interface FirstViewController ()
#end
#implementation FirstViewController
#synthesize metadatas;
#synthesize toggleButton;
#synthesize slider;
#synthesize mpVolumeView = _mpVolumeView;
#synthesize viewVolume;
- (void)viewDidLoad
{
//[super viewDidLoad];
//slider.transform = CGAffineTransformRotate(slider.transform,270.0/180*M_PI);
//[slider setMaximumValue:2];
//[slider setMinimumValue:0];
//[slider setSelected:YES];
//[[self mpVolumeView] setBackgroundColor:[UIColor clearColor]];
//MPVolumeView *myVolumeView = [[MPVolumeView alloc] initWithFrame: [[self mpVolumeView] bounds]];
//[[self mpVolumeView] addSubview:myVolumeView];
//toggleIsOn =TRUE;
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
toggleIsOn=TRUE;
MPVolumeView *volumeView = [[MPVolumeView alloc] initWithFrame:self.viewVolume.bounds] ;
[self.viewVolume addSubview:volumeView];
[volumeView sizeToFit];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
-(IBAction)playButtonPressed:(id)sender
{
if(toggleIsOn){
toggleIsOn=!toggleIsOn;
player = nil;
NSString *stringurl = #"";
stringurl = #"http://majestic.wavestreamer.com:6221/listen.pls";
NSURL *url = [NSURL URLWithString:stringurl];
asset = [AVURLAsset URLAssetWithURL:url options:nil];
playerItem = [AVPlayerItem playerItemWithAsset:asset];
player = [AVPlayer playerWithPlayerItem:playerItem];
player.actionAtItemEnd = AVPlayerActionAtItemEndNone;
[playerItem addObserver:self forKeyPath:#"timedMetadata" options:NSKeyValueObservingOptionNew context:nil];
[playerItem addObserver:self forKeyPath:#"status" options:NSKeyValueObservingOptionNew context:nil];
[player play];
[self.toggleButton setImage:[UIImage imageNamed:#"reload.png"] forState:UIControlStateNormal];
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];
[[AVAudioSession sharedInstance] setActive: YES error: nil];
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
}
else {
[self.toggleButton setImage:[UIImage imageNamed:#"playMusic.png"] forState:UIControlStateNormal];
self->player.rate=0.0;
toggleIsOn=!toggleIsOn;
}
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
[self becomeFirstResponder];
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
[[UIApplication sharedApplication] endReceivingRemoteControlEvents];
[self resignFirstResponder];
}
- (void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object
change:(NSDictionary *)change context:(void *)context {
[playerItem removeObserver:self forKeyPath:keyPath];
if ([keyPath isEqualToString:#"status"]) {
AVPlayerItem *pItem = (AVPlayerItem *)object;
if (pItem.status == AVPlayerItemStatusReadyToPlay)
{
metadatas.text = #"";
}
}
if ([keyPath isEqualToString:#"timedMetadata"]) {
for (AVAssetTrack *track in playerItem.tracks) {
for (AVPlayerItemTrack *item in player.currentItem.tracks) {
if ([item.assetTrack.mediaType isEqual:AVMediaTypeAudio]) {
NSArray *meta = [playerItem timedMetadata];
for (AVMetadataItem *metaItem in meta) {
NSString *source = metaItem.stringValue;
metadatas.text = source;
}
}
}
}
}
[self.toggleButton setImage:[UIImage imageNamed:toggleIsOn ? #"playMusic.png" :#"stop.png"] forState:UIControlStateNormal];
}
-(IBAction)fbButtonPressed:(id)sender
{
NSURL *url = [NSURL URLWithString:#"http://www.facebook.com"];
if (![[UIApplication sharedApplication] openURL:url])
NSLog(#"%#%#",#"Failed to open url:",[url description]);
}
-(IBAction)inButtonPressed:(id)sender
{
NSURL *url = [NSURL URLWithString:#"http://www.linkedin.com"];
if (![[UIApplication sharedApplication] openURL:url])
NSLog(#"%#%#",#"Failed to open url:",[url description]);
}
-(IBAction)tweetButtonPressed:(id)sender
{
NSURL *url = [NSURL URLWithString:#"http://www.twitter.com"];
if (![[UIApplication sharedApplication] openURL:url])
NSLog(#"%#%#",#"Failed to open url:",[url description]);
}
-(IBAction) sliderChanged:(id)sender
{
}
- (NSUInteger)supportedInterfaceOrientations{
return UIInterfaceOrientationMaskPortrait;
}
#end
Also, the code for inserting volume view is there, then also there is no volume controller in the UI. Why so.?
// // FirstViewController.m
#import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>
#import <MediaPlayer/MediaPlayer.h>
#class AVPlayer;
#class AVPlayerItem;
#interface FirstViewController : UIViewController
{
UIView *viewVolume;
AVAsset *asset;
AVPlayerItem *playerItem;
AVPlayer *player;
NSURL *mURL;
MPVolumeView *_mpVolumeView;
IBOutlet UILabel *metadatas;
IBOutlet UIButton *toggleButton;
BOOL toggleIsOn;
IBOutlet UISlider *slider;
}
-(IBAction)playButtonPressed:(id)sender;
-(IBAction)fbButtonPressed:(id)sender;
-(IBAction)inButtonPressed:(id)sender;
-(IBAction)tweetButtonPressed:(id)sender;
-(IBAction) sliderChanged:(id)sender;
#property (strong, nonatomic) IBOutlet UISlider *slider;
#property (nonatomic, retain) IBOutlet MPVolumeView *mpVolumeView;
#property (nonatomic, retain) IBOutlet UILabel *metadatas;
#property (nonatomic, retain) IBOutlet UIButton *toggleButton;
#property (nonatomic, strong) IBOutlet UIView *viewVolume;
#end
am unable to start the music after call. Please help with possible solutions.
You need to add observer in FirstViewController
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(resumePlayMusic) name:UIApplicationDidBecomeActiveNotification object:nil];
}
- (void) resumePlayMusic
{
.......
}
And don't forget to remove observer.
Go to your appDelegate file and there you will find the UIApplicationDelegate methods automatically having been implemented for you.
Simply add your music pause and resume code in the methods and everything else will be handled accordingly. Just make sure that you can access your music instance player from the app delegate.
- (void)applicationWillResignActive:(UIApplication *)application
{
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
}
- (void)applicationDidEnterBackground:(UIApplication *)application
{
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
- (void)applicationWillEnterForeground:(UIApplication *)application
{
// Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
}
- (void)applicationDidBecomeActive:(UIApplication *)application
{
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
This question already has answers here:
How do I programmatically play an MP3 on an iPhone?
(4 answers)
Closed 4 years ago.
I can't figure out how to play a music file in an iPhone game.
Im creating a Game and I am trying to figure out how to play music whenever the app is launched.
I tried this:
- (void)awakeFromNib {
NSString *path = [[NSBundle mainBundle] pathForResource:#"musicamenu" ofType:#"mp3"];
AVAudioPlayer *theAudio = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:NULL];
[theAudio play];
}
This is how you do it. In your v1AppDelegate.h file add
#import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>
#import <AudioToolbox/AudioToolbox.h>
#interface v1AppDelegate : UIResponder <UIApplicationDelegate>
{
AVAudioPlayer *myAudioPlayer;
}
#property (nonatomic, retain) AVAudioPlayer *myAudioPlayer;
#property (strong, nonatomic) UIWindow *window;
#end
Now in your v1AppDelegate.m file add this
#import "v1AppDelegate.h"
#import <AVFoundation/AVFoundation.h>
#import <AudioToolbox/AudioToolbox.h>
#implementation v1AppDelegate
#synthesize window = _window;
#synthesize myAudioPlayer;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
//start a background sound
NSString *soundFilePath = [[NSBundle mainBundle] pathForResource:#"Soothing_Music2_Long" ofType: #"mp3"];
NSURL *fileURL = [[NSURL alloc] initFileURLWithPath:soundFilePath ];
myAudioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:fileURL error:nil];
myAudioPlayer.numberOfLoops = -1; //infinite loop
[myAudioPlayer play];
// Override point for customization after application launch.
return YES;
}
If you wish to stop or start this music from anywhere else in your code then simply add this
#import "v1AppDelegate.h"
- (IBAction)stopMusic
{
v1AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
[appDelegate.myAudioPlayer stop];
}
- (IBAction)startMusic
{
v1AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
[appDelegate.myAudioPlayer play];
}
I recommend to add the play music method in applicationDidBecomeActive: method. Because you want the music played every time the app is launched. Note you should hold a reference to the player. Else the music will not be played.
- (void)applicationDidBecomeActive:(UIApplication *)application
{
// Play music on another queue so that the main queue is not blocked.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self playMusic];
});
}
- (void)playMusic
{
NSString *path = [[NSBundle mainBundle] pathForResource:#"done" ofType:#"mp3"];
NSError *error = nil;
NSURL *url = [NSURL fileURLWithPath:path];
self.player = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:&error];
[self.player play];
}
For Swift 3.1 :
Use this two imports :
import AVFoundation
import AudioToolbox
Create a reference for your AVAudioPlayer :
private var mAudioPlayer : AVAudioPlayer?
Use this function for play a sound you are storing in your app :
func onTapSound(){
let soundFile = Bundle.main.path(forResource: "slap_placeholder.wav", ofType: nil)
let url = URL(fileURLWithPath: soundFile!)
self.mAudioPlayer = try! AVAudioPlayer(contentsOf: url as URL)
self.mAudioPlayer?.play()
}