I have already set the clientID ,scope and then on button click in MyViewController ,i am calling method login from LoginCLass which works but after [signIn authenticate] ,the delegate implementation finishedWithAuth is not getting called.I have set .h file as
- (NSError *) login
{
NSLog(#"In login :%# %# %#",kClientId,scopes,actions);
if(!kClientId|| !scopes)
{
NSLog(#"Either client ID Or scope is not specified!! ");
NSError *err=[[NSError alloc]initWithDomain:#"Scope not specified" code:0 userInfo:nil];
return err;
}
else
{
NSLog(#"Client ID and Scope are set.");
GPPSignIn *signIn = [GPPSignIn sharedInstance];
signIn.delegate = self;
signIn.shouldFetchGooglePlusUser = YES;
[signIn authenticate];
[signIn trySilentAuthentication];
return nil;
}
}
- (void)finishedWithAuth:(GTMOAuth2Authentication *)auth error:(NSError *)error
{
NSLog(#"Received error %# and auth object %#",error, auth);
}
and also in AppDelegate i am adding the code
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {
return [GPPURLHandler handleURL:url
sourceApplication:sourceApplication
annotation:annotation];
}
I have checked the bundle ID and URL Types to be specified,they are set same as bundle ID from Google API access.
These methods are in LoginClass which are used in MyViewController class.
When i set the finishedWithAuth delegate to MyViewController ,by setting it as GPPSignInDelegate, the code runs fine.But, i want to use it from LoginClass.
Any idea , where am i going wrong ??
Since your LoginClass is a Swift class, the fix is to make it a subclass of NSObject.
I had the same issue: when I tried to set the delegate to a class that was not a subclass of NSObject, the assignment failed and the delegate remained nil. When I added NSObject as a superclass, the assignment worked as expected.
The problem seems to be where an instance of the GPPSignIn is not persisted between leaving the app to load Safari and coming back to your app.
Currently in your login method you have:
GPPSignIn *signIn = [GPPSignIn sharedInstance];
so this is a local instance variable. Try moving this to the class level:
#implementation LoginClass {
GPPSignIn *signIn;
}
then use that in your login method
You Can use
if (![signIn trySilentAuthentication])
[signIn authenticate];
Follow this link for more detail
trySilentAuthentication without Google+ button
This happened to me too in my apps running iOS 8. What did it for me was to set the clientId in the AppDelegate as soon as the app launched, and not in the viewDidLoad method of my UIViewController class as indicated in the Google+ Sign-in for iOS example in the following URL: https://developers.google.com/+/mobile/ios/sign-in
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
/
//Google+
// Set app's client ID for |GPPSignIn| and |GPPShare|.
[GPPSignIn sharedInstance].clientID = #"xxxxxx.......apps.googleusercontent.com";
...
return YES;
}
So, in your UIViewController class the sign-in method should be:
- (void)viewDidLoad {
[super viewDidLoad];
//Google+ for Logging in the user again if the app has been authorized
signIn = [GPPSignIn sharedInstance];
signIn.shouldFetchGooglePlusUser = YES;
signIn.shouldFetchGoogleUserID = YES;
signIn.shouldFetchGoogleUserEmail = YES;
signIn.scopes = #[ kGTLAuthScopePlusLogin ];
signIn.delegate = self;
[signIn trySilentAuthentication];
...
}
Here is the simple solution for this.
func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool {
if (url.absoluteString.range(of: "oauth2callback") != nil) {
GPPSignIn.sharedInstance().handle(url, sourceApplication: options[UIApplicationOpenURLOptionsKey.sourceApplication] as! String, annotation: nil)
}
return false
}
Related
i have implemented google play games in my app for leaderboard.
my requirement is to display info Alert when user login first time in safari(redirect to safari automatically for login)
i have written this code
[GPGManager sharedInstance].statusDelegate = self;
BOOL isSignedIn = [[GPGManager sharedInstance] signInWithClientID:kGoogleClient silently:flag];
NSLOG(#“is signedin %d",[GPGManager sharedInstance].isSignedIn);
but every time [GPGManager sharedInstance].isSignedIn this variable returns false.
any one have any idea ??
You must configure the GGLContext shared instance. You can do this in many places in your app. Often the easiest place to configure this instance is in your app delegate's application:didFinishLaunchingWithOptions: method.
In your app delegate's .h file, declare that this class implements the GIDSignInDelegate protocol.
#import <Google/SignIn.h>
#interface AppDelegate : UIResponder <UIApplicationDelegate, GIDSignInDelegate>
AppDelegate.h
In your app delegate's application:didFinishLaunchingWithOptions: method, configure the GGLContext shared instance and set the sign-in delegate.
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
NSError* configureError;
[[GGLContext sharedInstance] configureWithError: &configureError];
NSAssert(!configureError, #"Error configuring Google services: %#", configureError);
[GIDSignIn sharedInstance].delegate = self;
return YES;
}
Implement the application:openURL:options: method of your app delegate. The method should call the handleURL method of the GIDSignIn instance, which will properly handle the URL that your application receives at the end of the authentication process.
- (BOOL)application:(UIApplication *)app
openURL:(NSURL *)url
options:(NSDictionary *)options {
return [[GIDSignIn sharedInstance] handleURL:url
sourceApplication:options[UIApplicationOpenURLOptionsSourceApplicationKey]
annotation:options[UIApplicationOpenURLOptionsAnnotationKey]];
}
In the app delegate, implement the GIDSignInDelegate protocol to handle the sign-in process by defining the following methods:
- (void)signIn:(GIDSignIn *)signIn
didSignInForUser:(GIDGoogleUser *)user
withError:(NSError *)error {
// Perform any operations on signed in user here.
NSString *userId = user.userID; // For client-side use only!
NSString *idToken = user.authentication.idToken; // Safe to send to the server
NSString *fullName = user.profile.name;
NSString *givenName = user.profile.givenName;
NSString *familyName = user.profile.familyName;
NSString *email = user.profile.email;
// ...
}
- (void)signIn:(GIDSignIn *)signIn
didDisconnectWithUser:(GIDGoogleUser *)user
withError:(NSError *)error {
// Perform any operations when the user disconnects from app here.
// ...
}
i have implemented URL Scheme in my App so that whenever i click the URL, it will open up my app. I have also inserted some request in the URL such as
Yuvtime//:?registerName=Puppy&Passwords=67825
and i use the openUrl in AppDelegate to handle the processing of the URL and pass the data (registerName=Puppy&Passwords=67825`) to my rootViewController which is the registration page of my app, the code is as shown below.
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation{
// Check the calling application Bundle ID
if ([[url scheme] isEqualToString:#"yuvitime"])
{
NSLog(#"Calling Application Bundle ID: %#", sourceApplication);
NSLog(#"URL scheme:%#", [url scheme]);
self.yuvitimeRequest = [url query];
NSLog(#"URL query: %#", yuvitimeRequest);
return YES;
}
else
return NO;
}
And in the RegistrationviewController, I implemented the code as follows.
-(void)viewWillAppear:(BOOL)animated{
[super viewDidAppear:animated];
AppDelegate * myAppDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
self.requestFromURL = myAppDelegate.yuvitimeRequest;
NSLog(#"%# hello google", self.requestFromURL);
if (self.requestFromURL.length > 0){
self.isRequestFromURL = YES;
}
if(self.isRequestFromURL == YES){
self.mainViewController.joinRoomName = self.requestFromURL;
self.isRequestFromURL = NO;
self.requestFromURL = #"";
[self presentViewController:self.mainViewController animated:YES completion:nil];
}
}
However, the problem i encounter is that:
If the user already has its app opened, this viewWilAppear in the RegistrationViewController will not be called again, so the data will not be passed automatically from the URL. (Only by killing the app, and click the URL will the data be passed as what we initially desired).
I also understand that when an App is already open and called again, only
(void)applicationWillEnterForeground:(UIApplication *)application &
(void)applicationDidBecomeActive:(UIApplication *)application
will be called in sequence in the app delegate. But somehow i stuck on how do i pass data to my registrationViewController from these two methods and if i can manage to do it in these two application methods, that would mean that my app checks every time on whether there is any registration data available from URL when the app comes to the foreground.
Since we already have the
(BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
to handle the URL scheme, is it possible that we only check once without using the foreground and didBecomeActive app delegate functions when we click the URL?
EDIT: After implementing URL scheme, whenever you click a URL, a delegate method in AppDelegate.m will be triggered.
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation;
This is also the function that will enable us to process the URL in our app and pass it around to other viewControllers.
I was kinda thinking, is there a way that we can implement a notification/function such that only when this openURL function is called, we then call the triggerURL function in registrationViewController.
Just out of curiosity!
Thanks
Regards
In your RegistrationViewController, you can register for UIApplicationDidBecomeActiveNotification and get notified of application being awakened even when your view controller was already loaded.
Add this line in your loadView:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(triggerURL) name:UIApplicationDidBecomeActiveNotification object:[UIApplication sharedApplication]];
This will allow the function updateSettings to be called every time your app wakes. Also remember to remove this listener at the end by:
[[NSNotificationCenter defaultCenter] removeObserver:self];
in your dealloc method.
Post that, this is how your viewWillAppear & triggerURL will look like:
- (void)viewWillAppear:(BOOL)animated{
[super viewDidAppear:animated];
[self triggerURL];
}
- (void)triggerURL {
AppDelegate * myAppDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
self.requestFromURL = myAppDelegate.yuvitimeRequest;
NSLog(#"%# hello google", self.requestFromURL);
if (self.requestFromURL.length > 0){
self.isRequestFromURL = YES;
}
if(self.isRequestFromURL == YES){
self.mainViewController.joinRoomName = self.requestFromURL;
self.isRequestFromURL = NO;
self.requestFromURL = #"";
[self presentViewController:self.mainViewController animated:YES completion:nil];
}
}
I'm using Facebook SDK with Parse SDK in user Login.
Using 'logInInBackgroundWithReadPermissions' to perform login, Even though user is authenticated the app, 'user' is always nil in the response. And error is:
Error Domain=com.facebook.sdk.login Code=304 "The operation couldn’t
be completed. (com.facebook.sdk.login error 304.)"
Here is my Implementation:
• Basic configuration:
I have configured every thing in .plist
and followed guidelines at link1, link2
• Imported frameworks:
• Implementation in Appdelegate:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
[Parse setApplicationId:#"I have used real key here" clientKey:#"I have used real key here"];
[PFFacebookUtils initializeFacebookWithApplicationLaunchOptions:launchOptions];
return YES; }
- (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];
}
• Login Implementation:
NSArray *fbPermissions = [[NSArray alloc] initWithObjects: #"public_profile", nil];
[PFFacebookUtils logInInBackgroundWithReadPermissions:fbPermissions block:^(PFUser *user, NSError *error) {
if (!user) {
NSLog(#"Uh oh. The user cancelled the Facebook login.");
}
else if (user.isNew) {
NSLog(#"User signed up and logged in through Facebook!");
} else {
NSLog(#"User logged in through Facebook!");
}
}];
But in the call back, 'user' is always nil. Did anyone face the same issue?
- Thanks in advance.
I was not able to find out cause for the issue. But I just deleted all frameworks related to Parse and Facebook and Re-added all of them. It worked fine. So, there is no issue in the code.
in AppDelegate.m file, under didFinishLaunchingWithOptions method, initialize Parse before initializing PFFacebookUtils.
FBSDKSharingDelegate callback is not working. I can post to facebook fine with the ios SDK, but I'd like to detect if the post was successful and take additional action to notify the user. However, the callback is not working for me. The delegate methods are not being called and I don't know why.
Using ios8, Parse as my backend. In Parse, the user is linked to FB. I'm using the IOS simulator.
What I've tried:
I've ensured that publish permissions are granted, saved, and linked to the Parse user. I've run a check and "publish_actions" are detected OK. The posting works fine as I can see the post on the facebook account. It's just the callback that is not working. I've checked my fb setup and it looks fine. For good measure at the very bottom I've included that relevant code from my app delegate. I've blocked out confidential keys with XXXX.
Code:
1st: See if user is logged in to Parse, if not, send to sign in and link to facebook account. Once that is done, I request "publish" permissions and link that additional permission to the Parse user. I know this works b/c when I recompile, it remembers the "publish" permissions and goes right to into the post.
#interface FacebookAPIPost () <FBSDKSharingDelegate>
#end
#implementation FacebookAPIPost
-(void)shareSegmentFacebookAPI { //if statement below
//1) logged in?, if not send to sign up screen
//2) else if logged in, link account to facebook account, then send post
//3) else send to post b/c signed up and linked already.
PFUser *currentUser = [PFUser currentUser];
if(!currentUser) {
[self pushToSignIn];
} else if(![PFFacebookUtils isLinkedWithUser:currentUser]){
[self linkUserToFacebook:currentUser];
NSLog(#"user account not linked to facebook");
} else {
[self shareSegmentWithFacebookComposer];
}
}
-(void)linkUserToFacebook:currentUser{
[PFFacebookUtils linkUserInBackground:currentUser withPublishPermissions:#[#"publish_actions"] block:^(BOOL succeeded, NSError *error) {
if(error){
NSLog(#"There was an issue linking your facebook account. Please try again.");
}
else {
NSLog(#"facebook account is linked");
//Send the facebook status update
[self shareSegmentWithFacebookComposer];
}
}];
}
-(void)shareSegmentWithFacebookComposer{
if ([[FBSDKAccessToken currentAccessToken] hasGranted:#"publish_actions"]) {
[self publishFBPost]; //publish
} else {
NSLog(#"no publish permissions"); // no publish permissions so get them, then post
[PFFacebookUtils linkUserInBackground:[PFUser currentUser]
withPublishPermissions:#[ #"publish_actions"]
block:^(BOOL succeeded, NSError *error) {
if (succeeded) {
NSLog(#"User now has read and publish permissions!");
[self publishFBPost];
}
}];
Here is where the post gets made:
-(void) publishFBPost{
FBSDKShareLinkContent *content = [FBSDKShareLinkContent new];
content.contentURL = [NSURL URLWithString:[self.selectedSegment valueForKey:#"linkToContent"]];
content.contentTitle = [self.selectedProgram valueForKey:#"programTitle"];
content.contentDescription = [self.selectedSegment valueForKey:#"purposeSummary"];
PFFile *theImage = [self.selectedSegment valueForKey:#"segmentImage"];
NSString *urlString = theImage.url;
NSURL *url = [NSURL URLWithString:urlString];
content.imageURL = url;
FBSDKShareDialog *shareDialog = [FBSDKShareDialog new];
[shareDialog setMode:FBSDKShareDialogModeAutomatic];
// [FBSDKShareDialog showFromViewController:self.messageTableViewController withContent:content delegate:self];
[shareDialog setShareContent:content];
[shareDialog setDelegate:self];
[shareDialog setFromViewController:self.messageTableViewController];
[shareDialog show];
}
Delegate methods below are not working. Meaning after the post is complete, I can see it on the FB account, but none of these delegate methods execute.
#pragma mark - delegate methods
- (void)sharer:(id<FBSDKSharing>)sharer didCompleteWithResults:(NSDictionary *)results {
// if ([sharer isEqual:self.shareDialog]) {
NSLog(#"I'm going to go crazy if this doesn't work.%#",results);
// Your delegate code
// }
}
- (void)sharer:(id<FBSDKSharing>)sharer didFailWithError:(NSError *)error
{
NSLog(#"sharing error:%#", error);
NSString *message = error.userInfo[FBSDKErrorLocalizedDescriptionKey] ?:
#"There was a problem sharing, please try again later.";
NSString *title = error.userInfo[FBSDKErrorLocalizedTitleKey] ?: #"Oops!";
[[[UIAlertView alloc] initWithTitle:title message:message delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil] show];
}
- (void)sharerDidCancel:(id<FBSDKSharing>)sharer
{
NSLog(#"share cancelled");
}
Console output:
The only message I get back after posting is after a few seconds this message appears:
plugin com.apple.share.Facebook.post invalidated
Please help!
Footnote: appDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Initialize Parse.
[Parse enableLocalDatastore];
[Parse setApplicationId:#"XXXX"
clientKey:#"XXX"];
[PFFacebookUtils initializeFacebookWithApplicationLaunchOptions:launchOptions];
//Initialize Facebook
[FBSDKAppEvents activateApp];
return [[FBSDKApplicationDelegate sharedInstance] application:application didFinishLaunchingWithOptions:launchOptions];
}
//Method added for facebook integration
- (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 {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
[FBSDKAppEvents activateApp];
}
I think I am too late answering this question but someone else could trap into this as well, that's why sharing my knowledge.
As per Facebook API documentation
sharer:didCompleteWithResults: Sent to the delegate when the share completes without error or cancellation.
The results from the sharer. This may be nil or empty.
its probably because this delegate method is only get called when the post is successfully shared. In case of failure the other delegate method sharer:didFailWithError:get called. I think Facebook API should not need to add the result parameter is that case.
So in my experience if sharer:didCompleteWithResults whenever this is called that would mean success.
iOS Google+ SignIn finishedWithAuth never triggered after the application:openURL:sourceApplication:annotation: app delegate method. This was working, but now it does not.
The response is:
url:com.**************:/oauth2callback?state=19139956&code=4/<some token string>&authuser=0&num_sessions=1&prompt=consent&session_state=9efdca9285835ed58ace73b284e4f7521076fc97..4291*
The signIn instance is a class member, so I don't know what happens for the finishedWithAuth triggering.
Thanks!
-(void)googlePluseLogin
{
GPPSignIn *signIn = [GPPSignIn sharedInstance];
signIn.delegate = self;
signIn.shouldFetchGooglePlusUser = YES;
signIn.shouldFetchGoogleUserEmail = YES;
signIn.clientID = kClientID;
signIn.scopes = #[#"profile"];
if (![signIn trySilentAuthentication])
[signIn authenticate];
}
-(void)finishedWithAuth:(GTMOAuth2Authentication *)auth error:(NSError *)error
{
NSLog(#"%#",auth);
if (error)
{
}
else
{
}
}
You need to call GPPURLHandler handleURL in your application:openURL:sourceApplication:annotation: method, and you need to have setup the delegate on [GPPSignIn sharedInstance] before. I am guessing that you don't set the delegate until after the GPPURLHandler has been processed.
I forgot to setup a URL Type as shown in Step 3