I have implemented local notification for checking battery status. If the battery level is drop by 1% then local notification is received.This works for both i.e. app is in foreground or background for iOS version below 9.
When I update device OS to iOS 9,then I received local notification in foreground but unable to receive notification in background of the Application.
Following is the code which are used to implement.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Enable monitoring of battery status
**[[UIDevice currentDevice] setBatteryMonitoringEnabled:YES];**
// Request to be notified when battery charge or state changes
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(checkBatteryStatus) name:UIDeviceBatteryLevelDidChangeNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(checkBatteryStatus) name:UIDeviceBatteryStateDidChangeNotification object:nil];
}
- (void)applicationDidEnterBackground:(UIApplication *)application {
// Request to be notified when battery charge or state changes
[[UIDevice currentDevice] setBatteryMonitoringEnabled:YES];
**[[NSNotificationCenter defaultCenter] postNotificationName:UIDeviceBatteryLevelDidChangeNotification object:nil userInfo:nil];**
**[[NSNotificationCenter defaultCenter] postNotificationName:UIDeviceBatteryStateDidChangeNotification object:nil userInfo:nil];**
}
- (void)checkBatteryStatus
{
notifyAlarm = [[UILocalNotification alloc] init];
notifyAlarm.alertBody = #“battery alert";
notifyAlarm.soundName = UILocalNotificationDefaultSoundName;
[[UIApplication sharedApplication] presentLocalNotificationNow:notifyAlarm];
[self displayNotification];
}
In displayNotification method we display notification.
I also enable background mode of the app i.e. shown in screenshot.
enter image description here
Any help would be appreciated. Thanks in advance.
You have enabled background fetch mode, which means that your app can receive remote notifications and perform network requests while in the background.
Without using questionable and App Store rejectable methods, it is not possible to do what you want. Apple specifically doesn't want you to be able to run your application in the background unless you have one of their approved use cases.
Related
I'm writing an IOS application which will record ( over time ) the current battery level of the iPhone device.
I have working code executing within the foreground using UIDeviceBatteryLevelDidChangeNotification, this fires a notification ( which is handled successfully ) when the app in in foreground mode.
Code is as follows:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[[UIDevice currentDevice] setBatteryMonitoringEnabled:YES];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(batteryChanged:) name:UIDeviceBatteryLevelDidChangeNotification object:nil];
return YES;
}
- (void)batteryChanged:(NSNotification *)notification
{
NSLog(#"Battery Changed From Observer");
[self UpdateBatteryStatus];
}
-(void)UpdateBatteryStatus
{
UIDevice *myDevice = [UIDevice currentDevice];
double batLeft = (float)[myDevice batteryLevel] * 100;
NSLog(#"Battery level: %f", batLeft);
// Do some stuff related to battery status
}
This executes ( output via log proves it ) every 1% increment ( or decrement ) on the battery status on the phone, which works exactly as expected.
When the app is moved to the background however, the events stop firing. Upon moving the app back to the foreground, the events fire ( it's almost like they are queued up until it reaches the foreground ).
I have searched stack overflow, and most answers are all the same, basically this is a background-mode permissions problem. So I ticked all the boxes:
I added everything just to make sure it wasn't a background persmission problem. Unfortunately, even after a clean, and rebuild ( also a shutdown of Xcode, and re-plugin of iPhone ) the events still do not fire.
Please bear in mind, I have no intention of releasing this to the app store, I'm aware that faking background-mode use cases is a quick and easy rejection. But I would like to get it working for personal usage.
Edit: ios target 11.3
Your app won't get NSNotificationCenter notifications while being in background/suspended. What you could try is to use fetch background mode to mimic remote downloads. Note however downsides of this approach - system itself will decide when to call the callback.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[application setMinimumBackgroundFetchInterval:UIApplicationBackgroundFetchIntervalMinimum];
return YES;
}
- (void)application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
{
UIDevice *myDevice = [UIDevice currentDevice];
double batLeft = (float)[myDevice batteryLevel] * 100;
NSLog(#"Battery level: %f", batLeft);
completionHandler(UIBackgroundFetchResultNewData);
}
If you as stated do not plan to release your app in AppStore you can try another hacks with background modes like infinite playing a muted sound in background.
I need to show a universal custom view whenever i received a notification in a active app.
I have created a view , but i am not getting how to show that!
Can anyone help me out.
You have to handle the notification in the AppDelegate methods (usually application(_:didReceiveRemoteNotification:fetchCompletionHandler:)) and launch the view in the form it can be shown in any screen of your app.
You can read the docs for UIApplicationDelegate here, section Responding to Notifications and Events.
You will be receiving the push notification in AppDelegate's application(_:didReceiveRemoteNotification:fetchCompletionHandler:) from here you can handle.
- (void)application:(UIApplication *)application
didReceiveRemoteNotification:(NSDictionary *)userInfo
fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))handler
{
// 1. You can call your universal view from here
OR
// 2. You can post this local notification with information
NSDictionary *userInfo = [NSDictionary dictionaryWithObject:myObject forKey:#"info"];
[[NSNotificationCenter defaultCenter] postNotificationName:#"showNotification"
object:nil
userInfo:userInfo];
}
For 2nd Option, you will need add observer and receiving method:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(receiveNotification:)
name:#"showNotification"
object:nil];
-(void)receiveNotification:(NSNotification *)notification {
// call your view
}
I want to get battery usage data from my iPhone. I used UIDevice currentDevice.batteryLevel code, but its returning -1.0000 in NSLog value.
Anyone please help me?
One more question, can I able to fetch other app battery usages in my app?
First, you must enable batteryStatus notification (in appDelegate.m for instance):
- (void)applicationDidBecomeActive:(UIApplication *)application {
...
[[UIDevice currentDevice] setBatteryMonitoringEnabled:YES];
// Now, the system will post UIDeviceBatteryStateDidChangeNotification notification when batteryStatus (or connection) will change
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(batteryStatusDidChange:) name:UIDeviceBatteryStateDidChangeNotification object:nil];
...
}
Then, you can check battery level calling:
[UIDevice currentDevice].batteryLevel;
that will return you a value between 0.0 (0% chareg) and 1.0 (100% charge).
Without calling first setBatteryMonitoringEnabled, battery state will return UIDeviceBatteryStateUnknown and the value of this property is –1.0. (from docs).
In my app, there's a collection view displaying a set of images retrieved from a web service. Each image has tags. So the app has the ability to filter images using tags as well.
Now I'm trying to add push notifications to this app. A push notification is sent when new images have been added to the server. These images are tagged say, latest. I'm passing that tag as the message via a push notification and what I need is when the user taps on the push notification to open the app, it should load the latest new images to the collection view.
I'm half way done. I receive the push notification with the message successfully to the didReceiveRemoteNotification method in the AppDelegate.m file. Now I need to pass it on to the view controller where the collection view is. I'm stuck at this point. I can't figure out how to send it over to the view controller.
I tried declaring a property in the App delegate, assign the message value to it and referring it from the view controller but it didn't work. I tied delegates, notification center, user defaults but nothing worked.
Can anyone please tell me how to accomplish this?
Thank you.
Edit:
Here's my code. The last method I tried was the local notifications.
AppDelegate.m
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
[[NSNotificationCenter defaultCenter] postNotificationName:#"PushNotificationMessageReceivedNotification" object:nil userInfo:userInfo];
}
ViewController.m
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(remoteNotificationReceived:) name:#"PushNotificationMessageReceivedNotification"
object:nil];
}
- (void)remoteNotificationReceived:(NSNotification *)notification
{
NSLog(#"Notification: %#", notification.userInfo);
NSString *msg = [[notification.userInfo valueForKey:#"aps"] valueForKey:#"alert"];
self.label.text = msg;
}
Case 1: if your app is background and user launches app with notification click then you have the check if app launched form notification or normal
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
NSDictionary *remoteNotificationPayload = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
if (remoteNotificationPayload) {
[[NSNotificationCenter defaultCenter] postNotificationName:#"notification" object:nil userInfo:remoteNotificationPayload];
}
return YES; }
Case2: If your app is in forground notification will be received in didReceiveRemoteNotification
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
NSLog(#"userinfo %#",userInfo);
[[NSNotificationCenter defaultCenter] postNotificationName:#"notification" object:nil userInfo:userInfo];
}
Now you and add a observer in any controller with Local notification and do what you wand to do
I don't know it will work or not,its only my suggestion. I did't tried it before but in your case may be it work
user NSUserDefaults for this.
in your appDelegate.m
[[NSUserDefaults standardUserDefaults] setObject:imageArrayFromServer forKey:#"MyAppSpecificGloballyUniqueString"];
in your viewController.m
NSArray *myArray = [[NSUserDefaults standardUserDefaults] objectForKey:#"MyAppSpecificGloballyUniqueString"];
I registered my main view controller for listening to UIApplicationDidBecomeActiveNotification because I want to display a UIAlertView each time the user enters my app :
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(someMethod:)
name:UIApplicationDidBecomeActiveNotification
object:nil];
It's working like a charm, my only problem is if my app gets interrupted (by an UIAletView, such as a calendar event, or a popup asking for picture access confirmation), the notification gets called once the alert view's dismissed.
Any idea on how to detect ONLY when my app comes back from background mode ?
why don't you use AppDelegate method,
- (void)applicationWillEnterForeground:(UIApplication *)application
{
//do whatever you want when app comes from background to foreground
}
I know this is an old thread, but there is a UIApplicationWillEnterForegroundNotification. Works like this:
[[NSNotificationCenter defaultCenter]addObserver:self
selector:#selector(myMethod)
name:UIApplicationWillEnterForegroundNotification
object:nil];
Best regards,
Gabriel Tomitsuka
Check state (active/background) of your application by following code:
UIApplicationState state = [[UIApplication sharedApplication] applicationState];
if (state == UIApplicationStateActive)
{
/// your stuff of code:
}
Above code might be useful in your case: