iOS MultiTasking is not working - ios

- (IBAction)buttonPressed:(id)sender
{
UIDevice *device = [UIDevice currentDevice];
device.batteryMonitoringEnabled = YES;
if ([[UIDevice currentDevice] isMultitaskingSupported]) {
[self beingBackgroundUpdateTask];
}
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(batteryChanged:) name:#"UIDeviceBatteryLevelDidChangeNotification" object:device];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(batteryChanged:) name:#"UIDeviceBatteryStateDidChangeNotification" object:device];
[self currentBatteryState];
}
- (void) beingBackgroundUpdateTask
{
self->backgroundUpdateTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
[self endBackgroundUpdateTask];
}];
}
- (void) endBackgroundUpdateTask
{
[[UIApplication sharedApplication] endBackgroundTask: self->backgroundUpdateTask];
self->backgroundUpdateTask = UIBackgroundTaskInvalid;
}
For some reason, the notification's are not being observed. Am i doing something wrong? I want to observe for unto 10 minutes when unplugged

You shouldn't be calling endBackgroundUpdateTask in your buttonPressed: method, since that cancels your background task. Try removing this code:
if ([[UIDevice currentDevice] isMultitaskingSupported]) {
[self endBackgroundUpdateTask];
}
Also, you should pass the UIDeviceBatteryLevelDidChangeNotification constant to the "name" parameter, not the string. It should look like this (note the lack of double quotes):
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(batteryChanged:) name:UIDeviceBatteryLevelDidChangeNotification object:device];
(It's also possible that UIDevice simply doesn't send those notifications in the background.)

Have you added the applicable backgrounding code to your AppDelegate? Here are backgrounding instructions in the iOS Programming Guide

Related

iOS control center music controls stop working in iOS 11 update (remoteControlReceivedWithEvent is not called iOS 11)

I’m having an issue with iOS control center music controls Before the iOS 11 update, the Play Pause button was enabled and worked normally, as is expected.
However, in iOS 11 it stopped working. After a research, I found that in IOS 11 the remoteControlReceivedWithEvent is never being called, but, in older iOS versions such as iOS 9 it is being called normally
I set my events on AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Enable background audio listening
// https://developer.apple.com/library/ios/qa/qa1668/_index.html
NSError *error = nil;
if (![[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:&error]) {
NSLog(#"%#", error);
}
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
}
- (void)remoteControlReceivedWithEvent:(UIEvent *)receivedEvent {
if (receivedEvent.type == UIEventTypeRemoteControl) {
switch (receivedEvent.subtype) {
case UIEventSubtypeRemoteControlPlay:
[[NSNotificationCenter defaultCenter] postNotificationName:kCYCAppDelegatePlayPauseNotificationName object:nil];
break;
case UIEventSubtypeRemoteControlPause:
[[NSNotificationCenter defaultCenter] postNotificationName:kCYCAppDelegatePlayPauseNotificationName object:nil];
break;
case UIEventSubtypeRemoteControlTogglePlayPause:
[[NSNotificationCenter defaultCenter] postNotificationName:kCYCAppDelegatePlayPauseNotificationName object:nil];
break;
default:
break;
}
}
}
also I subscribe to remote events in another class to control play/pause buttons
- (void)subscribeToRemoteControlEvents {
if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(#"7.1")) {
// Disables the forward/backward buttons and only shows the play button.
// You can't just enable the command, you must subscribe for this to activate, so
// the subscription in this case doesn't do anything.
[MPRemoteCommandCenter sharedCommandCenter].togglePlayPauseCommand.enabled = YES;
[[MPRemoteCommandCenter sharedCommandCenter].togglePlayPauseCommand addTarget:self action:#selector(ignore_removeCommandCenterFired)];
}
[[NSNotificationCenter defaultCenter] addObserver:self forName:kCYCAppDelegatePlayPauseNotificationName object:nil queue:nil usingBlock:^(NSNotification *note, CYCCastManager *observer) {
if (observer.isCastPlaying) {
[observer pause];
}
else {
[observer play:NO];
}
}];
}
- (void)unsubscribeFromRemoteControlEvents {
if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(#"7.1")) {
[[MPRemoteCommandCenter sharedCommandCenter].togglePlayPauseCommand removeTarget:self action:#selector(ignore_removeCommandCenterFired)];
}
}
I want known why is not working anymore I did check in documentation for changes in the API, but I don't see changes
Note: I check the following links with no luck
iOS - UIEventTypeRemoteControl events not received
https://forums.developer.apple.com/thread/84204
Unable to receive remoteControlReceivedWithEvent - objective c - ios
remoteControlReceivedWithEvent in AVAudio is not being called
remoteControlReceivedWithEvent not Called in appDelegate
Finally I fix the issue by using remoteCommandCenter and play and pause buttons instead of tooglePlayPauseCommand
if(SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(#"11.0")){
//NOTE: this is the only way that I find to make this work on IOS 11 its seems to be that togglePlayPauseCommand is not working anymore
MPRemoteCommandCenter* commandCenter = [MPRemoteCommandCenter sharedCommandCenter];
[commandCenter.playCommand addTargetWithHandler:^MPRemoteCommandHandlerStatus(MPRemoteCommandEvent * _Nonnull event) {
[[NSNotificationCenter defaultCenter] postNotificationName:kCYCAppDelegatePlayNotificationName object:nil];
return MPRemoteCommandHandlerStatusSuccess;
}];
[commandCenter.pauseCommand addTargetWithHandler:^MPRemoteCommandHandlerStatus(MPRemoteCommandEvent * _Nonnull event) {
[[NSNotificationCenter defaultCenter] postNotificationName:kCYCAppDelegatePauseNotificationName object:nil];
return MPRemoteCommandHandlerStatusSuccess;
}];
[[NSNotificationCenter defaultCenter] addObserver:self forName:kCYCAppDelegatePlayNotificationName object:nil queue:nil usingBlock:^(NSNotification *note, CYCCastManager *observer) {
if (!observer.isCastPlaying) {
[observer play:NO];
}
}];
[[NSNotificationCenter defaultCenter] addObserver:self forName:kCYCAppDelegatePauseNotificationName object:nil queue:nil usingBlock:^(NSNotification *note, CYCCastManager *observer) {
if (observer.isCastPlaying) {
[observer pause];
}
}];
}
Just modified by Juan's answer.
if(#available(iOS 11, *)) {
MPRemoteCommandCenter* commandCenter = [MPRemoteCommandCenter sharedCommandCenter];
[commandCenter.playCommand addTargetWithHandler:^MPRemoteCommandHandlerStatus(MPRemoteCommandEvent * _Nonnull event) {
[[NSNotificationCenter defaultCenter] postNotificationName:#"RemotePlayCommandNotification" object:nil];
return MPRemoteCommandHandlerStatusSuccess;
}];
[commandCenter.pauseCommand addTargetWithHandler:^MPRemoteCommandHandlerStatus(MPRemoteCommandEvent * _Nonnull event) {
[[NSNotificationCenter defaultCenter] postNotificationName:#"RemotePauseCommandNotification" object:nil];
return MPRemoteCommandHandlerStatusSuccess;
}];
[[NSNotificationCenter defaultCenter] addObserverForName:#"RemotePlayCommandNotification" object:nil queue:nil usingBlock:^(NSNotification * _Nonnull note) {
NSLog(#"Clicked the play button.");
}];
[[NSNotificationCenter defaultCenter] addObserverForName:#"RemotePauseCommandNotification" object:nil queue:nil usingBlock:^(NSNotification * _Nonnull note) {
NSLog(#"Clicked the pause button.");
}];
}

change orientation when video is finished in iOS

I think my coding on done button is not working as i am changing my screen orientation when video is starting and when video is finished i need to come back to my normal orientation my coding is.
vid = [[MPMoviePlayerViewController alloc] initWithContentURL:url];
//[self presentModalViewController:vid animated:YES];
[self presentMoviePlayerViewControllerAnimated:vid];
NSNumber *value = [NSNumber numberWithInt:UIInterfaceOrientationLandscapeLeft];
[[UIDevice currentDevice] setValue:value forKey:#"orientation"];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(donebutton) name:MPMoviePlayerDidExitFullscreenNotification object:vid];
and then the coding done button method
-(void) donebutton{
NSLog(#"done");
NSNumber *value = [NSNumber numberWithInt:UIInterfaceOrientationPortrait];
[[UIDevice currentDevice] setValue:value forKey:#"orientation"];
}
Hope this code will help you to change device orientation when a video playing is completed.
-(void)playVideo {
moviePlayer = [[MPMoviePlayerController alloc] initWithContentURL:url];
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:#selector(moviePlayBackDidFinish:)
name:MPMoviePlayerPlaybackDidFinishNotification
object:moviePlayer];
[moviePlayer setFullscreen:YES animated:YES];
}
- (void)moviePlayBackDidFinish:(NSNotification *)notification {
moviePlayer = [notification object];
[[NSNotificationCenter defaultCenter]
removeObserver:self
name:MPMoviePlayerPlaybackDidFinishNotification
object:moviePlayer];
// If the moviePlayer.view was added to full screen, it needs to be removed
moviePlayer.fullscreen = NO;
}

postNotificationName is not yet trigger in appdelegate class

In Appdelegate.m added postNotification method
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
if(application.applicationState == UIApplicationStateBackground) {
[[NSNotificationCenter defaultCenter] postNotificationName: #"SuggetionPushNotification" object:nil userInfo:userInfo];
AppDelegate *appDel = (AppDelegate *)[[UIApplication sharedApplication] delegate];
SideMenuViewController *leftMenuViewController = [[SideMenuViewController alloc] init];
MFSideMenuContainerViewController *container = [MFSideMenuContainerViewController
containerWithCenterViewController:[[UINavigationController alloc]
initWithRootViewController:[[SuggetionViewController alloc] init]]
leftMenuViewController:leftMenuViewController
rightMenuViewController:Nil];
[self.window makeKeyAndVisible];
appDel.window.rootViewController = container;
}
}
ViewController B (SuggetionViewController) In viewDidLoad
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(receiveTestNotification:)
name:#"SuggetionPushNotification"
object:nil];
- (void) receiveTestNotification:(NSNotification *) notification {
NSLog(#"working");
}
But here not yet fire Notification, if added both post and addobserver in same class then only it fire. what wrong i made. I referred from Send and receive messages through NSNotificationCenter in Objective-C? Please help
Your View Controller B is not in memory when you are posting the notification thats why Controller B is unable to observe the notification. Add Delay before posting the notification will help.
double delayInSeconds = 2.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
[[NSNotificationCenter defaultCenter] postNotificationName: #"SuggetionPushNotification" object:nil userInfo:nil];
});
You're calling your notification from the launch method in the app delegate before any view/viewcontroller hierarchy has a change to instantiate and load. The reason you are not getting the notification is because your SuggetionViewController has not been instantiated yet. If you want the notification to be received, you need to fire it after the view controller gets a change to be created.
You can't receive notification inside your SuggetionViewController if it's now loaded.
You add the observer in the viewDidLoad so it can happens that you recieve a remote notification while the SuggetionViewController is not loaded.
You should ensure that your controller is loaded before processing notifications.
In your AppDelegate implementation add this
static void displayStatusChanged(CFNotificationCenterRef center, void *observer,
CFStringRef name, const void *object,
CFDictionaryRef userInfo) {
if (name == CFSTR("com.apple.springboard.lockcomplete")) {
[[NSUserDefaults standardUserDefaults] setBool:YES
forKey:#"kDisplayStatusLocked"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
}
In applicationDidFinishLaunchingWithOptions, add this below code
CFNotificationCenterAddObserver(
CFNotificationCenterGetDarwinNotifyCenter(), NULL, displayStatusChanged,
CFSTR("com.apple.springboard.lockcomplete"), NULL,
CFNotificationSuspensionBehaviorDeliverImmediately);
Post it in your didRecieveRemoteNotification method.
[[NSNotificationCenter defaultCenter]postNotificationName:#"TestNotification" object:self];
Post this in your view controller viewDidLoad method.
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(receiveTestNotification:)
name:#"TestNotification"
object:nil];
Then it will trigger this method.
- (void) receiveTestNotification:(NSNotification *) notification
{
if ([[notification name] isEqualToString:#"TestNotification"]) {
NSLog (#"Successfully received the test notification!");
}
}
Your 'SuggetionViewController' object is not initialized when you post the notification. So there is no 'SuggetionViewController' object to catch the notification.
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo{
if(application.applicationState == UIApplicationStateBackground) {
AppDelegate *appDel = (AppDelegate *)[[UIApplication sharedApplication] delegate];
SideMenuViewController *leftMenuViewController = [[SideMenuViewController alloc] init];
SuggetionViewController *sug_controller = [[SuggetionViewController alloc] init]];
[sug_controller registerNotification];
[[NSNotificationCenter defaultCenter] postNotificationName: #"SuggetionPushNotification" object:nil userInfo:userInfo];
MFSideMenuContainerViewController *container = [MFSideMenuContainerViewController containerWithCenterViewController:[[UINavigationController alloc] initWithRootViewController:sug_controller leftMenuViewController:leftMenuViewController rightMenuViewController:Nil];
[self.window makeKeyAndVisible];
appDel.window.rootViewController = container;
}
}
Add the following instance method to SuggetionViewController
- (void)registerNotification
{
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(receiveTestNotification:) name:#"SuggetionPushNotification" object:nil];
}
- (void)receiveTestNotification
{
NSlog(#"Notification recieved-->>>");
}

How to Show Push Notifications on another ViewController. I am receiveing it on Appdelegate page on all the three cases

Please tell me how to send the appdelegate to another viewcontroller using NSdoctionary and receive it on the new view controller and show it.
-(void)application:(UIApplication*)application didReceiveRemoteNotification: (NSDictionary*)userInfo
{
NSLog(#"Push received: %#", userInfo);
}
There are few ways/ But I prefer using https://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Classes/NSNotificationCenter_Class/index.html
Somrewere in constants
NSString *const NOTIFICATION_ID = #"com.yourapp.notificationID";
ViewController.m
- (void)viewDidLoad
{
NSNotificationCenter * notificationCenter = [NSNotificationCenter defaultCenter];
[notificationCenter addObserver:self
selector:#selector(notificationRecieved:)
name:NOTIFICATION_ID
object:nil];
}
- (void)notificationRecieved:(NSNotification*)notification
{
NSLog(#"Push received: %#", notification.userInfo);
}
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self name:NOTIFICATION_ID object:nil];
}
AppDelegate.m
-(void)application:(UIApplication*)application didReceiveRemoteNotification: (NSDictionary*)userInfo
{
[[NSNotificationCenter defaultCenter] postNotificationName:NOTIFICATION_ID object:nil userInfo:userInfo];
}
Use Notifications. The app delegate will post the notification with the notification dictionary, the view controller will be listening for it.

Where is the best place to remove Observer from Notification Center

I think that should be here:
-(void) viewWillDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
[nc removeObserver:self];
}
or maybe in -dealloc.
Both sound strange to me so I´m not totally sure of it.
First, in my AppDelegate I´m listening to a Remote Notification Via Parse
- (void)application:(UIApplication *)application
didReceiveRemoteNotification:(NSDictionary *)userInfo {
[PFPush handlePush:userInfo];
NSString * urlToGo = [userInfo objectForKey:#"url"];
NSLog (#"Recibo notificación con paremetro url: %#", urlToGo);
NSNotification *note = [NSNotification
notificationWithName:PUSH_NOTIFICATION
object:self
userInfo:userInfo];
[[NSNotificationCenter defaultCenter] postNotification:note];
}
and in myViewController
- (void) viewDidLoad {
[super viewDidLoad];
_lastMenuSelected=menu1;
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
NSOperationQueue *mainQueue = [NSOperationQueue mainQueue];
[center addObserverForName:PUSH_NOTIFICATION
object:nil
queue:mainQueue
usingBlock:^(NSNotification *note) {
// Save in property to load parameter in prepareForSegure
_urlToLoadFromPush = urlToGoReceivedFromPush;
[self showPush:self];
}];
}
- (void)showPush:(id)sender {
PushViewController * pushViewController=(PushViewController*)[self.storyboard instantiateViewControllerWithIdentifier:#"PushId"];
pushViewController.url = _urlToLoadFromPush;
UINavigationController* nVC=[[UINavigationController alloc] initWithRootViewController:pushViewController];
[self presentViewController:nVC animated:YES completion:^{
//[_delegate logout];
}];
}
Since you seem to be adding the observer in the viewDidLoad method (which is only called once as of iOS 6), you should remove the observer in the dealloc method.
Don't remove the observer in viewWillDisappear beacause generally we require to post the notification when the view is in the stack but not appearing. So always try to remove the observers in -(void)dealloc with the name of observer.

Resources