Receiving push notifications in iOS without alert message even when app is not active - ios

From Apple's Push Notification Guide:
If the target application isn’t running when the notification arrives, the alert message, sound, or badge value is played or shown. If the application is running, iOS delivers it to the application delegate as an NSDictionary object. The dictionary contains the corresponding Cocoa property-list objects (plus NSNull).
I have implemented this in my app and everything works fine. If the app is in focus, the app gets the message directly. If not active, an alert is shown, the app launches when the user clicks the alert, and finally the app gets hold of the message.
Would it be possible, however, in the case of a message arriving when the app is not active, to get iOS to activate the app and pass the message on without showing any message or requiring any user interaction?
I would like this behavior because the push message from my server only might be of interest to the user, depending on her current position. The app works like this: When it starts, it registers for push and tells my server: I am at this position and would like to be notified when something interesting happens near me. At a later point the server sends a message, but since the user might have moved from the area, I would like the app to check the user's position again, and not bother the user if she now is too far from the original position.
I suppose it would be possible to have a background service that notifies the server about the current position every n minutes, but I fear that this will drain the battery.
Any thoughts on this?

Unfortunately, you can't — in iOS — directly open your app when a notification is received. The user must choose himself to open it via the alert displayed by the system.
However, using the background location is not that battery-unfriendly. It depends on the location accuracy you set for your CLLocationManager object.
All the informations about location accuracy can be found here : Location Awareness Programming Guide
In your case, you may want to use the significant location changes methods or the kCLLocationAccuracyKilometer accuracy for example.
Here is a good tutorial to get started : iOS Multitasking: Background Location
Hope this will help.

Related

Is anybody else seeing duplicate calls to handleActionWithIdentifier:forLocalNotification: in WatchKit?

I am getting some very strange behavior with my WatchKit handling of local notification actions that I'm pretty sure is a system bug. I'm wondering if anybody else is seeing the same thing.
(This is using iOS 8.4 and WatchKit 1.0, with an Objective-C app build with Xcode 6.4)
It's too much code to post, and the code is property of the client, so I'll have to describe it.
The background:
I am adding custom "long look" notification support to a client's app.
The app creates geofences around vendor locations. When the user enters one of the geofences, the location manager send a didEnterRegion message to my class that handles geofences.
I turn around and generate a local notification of a defined category. That category is defined as having 2 different UIMutableUserNotificationActions attached to it, one for showing more info about the vendor, and one for displaying driving directions to that vendor's location. (We won't talk about the fact that the user is in shouting distance of the vendor when the geofence fires, so they can SEE the vendor's shop. This is what the client wants, and he's paying me to do it this way.)
The local notification is set to fire immediately (or for testing, I create notifications set to fire in a few seconds.)
The system can do one of 3 things when the notification fires.
1. If the app is running in the foreground, it will send the app delegate a `application:didReceiveLocalNotification:` message.
2. If phone is awake but the app is in the background, it displays the local notification with a system banner/alert (depending on the user's settings.) That banner/alert has buttons for my 2 actions.
3. If the phone is locked and the user has a paired Apple Watch that is allowed to receive notifications, the local notification is sent to the watch.
The Apple Watch app has a custom subclass of WKUserNotificationInterfaceController that is set up to handle this category of user notifications. It adds an image, a title, and a message body to a custom interface controller, with data it gets from the the userInfo dictionary attached to the local notification.
If the user taps one of the action buttons on the WKUserNotificationInterfaceController ("more info" or "directions"), the watch's main interface controller gets a handleActionWithIdentifier:forLocalNotification: message. The code is set up to then send an `openParentApplication:reply:error:' message to the iPhone app. It passes along the user info dictionary it received in the local notification.
The iPhone app responds to the openParentApplication:reply:error message by either requesting driving directions from the location manager (which launches the maps app) or displaying the appropriate info page from the app for the specified vendor.
If the phone is locked when the watch sends the `openParentApplication:reply:error: message to the iPhone, the user doesn't get any feedback, since the phone is locked and Apple doesn't allow a phone to wake itself up.
In that case I therefore invoke the reply block with a dictionary entry of #{#inBackGround: #(YES)}. The watch's reply block checks for inBackground==YES, and if it is, it displays a message to the user that they nee to open the iPhone app in order to see the info/directions.
The problem:
If I launch the iPhone app and trigger a local notification when the phone is locked the first time, the message goes to the watch, the watch displays my custom long look with "more info" and "directions" buttons, and tapping one of the action buttons invokes the watch's handleActionWithIdentifier:forLocalNotification: method, as expected. The watch's handleActionWithIdentifier:forLocalNotification: method sends an openParentApplication:reply:error message to the phone, and the phone displays the appropriate response to the user when the user goes back to the app.
However, the problem comes in if I then trigger a new local notification (also with the phone locked) for a different vendor, with different GPS coordinates and userInfo that points to a different screen of information to display on the phone. When my watch buzzes and I raise it to my wrist, as the "long look" notification for the new local notification is displayed, the watch's handleActionWithIdentifier:forLocalNotification: method fires again, with the identifier and userInfo dictionary from the previous local notification. (I haven't tapped any action buttons on this new notification, or responded to a local notification message on the phone.)
Then, if the user clicks the "more info" action button on the watch's new long look notification controller, that action fires.
The result of this is that when the user goes to his phone, he sees the information for the new vendor he asked about, but when he clicks that away, there is a duplicate copy of the info for the first vendor on his screen.
I've debugged this very carefully, and confirmed that the watch app's interface controller's handleActionWithIdentifier:forLocalNotification: method is being called spuriously. I added a unique NSDate timestamp to the userInfo in the local notification that the iPhone posts, and I see that exact same timestamp repeated in the second (spurious) invocation of the first handleActionWithIdentifier:forLocalNotification: when the second long look notification is displayed.
Has anybody else run across this problem? I guess it's time to file a Radar bug, but I'm not sure what set of steps from my client's app triggers the problem, and it might take me a full day or more to work out a minimum demo app to demonstrate the problem. I know from experience that Apple won't pay any attention to my bug report unless I give them an app that lets them create a repeatable fail-case, along with painfully detailed instructions on how to use it.
The fix:
The fix I have come up with is a dreadful hack. On the phone, I embed a unique "actionFireDate" NSDate into the userInfo dictionary for the local notification. On the watch, I create an empty NSMutableSet "actionFireDates" at startup. When I get a handleActionWithIdentifier:forLocalNotification: call, I get the userInfo for the local notification, get the timestamp NSDate I put in the userInfo dictionary, and check to see if that unique NSDate is in my "actionFireDates" set. If it is, I simply ignore the action. If it's not, I add the new NSDate from the userInfo dictionary in to my set of action fire dates.
I'm pretty sure this is a system bug, and have opened a bug at Apple's bug reporter website (A.K.A. Filed a "radar bug".)
The fix I came up with for this was to add code to my custom WKInterfaceController class's awakeWithContext method that calls dispatch_after to call dismissController 10 seconds after the alert is displayed. If the user does nothing, the alert goes away on it's own.
I'm not going to accept my answer for another couple of days in case somebody else has insights to share on the subject.
EDIT:
Apple closed my Radar bug as a duplicate. I take that to mean that this really is a system bug.

iOS app runs in background and gets notification when a contact is inserted

Is this possible to do? I know basic iOS programming (i've only been playing around with it for a couple weeks), but I was wondering if Apple gives you the ability to do this. I would like the app to receive a notification when a new contact is added and then execute a method from there. Any advice would be great. Thanks!
P.S. I would like the app to not even be running when it gets these notifications too if thats even possible
You mean, when a contact is inserted in the device's address book? No, there's no way to automatically receive a notification triggered by activity in the device's address book.
But with iOS7's added background modes, you could probably take advantage of the Background Fetch mode or Remote Notification mode to regularly check for updates to the user's address book. Background Fetch is technically supposed to be used to fetch data from a server, but you may be able to use it to fetch address book data in this case… Your app would still have to be running though, albeit in the background.

IOS App in Background?

I currently have a discussion with my developers, and we're facing an issue.
We are working on an application which should find offers when user is near some latitudes and longitudes in the GPS Position Tracker. It should send a push notification when user is near a position.
The issue is, it works perfectly when app is "on", but when user "quits" the application the app should go in "Background Mode" and still be available to find users gps position and send back to our webservice in the background mode.
How is that possible?
Is this the solution of do you have a better solution?
1. First time user launch the application we find the users position and make call to webservice to get places nearby 100km and save it to local storage incl. the users unique deviceID (UDID).
User quits the application - here it should run in backgroundMode.
User is near a place in our localstorage database for lat and longitude and now we send a push notification to the users device from the localstorage.
Every 20 minutes we make a call for app to refresh all positions for my currently lng and lat to keep it updated ,
You can preconfigure areas for the app to be notified when the user enters those regions without the need for the app to be in the foreground.
https://developer.apple.com/library/ios/documentation/CoreLocation/Reference/CLLocationManager_Class/CLLocationManager/CLLocationManager.html#//apple_ref/occ/instm/CLLocationManager/startMonitoringForRegion:
So get your places of interest and register those places with the above api, then when your app springs back to life, fire your notification off for whatever you are near.
In iOS, the regions you register with the location manager persist
between launches of your application. If a region crossing occurs
while your iOS app is not running, the system automatically wakes it
up (or relaunches it) in the background so that it can process the
event. When relaunched, all of the regions you configured previously
are made available in the monitoredRegions property of any location
manager objects you create.
The feature you are looking is GeoFencing not push notification. It will create a virtual fence to the specific coordinate and when the user enters into specific distance(say 5km) it will call some delegate methods. So we can implement a local notification with necessary message in that.
I think your solution is something complex and i suggest you to go on with GeoFencing
Find a nice a tutorial here
http://www.creativebloq.com/ipad/get-started-geofencing-ios-9122867

Launch my app from bluetooth iBeacon connection (Private API)

I am creating a private distribution app and I am wondering if it is possible, using any methods or private API's, to open my app when a bluetooth connection has been made.
What I have discovered so far is that with iOS 7 and the ability to use iBeacons you can enter into bluetooth proximity and you can have your app send a notification to allow the user to then open the app.
What I am hoping to do then is have the app running in the background and listen for an iBeacon connection and, if one has been made, actually launch the app without the users control instead of just sending a notification.
I realize this would never be allowed publically, however is there anything private I can look at to achieve this without jailbreaking? I know to launch some apps you can do [[UIApplication sharedApplication] openURL:[NSURL URLWithString:url]]; however I want my app to listen for an iBeacon and then open itself up.
Is there any way or work around to achieve this?
Moving app from background to foreground without user interaction is pain in the ass. Sorry, don't have a solution, just want to share some information:
I asked the same question here and posted a bounty on it and got no good response:
Show some UI from background in audio player or VOIP app on iOS
At some moment I found a solution with the help of another person. It was based on usage of GSEvent (sending clicks to UI). You can look following questions. However, as I know, in iOS 7 these API became protected by entitlement. So, this method is dead (most likely).
Using GraphicsServices.h/GSEvent as well as compiling CLI iPhone tools with Xcode
Use GSEvent to send touch event,but it's invalid.
Simulating System Wide Touch Events on iOS
iPhone, how to fire a button event in programmatically
Apps can use region monitoring to be notified when the user crosses geographic boundaries or when the user enters or exits the vicinity of a beacon. While a beacon is in range of the user’s device, apps can also monitor for the relative distance to the beacon.
In iOS, regions associated with your app are tracked at all times, including when your app is not running. If a region boundary is crossed while an app is not running, that app is relaunched into the background to handle the event. Similarly, if the app is suspended when the event occurs, it is woken up and given a short amount of time (around 10 seconds) to handle the event. When necessary, an app can request more background execution time.
For detailed info:
https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/LocationAwarenessPG/RegionMonitoring/RegionMonitoring.html#//apple_ref/doc/uid/TP40009497-CH9-SW1
There are two scenarios: you either want users to be able to do something with your device other then use your app, or you want them to always be locked into your app.
In the former case you should trust user. Just show the push, timer or location notification and let them decide to launch the app or not.
In the latter case just lock the device using guided access mode.

Recording events with Flurry after app was launched due to a monitored region being entered

The scenario is as follows. I have an iOS app that uses the CLLocationManager's region monitoring feature to notify the app when a predefined geographic region is entered. The way region monitoring works, the app can be notified of a user entering a region, even if the app was previously terminated. Basically, the operating system will launch the app (without bringing it to the foreground), when the region is entered, and gives the app a chance to respond to the region being entered.
What I am trying to do is log an event using Flurry when the region is entered. Currently, it does not seem to be working, as the events are not showing up in Flurry, even after several days. I should note that I have tested both i) that Flurry event logging is otherwise working OK when the app is launched as normal by the user and ii) that my app is indeed receiving the region entered and exited events (I use local notifications each time the region is entered or exited).
My suspicion is that it has something to do with the application delegate lifecycle differing when the app is launched as a result of entering a region versus when the app is launched as a result of the user starting it. My first suspicion was that application:didFinishLaunchingWithOptions: was not called when the app was launched in the background. Because my call to [Flurry startSession:#"my_key"] is in the application:didFinishLaunchingWithOptions: method, this would have explained things. However, the Apple documentation for startMonitoringForRegion:desiredAccuracy: suggests that application:didFinishLaunchingWithOptions: is in fact called:
If you begin monitoring a region and your application is subsequently
terminated, the system automatically relaunches it into the background
if the region boundary is crossed. In such a case, the options
dictionary passed to the application:didFinishLaunchingWithOptions:
method of your application delegate contains the key
UIApplicationLaunchOptionsLocationKey to indicate that your
application was launched because of a location-related event.
Although I'm using startMonitoringForRegion: and not startMonitoringForRegion:desiredAccuracy: (deprecated), I'm assuming that both call application:didFinishLaunchingWithOptions:. I then read a note in the Flurry documentation about startSession: (emphasis mine):
This method serves as the entry point to Flurry Analytics collection.
It must be called in the scope of applicationDidFinishLaunching. The
session will continue for the period the app is in the foreground
until your app is backgrounded for the time specified in
setSessionContinueSeconds:. If the app is resumed in that period the
session will continue, otherwise a new session will begin.
Note:
If testing on a simulator, please be sure to send App to background via home button. Flurry depends on the iOS lifecycle to be complete for full reporting.
So, my suspicion is that even though I am testing on a real device, the app never gets "sent to the background" because when it launches it never enters the foreground to begin with. Can anyone clarify whether this is the reason for my logged events never showing up, or whether there is perhaps some other reason? And, is there a workaround for this?
So I contacted Flurry support and this is what I heard back:
So, at present its not possible to record / log events while the app is in the background.
Our engineering team is working on a solution to this and this should be available in one of the future versions of our SDK, in probably a months time.
So I guess we'll wait and see.

Resources