I am trying to implement Push Notifications into my app, but I have, what I believe, may be a dumb question. I have my Push Notifications working, but they work because I am putting the Device Token into my asp.net code on the server.
My question is, am I supposed to keep track of the device tokens my app obtains? In other words, when the app launches and I get the device token, do I need to send those up to my server and store them so that when I need to send a notification to all the users of my App i can go through the list of tokens and send the notification to each device token?
Thanks for any clarity you can bring, as you guessed this is my first attempt at Push Notifications.
You have to store the device tokens in a database. Then you send a notification addressed to each device token. You can create the system by yourself, but there are open source libraries that have done this already. Although it is for PHP, Easy APNS is an example.
I'd run into this scenario myself, as it turns out hardcoding device tokens is one way to limit the devices which can be sent push notifications but if you wanted to allow any device who has downloaded your app you need to create a mechanism to send the device's device token to your server so that a push notification is sent to it. You could setup this request to your server on app load, and in my case silently succeed and on failure let the user know that they were not added to the notification list.
Here's an example from raywenderlich.com that creates a chat program. -- basically they are creating a post request with device info that they are storing in a database, and later accessing the DB info to iterate through and send out the notification.
Some relevant code:
- (void)postJoinRequest
{
MBProgressHUD* hud = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
hud.labelText = NSLocalizedString(#"Connecting", nil);
NSURL* url = [NSURL URLWithString:ServerApiURL];
__block ASIFormDataRequest* request = [ASIFormDataRequest requestWithURL:url];
[request setDelegate:self];
[request setPostValue:#"join" forKey:#"cmd"];
[request setPostValue:[dataModel udid] forKey:#"udid"];
[request setPostValue:[dataModel deviceToken] forKey:#"token"];
[request setPostValue:[dataModel nickname] forKey:#"name"];
[request setPostValue:[dataModel secretCode] forKey:#"code"];
[request setCompletionBlock:^
{
if ([self isViewLoaded])
{
[MBProgressHUD hideHUDForView:self.view animated:YES];
if ([request responseStatusCode] != 200)
{
ShowErrorAlert(NSLocalizedString(#"There was an error communicating with the server", nil));
}
else
{
[self userDidJoin];
}
}
}];
[request setFailedBlock:^
{
if ([self isViewLoaded])
{
[MBProgressHUD hideHUDForView:self.view animated:YES];
ShowErrorAlert([[request error] localizedDescription]);
}
}];
[request startAsynchronous];
}
Related
Hi I am beginner to IOS development. I am developing small IOS application. Required functionality of that application is like this. Application have login for user. once your logged in it will not ask for login again until user do logout. I completed login part. I done with login using NSURLSession.Now after login I want to fetch some thing from server but it is giving error with status code 0 or 1012. I don't know why it is giving this error. So my questions are like this
How NSURLConnection works?
Is it taking care of session for user or I have to take care of that?
After login process I am not able to do anything, mostly because of unauthorised access. I did login in following way
NSURLSession *session = [NSURLSession sharedSession];
[[session dataTaskWithURL:url completionHandler:
^(NSData *data, NSURLResponse *response, NSError *error)
{
NSHTTPURLResponse *httpResp = (NSHTTPURLResponse*) response;
NSLog(#"sttaus code %i", httpResp.statusCode);
if(error)
{
[self.delegate signinWithError:error];
}
else
{
[self.delegate signinWithJson:data];
}
}] resume];
I have to set NSURLSession globally or I can use it locally as well?
Is there any one have good explanation about it? Any good example ? Need Help. Thank you.
I'm trying to determine whether or not the user enabled push notification for my app using phonegap (ver 1.7).
So far I only came up with this plugin which doesn't have a method specifically to check that issue, but does have a method to register push notification, which may return an error, which may be an indication to the user disabling push notification. But as you can see, that's very vague.
So my question is - is there a plugin (or any other way) to determine if the user enabled push notification for my app?
You can check if any type of push notifications are enabled by using this :
if([UIApplication sharedApplication].enabledRemoteNotificationTypes == UIRemoteNotificationTypeNone)
this status can be accesd by call a simple plugin after device ready.
UPDATE :Write a plugin and inside that plugin please check the status and return to javascript
if you need to save it on server first thing you need one server side api and some native side code, after registering push notification on ios there are two callback functions
didFailToRegisterForRemoteNotificationsWithError
didRegisterForRemoteNotificationsWithDeviceToken
so if success you can send a request to your server with the device id or any unique ID so you can save the registered devices.
(void)application:(UIApplication*)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken
{
NSString *token = [[[[deviceToken description] stringByReplacingOccurrencesOfString:#"< "withString:#""] stringByReplacingOccurrencesOfString:#">" withString:#""]
stringByReplacingOccurrencesOfString: #" " withString: #""];
[self postUpdateRequest:token]; // request to your server
}
for sending POST request use
NSURL *aUrl = [NSURL URLWithString:uRI];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:aUrl cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];
[request setHTTPMethod:#"POST"];
NSString *postString =#"Your Data";
[request setHTTPBody:[postString dataUsingEncoding:NSUTF8StringEncoding]];
NSURLConnection *connection= [[NSURLConnection alloc] initWithRequest:request
delegate:self];
[connection start];
if(connection) {
// success
} else {
//error
}
if registration was failed (didFailToRegisterForRemoteNotificationsWithError) you can send a requset to server with error data OR Not.
from phonegap side after device ready send one ajax request to you server and check whether your device is registerted or not. for getting unique id you may use simple plugin. for writing simple plugin please follow this http://docs.phonegap.com/en/edge/guide_hybrid_plugins_index.md.html#Plugin%20Development%20Guide
Unfortunately you can't enable or disable the Push Notifications for your app from the app code. check this
I am wondering if there is a simple way to push a notification, to all your users currently using your application.
So the next time they launch the application and they are connected to Wi-Fi, they receive a alert telling them that, i.e., "An update is available".
EDIT:
To explain in greater detail what I am looking for. I am developing an application that should only be used when it is the most recent version of the software, so I would like to be able to send out a message (notification) for when an update is available in the AppStore. This is seen in some games such as AngryBirds and Cut the Rope.
Maybe even change a BOOL in the code to TRUE, leaving a red flag if{} BOOL is TRUE. (Of course first I'd like an answer to the more basic version. This would be helpful though as well)
Hope this clears things up.
With regards,
SirKaydian
Local Notification Solution
Essentially what Oscar said previously, you could make this really simple. If you wanted to check after every launch of the application you could easily call some sort of local API (or similar) call from your application to a web service you might host. So for example you have a PHP file:
<?php
$currentVersion = 1.3;
echo $currentVersion;
?>
That simple PHP script can be updated by you whenever you release an update. The iPhone can recognize this by querying that PHP file on every startup (check NSURLConnection delegate methods to get the response from any particular URL). Now from previous checks by your application it can store those in an NSUserDefaults value by the following:
NSUserDefaults *defaults = [[NSUserDefaults alloc] init];
NSString *loadedVersion = [defaults valueForKey:#"MYAPP_CURR_VERSION"];
Now we need to compare the two from your NSURLConnection delegate method that receives the string back from the PHP file on your web service.
NSMutableURLRequest *urlRequest = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:#"http://www.website.com/folder/version.php"]];
[urlRequest setHTTPMethod:#"GET"];
[urlRequest setHTTPBody:[postParams dataUsingEncoding:NSUTF8StringEncoding]];
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:urlRequest delegate:self startImmediately:YES];
[connection start];
The above code will send the request to your server URL that you tell it to. Now when we get the response we'll do it like this:
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
NSString *responseVersionFromServer = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
if(![loadedVersion isEqualToString:responseVersionFromServer]) {
//execute code here to show a local notification or UIAlertView
}
}
That will do all the comparison for you.
NOTE: You must add NSURLConnectionDelegate in your .h Header file!
Push Notifications Solution
There are services out there for allowing your application to have push notifications such as Urban Airship that you can log into and send a push notification to all of your users when an update becomes available. It's really simple to use, check out their website. (www.urbanairship.com)
You could consume a webservice and compare versions of your app (maybe save the version to NSUserDefaults), I'm sure there are other solutions but this one comes to mind. You could show an alert that links to the app store if the versions are different.
I'm working on an iPhone app that uses ASIHTTPRequest to interact with a web service using NTLM authentication. And the credentials should be stored in the keychain. It logs in fine, but I'd like to have a logout button that clears the credentials from the app, and I can't get that to work.
After I click the logout button, I expect that when I return to the view that queries the server that I'll get prompted to log back in again. However, that doesn't happen and the call to the server still authenticates.
The code that makes the request looks like this:
NSString *urlString = [NSString stringWithFormat:#"http://myserver.mydomain.com/myapp/items/%#", itemGroupId];
NSURL *url = [NSURL URLWithString:urlString];
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request setUseKeychainPersistence:YES];
[request setShouldPresentAuthenticationDialog:YES];
[request setRequestMethod:#"POST"];
[request addRequestHeader:#"content-type" value:#"application/json;charset=utf-8"];
[request addRequestHeader:#"content-length" value:#"0"];
[request setDelegate:self];
[request startAsynchronous];
For the logout, I've tried calling:
[ASIHTTPRequest removeCredentialsForHost:#"myserver.mydomain.com" port:0 protocol:#"http" realm:nil];
But that doesn't work. The code inside that method doesn't find the NSURLCredential that was saved so that it can remove it, even though those arguments are what I've seen get passed to saveCredentials:forHost:port:protocol:realm: in the first place.
I've also tried calling clearSession, and I've tried disabling session persistence altogether when creating the request using setUseSessionPersistence, but no luck.
I also tried using code based on this example that loops through all of the credentials in the app's keychain and removes them all:
NSURLCredentialStorage *store = [NSURLCredentialStorage sharedCredentialStorage];
for (NSURLProtectionSpace *space in [store allCredentials]) {
NSDictionary *userCredentialMap = [store credentialsForProtectionSpace:space];
for (NSString *user in userCredentialMap) {
NSURLCredential *credential = [userCredentialMap objectForKey:user];
[store removeCredential:credential forProtectionSpace:space];
}
}
That sort of works, because the next time the app is launched it'll prompt for a login again. But it doesn't prompt for another login if the app continues to run.
Are you sure using port 0 and no realm is correct?
Just to make sure I create a NSURL from my connect-url-string (the same url I use for all ASIHTTPRequest), and retrieve the host, port and protocol from that. I only have to mention the realm by hand for now.
Using this code I am able to logout successfully in my app:
// clear keychain
NSURL *url = [NSURL URLWithString:kConnectorUrlString];
[ASIHTTPRequest removeCredentialsForHost:[url host] port:[[url port] intValue] protocol:[url scheme] realm:kConnectorRealm];
My app prompts me again when I let my app continue to run.
I am using the same arguments who get passed to saveCredentials too.
Is there any way to spoof the user agent on Safari on the iPhone?
So for example, you would create an application on the iPhone that has the embedded Safari browser, however any website the user visits with this browser wouldn't know you were on Safari on the iPhone, it would think you are on something like Safari on a PC, or even IE/FireFox.
Thanks
Yes I think you could change this. It would require a bit of a work around to get it working.
You would need to manually manage all requests. By making your own data requests.
In this data request you can add a HTTPheader for User-Agent which will override the default headers.
NSMutableURLRequest* urlRequest = [[[NSMutableURLRequest alloc] initWithURL:requestURL] autorelease];
[urlRequest setHTTPMethod: #"POST"];
[urlRequest setHTTPBody: [nvpString dataUsingEncoding:NSUTF8StringEncoding]];
[urlRequest addValue:#"Your+User+Agent+String" forHTTPHeaderField:#"User-Agent"];
receivedData = [[NSMutableData alloc] retain];
[receivedData setLength:0];
[NSURLConnection connectionWithRequest: urlRequest delegate: self];
If you embed the Safari Web Browser in your app you can subscribe to its delegate methods. One of them will notify your application that safari would like to load a URL, this is where you catch this load and get the data your self.
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType{
now you put your code in here to do the data load.
Once the data has loaded. Give it the data string back to the webView. I have set "baseURL:nil" but you might have to correctly set this to maybe the correct domain for this app.
[webView loadHTMLString:newString baseURL:nil]