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
Related
I am working in XMPP Application.
When I terminate and kill My Application than,
1)User is Not Connected In XMPP Server. User is Offline. But I want User is Connected and Online. Like Whats App(Appliction).
2)I can't get Any Messages From XMPP Server Side at that time,
- (void)xmppStream:(XMPPStream *)sender didReceiveMessage:(XMPPMessage *)message
This method is not call. So, How Can I get Messages ?
And i also implement Pushnotification but in this way same issue Like,When app is Kill and Terminate than,This method is not call,
- (void)application:(UIApplication )application didReceiveRemoteNotification:(NSDictionary )userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))handler
So, Please Guide me In Proper Way and Suggest me How to work as like same Whats App(Application).
Also, We can't set VOIP Flag In .plist file Because this way is not Proper and reject by the apple.
My Goal is Only Notification Work As like Whats App.
1)User is Not Connected In XMPP Server. User is Offline. But I want
User is Connected and Online. Like Whats App(Appliction).
Once you closed or minimized WhatsApp the user gets offline (tested on iPhone4s), and messages received in this state are as push notifications.
2)I can't get Any Messages From XMPP Server Side at that time,
(void)xmppStream:(XMPPStream *)sender didReceiveMessage:(XMPPMessage *)message
This method get called only when application is active. So you can not get messages here after you killed your application.
- (void)application:(UIApplication )application didReceiveRemoteNotification:(NSDictionary )userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))handler
This method will get called in following scenarios
If your app is active and you got any new push notification.
If your app is in background or killed or not started then system will show only notification on the top bar, once user tapped on notification it will open your application and then the method will get called.
And of course you can not use VOIP.
WhatsApp shows custom notification when user is active in WhatsApp.
You need to send push notification for every message of your conversation. In this case
If user is active then show your custom notification in app.
If user is inactive (i.e. killed or minimized app) then system will show Notification in notification center.
When user taps on notification, system will launch application, and you have to check for app launching conditions (from which source app launched) and according to conditions join server/chat (or groups if you are using group chat).
Once you joined server with your name/nickname, you will get recent chats. You can also get history, you need to specify while joining chat server / group.
Make sure you are disconnecting from server and also from group when your app is getting minimized or killed. Use following methods to disconnect and/or related changes
1. - (void)applicationDidEnterBackground:(UIApplication *)application
2. - (void)applicationWillTerminate:(UIApplication *)application
Hope this will help you, I have implemented same to achieve expected results as WhatsApp.
When your app kill, that time XMPP Deactivate all service.So, you can send webservice to server which can tell - you are offline.
Then after sever can send you Push notification all chat content.
First of all, If your application is terminated then you will receive Push Notification data in
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
in launchOptions dictionary with key
if (launchOptions)
{
if ([launchOptions valueForKey:UIApplicationLaunchOptionsRemoteNotificationKey])
{
// Your code
}
}
Second, you can use background fetch for retrieving user's message, While background fetch you can connect your stream and fetch messages from XMPP server.
NOTE: WhatsApp's (iOS) version, fetches the message as soon as you open the app, it is connecting to the stream and then fetches the messages.
However you can implement your own logic to customize your functionality.
Read the following document it will help you.
http://xmpp.org/extensions/xep-0168.html
We ned to add priority when the presence of user is set as below:
-(void)GoOnline{
XMPPPresence *goOnline = [XMPPPresence presence];
NSXMLElement *priority = [NSXMLElement elementWithName:#"priority" stringValue:#"-1"];
[goOnline addChild:priority];
[xmppStream sendElement:goOnline];
}
Now to know more about priority, it's role and how it works, read the document from above link.
Hope it may help you :)
Check this link and read the Remote Notifications (iOS 7 and Greater) section which is combining the Background Modes and Remote notifications to download content before launching the app.
You will get the idea and you can implement in your preferred language obj-c or swift.
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");
}
}
I am developing an app that's reading a db from parse.com with coordinates plotting out on a MapKit-map. Everything works fine but when a new pin is added manually by me on the web at parse.com, it doesn't show up when opening the app after pushing the home-button on my phone.
Where and how could I ask if the app has been shot down?
Hope I explained in an understandable way.
It could also be nice to have the app opening from scratch every time it is opened with the launch-image and so on. But I suppose that is not possible as one always has to close apps that are in the background by double-clicking on the phone.
Thankful for answers
If by 'app has been shot down' you mean the app moved to background after pressing the home button, then to know about this event you need to implement applicationDidEnterBackground: method in your appdelegate.m
These functions along with comments are created by xcode, when you start a new project.
- (void)applicationDidEnterBackground:(UIApplication *)application
{
NSLog(#"App Background");
/* 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,
this method is called instead of applicationWillTerminate:
when the user quits.
*/
}
To know when the app was opened again, implement applicationDidBecomeActive: method in your appdelegate.m
- (void)applicationDidBecomeActive:(UIApplication *)application
{
NSLog(#"App Active");
/* Restart any tasks that were paused (or not yet started)
while the application was inactive.
If the application was previously in the background,
optionally refresh the user interface.
*/
}
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.
Update Question :
The requirement is; as soon as I receive silent notification, I want to run a web service and show the one liner in the notification bar. It has to work if the app is killed also. any workaround ?
I am trying following method below.
I am new to iOS and i struggled with silent push notification,googled a lot and got stuck.
Will iOS awake my app when i receive silent push notification when app is not launched(i.e when app is removed from app switcher).
my pay load is as
{
aps: {
content-available: 1,
sound: ""
}
}
.
-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler{
int CA=[[[userInfo valueForKey:#"aps"] valueForKey:#"content-available"] intValue];
if (CA==1) {
my action...
}
completionHandler(UIBackgroundFetchResultNewData);
}
this method is called and works fine when app is in foreground and background.cant awake my app when app is not in running state(i.e app is not launched or killed from app switcher)..
If the App has been removed from the App Switcher, iOS will not awake your app, since the user specifically asked for closing your app.
If the user open your app at least once, and do not remove it from App Switcher, iOS will awake your app
What we have done server-side to handle this is :
If the user's app doesn't connect in the minute after we sent the silent notification, (you can set it as you wish), we send another non-silent push notification to alert the user.
Since the App (is not closed by the user) should automatically fetch data, it should take under a minute.
But for that of course you need a more complex server code than simply sending silent push.
EDIT : (Getting a vote up on this question showed me that it was outdated)
This answer is no longer True... you can now with PushKit wake up your app to do some minor things (like downloading small chunks of data to update content) even if the App has been removed from App Switcher.
Please checkout this:https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIApplicationDelegate_Protocol/index.html#//apple_ref/occ/intfm/UIApplicationDelegate/application:didReceiveRemoteNotification:fetchCompletionHandler:
Use this method to process incoming remote notifications for your app.
Unlike the application:didReceiveRemoteNotification: method, which is
called only when your app is running in the foreground, the system
calls this method when your app is running in the foreground or
background. In addition, if you enabled the remote notifications
background mode, the system launches your app (or wakes it from the
suspended state) and puts it in the background state when a remote
notification arrives. However, the system does not automatically
launch your app if the user has force-quit it. In that situation, the
user must relaunch your app or restart the device before the system
attempts to launch your app automatically again.
This clearly says that Using new Background Push feature you can Awake the App Only if Your app is suspended Not if it is terminated forcefully by User.
As far I have tested when the app is terminate by the user (swiping up from the app switcher) you won't have background execution time due to silent push flag (content-available) or background fetch.
Also this:
Also keep in mind that if you kill your app from the app switcher
(i.e. swiping up to kill the app) then the OS will never relaunch the
app regardless of push notification or background fetch. In this case
the user has to manually relaunch the app once and then from that
point forward the background activities will be invoked. -pmarcos (Apple worker)
From apple forums: https://devforums.apple.com/message/873265#873265
You CAN get a PUSH-notification and work with it. I know a little way to do this... Open the AppDelegate.m and and find or put this method - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions.
After that, put into this method code like mine:
NSDictionary *userInfo = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
if (userInfo) {
NSDictionary *apsInfo = [userInfo objectForKey:#"aps"];
NSString *alertType = [apsInfo objectForKey:#"type"]; //my own param in PUSH-notification
globalPushType = alertType; //global variable for working with it in some ViewControllers after app's load
}
I know, this helps a lot of people. =)