IOS: Available actions after iBeacon detection - ios

If a locked iPhone detects an iBeacon signal registered with my app, can my app, during its ~5-10sec wake up time:
contact my web server to send some data?
send a predefined text message?
access the iPhone's current GPS location?

Yes, I can confirm you can contact a web server, and access fine location (GPS) as I commonly do this during the window you mention.
I have less experience sending SMS text messages on iOS, but my basic understanding is that you cannot send SMS messages at all in an automated fashion on iOS, you can only present the screen to the user to initiate the send. I do not believe you can do this when your app is not in the foreground.
You can, however, send local notifications that appear on the lock screen.

Yes app can do all these actions while phone is locked.
Also if you want to continue scanning and all these functionalities in the background you can use UIBackgroundTaskIdentifier
It will continue scanning in the background till there is any beacon detected. Once there will be no beacon available, it stops scanning in background at the end of tolerate time.
- (void)applicationDidEnterBackground:(UIApplication *)application
{
NSLog(#"=== DID ENTER BACKGROUND ===");
UIBackgroundTaskIdentifier bgTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
NSLog(#"End of tolerate time. Application should be suspended now if we do not ask more 'tolerance'");
}];
if (bgTask == UIBackgroundTaskInvalid) {
NSLog(#"This application does not support background mode");
}
else {
//if application supports background mode, we'll see this log.
NSLog(#"Application will continue to run in background");
}
}

Related

Asynchronous code doesn't execute until app foregrounded in application:didReceiveRemoteNotification:fetchCompletionHandler:

In our app, we want to download a small amount of data in response to a push notification. So far, push notifications are working smoothly, launching the app in the background and causing didReceiveRemoteNotification to be called.
The problem is that, after this method returns, the app doesn't get any more CPU time until it's foregrounded again, so there's no opportunity to fetch that data asynchronously in the background.
Reducing this to the simplest case, I'm still unable to get asynchronous code running.
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
[application setApplicationIconBadgeNumber:1];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[application setApplicationIconBadgeNumber:9];
completionHandler(UIBackgroundFetchResultNewData);
});
}
In response to a push, the app launches in the background and the badge count is set to 1, but the badge number is not set to 9 until the app is launched from the home screen.
Shouldn't iOS keep running the app until that completion handler is called, up to 30 seconds?
The Info.plist has the remote-notification background mode specified, the push payload contains 'content-available' : '1', and I'm not quitting the app by swiping up in the app switcher.
To add, we're using Parse to send this push notification using the following Javascript:
Parse.Push.send({
where: installationQuery,
data: {
"content-available": 1,
}
}, { success: function() {},
error: function(error) {}
});
First take a here and make sure you enabled push notification and added the content-available field:
Using Push Notifications to Initiate a Download
If your server sends push notifications to a user’s device when new content is available for your app, you can ask the system to run your app in the background so that it can begin downloading the new content right away. The intent of this background mode is to minimize the amount of time that elapses between when a user sees a push notification and when your app is able to able to display the associated content. Apps are typically woken up at roughly the same time that the user sees the notification but that still gives you more time than you might have otherwise.
To support this background mode, enable the Remote notifications option from the Background modes section of the Capabilities tab in your Xcode project. (You can also enable this support by including the UIBackgroundModes key with the remote-notification value in your app’s Info.plist file.)
For a push notification to trigger a download operation, the notification’s payload must include the content-available key with its value set to 1. When that key is present, the system wakes the app in the background (or launches it into the background) and calls the app delegate’s application:didReceiveRemoteNotification:fetchCompletionHandler: method. Your implementation of that method should download the relevant content and integrate it into your app.
When downloading any content, it is recommended that you use the NSURLSession class to initiate and manage your downloads. For information about how to use this class to manage upload and download tasks, see URL Loading System Programming Guide.
Next, is there a reason your using "dispatch_after" with 2 seconds delay?
It is possible that since you call "dispacth_after" by the end of the run loop iOS "thinks" there's no pending work to do and puts the process to sleep so by the time the block is dispatched no one is listening to it.
Replacing it with "dispatch_async" might solve this.
Finally, if you do need to delay, you should tell iOS you need some time in the background, like this -
UIApplication *application = [UIApplication sharedApplication];
UIBackgroundTaskIdentifier __block backgroundTaskId = [application beginBackgroundTaskWithExpirationHandler:^{
if (backgroundTaskId != UIBackgroundTaskInvalid) {
[application endBackgroundTask:backgroundTaskId];
backgroundTaskId = UIBackgroundTaskInvalid;
}
}];
Then do your background work.
Don't forget end the task when your work is done. call something like -
if (backgroundTaskId != UIBackgroundTaskInvalid) {
[application endBackgroundTask:backgroundTaskId];
backgroundTaskId = UIBackgroundTaskInvalid;
}

How to Execute a task continuously when application is in Background state in iOS 8

I Write the below code for executing a task when application is in background state it is working fine in iOS 7 but it is not working in iOS 8.
Can someone give me solution to execute a task continuously in iOS 8 when application is in background state.
- (void)applicationDidEnterBackground:(UIApplication *)application
{
UIApplication *app = [UIApplication sharedApplication];
UIBackgroundTaskIdentifier bgTask;
bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
[app endBackgroundTask:bgTask];
}];
}
There is no way to execute task continuously in background (except in few cases).
Most apps can move to the extended state easily enough but there are
also legitimate reasons for apps to continue running in the
background. The techniques offered by iOS fall into three
categories:
Apps that start a short task in the foreground can ask for time to
finish that task when the app moves to the background.
Apps that initiate downloads in the foreground can hand off management of those downloads to the system, thereby allowing the app to be suspended or
terminated while the download continues.
Apps that need to run in the background to support specific types of tasks can declare their support for one or more background execution modes.
For tasks that require more execution time to implement, you must
request specific permissions to run them in the background without
their being suspended. In iOS, only specific app types are allowed to
run in the background:
Apps that play audible content to the user while in the background,
such as a music player app
Apps that record audio content while in the
background
Apps that keep users informed of their location at all
times, such as a navigation app
Apps that support Voice over Internet
Protocol (VoIP)
Apps that need to download and process new content
regularly
Apps that receive regular updates from external accessories
Apps that implement these services must declare the services they
support and use system frameworks to implement the relevant aspects of
those services. Declaring the services lets the system know which
services you use, but in some cases it is the system frameworks that
actually prevent your application from being suspended.
yes i have implement the background condition while implementing ibeacon. delegate was set in interface
#interface HomeMainVC ()<ESTBeaconManagerDelegate>{
and i was able to send local notification if user enters or exist the beacon region throug following function. So there must be some way to send user location to.
//Beacon manager did enter region
- (void)beaconManager:(ESTBeaconManager *)manager didEnterRegion:(ESTBeaconRegion *)region
{}
//Beacon Manager did exit the region
- (void)beaconManager:(ESTBeaconManager *)manager didExitRegion:(ESTBeaconRegion *)region
{}
You have used following code but it is called only once when application is send to background mode so there is no use of it for you. If you want to do some things only once a time while going in background mode then it is useful for you.
- (void)applicationDidEnterBackground:(UIApplication *)application
{
UIApplication *app = [UIApplication sharedApplication];
UIBackgroundTaskIdentifier bgTask;
bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
[app endBackgroundTask:bgTask];
}];
}

Pubnub connection stops when application goes into background state iOS 8

Title says it all.
I've looked at this question and also here on the pubnub forums (same question, just different suggestion).
The core of the issue is that as soon as the application suspends, pubnub connectivity is queued and not sent until the app goes back to foreground. It seems to be a reasonable thing to do to send a notification saying that you're going in the background on your channel but it doesn't work.
From my readings I understand that pubnub uses websockets and that it is not allowed in background mode. Even tried to enable VOIP as a background mode with no luck but Location updates bg mode works. However, using this will have my app rejected as I don't use location services.
When running this code
- (void)applicationDidEnterBackground:(UIApplication *)application {
[PubNub sendMessage:#"Hello from PubNub iOS!" toChannel:self.myChannel;
}
I get this log entry from pubnub (so at least I know the command is ran):
Looks like the client suspended"; Fix suggestion="Make sure that your application is configured to run persistently in background
I have been killing myself over this for a day. One of these days where you start doing something that you think is pretty simple, a 15min thing and it turns into a day of frustration ... You know what I mean :)
I was actually able to send the messages I needed when the app was about to enter Background. And without enabling any of the background modes.
I took advantage of the background finite task as explained is this tutorial.
- (void)applicationWillResignActive:(UIApplication *)application {
[PubNub updateClientState:#"MyID" state:#{#"appState":#"Background",#"userNickname":#"MyNickname"} forObject:[PNChannel channelWithName:#"MyChannel"]];
self.backgroundTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
NSLog(#"Background handler called. Not running background tasks anymore.");
[[UIApplication sharedApplication] endBackgroundTask:self.backgroundTask];
self.backgroundTask = UIBackgroundTaskInvalid;
}];
}
And implementing the stop background when coming back online
- (void)applicationDidBecomeActive:(UIApplication *)application {
if (self.backgroundTask != UIBackgroundTaskInvalid)
{
[[UIApplication sharedApplication] endBackgroundTask:self.backgroundTask];
self.backgroundTask = UIBackgroundTaskInvalid;
NSLog(#"Task invalidated");
}
}

XMPPFramework - XMPP Connection staying alive for a long time - applicationDidEnterBackground

I am using xmppframework to develop an iOS chat application. The issue is, I expect the XMPP connection to go offline when the app is minimised/not active in some time.
But to my surprise, the user is not going offline. I believe thats my issue. The reason, I want the user to go offline is that when the user is offline, and the user receives a push notification (through APNS), I have programmed in such a way that the XMPP connection is reestablished when the user clicks on the push notification and launches the app.
This works fine when the user goes offline
But when the user is online ( say 12 hrs the user is online) for a long time after the app is minimised (which is happening to me at the moment), when I try to send a message to the user, the user is not receiving the internal push notification nor the messages which I am sending though the user status is ONLINE .This mostly happens in iPhone 4 running in version iOS7.
Below is the applicationDidEnterBackground code
- (void)applicationDidEnterBackground:(UIApplication *)application
{
NSMutableArray *tempaaray=[DatabaseAccess getBedageValueFromConversation];
NSLog(#"getBedageValueFromConversation is :%lu",(unsigned long)tempaaray.count);
//================XMPP
// Use this method to release shared resources, save user data, invalidate timers, and store
// enough application state information to restore your application to its current state in case
// it is terminated later.
//
// If your application supports background execution,
// called instead of applicationWillTerminate: when the user quits.
DDLogVerbose(#"%#: %#", THIS_FILE, THIS_METHOD);
#if TARGET_IPHONE_SIMULATOR
DDLogError(#"The iPhone simulator does not process background network traffic. "
#"Inbound traffic is queued until the keepAliveTimeout:handler: fires.");
#endif
if ([application respondsToSelector:#selector(setKeepAliveTimeout:handler:)])
{
[application setKeepAliveTimeout:600 handler:^{
DDLogVerbose(#"KeepAliveHandler");
// Do other keep alive stuff here.
}];
}
}
Can I add the below line in the applicationDidEnterBackground delegate method
if (![xmppStream isDisconnected]) {
[self disconnect];
}
This will forcefully disconnect the user and make the user go offline every time the user minimises the app. And once he comes online, messages will resume. Or do I need to localise this code for only iPhone4 and iOS7 users?
Or is there any other good way of tackling this issue?
Please let me know

Handling push notification when app is in background and device is locked

I am working on developing an Enterprise application where maintaining users session synced with device session is a key and required feature.
The basic requirement was to end user session from server as soon as user kills the app, but as there is know way we can get app termination event in code (except starting a background task which can run maximum for 10 mins), server remains unaware about app kill.
I made some workaround to solve this problem.
First, I Used background modes -
a) App downloads content from the network.
b) App downloads content in response to push notifications.
The idea is when user send app in background by switching to another app or by home button or locks device, app is sending a request to the server that app is going in background, and server get to know that app went in background.
-(void)applicationWillResignActive:(UIApplication *)application
{
// notify server that app is in background
}
As soon as server receives the request, it starts the timer for this specific device, which keep on counting apps time spent in background. For every five minutes server sends a request to the device which is in background to get its STATUS.
-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary*)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler{
NSDictionary *aps = [userInfo objectForKey:#"aps"];
NSLog(#"NOTIFICATION IN BG %#",[aps objectForKey:#"message"]);
NSString *message = [aps objectForKey:#"message"];
if([message isEqualToString:#"Please update your status"]){
// NOTIFY SERVER THAT APP IS IN BACKGROUND
}
if(application.applicationState != UIApplicationStateBackground){
[self application:application didReceiveRemoteNotification:userInfo];
}
completionHandler(UIBackgroundFetchResultNewData);
}
As soon as app again comes in foreground or become active app notifies server that it has become active.
- (void)applicationDidBecomeActive:(UIApplication *)application
{
// notify server that app is in Foreground // server resets the background timer to 0 for corresponding device
}
This approach helps in tracking if app is terminated or not, if server does not get any response from the notification that it sent, it clears the user session from server.
NOW, There are two scenarios in 1st one it works perfectly as expected and in second it doesent.
CASE 1 : App in BackGround but DEVICE NOT LOCKED
App Launched
User logged in
App went in BG
Server has been notified that app is in BG.
Server starts timer.
Elapsed time exceeds 5 mins on server for this device (As app still in BG) .
Server sends notification.
App receives remote push notification in BG.
App notifies its status to server that is in BG (Hence server came to know that it is not terminated and user session should not be cleared off)
This cycle of remote notification and reply to server from device from BackGround goes on till the time either app becomes active again or it is terminated.
Works perfectly fine as expected.
CASE 2 : App in BackGround and DEVICE LOCKED
App Launched
User logged in
App went in BG
Server has been notified that app is in BG.
Server starts timer.
Device is lOCKED
Elapsed time exceeds 5 mins on server for this device (As app still in BG) .
Server sends notification.
Device receives Notification, Device displays banner for notification.
BUT App which is inactive mode does not receives remote push notification in BG.
As a Result App is not able to reply to the server
And whole cycle goes for a toss.
THE ULTIMATE QUESTION IS HOW TO MAKE IT WORK WHEN DEVICE IS LOCKED.
-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
NSLog(#"user info %#",userInfo );
}
by this delegate method you can receive dictionary from server.And can do your work accordingly.This method will call in your app after click on notification in notification tray.

Resources