Facebook login: persisting across app launches - ios

I'm logging in users with the following method, which works fine. However, each time the app relaunches, I need to run this method again to regain access.
The Facebook documentation seems to be very limited, and all the advice I can find (including on Stack Overflow) is related to the old Facebook SDK.
From what I can understand, a FBSDKAccessToken should be being cached when the user is first logged in. However, when I check [FBSDKAccessToken currentAccessToken] on subsequent launches, nothing is returned.
Any advice very welcome.
FBSDKLoginManager *login = [[FBSDKLoginManager alloc] init];
[login logInWithPublishPermissions:#[#"publish_actions"] handler:^(FBSDKLoginManagerLoginResult *result, NSError *error) {
if (error) {
// Process error
} else if (result.isCancelled) {
// Handle cancellations
} else {
if ([result.grantedPermissions containsObject:#"publish_actions"]) {
// success
}
}
}];

Lol, searched for hours then came here 5 minutes too soon. The problem was that I needed to add the following in AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
return [[FBSDKApplicationDelegate sharedInstance] application:application
didFinishLaunchingWithOptions:launchOptions];
}

You ALSO want to add this in the following method:
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {
BOOL facebookCheck = [[FBSDKApplicationDelegate sharedInstance] application:application
openURL:url
sourceApplication:sourceApplication
annotation:annotation];
if (!facebookCheck){
...
}
return true;
}
You probably wont need it now, but it doesn't hurt. :)

Related

iOS Facebook SDK 4 FBSDKShareDialog

I have some trouble when I try to implement FBSDKShareDialog to perform facebook sharing via my app. If official fb app is installed it shows blank dialog (where user allows to type some text etc). If user doesn't have fb app it shows correct info but FBSDKSharingDelegate methods doesn't work. (It doesn't work even when user has fb application)
- (void)sharer:(id<FBSDKSharing>)sharer didCompleteWithResults:(NSDictionary *)results
{
NSLog(#"complete");
}
- (void)sharerDidCancel:(id<FBSDKSharing>)sharer
{
NSLog(#"did cancel");
}
- (void)sharer:(id<FBSDKSharing>)sharer didFailWithError:(NSError *)error
{
NSLog(#"%#", error);
}
It's never called even when I cancel or share via FB application.
My code is:
FBSDKShareLinkContent *content = [[FBSDKShareLinkContent alloc] init];
content.contentTitle = _place.title;
content.imageURL = [NSURL URLWithString:_place.logoUrl];
content.contentDescription = _place.info;
[FBSDKShareDialog showFromViewController:_viewController withContent:content delegate:self];
I have a delegate inside #interface declaration.
#interface FacebookHandler () < FBSDKSharingDelegate >
#end
My app delegate has
#import <FBSDKCoreKit/FBSDKCoreKit.h>
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
return [[FBSDKApplicationDelegate sharedInstance] application:application
didFinishLaunchingWithOptions:launchOptions];
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
[FBSDKAppEvents activateApp];
}
- (BOOL)application:(UIApplication *)application
openURL:(NSURL *)url
sourceApplication:(NSString *)sourceApplication
annotation:(id)annotation {
return [[FBSDKApplicationDelegate sharedInstance] application:application
openURL:url
sourceApplication:sourceApplication
annotation:annotation];
}
Where I was wrong? And is it good idea to post some image and title via FBSDKShareLinkContent. Thanks in advance.
Are you calling [FBSDKShareAPI shareWithContent:content delegate:self] from the main thread?
I've already fixed this issue. The problem was that I've delegate to file inherited from NSObject, which can't be a delegate

Facebook SDK share always returns sharerDidCancel [duplicate]

This question already has answers here:
FBSDKShareDialog cancels when it should post
(4 answers)
Closed 7 years ago.
I'm trying to share a post with the Facebook SDK, but sharerDidCancel is always called, either if I share or cancel the post.
Here is my code
- (void)shareFacebook {
FBSDKShareLinkContent *content = [[FBSDKShareLinkContent alloc] init];
content.contentURL = [NSURL URLWithString:#"http://www.google.com"];
[FBSDKShareDialog showFromViewController:view
withContent:content
delegate:self];
}
- (void)sharer:(id<FBSDKSharing>)sharer didCompleteWithResults :(NSDictionary*)results {
NSLog(#"FB: SHARE RESULTS=%#\n",[results debugDescription]);
}
- (void)sharer:(id<FBSDKSharing>)sharer didFailWithError:(NSError *)error {
NSLog(#"FB: ERROR=%#\n",[error debugDescription]);
}
- (void)sharerDidCancel:(id<FBSDKSharing>)sharer {
NSLog(#"FB: CANCELED SHARER=%#\n",[sharer debugDescription]);
}
This class implements the FBSDKSharingDelegate, in my Info.plist I already entered the FacebookAppID and FacebookDisplayName.
In my AppDelegate I have this method:
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
{
return [FBAppCall handleOpenURL:url sourceApplication:sourceApplication];
}
What I'm doing wrong? I exactly followed the Facebook SDK guide.
Thanks
Solved, my error was in the AppDelegate method:
here is a link with the solution http://jitu1990.blogspot.it/2015/05/share-with-facebook-from-ios-app.html
And here is the code
- (BOOL)application:(UIApplication *)application openURL:(NSURL* )url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {
return [[FBSDKApplicationDelegate sharedInstance] application:application
openURL:url sourceApplication:sourceApplication annotation:annotation];
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
[FBSDKAppEvents activateApp];
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
return [ [FBSDKApplicationDelegate sharedInstance] application :application
didFinishLaunchingWithOptions:launchOptions]
}

FBSDKLoginManager logInWithPublishPermissions always returns isCancelled=YES

I am having trouble figuring out how to log a user into my app. [FBSDKAccessToken currentAccessToken] is nil, so I am calling:
[[[FBSDKLoginManager alloc] init] logInWithPublishPermissions:#[#"publish_actions"] handler:…];
as per the included sample project. This switches to the Facebook app, but the message says "You have already authorized App Name.". I click OK and it goes back into the app, but grantedPermissions and declinedPermissions are both nil on the result, and isCancelled is YES. [FBSDKAccessToken currentAccessToken] is still nil.
I can't figure out how I'm supposed to get currentAccessToken to be filled in. It seems to me the call to logInWithPublishPermissions should do that, but it isn't.
You should try adding in your AppDelegate didFinishLaunchingWithOptions :
return [[FBSDKApplicationDelegate sharedInstance] application:application
didFinishLaunchingWithOptions:launchOptions];
This would get u [FBSDKAccessToken currentAccessToken] when user is logged in.
and
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {
return [[FBSDKApplicationDelegate sharedInstance] application:application
openURL:url
sourceApplication:sourceApplication
annotation:annotation];
}
If this method is not present into AppDelegate then it results into cancelled state.
Refer to : https://developers.facebook.com/docs/ios/getting-started#startcoding
This can happen when your Facebook App doesn't have "publish_actions" permission, or you're not using a test user.
On Facebook, go to manage your app, then make sure that the Facebook user you're using is defined under "Roles" as an admin or tester.
If it's not a test user or admin - Facebook will require "publish_actions" permission to be reviewed and approved before allowing your app to use it, until then you'll receive a "isCancelled=YES" result.
After testing your app with this permission, it is possible to submit this permission for review, you'll need to upload a binary that demonstrates usage of this permission with exact details on how to use it. After it's approved, you'll be able to use it with non-test Facebook users.
Since FBSDKLoginKit 4.6.0, the logInWithReadPermissions and logInWithPublishPermissions methods of FBSDKLoginManager seems to have additional fromViewController argument and use that to present modals.
I was calling logInWithPublishPermissions inside the callback of logInWithReadPermissions, which at that point the modal is not fully dismissed yet. (I know it's a bad practice to ask permission when it's not needed, but in my case this seems to be the right place to do.) This cause it to fail with isCancelled equals to YES. I added some delay and wait for the modal to be fully dismissed fixed the problem.
I had the same problem when I landed here, turns out I was only using the deprecated application openURL method because i was using google sign in too. To support iOS 8 and before you have to implement both the current and the deprecated method:
func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool {
return GIDSignIn.sharedInstance().handle(url, sourceApplication: options[UIApplicationOpenURLOptionsKey.sourceApplication] as! String!, annotation: options[UIApplicationOpenURLOptionsKey.annotation]) || FBSDKApplicationDelegate.sharedInstance().application(app, open: url, sourceApplication: options[UIApplicationOpenURLOptionsKey.sourceApplication] as! String, annotation: options[UIApplicationOpenURLOptionsKey.annotation])
}
func application(_ application: UIApplication, open url: URL, sourceApplication: String?, annotation: Any) -> Bool {
return GIDSignIn.sharedInstance().handle(url, sourceApplication: sourceApplication, annotation: annotation) || FBSDKApplicationDelegate.sharedInstance().application(application, open: url, sourceApplication: sourceApplication, annotation: annotation)
}
The deprecated is the second.
Note: The FBSDK method is added after the google one with an or "||" operator but the order doesn't matter and if you wanna only use facebook method just erase the method and the or operator.
Note 2: As swift 3 still stabilizing the method name can change I suggest you always use the auto complete from XCode when overriding and implementing a delegate's method.
Hope this Helps o/
FBSDKLoginManagerLoginResult.isCancelled is unexpectedly YES:
The SDK will report a cancellation if the user explicitly taps a cancel button in the login dialogs, or if they manually app switch back to your app (known as an implicit cancellation). You should make sure you are not initiating a login flow as part of your app delegate's lifecycle (such as starting a login inside application:openURL:sourceApplication:annotation:) as that will mimic an implicit cancellation. If you must, dispatch the login initiation later to the main queue so that the app delegate's lifecycle completes first.
This method works in iOS 9
// Facebook Login Completion delegate
- (void)loginButton:(FBSDKLoginButton *)loginButton didCompleteWithResult:(FBSDKLoginManagerLoginResult *)result error:(NSError *)error
{
if (result){
NSLog(#"%#",result);
NSLog(#"%#",result.grantedPermissions);
[self getFacebookData:result];
}
}
- (void)getFacebookData:(FBSDKLoginManagerLoginResult *)result{
if (![result.grantedPermissions containsObject:#"email"])
{
FBSDKLoginManager *login = [[FBSDKLoginManager alloc] init];
login.loginBehavior = FBSDKLoginBehaviorWeb;
[login logInWithReadPermissions:#[#"email"] fromViewController:self handler:^(FBSDKLoginManagerLoginResult *result, NSError *error)
{
if (error)
{
// Process error
}
else if (result.isCancelled)
{
// Handle cancellations
}
else
{
if ([result.grantedPermissions containsObject:#"email"])
{
NSLog(#"result is:%#",result);
if ([FBSDKAccessToken currentAccessToken]) {
[[[FBSDKGraphRequest alloc] initWithGraphPath:#"me" parameters:#{#"fields": #"first_name, last_name, email, id"}]
startWithCompletionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error) {
if (!error) {
NSLog(#"fetched user:%#", result);
[self registerWithFacebook:result];
}else{
NSLog(#"%#",error);
}
}];
}
}
}
}];
}else{
if ([FBSDKAccessToken currentAccessToken]) {
[[[FBSDKGraphRequest alloc] initWithGraphPath:#"me" parameters:#{#"fields": #"first_name, last_name, email, id"}]
startWithCompletionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error) {
if (!error) {
NSLog(#"fetched user:%#", result);
[self registerWithFacebook:result];
}else{
NSLog(#"%#",error);
}
}];
}
}
}
NOTE : Use FBSDKLoginBehaviorWeb instead of FBSDKLoginBehaviorBrowser. This will surely work
Also, make sure you are not calling for FBSDKAccessToken.currentAccessToken INSIDE your didFinishLaunchingWithOptions method. The setup in didFinishLaunchingWithOptions needs to complete so the token can initialize before you try to log in to Facebook.
I also faced the same issue and i spent almost 2 hours to resolve the issue. What i did is
FBSDKLoginManager *login = [[FBSDKLoginManager alloc] init];
**[login logOut];** // adding this single line fixed my issue
[login logInWithReadPermissions: #[#"public_profile"] fromViewController:self handler:^(FBSDKLoginManagerLoginResult *result, NSError *error) {
if (error) {
NSLog(#"Process error");
} else if (result.isCancelled) {
NSLog(#"Cancelled");
} else {
NSLog(#"Logged in");
[self GetData];
}
}] // I called this logout function
and the issue was fixed
i was using both google and Facebook login so i had to implement my openURL method like this, iOS 9+
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {
if ([[url absoluteString] containsString:#"YOURFBID"]) {
return [[FBSDKApplicationDelegate sharedInstance] application:app openURL:url options:options];
} else {
return [[GIDSignIn sharedInstance] handleURL:url
sourceApplication:options[UIApplicationOpenURLOptionsSourceApplicationKey]
annotation:options[UIApplicationOpenURLOptionsAnnotationKey]];
}
return NO;
}
// you can perform further any operations using the access token
- (void)GetData {
if ([FBSDKAccessToken currentAccessToken]) {
NSDictionary *AccessToken = [FBSDKAccessToken currentAccessToken];
[[[FBSDKGraphRequest alloc] initWithGraphPath:#"me" parameters:#{#"fields": #"id, name, first_name, picture.type(large) ,last_name"}]
startWithCompletionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error) {
if (!error) {
//NSLog(#"fetched user:%#", result);
//NSDictionary *Result = result;
NSDictionary *params = [NSMutableDictionary dictionaryWithObject:[AccessToken tokenString] forKey:#"access_token"];
} else {
[self showAlertController:#"Error" message:error.localizedDescription];
}
}];
} }
(BOOL)application:(UIApplication *)application
openURL:(NSURL *)url
options:(nonnull NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options
{
return [[FBSDKApplicationDelegate sharedInstance] application:application
openURL:url
options:options];
}
// **Still need this for iOS8**
- (BOOL)application:(UIApplication *)application
openURL:(NSURL *)url
sourceApplication:(nullable NSString *)sourceApplication
annotation:(nonnull id)annotation
{
return [[FBSDKApplicationDelegate sharedInstance] application:application
openURL:url
sourceApplication:sourceApplication
annotation:annotation];
}
1.check already added
[[FBSDKApplicationDelegate sharedInstance] application:application
didFinishLaunchingWithOptions:launchOptions];
2.check already added
- (BOOL)application:(UIApplication *)application
openURL:(NSURL *)url
sourceApplication:(nullable NSString *)sourceApplication
annotation:(nonnull id)annotation
{
return [[FBSDKApplicationDelegate sharedInstance] application:application
openURL:url
sourceApplication:sourceApplication
annotation:annotation];
}
3.
write this statement [FBSDKProfile enableUpdatesOnAccessTokenChange:YES];
before
[[FBSDKApplicationDelegate sharedInstance] application:application
didFinishLaunchingWithOptions:launchOptions];
4.call logInWithReadPermissions method in dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{}
call this methord,
FBSDKLoginManager *loginManager = [[FBSDKLoginManager alloc] init];
[loginManager logInWithReadPermissions:#[#"user_friends"] handler:^(FBSDKLoginManagerLoginResult *result, NSError *error) {
code
}];

How to Get URL when application launch via facebook?

I am sharing a facebook link using this method presentShareDialogWithLink in my application. When user tap on the post in facebook application then this opens my application automatically, at that time i want to get the url on what user tap in facebook application. How do i get that url and where i'll get that url?
You can get the URL by method handleOpenURL in AppDelegate
-(BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url {
/* Do something with the url */
}
If you've set up a handler during the present* call, something like:
[FBDialogs presentShareDialogWithLink:url
handler:^(FBAppCall *call, NSDictionary *results, NSError *error) {
if(error) {
NSLog(#"Error: %#", error.description);
} else {
NSLog(#"Success!");
}
}];
Then in your AppDelegate, override the application:openURL:sourceApplication:annotation: method:
- (BOOL)application:(UIApplication *)application
openURL:(NSURL *)url
sourceApplication:(NSString *)sourceApplication
annotation:(id)annotation {
BOOL urlWasHandled = [FBAppCall handleOpenURL:url
sourceApplication:sourceApplication
fallbackHandler:^(FBAppCall *call) {
NSLog(#"Unhandled deep link: %#", url);
}];
return urlWasHandled;
}
Then your handler should get a callback.
For more info, see https://developers.facebook.com/docs/ios/share-dialog/, in particular, https://developers.facebook.com/docs/ios/share-dialog/#handling-responses

Google+ Sign-In button customization

How to customize Google+ Sign-In button ios ?
is there a way to go directly for sign in with out clicking Google+ Sign-In button ?
Yes, there is way to directly sign in Google+.
In AppDelegate, add this,
- (BOOL)application:(UIApplication *)application
openURL:(NSURL *)url
sourceApplication:(NSString *)sourceApplication
annotation:(id)annotation
{
return [GPPURLHandler handleURL:url
sourceApplication:sourceApplication
annotation:annotation];
}
And your login view controller this code parts should be added.
- (void)loginWithGooglePlus
{
[GPPSignIn sharedInstance].clientID = kClientID;
[GPPSignIn sharedInstance].scopes= [NSArray arrayWithObjects:kGTLAuthScopePlusLogin, nil];
[GPPSignIn sharedInstance].shouldFetchGoogleUserID=YES;
[GPPSignIn sharedInstance].shouldFetchGoogleUserEmail=YES;
[GPPSignIn sharedInstance].delegate=self;
[[GPPSignIn sharedInstance] authenticate];
}
- (void)finishedWithAuth:(GTMOAuth2Authentication *)auth
error:(NSError *)error
{
if (!error)
{
NSLog(#"Google+ login successful");
}
else
{
NSLog(#"Error: %#", error);
}
}
kClientID is your app client id taken from google your registered apps. Of course you need to set the delegate ( GPPSignInDelegate ).

Resources