Checking if user enabled push notification on iPhone using phonegap 1.7 - iphone

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

Related

Device Token and Push Notification

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];
}

Network push notification

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.

http authentication in devise and rails 3

I have an application which uses devise on rails 3. I would like to enable http authentication so that I can authenticate to my web app from an iPhone app. How can I authenticate from my iPhone app to devise?
Is this secure or should I be authenticating differently?
From the design point of view you have got 3 options:
1) Use basic http authentication: your IPhone app has a secret key -which is baked in your IPhone app code - that uses to authenticate each request with the web app.
Google search: "Devise basic http authentication"
2) You can use https by having a public certificates in your IPhone app and a private certificates on your web app. This is a lot of work to configure right, it is very secure since your IPhone app and the Rails server are exchanging messages over an encrypted channel. The security is also transparent to your rails code since authentication is done at the transport level.
3) The IPhone app connects to the web app using https, get an authentication token that it then uses to make calls to the web app over regular http. More secure than 1 since the key can expire, quite a bit of work to implement and very scalable.
(http://matteomelani.wordpress.com/2011/10/17/authentication-for-mobile-devices/)
Most of apps use solution 1.
Hope this help.
EDIT: to implement http authentication (either basic or digest) I suggest you look at:
http://api.rubyonrails.org/classes/ActionController/HttpAuthentication/Basic.html
and
https://github.com/plataformatec/devise/wiki/How-To:-Use-HTTP-Basic-Authentication
The precise steps will depends on your Rails server stack.
EDIT 2: I do not think Devise provide a way to get the auth_token. I can see you can try several solutions:
when the user logs in the server retrieves the authentication_token and puts it in the cookie. Not very secure unless you encrypt it with a shared secret key.
you can provide a https web service that your IPhone app uses to get a user token. Your IPhone app would make the request right after receiving the user request to sign in.
Sorry I cannot be of more help with some real code.
This largely depends on how you are implementing things on the server side, but we implemented this using Matteo's 3rd option. I have a rails 3.1 implementation using devise. The route to the login is /users/login.json . First build up the JSON body for login with code like this:
NSMutableDictionary *loginDictionary = [NSMutableDictionary dictionary];
NSMutableDictionary *usernamePasswordDictionary = [NSMutableDictionary dictionary];
[usernamePasswordDictionary setObject:username forKey:#"email"];
[usernamePasswordDictionary setObject:password forKey:#"password"];
[loginDictionary setObject:usernamePasswordDictionary forKey:#"user"];
NSData *data = [NSJSONSerialization dataWithJSONObject:loginDictionary options:0 error:&error];
which yields this JSON:
{"user":{"password":"blahblahblah","email":"admin#*****.com"}}
I send a POST url request with code like this:
NSString *postUrlString = [NSString stringWithFormat:#"%#users/login.json", kServerAPIBaseURL];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:postUrlString] cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:kTimeoutInterval];
[request setHTTPMethod:#"POST"];
[request setValue:#"application/json" forHTTPHeaderField:#"Content-type"];
[request setHTTPBody:data];
The response I get back contains JSON. We configured the server side to return the a session_auth_token:
{
admin = 1;
"created_at" = "2012-01-25T00:15:58Z";
"current_sign_in_at" = "2012-04-04T04:29:15Z";
"current_sign_in_ip" = "75.163.148.101";
email = "admin#******.com";
"encrypted_password" = "*****";
"failed_attempts" = 0;
id = 1;
"last_sign_in_at" = "2012-04-03T03:37:18Z";
"last_sign_in_ip" = "75.163.148.101";
"locked_at" = "<null>";
name = "Joe Smith";
"remember_created_at" = "2012-03-29T20:35:43Z";
"reset_password_sent_at" = "<null>";
"reset_password_token" = "<null>";
"session_auth_token" = "3FRgX6CYlzQJGC8tRWwqEjFaMMFKarQAYKTy3u84M0U=";
"sign_in_count" = 145;
status = 1;
"unlock_token" = "<null>";
"updated_at" = "2012-04-04T04:29:15Z";
}
We store that session_auth_token and then send it back with every request in a header, something like this:
NSMutableURLRequest *postRequest = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:[self postUrlString]]...
[postRequest setHTTPMethod:#"POST"];
[postRequest setValue:#"application/json" forHTTPHeaderField:#"Content-type"];
[postRequest setValue:[self sessionAuth] forHTTPHeaderField:#"X-CSRF-Token"];
[postRequest setHTTPBody:data];
That parameter [self sessionAuth] contains the session_auth_token.
Let me know if you need clarification.

Clearing credentials from ASIHTTPRequest

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.

Upload image from iphone to facebook without dialog

i want to send image from my iphone to facebook of my account without showing any dialog (in fbconnect there is dialog) . I want a simple way to just test whether it is uploaded in the facebook are not.
I tested with twitter api send message from my iphone and its work fine its few lines of code,
I pasted below
NSMutableURLRequest *theRequest=[NSMutableURLRequest requestWithURL:[NSURL URLWithString:#"http://username:password#twitter.com/statuses/update.xml"]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval: 60.0];
[theRequest setHTTPMethod:#"POST"];
[theRequest setHTTPBody:[[NSString stringWithFormat:#"status=%#", #"test message sends from iphone"] dataUsingEncoding:NSASCIIStringEncoding]];
NSURLResponse* response;
NSError* error;
NSData* result = [NSURLConnection sendSynchronousRequest:theRequest returningResponse:&response error:&error];
NSLog(#"%#", [[[NSString alloc] initWithData:result encoding:NSASCIIStringEncoding] autorelease]);
Like wise i want to send text and photo to facebook account ? Is it possible ?
The fbconnect is more no of blocks and lines , can anyone help me ? a simple way to understand it ?
Thanks in advance
With the new OAuth Facebook API and the new facebook-ios-sdk I don't think you can do without the dialog. The whole point is that your app never sees and stores the user credentials. If you then close the app and the login dialog appears again a cookie (set/used by the UIWebView, AFAIK) logs you in without you needing to enter the credentials again.