Right way to handle user session with IOS NSURLSession - iphone

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.

Related

Connecting to external URL from WatchKit 2.0

I would like to load some information in the WatchKit interface from a REST backoffice. Is there some fast way to execute a URL request passing by the host iOS app or I must concoct a specific protocol taking advantage of the bare WatchConnectivity functionalities?
You should use NSURLSession directly from your WatchKit extension.
NSURLSession works fine with Watchkit, but you will need to add Allows Arbitrary Loads on Watchkit Extension too if it is relevant.
Please see this post,
NSURLSession returns data as Null on Watch OS2 using Objective-C
I am using sendMessageData:replyHandler:, yet I have problems in having it properly working. The relative ticket is at:
https://stackoverflow.com/questions/33211760/sendmessagedata-does-not-call-didreceivemessagedata-on-the-counterpart
Although Apple's example is in swift see https://developer.apple.com/videos/play/wwdc2015-228/?time=345 , I've pasted a snippet in obejctive-c utlisin the NSProcessInfo wrapper.
Apple's example also makes use of Semaphore's, should the extension be put to sleep, which I have omitted from below.
Following the below pattern enables you to hit a desired service directly from the watch.
NSProcessInfo *processInfo = [NSProcessInfo processInfo];
[processInfo performExpiringActivityWithReason:#"networkReq" usingBlock:^(BOOL expired) {
if (!expired){
NSLog(#"we have an assertion");
NSTimeInterval secondsInThreeHours = 3 * 60 * 60;
NSURL *forecast = [NSURL URLWithString:#"http::address"];
NSURLSession *session = [NSURLSession sharedSession];
[[session dataTaskWithURL:forecast
completionHandler:^(NSData *data,
NSURLResponse *response,
NSError *error) {
// handle response
}] resume];
else{
NSLog(#"Not background assertion or we are out of time");
}
}];

Facebook share example not working

I followed the set up for my own application. https://developers.facebook.com/docs/ios/getting-started/
I then used the overview example, found here: https://developers.facebook.com/docs/ios/share-dialog/
NSURL* url = [NSURL URLWithString:#"https://developers.facebook.com/"];
[FBDialogs presentShareDialogWithLink:url
handler:^(FBAppCall *call, NSDictionary *results, NSError *error) {
if(error) {
NSLog(#"Error: %#", error.description);
} else {
NSLog(#"Success!");
}
}];
The share dialog appears, like in the example. I press post and it successfully returns to the app. All looks like its working right? But when I return to the facebook wall and my profile there is no status update. The logs are not displayed so something is going wrong.
if(error) {
NSLog(#"Error: %#", error.description);
} else {
NSLog(#"Success!");
}
Any ideas? Facebook redirect you to stackoverflow to get help because they have facebook developers registered.
First, the final part on the first link, about the .plist, is really important. It has to be with the correct info from your app, in order to the share feature to work. Re-check that if you can.
Anyway, the NSLog not printing anything on the console is strange, have you tried searching(command + f) for the message output on the console? Did you try debugging your app and putting breaking points on the 'if' condition to see the state of the error instance?
I don't know if you didn't put it here, or forgot to do it on code, but are you logging the user and checking if the facebook user session is valid? That has to be checked in order for the share to work.
PS: If you are using your facebook App on sandbox mode, any share you do, will only appear on the timeline of the users that are allowed to use the fbApp.

facebook login works on iphone simulator but not on iphone device

In my app, I want to take photos from the facebook. so i used facebook ios sdk. i can be able to authorize from the below code:
if (appDelegate.session.isOpen) {
//[appDelegate.session closeAndClearTokenInformation];
[self retrieveAlbums];
} else {
if (appDelegate.session.state != FBSessionStateCreated) {
// Create a new, logged out session.
appDelegate.session = [[FBSession alloc] init];
}
// if the session isn't open, let's open it now and present the login UX to the user
[appDelegate.session openWithCompletionHandler:^(FBSession *session,
FBSessionState status,
NSError *error) {
// and here we make sure to update our UX according to the new session state
//NSLog(#"%#",session.accessTokenData.accessToken);
[self retrieveAlbums];
}];
It works fine on iphone simulator. But I can't able to login on my iphone 4 device.
When I tried to login it will open a safari and then shows the message Updating.
Then it will redirect without authorization. access token retrieved as nil. So I cant able to retreive images.
Please help me.
EDIT
Thanks for everyone .Finally I solved my problem. It is because i enabled sandbox mode in facebook developer account settings. When i disabled the sandbox mode, it works normally.
Try clearing the cookies and cache of your safari, going to Settings.
Also if you do not want the app to redirect to Safari, just dont provide the URL Scheme in your info.plist that is something like "fb-AppId-" and it will open a popup for login
I was having the similar problem and solved it by composing couple of solutions in this website. First of all I got rid of the url scheme at my info plist. So now my app opens up the facebook login dialog inside my registration page. Which is a good thing because it doesn't go back and forth to safari for facebook authentication and you stay inside the app. The second thing I made is, putting an error handling mechanism inside my code for facebook login. So if login with facebook fails, it uses another strategy for logging in.
Here is my code.
- (void)loginView:(FBLoginView *)loginView handleError:(NSError *)error {
NSArray *permissions = [[NSArray alloc] initWithObjects:
#"public_profile", #"user_friends", #"email",
nil];
FBSession *session = [[FBSession alloc] initWithPermissions:permissions];
[FBSession setActiveSession:session];
[self openSessionWithAllowLoginUI:YES completionHandler:^(FBSession *session, FBSessionState status, NSError *error) {
if (!error && status == FBSessionStateOpen) {
NSString *token = session.accessTokenData.accessToken;
NSLog(#"Logged in! - Token -- %#", token);
} else {
NSLog(#"Something wrong happened");//you can check the error code here
}
}];
}

twitter update using TWRequest gives 403 error

i'm using the following code to tweet in user's timeline using the iOS 5 twitter API
// Create an account store object.
ACAccountStore *accountStore = [[ACAccountStore alloc] init];
// Create an account type that ensures Twitter accounts are retrieved.
ACAccountType *accountType = [accountStore accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierTwitter];
// Request access from the user to use their Twitter accounts.
[accountStore requestAccessToAccountsWithType:accountType withCompletionHandler:^(BOOL granted, NSError *error)
{
if(granted)
{
// Get the list of Twitter accounts.
NSArray *accountsArray = [accountStore accountsWithAccountType:accountType];
// For the sake of brevity, we'll assume there is only one Twitter account present.
// You would ideally ask the user which account they want to tweet from, if there is more than one Twitter account present.
// Grab the initial Twitter account to tweet from.
ACAccount *twitterAccount = [accountsArray objectAtIndex:buttonIndex];
// Create a request, which in this example, posts a tweet to the user's timeline.
// This example uses version 1 of the Twitter API.
// This may need to be changed to whichever version is currently appropriate.
TWRequest *postRequest = [[TWRequest alloc] initWithURL:[NSURL URLWithString:#"http://api.twitter.com/1/statuses/update.json"] parameters:[NSDictionary dictionaryWithObject:#"hello this is a tweet" forKey:#"status"] requestMethod:TWRequestMethodPOST];
// Set the account used to post the tweet.
[postRequest setAccount:twitterAccount];
// Perform the request created above and create a handler block to handle the response.
[postRequest performRequestWithHandler:^(NSData *responseData, NSHTTPURLResponse *urlResponse, NSError *error)
{
NSString *output = [NSString stringWithFormat:#"%i", [urlResponse statusCode]];
[self performSelectorOnMainThread:#selector(TweetStatus:) withObject:output waitUntilDone:NO];
}];
}
}];
i've been using this method for more than a month now for testing the application and it used to work fine with no problems.
few weeks a goo it started to return a 403 error in the following method.
[postRequest performRequestWithHandler:^(NSData *responseData, NSHTTPURLResponse *urlResponse, NSError *error)
{
NSString *output = [NSString stringWithFormat:#"%i", [urlResponse statusCode]];
[self performSelectorOnMainThread:#selector(TweetStatus:) withObject:output waitUntilDone:NO];
}];
it gives the following error:
Error Domain=NSURLErrorDomain Code=-1012 "The operation couldn’t be completed. (NSURLErrorDomain error -1012.)" UserInfo=0x1f8b3250 {NSErrorFailingURLKey=http://api.twitter.com/1/statuses/update.json, NSErrorFailingURLStringKey=http://api.twitter.com/1/statuses/update.json, NSUnderlyingError=0x1ed19f90 "The operation couldn’t be completed. (kCFErrorDomainCFNetwork error -1012
i've searched a lot and could not find any solution or real cause to this problem.
a few notes to keep in mind that might help understanding the problem:
the application is used for testing which means that we used the twitter sharing and mentions a lot with other users.
the sharing content is not always the same so no duplication issue should occur as we were clearing the timeline frequently.
thanks
The text you have been trying to tweet must be similar to what has been tweeted by you previously, hence you are getting this error. According to the documentation here, the same text cannot be posted more than once.
EDIT:
It might also depend on the total number of tweets as mentioned in their website.
i've been using this method for more than a month now for testing the application and it used to work fine with no problems.
I think that's the issue right there. this account you are testing might been marked as a spammer by other people.
If you use another account or other phone and the code works, then that's the only explanation my friend.
Good luck
I noticed you are using the following URL to post a tweet from your user:
http://api.twitter.com/1/statuses/update.json
This is using version 1.0 of the Twitter API which is deprecated and slowly will stop working over the next few months
Instead you should try using
https://api.twitter.com/1.1/statuses/update.json (There has been a recent change to the Twitter API. You can now only call it using HTTPS.)
This will specify the latest version of the API.

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