How to Add Facebook like button to iOS application using Webview? - ios

Right now i am struggling with adding Facebook like button to my App.I referred many sites and even developers.Facebook also not provided proper explanation.They just gave frame for like button. Can any one please help in adding Facebook like button in my App using Webview.
Thanks in Advance

Ok, this is from working project:
NSDictionary *params = [NSDictionary dictionaryWithObjectsAndKeys:URL, #"object", nil];
if (FBSession.activeSession.isOpen) {
if (FBSession.activeSession.accessTokenData.accessToken) {
[FBRequestConnection startWithGraphPath:#"/me/og.likes"
parameters:params
HTTPMethod:#"POST"
completionHandler:^(FBRequestConnection *connection, id result, NSError *error) { }];
} else NSLog(#"FBSession.activeSession.accessToken IS NULL");
}
URL is the URL of object what you want to like.
There's no code for completionHandler block and for FB-authentification, I hope you can do it as you need.

To get count of Likes for some URL you can use this code:
NSString *likesRequestURL = [[NSString stringWithFormat:#"https://graph.facebook.com/fql?q=SELECT+total_count,+url+FROM+link_stat+WHERE+url+=\"%#\"&access_token=%#", URL, FBSession.activeSession.accessTokenData.accessToken] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:likesRequestURL]
cachePolicy:NSURLRequestReloadIgnoringCacheData
timeoutInterval:60.0f];
__block NSString *result = [NSString string];
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
if (error == nil) {
NSString *jsonString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
SBJsonParser *jsonParser = [[[SBJsonParser alloc] init] autorelease];
result = [NSString stringWithFormat:#"%#", [[[[jsonParser objectWithString:jsonString] objectForKey:#"data"] objectAtIndex:0] objectForKey:#"total_count"]];
[jsonString release];
} else {
NSLog(#"Error = %#", error);
}
}];
Note. In this case was used SBJSONParser, you can use it or replace by something else, just slightly change corresponding code.
Now you can to create fully customized like-button.

It's not right. There is a way to realize Like feature not with UIWebView bit with FBRequestConnection. If you want to use UIWebView - colleague Shan gives right answer, but if you want to use another way - let me to know.

Related

Get all friends list from Facebook and get list of those who is having birthday on today and other aslo

I have tried to get friend list from facebook using Graph API but it's not returning friend list. I have tried following code to get list after a successful login in facebook...
FBRequest *req = [FBRequest requestForMe];
[req startWithCompletionHandler:^(FBRequestConnection *connection, NSDictionary<FBGraphUser> *result, NSError *error) {
if (!error)
{
[[VSFacebook sharedFacebook] setFbUser:result];
FriendsViewController *f = [[FriendsViewController alloc] initWithNibName:#"FriendsViewControlleriPad" bundle:nil];
[self presentViewController:f animated:YES completion:nil];
}
}];
and after connecting on FriendsViewContrller.m file I have call graph API to get friend list as following
self.facebookBlock = completionBlock;
NSString *fields = #"id,name,picture,birthday";
NSString *format = #"json";
NSString *urlString = [NSString stringWithFormat:#"https://graph.facebook.com/%#/friends?fields=%#&format=%#&access_token=%#", #"me", fields, format, self.fbAccessTokenData.accessToken];
NSURL *url = [NSURL URLWithString:urlString];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
NSURLResponse *response = nil;
NSError *error = nil;
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
id result = nil;
if (data)
{
result = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:nil];
}
self.facebookBlock([result valueForKey:#"data"], error);
I got on result only three value pair like "summary", "data", "paging"
You cann't get all friends list from facebook using Graph API. It's
not possible to get all Friend's List , according to new API version

Braintree iOS SDK saying no known class method

I m getting this error. Anyone?
-(void)clientToken{
NSURL *clientTokenURL = [NSURL URLWithString:#"http://tectutiveclients.com/projects/carboss/api/getToken"];
NSMutableURLRequest *clientTokenRequest = [NSMutableURLRequest requestWithURL:clientTokenURL];
[clientTokenRequest setValue:#"text/plain" forHTTPHeaderField:#"Accept"];
[NSURLConnection
sendAsynchronousRequest:clientTokenRequest
queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
// TODO: Handle errors in [(NSHTTPURLResponse *)response statusCode] and connectionError
clientToken = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
// Initialize `Braintree` once per checkout session
[Braintree setupWithClientToken:clientToken
completion:^(Braintree *braintree, NSError *error) {
UIViewController *dropin = [braintree dropInViewControllerWithDelegate:self];
[self presentViewController:[[UINavigationController alloc] initWithRootViewController:dropin]
animated:YES
completion:nil];
// No known class method for selector setupwithClientToken Error
}];
UIViewController *dropin = [self.braintree dropInViewControllerWithDelegate:self];
[self presentViewController:[[UINavigationController alloc] initWithRootViewController:dropin]
animated:YES
completion:nil];
}];
}
I work at Braintree. If you have any more problems, please get in touch with our support team.
This is an inaccuracy in the docs. Instead, please use braintreeWithClientToken:
Example:
NSString *clientToken = [[NSString alloc] initWithData:data
encoding:NSUTF8StringEncoding];
// Initialize `Braintree` once per checkout session
self.braintree = [Braintree braintreeWithClientToken:clientToken];
Thanks for pointing this out! The docs will be updated shortly.

iOS: why i need to use antire mixpanel sdk to just tracking the event?

I integrated the mixpanel iOS sdk with my ios app. It's working fine
but my question is this, for just track the events why i need the
storyboard and assets and all?. Does any one knows here what are all
the necessary files that is enough to track the events?. The thing is, why i need to keep unused files in my project?.
Any help that might be really appreciated.
I've created a cut down version of MixPanel for iOS that uses the MixPanel spec.
You can download it, and a demo app from my github page:
https://github.com/peterept/mixpanellite
The crux of the code is:
+(void)track:(NSString*)event properties:(NSDictionary*)properties {
NSMutableDictionary *allProperties = [NSMutableDictionary dictionaryWithObjectsAndKeys:[mixpanellite distinctIdentifier],#"distinct_id", MIXPANELLITE_TOKEN, #"token", nil];
if (properties != nil) {
[allProperties addEntriesFromDictionary:properties];
}
NSMutableDictionary *eventDict = [NSMutableDictionary dictionaryWithObjectsAndKeys:event,#"event", allProperties, #"properties", nil];
NSError *error = nil;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:eventDict options:0 error:&error];
if (error == nil)
{
NSLog(#"[MIXPANELLITE] %#", [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]);
NSString *urlTemplate = #"http://api.mixpanel.com/track/?data=%#";
NSString *url = [NSString stringWithFormat:urlTemplate, [jsonData mp_base64EncodedString]];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:url]];
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:nil];
}
}
The only dependency is Matt Gallagher's excellent NSData Base64 category.

Twitter iOS GET statuses/home_timeline using Parse

This will be my first iPhone app and I am running into difficulties that I thought I'd be able to find a tutorial on, but alas.... nothing on the inter webs that I can find.
I'm trying to get an initial 20 or so tweets from a signed in user (signed in using Parse's Twitter authentication) and I can't seem to get it to work. I put a breakpoint in when I get an error and this is what it shows:
I'm contemplating abandoning Parse all together and doing my own authentication using https://github.com/nst/STTwitter but wanted to quickly see if there was a way to simply do what I am trying to. The code is question is at this github: https://github.com/johndangerstorey/twiz and outlined below as found in my MyLoginViewController.m file:
NSString *bodyString = [NSString stringWithFormat:#"https://api.twitter.com/1.1/statuses/home_timeline.json?screen_name=johnDANGRstorey"];
// Explicitly percent-escape the '!' character.
bodyString = [bodyString stringByReplacingOccurrencesOfString:#"!" withString:#"%21"];
NSURL *url = [NSURL URLWithString:bodyString];
NSMutableURLRequest *tweetRequest = [NSMutableURLRequest requestWithURL:url];
tweetRequest.HTTPMethod = #"GET";
tweetRequest.HTTPBody = [bodyString dataUsingEncoding:NSUTF8StringEncoding];
[[PFTwitterUtils twitter] signRequest:tweetRequest];
NSURLResponse *response = nil;
NSError *error = nil;
// Post status synchronously.
NSData *data = [NSURLConnection sendSynchronousRequest:tweetRequest
returningResponse:&response
error:&error];
// Handle response.
if (!error) {
NSLog(#"Response: %#", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
} else {
NSLog(#"Error: %#", error);
}
Thanks for your reply and help.
I figured it out, GET requests don't require .body or .method requests so I just removed
tweetRequest.HTTPMethod = #"GET";
tweetRequest.HTTPBody = [bodyString dataUsingEncoding:NSUTF8StringEncoding];
and was golden.

Wait until NSURLConnection sendAsynchronousRequest is finished

I have the following problem. I have a Model, called User. When the user now logins with Facebook, my app checks if the user exists already in the database. To not freeze the UI (since I'm coming from Android) I thought to use NSURLConnection sendAsynchronousRequest. What worked at first was the following:
My User Model had a method to do the whole task of the AsynchronousRequest and then when finished would set a variable to loading. Then other classes, could simply check with
while ( !user.loading ) if the Request was finished or not. The problem that came here to me, was, that now, I had to put this method in every Model. So instead of this, I created a new Class HTTPPost. This class now has the method that gets an NSDictionary passed and returns one. This works ALMOST. The problem I was now encountering is, that I couldn't really determine if the process was finished or not. So I started to create a new class called Globals and use global Variable loading. But the global variable is ALWAYS NO. So, what would be the best way to do this?
Here is my code:
This is where I check for the user and load it. resultDictionary is the NSDictionary where everything gets loaded in, but is always nil
[user loadModelFrom:[NSString stringWithFormat:#"WHERE facebookId='%#'", graphUser.id]];
NSLog(#"%#", user.resultDictionary);
if ( user.resultDictionary == nil ) {
NSLog(#"NIL");
} else {
NSLog(#"NOT NIL");
}
The problem now, is, that, since I'm sending an AsynchronousRequest, the resultDictionary is always nil. What I did before and worked was the following.
In my Model I had the HTTP Request and a variable named loading. Now I set loading to false until the response has been made into a NSDictionary
returnDict = [NSJSONSerialization JSONObjectWithData: [responseBody dataUsingEncoding:NSUTF8StringEncoding]
options: NSJSONReadingMutableContainers
error: &error];
But, then I had another problem. I had to do this in all my Models again... So I created a new Class that subclasses NSObject, that has the asynchronousRequest. This is the whole request
-(NSDictionary *)doHttpRequest:(NSDictionary *)postDict{
loading = NO;
__block NSDictionary *returnDict;
NSError *error;
NSString *jsonString;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:postDict
options:NSJSONWritingPrettyPrinted // Pass 0 if you don't care about the readability of the generated string
error:&error];
if (! jsonData) {
NSLog(#"Got an error: %#", error);
} else {
jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
}
NSURL *aUrl = [NSURL URLWithString:#"http://xx.xx-xx.xx/xx.xx"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:aUrl
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:60.0];
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
NSString *authStr = [NSString stringWithFormat:#"%#:%#", #"xx", #"xx"];
NSData *authData = [authStr dataUsingEncoding:NSASCIIStringEncoding];
NSString *authValue = [NSString stringWithFormat:#"Basic %#", [authData base64EncodedString]];
[request setValue:authValue forHTTPHeaderField:#"Authorization"];
[request setValue:#"application/json" forHTTPHeaderField:#"Content-type"];
[request setHTTPMethod:#"POST"];
[request setHTTPBody:[jsonString dataUsingEncoding:NSUTF8StringEncoding]];
[NSURLConnection sendAsynchronousRequest:request queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error)
{
NSString *responseBody = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
returnDict = [NSJSONSerialization JSONObjectWithData: [responseBody dataUsingEncoding:NSUTF8StringEncoding]
options: NSJSONReadingMutableContainers
error: &error];
}];
[queue waitUntilAllOperationsAreFinished];
loading = YES;
return returnDict;
}
As you can see I have now a variable called loading. It is a global variable. But somehow, the variable is always NO.
What would be the best way to do this? I hope I'm understandable, I'm new to Objective-C, and English isn't my native language.
UPDATE
I modified the code to look like a user provided here, but still not working!
HTTPPost.h
-(void)doHttpRequest:(NSDictionary *)postDict completion:(void(^)(NSDictionary *dict, NSError *error))completion {
__block NSDictionary *returnDict;
NSError *error;
NSString *jsonString;
NSString *authValue;
NSString *authStr;
NSData *jsonData;
NSData *authData;
NSURL *aUrl;
NSMutableURLRequest *request;
NSOperationQueue *queue;
jsonData = [NSJSONSerialization dataWithJSONObject:postDict
options:NSJSONWritingPrettyPrinted
error:&error];
if (! jsonData) {
NSLog(#"Got an error: %#", error);
} else {
jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
}
aUrl = [NSURL URLWithString:#"http://xx.xx-xx.com/xx.php"];
request = [NSMutableURLRequest requestWithURL:aUrl
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:60.0];
queue = [[NSOperationQueue alloc] init];
authStr = [NSString stringWithFormat:#"%#:%#", #"xx", #"xx"];
authData = [authStr dataUsingEncoding:NSASCIIStringEncoding];
authValue = [NSString stringWithFormat:#"Basic %#", [authData base64EncodedString]];
[request setValue:authValue forHTTPHeaderField:#"Authorization"];
[request setValue:#"application/json" forHTTPHeaderField:#"Content-type"];
[request setHTTPMethod:#"POST"];
[request setHTTPBody:[jsonString dataUsingEncoding:NSUTF8StringEncoding]];
[NSURLConnection sendAsynchronousRequest:request queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error)
{
NSString *responseBody = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
returnDict = [NSJSONSerialization JSONObjectWithData: [responseBody dataUsingEncoding:NSUTF8StringEncoding]
options: NSJSONReadingMutableContainers
error: &error];
if ( completion ) {
completion(returnDict, error);
}
}];
}
//User.h
[_httpPost doHttpRequest:_dbDictionary completion:^(NSDictionary *dict, NSError *error) {
NSLog(#"completed") // NEVER GETS FIRED
}];
It seems that you're trying to take an asynchronous process (sendAsynchronousRequest) , and make it behave like a synchronous process (i.e. you appear to want to wait for it). You should not do that. You should to embrace the asynchronous patterns rather than fighting them.
The sendAsynchronousRequest method has a completion block that specifies what you want to do when the request is done. Do not try to put the code after the block and (try to) wait for the block to complete, but rather put any of your code that is dependent upon the completion of the network request inside the completion block, or have the completion block call your code.
A common way would be to give your own methods their own completion blocks and then call those blocks in the completionHandler of sendAsynchronousRequest, something like:
- (void)performHttpRequest:(NSDictionary *)postDict completion:(void (^)(NSDictionary *dictionary, NSError *error))completion
{
// prepare the request
// now issue the request
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
if (error) {
if (completion)
completion(data, error);
} else {
NSString *responseBody = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
returnDict = [NSJSONSerialization JSONObjectWithData:data
options: NSJSONReadingMutableContainers
error: &error];
if (completion)
completion(returnDict, error);
}];
}
Now, when you want to perform your request, you simply do:
[self performHttpRequest:someDictionary completion:^(NSDictionary *dictionary, NSError *error) {
if (error) {
// ok, handle the error here
} else {
// ok, use the `dictionary` results as you see fit here
}
];
Note, the method that calls this performHttpRequest (let's imagine you called it from loadModelFrom ) now behaves asynchronously, itself. So you might want to employ this completion-block pattern again, e.g. adding your own completion block parameter to loadModelFrom, and then invoke that block in the completion handler loadModelFrom passes to performHttpRequest.
But hopefully you get the idea: Never try to wait for a completion block, but rather just put inside that block anything you want it to do when its done. Whether you use AFNetworking (which I'd advise), or continue to use sendAsynchronousRequest, this is a very useful pattern with which you should become familiar.
Update:
The revised code sample (largely) works great for me. Seeing your revised question, a couple of observations:
I am not familiar with this base64EncodedString method. In iOS 7, there is the native base64EncodedStringWithOptions method (or for earlier iOS versions use base64Encoding). Or are you using a third party base-64 NSData category?
There's no point in creating jsonString, only to then convert it back to a NSData. Just use jsonData in your request.
The same is true with responseBody: Why convert to string only to convert back to NSData?
There's no point in having returnDict to be defined as __block outside the sendAsynchronousRequest block. Just define it inside that block and the __block qualifier is then no longer necessary.
Why create a NSOperationQueue for the completionHandler of sendAsynchronousRequest? Unless I'm doing something really slow that merits running on a background queue, I just use [NSOperationQueue mainQueue], because you invariably want to update the app's model or UI (or both), and you want to do that sort of stuff on the main queue.
The request still runs asynchronously but the queue parameter just specifies which queue the completion block will run on.
By the way, in sendAsynchronousRequest, you aren't checking to see if the request succeeded before proceeding with JSONObjectWithData. If the request failed, you could theoretically be losing the NSError object that it returned. You really should check to make sure the request succeeded before you try to parse it.
Likewise, when you originally dataWithJSONObject the parameters in postDict, you really should check for success, and if not, report the error and quit.
I notice that you're using the NSJSONReadingMutableContainers option. If you really need a mutable response, I'd suggest making that explicit in your block parameters (replacing all the NSDictionary references with NSMutableDictionary). I assume you don't really need it to be mutable, so I therefore recommend removing the NSJSONReadingMutableContainers option.
Likewise, when creating the JSON, you don't need to use the NSJSONWritingPrettyPrinted option. It only makes the request unnecessary larger.
Combining all of this, that yields:
-(void)performHttpRequest:(NSDictionary *)postDict completion:(void(^)(NSDictionary *dict, NSError *error))completion {
NSError *error;
NSString *authValue;
NSString *authStr;
NSData *jsonData;
NSData *authData;
NSURL *aUrl;
NSMutableURLRequest *request;
jsonData = [NSJSONSerialization dataWithJSONObject:postDict options:0 error:&error];
if (!jsonData) {
if (completion)
completion(nil, error);
return;
}
aUrl = [NSURL URLWithString:#"...."];
request = [NSMutableURLRequest requestWithURL:aUrl
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:60.0];
authStr = [NSString stringWithFormat:#"%#:%#", #"xx", #"xx"];
authData = [authStr dataUsingEncoding:NSASCIIStringEncoding];
if ([authData respondsToSelector:#selector(base64EncodedStringWithOptions:)])
authValue = [NSString stringWithFormat:#"Basic %#", [authData base64EncodedStringWithOptions:0]];
else
authValue = [NSString stringWithFormat:#"Basic %#", [authData base64Encoding]]; // if only supporting iOS7+, you don't need this if-else logic and you can just use base64EncodedStringWithOptions
[request setValue:authValue forHTTPHeaderField:#"Authorization"];
[request setValue:#"application/json" forHTTPHeaderField:#"Content-type"];
[request setHTTPMethod:#"POST"];
[request setHTTPBody:jsonData];
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error)
{
if (!data) {
if (completion)
completion(nil, error);
return;
}
NSError *parseError = nil;
NSDictionary *returnDict = [NSJSONSerialization JSONObjectWithData:data options:0 error:&parseError];
if (completion) {
completion(returnDict, parseError);
}
}];
}
And if this is being called from another method that needs to handle the fact that this is happening asynchronously, then it would employ a completion block pattern, too:
- (void)authenticateUser:(NSString *)userid password:(NSString *)password completion:(void (^)(BOOL success))completion
{
NSDictionary *dictionary = #{ ... };
[self performHttpRequest:dictionary completion:^(NSDictionary *dict, NSError *error) {
if (error) {
completion(NO);
return;
}
// now validate login by examining resulting dictionary
BOOL success = ...;
// and call this level's completion block
completion(success);
}];
}
Then the view controller might access that method with something like:
// maybe add UIActivityIndicatorView here
[self.userModel authenticateUser:self.userTextField.text password:self.passwordTextField.text completion:^(BOOL success) {
// remove UIActivityIndicatorView here
if (success) {
// do whatever you want if everything was successful, maybe segue to another view controller
} else {
// show the user an alert view, letting them know that authentication failed and let them try again
}
}];
After seeing you adding specific code to handle request and its responses, I would point out that you should try using AFNetworking. It abstracts out lots of boiler plate code.
As you mentioned, you are new to obj-c, it may take some time to understand AFNetworking but in long run, it will save you lots of headache. Plus it is one of the widely used open source for network related stuff.
I hope this would be helpful.
If you want to wait for a request, then you should not use sendAsynchronousRequest.
Use sendSynchonousRequest instead. That's where it's made for:
NSURLResponse *response;
NSError * error;
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
But, the UI is blocked when the synchronous call is made. I doubt if that is what you want.

Resources