Reputation: 203
In my iPhone app, I want to keep playing a video when the app enters is no longer in the foreground.
I am using AVPlayer and can't find any way to play videos in the background. I will be very grateful if any one can help me in this. Thanks
Upvotes: 9
Views: 13968
Reputation: 1954
Set AVAudioSession category to .playback mode in viewDidLoad
let audioSession = AVAudioSession.sharedInstance()
do {
try audioSession.setCategory(.playback, mode: .moviePlayback, options: [])
} catch {
print("Failed to set audio session category.")
}
Add NotificationObservers
NotificationCenter.default.addObserver(self, selector: #selector(applicationWillEnterForeground), name: UIApplication.willEnterForegroundNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(applicationDidEnterBackground), name: UIApplication.didEnterBackgroundNotification, object: nil)
//App enter in forground.
@objc func applicationWillEnterForeground(_ notification: Notification) {
// Reconnect the AVPlayer to the presentation when returning to the foreground
// If presenting video with AVPlayerViewController
playerViewController.player = player
// If presenting video with AVPlayerLayer
playerLayer.player = player
}
//App enter in foreground.
@objc func applicationDidEnterBackground(_ notification: Notification) {
// Disconnect the AVPlayer from the presentation when entering background
// If presenting video with AVPlayerViewController
playerViewController.player = nil
// If presenting video with AVPlayerLayer
playerLayer.player = nil
}
References
Playing Audio from a Video Asset in the Background,
Upvotes: 0
Reputation: 13537
You can achive your requirement by using below sets of below code.
Swift: 4.2
Just, Create subclass of UIViewController
import UIKit
import AVFoundation
class VideoPlayer:UIViewController{
var avPlayer: AVPlayer!
var avPlayerLayer: AVPlayerLayer!
var paused: Bool = false
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
view.backgroundColor = .clear
avPlayer?.play()
paused = false
}
override func viewDidLoad() {
super.viewDidLoad()
let theURL = Bundle.main.url(forResource:"VIDEO_NAME", withExtension: "VIDEO_TYPE") //VIDEO_TYPE -> MP4
avPlayer = AVPlayer(url: theURL!)
avPlayerLayer = AVPlayerLayer(player: avPlayer)
avPlayerLayer.videoGravity = AVLayerVideoGravity.resizeAspectFill
avPlayer.volume = 0
avPlayer.actionAtItemEnd = .none
avPlayerLayer.frame = view.layer.bounds
view.backgroundColor = .clear
view.layer.insertSublayer(avPlayerLayer, at: 0)
addPlayerNotifications()
}
deinit {
removePlayerNotifations()
}
func addPlayerNotifications() {
NotificationCenter.default.addObserver(self,
selector: #selector(playerItemDidReachEnd(notification:)),
name: NSNotification.Name.AVPlayerItemDidPlayToEndTime,
object: avPlayer.currentItem)
NotificationCenter.default.addObserver(self, selector: #selector(applicationWillEnterForeground), name: UIApplication.willEnterForegroundNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(applicationDidEnterBackground), name: UIApplication.didEnterBackgroundNotification, object: nil)
}
func removePlayerNotifations() {
NotificationCenter.default.removeObserver(self, name: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: nil)
NotificationCenter.default.removeObserver(self, name:UIApplication.willEnterForegroundNotification, object: nil)
NotificationCenter.default.removeObserver(self, name:UIApplication.didEnterBackgroundNotification, object: nil)
}
@objc func playerItemDidReachEnd(notification: Notification) {
let p: AVPlayerItem = notification.object as! AVPlayerItem
p.seek(to: CMTime.zero)
}
//App enter in forground.
@objc func applicationWillEnterForeground(_ notification: Notification) {
paused = false
avPlayer?.play()
}
//App enter in forground.
@objc func applicationDidEnterBackground(_ notification: Notification) {
paused = true
avPlayer?.pause()
}
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
avPlayer.pause()
paused = true
}
}
Now, Almoast done. Just create UIViewcontroller
class by using sub-class as below.
class Classname: VideoPlayer{
override func viewDidLoad() {
super.viewDidLoad()
}
}
Upvotes: 0
Reputation: 3267
The above answers pause the video for a second when the app enters background, but by using the method mentioned below it keeps the video playing while app goes to background without any glitch.
If the AVPlayer's current item is displaying video on the device's display, playback of the AVPlayer is automatically paused when the app is sent to the background. There are two ways to prevent this pause:
REFERENCE
Playing media while in the background using AV Foundation on iOS
Upvotes: 0
Reputation: 2942
Try this code in your applicationDidEnterBackground
:
UIApplication *app = [UIApplication sharedApplication];
bgTask = 0;
backgroundTimer = [NSTimer scheduledTimerWithTimeInterval:60 target:self selector:@selector(backgroundTask) userInfo:nil repeats:YES];
bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
[app endBackgroundTask:bgTask];
i found it somewhere on the stack works for me
Also check out this tutorial which covers background modes including background audio.. http://www.raywenderlich.com/29948/backgrounding-for-ios
Upvotes: 1
Reputation: 2686
With surprise I can say that this can be achieved and I just did it.
This method supports all the possibilities:
As long as you have an instance of AVPlayer
running iOS prevents auto lock of the device.
First you need to configure the application to support audio background from the Info.plist file adding in the UIBackgroundModes
array the audio
element.
Then put in your AppDelegate.m into - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions:
these methods
[[AVAudioSession sharedInstance] setDelegate: self];
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];
and #import <AVFoundation/AVFoundation.h>
Then in your view controller that controls AVPlayer
-(void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
[self becomeFirstResponder];
}
and
- (void)viewWillDisappear:(BOOL)animated
{
[mPlayer pause];
[super viewWillDisappear:animated];
[[UIApplication sharedApplication] endReceivingRemoteControlEvents];
[self resignFirstResponder];
}
then respond to the
- (void)remoteControlReceivedWithEvent:(UIEvent *)event {
switch (event.subtype) {
case UIEventSubtypeRemoteControlTogglePlayPause:
if([mPlayer rate] == 0){
[mPlayer play];
} else {
[mPlayer pause];
}
break;
case UIEventSubtypeRemoteControlPlay:
[mPlayer play];
break;
case UIEventSubtypeRemoteControlPause:
[mPlayer pause];
break;
default:
break;
}
}
Another trick is needed to resume the reproduction if the user presses the home button (in which case the reproduction is suspended with a fade out).
When you control the reproduction of the video (I have play:
and pause:
methods) set
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationDidEnterBackground:) name:UIApplicationDidEnterBackgroundNotification object:nil];
and
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidEnterBackgroundNotification object:nil];
and the corresponding method to be invoked that will launch a timer and resume the reproduction.
- (void)applicationDidEnterBackground:(NSNotification *)notification
{
[mPlayer performSelector:@selector(play) withObject:nil afterDelay:0.01];
}
Upvotes: 19
Reputation: 1918
You can do this background task when application is in background :
1> audio
2> location
3> voip
4> newsstand-content
5> external-accessory
6> bluetooth-central
7> bluetooth-peripheral
see this link,
http://developer.apple.com/library/ios/#documentation/iphone/conceptual/iphoneosprogrammingguide/ManagingYourApplicationsFlow/ManagingYourApplicationsFlow.html
http://www.rideitdown.com/2012/10/how-to-listen-youtube-videos-in.html
also this may help you: AVPlayer play video in background
Upvotes: 0