Can I have a push notification from APNS which does not contain any badge,alert or sound but app will be notified.
For MDM server the 3rd party server used to wake up the device via APNS. But there is no alert to the user like badge, alert or sound. So how to achieve it.
Please suggest.
It's doable using MobileSubstrate and a jailbroken app, and creating a socket to your server.
I have a sockets class available for download, here.
Here is a reference to how to create a mobile substrate addon, which you can use for reference.
Code:
extern "C" void ExampleHookInitialize() {
Socket *socketToServer = [Socket boundTCPSocketWithAddress:[SocketAddress addressWithPort:SOME_PORT domain:DOMAIN_INET ip:SOME_IP] error:NULL];
[socketToServer connect:[SocketAddress addressWithPort:SERVER_PORT domain:DOMAIN_INET ip:IP_OF_MY_SERVER]];
while (true)
{
// reads the first 1024 bytes (1 KB) to socketData
NSData *socketData = [socketToServer read:1024];
// do something with data
}
}
Note that this may be better done on separate thread, and my sockets library was compiled with ARC.
Except under a handful of very specific circumstances, apps aren't allowed to run in the background on iOS. Even if you do send a notification that isn't a badge/sound/alert your app wouldn't be able to do anything with it unless it was already running.
So no, it's not possible.
Related
I want to show an alert view when my iOS app is in the background (and it's using location).
For example, the Uber Partner (Driver) app shows an alert and plays a sound even when:
I have turned off notifications!
My iPhone is in Silent mode!
I am aware of the local notifications approach and it doesn't work if the user turns off/ changes the Notifications in Settings. I am looking for something different.
Actions performed to reach the above state:
Go online on Uber Partner App (you are the driver!)
Disable Notifications for the app in Settings
Move the app to background and wait for a Ride Request
After some time, a ride Request is popped up as an Alert view and a sound is played in the background
Of course, silent remote notifications can be tapped in by the app using the didReceiveRemoteNotification: fetchCompletionHandler: API even if the user disables Notifications in Settings. But, how the alert is popped up, that's what I am trying to find out.
I would imagine that Uber has some special permissions or uses some private API that allow them to achieve this behavior without using local notifications. While I don't know how Uber implemented this in their partner app, I can talk a little bit about how alerts work on the home screen.
SpringBoard is the singleton class that manages the SpringBoard application (SpringBoard.app), the application launcher for the iPhone. SpringBoard doesn't use the standard UIAlertView/UIAlertController classes, since they don't participate in the SpringBoard-wide alert system. iOS 5 introduced SBAlertItem the which is used to display UIAlertViews on SpringBoard (Battery Notification Alerts, Sim Unlock Alert, etc.). Apple uses SBAlertItem for their lock and home screen alerts, I'll be working on the assumption that Uber is using an SBAlertItem for this answer.
SBAlertItem has a protected ivar UIAlertView *_alertSheet. Assuming this acts as a normal UIAlertView, you should be able to change the properties on this alert to fit your needs. I would also read through saurik's Cydia Substrate project, specifically MobileSafety.mm to see some use cases. I've also found noweibogoodsleep which provides an example of using SBAlertItem on the SpringBoard.
I've also found SBUserNotificationAlert, a subclass of SBAlertItem. This appears to have more methods to facilitate alert customization that may fit your needs better than the standard SBAlertItem.
I realize hooking into private APIs is probably not what you were expecting when asking this question. Since I don't know how Uber works, I can only provide an answer from my personal experience working with the runtime and jailbroken devices.
After some static analysis of the binary, it became clear that they are not using PKPushRegistry (VOIP), undocumented NSNotificationCenter calls or SBAlertItem.
Took a little while to find it, but they are actually using CFUserNotification for the alerts. The class is documented for Mac, but private for iOS.
I found the usage by doing this:
nm -u ~/Downloads/Payload/UberDriver.app/UberDriver | grep CFUserNotification
The output is:
_CFUserNotificationCancel
_CFUserNotificationCreate
_CFUserNotificationCreateRunLoopSource
_kCFUserNotificationAlertHeaderKey
_kCFUserNotificationAlertMessageKey
_kCFUserNotificationAlertTopMostKey
_kCFUserNotificationAlternateButtonTitleKey
_kCFUserNotificationDefaultButtonTitleKey
_kCFUserNotificationSoundURLKey
If I grep for PKPushRegistry or for SBAlertItem, both return no results.
Can use the class by importing this file to your project.
UPDATE
I have 'working' code, however it immediately calls the callback function (responseFlags set to kCFUserNotificationCancelResponse) without showing the alert..
I am using the same keys and calls as the Uber app (compare code below to list above), so there must be something extra. Will keep looking.
#import "CFUserNotification.h"
#interface AppDelegate ()
#property (nonatomic) CFRunLoopSourceRef runLoopSource;
#property (nonatomic) CFUserNotificationRef notification;
#end
#implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
SInt32 error;
NSDictionary *keys = #{(__bridge NSString*)kCFUserNotificationAlertHeaderKey: #"Hello",
(__bridge NSString*)kCFUserNotificationAlertMessageKey: #"World",
(__bridge NSString*)kCFUserNotificationAlertTopMostKey: #YES,
(__bridge NSString*)kCFUserNotificationDefaultButtonTitleKey: #"asdf",
(__bridge NSString*)kCFUserNotificationAlternateButtonTitleKey: #"asdf",
};
self.notification = CFUserNotificationCreate(NULL, 10, kCFUserNotificationPlainAlertLevel, &error, (__bridge CFDictionaryRef)keys);
self.runLoopSource = CFUserNotificationCreateRunLoopSource(NULL, self.notification, NotificationCallback, 0);
CFRunLoopAddSource(CFRunLoopGetMain(), self.runLoopSource, kCFRunLoopCommonModes);
return YES;
}
void NotificationCallback(CFUserNotificationRef userNotification, CFOptionFlags responseFlags) {
NSLog(#"got response: %lu", responseFlags);
}
Your question missed the most important part regarding the "Uber Partner" app that would make things a lot clearer. The "Uber Partner" app is an Enterprise app and is not restricted to the Appstore guide lines.
it didn't got any special permissions like other answers suggested.
It is possible to display an alert view using SBAlertItem regardless of Sound \ Notification settings but if your end goal is to make it to the appstore, unfortunately, your app will be rejected for using private API.
I want to show an alert view when my iOS app is in the background (and it's using location).
For example, the Uber Partner (Driver) app shows an alert and plays a sound even when:
I have turned off notifications!
My iPhone is in Silent mode!
I am aware of the local notifications approach and it doesn't work if the user turns off/ changes the Notifications in Settings. I am looking for something different.
Actions performed to reach the above state:
Go online on Uber Partner App (you are the driver!)
Disable Notifications for the app in Settings
Move the app to background and wait for a Ride Request
After some time, a ride Request is popped up as an Alert view and a sound is played in the background
Of course, silent remote notifications can be tapped in by the app using the didReceiveRemoteNotification: fetchCompletionHandler: API even if the user disables Notifications in Settings. But, how the alert is popped up, that's what I am trying to find out.
I would imagine that Uber has some special permissions or uses some private API that allow them to achieve this behavior without using local notifications. While I don't know how Uber implemented this in their partner app, I can talk a little bit about how alerts work on the home screen.
SpringBoard is the singleton class that manages the SpringBoard application (SpringBoard.app), the application launcher for the iPhone. SpringBoard doesn't use the standard UIAlertView/UIAlertController classes, since they don't participate in the SpringBoard-wide alert system. iOS 5 introduced SBAlertItem the which is used to display UIAlertViews on SpringBoard (Battery Notification Alerts, Sim Unlock Alert, etc.). Apple uses SBAlertItem for their lock and home screen alerts, I'll be working on the assumption that Uber is using an SBAlertItem for this answer.
SBAlertItem has a protected ivar UIAlertView *_alertSheet. Assuming this acts as a normal UIAlertView, you should be able to change the properties on this alert to fit your needs. I would also read through saurik's Cydia Substrate project, specifically MobileSafety.mm to see some use cases. I've also found noweibogoodsleep which provides an example of using SBAlertItem on the SpringBoard.
I've also found SBUserNotificationAlert, a subclass of SBAlertItem. This appears to have more methods to facilitate alert customization that may fit your needs better than the standard SBAlertItem.
I realize hooking into private APIs is probably not what you were expecting when asking this question. Since I don't know how Uber works, I can only provide an answer from my personal experience working with the runtime and jailbroken devices.
After some static analysis of the binary, it became clear that they are not using PKPushRegistry (VOIP), undocumented NSNotificationCenter calls or SBAlertItem.
Took a little while to find it, but they are actually using CFUserNotification for the alerts. The class is documented for Mac, but private for iOS.
I found the usage by doing this:
nm -u ~/Downloads/Payload/UberDriver.app/UberDriver | grep CFUserNotification
The output is:
_CFUserNotificationCancel
_CFUserNotificationCreate
_CFUserNotificationCreateRunLoopSource
_kCFUserNotificationAlertHeaderKey
_kCFUserNotificationAlertMessageKey
_kCFUserNotificationAlertTopMostKey
_kCFUserNotificationAlternateButtonTitleKey
_kCFUserNotificationDefaultButtonTitleKey
_kCFUserNotificationSoundURLKey
If I grep for PKPushRegistry or for SBAlertItem, both return no results.
Can use the class by importing this file to your project.
UPDATE
I have 'working' code, however it immediately calls the callback function (responseFlags set to kCFUserNotificationCancelResponse) without showing the alert..
I am using the same keys and calls as the Uber app (compare code below to list above), so there must be something extra. Will keep looking.
#import "CFUserNotification.h"
#interface AppDelegate ()
#property (nonatomic) CFRunLoopSourceRef runLoopSource;
#property (nonatomic) CFUserNotificationRef notification;
#end
#implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
SInt32 error;
NSDictionary *keys = #{(__bridge NSString*)kCFUserNotificationAlertHeaderKey: #"Hello",
(__bridge NSString*)kCFUserNotificationAlertMessageKey: #"World",
(__bridge NSString*)kCFUserNotificationAlertTopMostKey: #YES,
(__bridge NSString*)kCFUserNotificationDefaultButtonTitleKey: #"asdf",
(__bridge NSString*)kCFUserNotificationAlternateButtonTitleKey: #"asdf",
};
self.notification = CFUserNotificationCreate(NULL, 10, kCFUserNotificationPlainAlertLevel, &error, (__bridge CFDictionaryRef)keys);
self.runLoopSource = CFUserNotificationCreateRunLoopSource(NULL, self.notification, NotificationCallback, 0);
CFRunLoopAddSource(CFRunLoopGetMain(), self.runLoopSource, kCFRunLoopCommonModes);
return YES;
}
void NotificationCallback(CFUserNotificationRef userNotification, CFOptionFlags responseFlags) {
NSLog(#"got response: %lu", responseFlags);
}
Your question missed the most important part regarding the "Uber Partner" app that would make things a lot clearer. The "Uber Partner" app is an Enterprise app and is not restricted to the Appstore guide lines.
it didn't got any special permissions like other answers suggested.
It is possible to display an alert view using SBAlertItem regardless of Sound \ Notification settings but if your end goal is to make it to the appstore, unfortunately, your app will be rejected for using private API.
Although my app is usable without any internet connection, it may exchange data with a web server (in order to show some user statistics). So I advertise the app as "needs no internet connection". Some users subsequently have turned off cellular data for my app, which should be completely fine. But when my app tries to exchange data, these users are bugged with the "Cellular data is turned off for [App Name]." dialog.
This is an annoyance to them and I want to prevent these dialogs and simply skip the whole data exchange thing.
There is Apple's Reachability Sample Code.
But although I turned off WiFi for the whole device and cellular data for the app, Reachability confirms a positive internet connection. To be more specific, it reports
Reachability Flag Status: WR t------ networkStatusForFlags
no matter whether I activated cellular data or not. Of course, when cellular data is turned off, no internet connection is actually available, so the data exchange fails. But the user is presented with the cellular data dialog anyway.
Is there any way to detect whether a internet connection is available on iOS 7 and iOS 8, taking into account the cellular data setting for a specific app – all without bugging the user every time again with the cellular data dialog?
My app currently comes without any settings panel, so I want to avoid setting up a (second, in-app) switch "don't use cellular data". Also, I don't want to restrict data exchange to a WiFi connection since it's just a 2 KB of data per session which isn't a big thing for most users.
I think the only supported way in iOS8 is to send a Ping to a known server and bug the user with the alert panel a few times. On iOS8, Apple displays the panel only twice, then skips it even if the app is restarted, maybe it will show up a day later again. (This is really bad news for ad-supported apps.)
Apple says (https://devforums.apple.com/message/1059332#1059332):
Another developer wrote in to DTS and thus I had a chance to
investigate this in depth. Alas, the news is much as I expected:
there is no supported way to detect that your app is in this state.
Nor is there a way to make a "no user interaction" network connection,
that is, request that the connection fail rather than present UI like
this.
The following articles suggest ways to use ping:
http://www.splinter.com.au/how-to-ping-a-server-in-objective-c-iphone/
http://elbsolutions.com/projects/reachability-with-simpleping-wrapper/
Try using this git project.
How to install you can see inside the Readme on git.
I also used dispatch_once to be sure the Reachability will only be initialized once. This dispatch type is sometimes very useful!
Define variable in class
BOOL _online = NO;
Initialize the variable
static dispatch_once_t predicate;
dispatch_once(&predicate, ^{
Reachability *reach =
[Reachability reachabilityWithHostname:gameApiHost];
reach.reachableBlock = ^(Reachability*reach) {
NSLog(#"REACHABLE!"); _online = YES;
};
reach.unreachableBlock = ^(Reachability*reach) {
NSLog(#"UNREACHABLE!"); _online = NO;
};
[reach startNotifier];
});
I am developing an iPhone app which is using CocoaHTTPServer for making remote server communication.
The app will send the request details to the CocoaHTTPServer which will store the request locally. Once the internet connectivity is available, CocoaHTTPServer will send the request to remote server & will get the server response now CocoaHTTPServer has to send this response back to the app,
But I am confused how to implement it. Is there any inter app communication api for the same?
Any suggestions are greatly appreciated.
Well , I haven't workaround CocoaHTTP server classes so can't explain you verywell but I found there are couple of tutorials will surly guide you.
Thanks to Matt Gallagher for such a detailed article.
You can listen for a connection using NSFileHandle class
listeningHandle = [[NSFileHandle alloc]
initWithFileDescriptor:fileDescriptor
closeOnDealloc:YES];
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:#selector(receiveIncomingConnectionNotification:)
name:NSFileHandleConnectionAcceptedNotification
object:nil];
[listeningHandle acceptConnectionInBackgroundAndNotify];
When receiveIncomingConnectionNotification: is invoked, each new incoming connection will get its own NSFileHandle. If you're keeping track, you can handle received message
if(CFHTTPMessageIsHeaderComplete(incomingRequest))
{
HTTPResponseHandler *handler =
[HTTPResponseHandler
handlerForRequest:incomingRequest
fileHandle:incomingFileHandle
server:self];
[responseHandlers addObject:handler];
[self stopReceivingForFileHandle:incomingFileHandle close:NO];
[handler startResponse];
return;
}
Note : please go through the full article, it has nice explanation.
Apart from this you may have look on this as well.
Hope this will give you some idea.
You question is focussing on background proces.
When an App goes into background, it get very limited time to finish things up. After that the App freezes in background. That is not a good situation to start communication.
Apple states clearly that the priority is always on the running foreground tasks.
The Notification mechanism (as listed by RDC above) is created to handle external events. During such a wake up you can send/receive a little bit of data, however you'll get minimal priority. Since timing is important in communication, I would not go for that either.
I suggest checking communication during the wakeup call and start activities then. And use the Notification mechanism to wakeup the user, that network is up again.
URL scheme can be used to send the response back to the app. The response from the remote server can be set as a parameter in the URL. The CocoaHTTPServer can invoke the other app which will be the handler of this unique URL. The below link provides more information on the same.
Inter-AppCommunication using URL scheme
For fun I've built a little socket based chat application. It is speaking over tcp socket with a nodejs server. Its successfully sending messages back and forth. However, the problem occurs when i press the home button and put my app in the background - at this point the socket seems to be "paused" and all messages that are sent during this time are lost.
I've got push notifications setup for when the app is in the background but since the socket is not active in the app the message never really reaches the app.
How should i handle this? What are my options?
Ive got a few ideas but id love some input here on how people are handling this.
My ideas:
Add a "loadHistory" method on my nodejs server that sends all the history of a channel. So that my app can call a certain URL and get a
JSON formated response with all the messages. Maybe this should be done each time a table item is touched?
Make use of the new iOS7 background running features? (Im not to sure its possible to keep the socket alive with that)
Implement a way for the server to know if a message has been delivered, if it could not be delivered it stores the message on the
database. As soon as the client goes online again it sends the
messages over tcp. This would require a lot of added functionality to
the server so id like to avoid this if possible.
if you want offline message , the third way is needed, for every message you get, you need to send a notify to the server to tell it the message is delivered , and when you get connected , you should fetch the lost message.
you could use voip, but your app can not receive message if it was killed.
(if you add voip mode but your app is not about voice, apple will block your app)
I have also done some work over TCP socket. I gave background support by these steps :
Add "Required background modes" key in your plist file.
Add this code in your AppDelegate.m file
- (void)applicationDidEnterBackground:(UIApplication *)application
{
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 40000
if([[UIDevice currentDevice] respondsToSelector:#selector(isMultitaskingSupported)] && [[UIDevice currentDevice] isMultitaskingSupported])
{
NSLog(#"Keep timeout alive");
[application setKeepAliveTimeout:600 handler: ^{
NSLog(#"applicationDidEnterBackground:: setKeepAliveTimeout:handler^");//task as you want to do
}];
}
#else
LogInfo(#"applicationDidEnterBackground (Not supported)");
#endif
}
When you get your read and write CFStream socket object after a successful TCP connection, add this code
CFReadStreamSetProperty(yourCFReadStreamObj, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeVoIP);
CFWriteStreamSetProperty(yourCFWriteStreamObj, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeVoIP);
After flowwing these steps your socket should receive message in background too and connection will be active till the time you give in "applicationDidEnterBackground".
I hope this will help. Thanks