AVPlayer stopped early Swift 3 - ios

I currently have the following listener for my AVPlayer
NotificationCenter.default.addObserver(self, selector: #selector(self.didFinishPlaying), name: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: video.currentItem)
I am wondering how to add a listener for when the AVPlayer is stopped prematurely, as when I user is watching at full scene and hits the done in the top corner.

Register your listener as an observer in Notification Center, for a
custom notification name e.g.
Notification.Name("UserStoppedAvPlayer"), register a selector for this notification such as func userDidStopAvPlayer().
When your user taps the done button, within the selector/method thats triggered, where you stop the AvPlayer you should then post a notification to Notification Center with the custom name you registered on the listner.
Your listener will then fire the selector you registered and you should do your logic in there.

Related

How to know when MPMusicPlayerController changes playing item naturally

I am using the MPMusicPlayerController to create a music player in my app. I have got it all working great except for one small issue:
When the songs changes naturally - one song finishes and the next starts from the set queue - the notification MPMusicPlayerControllerNowPlayingItemDidChange doesn't appear to be called.
At the moment I am utilising both the MPMusicPlayerControllerNowPlayingItemDidChange and MPMusicPlayerControllerPlaybackStateDidChange notifications. These cover playing, pausing, shuffle, repeat, next, previous etc. When the notifications are hit I then refresh the screen based on the MPMusicPlayerController to show the new song, artist or different button icons required. Neither of these are called though when a song finishes and the next one automatically starts playing - this means that the title and artist of the previous song is left until the user reloads the screen or interacts with the audio controls which is not good user experience.
Short of regularly checking whether the current name matches the playing name I don't know how to update this in the normal flow of the app.
NotificationCenter.default.addObserver(
forName: NSNotification.Name.MPMusicPlayerControllerNowPlayingItemDidChange,
object: musicPlayerController,
queue: nil) { _ in
// Update view
}
The answer to this turns out to be very simple but also difficult to spot if you're not looking in the right place.
Before we add our observers we need to begin generating the playback notifications:
musicPlayerController.beginGeneratingPlaybackNotifications()
NotificationCenter.default.addObserver(self,
selector: #selector(refreshView),
name: .MPMusicPlayerControllerPlaybackStateDidChange,
object: musicPlayerController)
NotificationCenter.default.addObserver(self,
selector: #selector(refreshView),
name: .MPMusicPlayerControllerNowPlayingItemDidChange,
object: musicPlayerController)
We also need to remember to end generating them when we leave (deallocate) the view:
deinit {
NotificationCenter.default.removeObserver(self, name: .MPMusicPlayerControllerPlaybackStateDidChange, object: nil)
NotificationCenter.default.removeObserver(self, name: .MPMusicPlayerControllerNowPlayingItemDidChange, object: nil)
musicPlayerController.endGeneratingPlaybackNotifications()
}
The confusion came from the musicMediaPlayer returning a number of notifications even without this which didn't point to the fact we weren't observing all the notifications that were being fired.
Note: It is worth noting that as of the time of writing this it was in discussion whether there was a need to manually remove observers - I have included it here for answer completeness.

How to prevent SpriteKit game from crashing when Notification Center is opened

I am having a weird issue with a SpriteKit game. The app crashes when a user opens Notification center or Control Center. I want the worldNode layer to be paused and the menuNode layer to be presented when the applicationWillResignActive is called, which is working fine when the home button is pressed. I've tried pausing my game from within the AppDelegate functions applicationWillResignActive and I've tried pausing when applicationDidBecomeActive is called if the game has started. I've tried using the NotificationCenter approach from within the ViewController both work when the Home Button/Home Gesture is used. How Should I handle this? Or is this just a bug in iOS 11?
I have this in the viewDidLoad method of my ViewController
NotificationCenter.default.addObserver(self, selector: #selector(appWillResignActive), name: NSNotification.Name.UIApplicationWillResignActive, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(appDidBecomeActive), name: NSNotification.Name.UIApplicationDidBecomeActive, object: nil)
Then each one of those selectors
It crashes on both if trying to present the menu when the appDidBecomeActive and appWillResignActive
#objc func appDidBecomeActive() {
print("appDidBecomeActive")
if GameScene.sharedInstance != nil {
print("presentingMenu")
GameScene.sharedInstance.presentMenuNode()
}
}
#objc func appWillResignActive() {
print("appWillResignActive")
if GameScene.sharedInstance != nil {
print("presentingMenu")
GameScene.sharedInstance.presentMenuNode()
}
}
I feel like I may be trying to approach this the wrong way, but what I don't understand is why does it work when the Home button/Home gesture is fired?
Edit:
After more testing I found that everything works as expected when running on iOS 10 devices. However when I run the DemoBots app that apple provides from their sample code it doesn't crash on iOS 11 and basically does what I want to do, so there has got to be a better way to handle the transitions of the game state, any input is appreciated.

iOS swift 3 reload tableview when open app from background

I implemented push notifications into my app. The user gets a push notification from the server whenever there is a new message for him.
When the user clicks on the push notification, it opens the app. I want my app to reload a tableview when this happens, showing the user the recent newsfeed.
Is it possible in Swift 3?
As I understand, you are interesting in case of app that was opened on your recent newsfeed ViewController, then is closed to background by the user. Later on while receiving push, user clicks on it and opens the same newsfeed controller.
You have to subscribe to UIApplicationWillEnterForeground notification in your UIViewController like
NotificationCenter.default.addObserver(self, selector: #selector(yourMethod), name: NSNotification.Name.UIApplicationWillEnterForeground, object: nil)
and implement yourMethod like
func yourMethod() {
// send request to update newsfeed
// then update tableView
// tableView.reloadData()
}
Don't forget unsubscribe
deinit {
NotificationCenter.default.removeObserver(self)
}
It's the simplest solution and I described the simplest case. There are some more complicated cases I didn't describe, for example
The app is closed and you have to make hierarchy based on the push received in willFinishLaunchingWithOptions.
The app is opened on the other page, in this case you have to reconfigure viewControllers hierarchy to show required ViewController.
In this case you have to pass some data to required ViewController from the pressed Push Notification.
Hope it helps!

How to detect when a user exits the YouTube Player view on iOS?

When using the YouTube helper library for iOS, I want to be able to detect the change of state when a user exits the player to stop playback. I've tried to use kYTPlayerStateEnded but that only triggers after the video has reached the end.
After looking through the YTPlayerView.m file, I can't seem to find a state that will achieve this. Is there another means of detecting when you've pressed 'Done' and exited the player view?
What do you mean "exits the player?" Do you mean when the user pauses this video or if the user exits the full screen player?
For leaving full the screen player, you can use the UIWindowDidBecomeVisibleNotification notification:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(videoExitFullScreen:) name:UIWindowDidBecomeVisibleNotification object:self.view.window];
For detecting pauses, you can listen for the YTPlayerState kYTPlayerStatePaused in the state change callback:
- (void)playerView:(YTPlayerView *)playerView didChangeToState:(YTPlayerState)state;
If your YTPlayerView is a subview of a UIViewController, you can use viewWillDisappear: on the view controller to clean up your player.
To get around the issue you are describing you can use a notification with UIWindow.didBecomeHiddenNotification (Swift). This should be placed in the view controller where you are playing the video.
NotificationCenter.default.addObserver(self, selector: #selector(playerExited), name: UIWindow.didBecomeHiddenNotification, object: nil)

Prevent SKNode from unpausing automatically when app resumes

In my game, I have functions to pause and unpause an SKNode that contains the gameplay elements. Currently, the system automatically pauses when the home button is pressed, and unpauses when the app becomes active again.
I would like to do this on my own terms. For instance, when the app becomes active again, it should show the pause menu, and stay paused until the user manually unpauses.
Is there a way to override this system behavior?
You can register to receive the UIApplicationDidEnterBackgroundNotification or UIApplicationWillEnterForegroundNotification notification, and trigger the pause menu in the notification selector.
Somewhere in your code, you'd have to register a notification. There are plenty of notifications to choose from. Here is one for when the App comes back from the background:
override func viewDidLoad() {
super.viewDidLoad()
NSNotificationCenter.defaultCenter().addObserver(self, selector: "didBecomeActive:", name: UIApplicationDidBecomeActiveNotification, object: nil)
}
func didBecomeActive(test: NSNotification) {
self.unpause()
}
Notice that the selector in the addObserver method is the name of the function that will be called when the application comes back from the background. Also the didBecomeActive method needs an argument of type NSNotification.

Resources