I'm trying to insert a "Moment" into a user's Google+ account, using the google-api-objectivec-client library. I think have the authentication process working properly. It's primarily the same way I have YouTube authentication set up, but with the correct scope and keychain name. However, when I try to run the query to insert the moment I get the following error:
Error Domain=com.google.GTLJSONRPCErrorDomain Code=401 "The operation
couldn’t be completed. (Unauthorized)"
After looking at Google's documentation more carefully (here) I found the following comment:
When authenticating for moments.insert, you must include the data-requestvisibleactions
parameter to specify which types of App Activities your application will write.
Google has several examples of how to do this with other programming languages, but they don't have any examples for the objective-c library, and the objective-c project doesn't contain any examples of how to do this either.
I know that there's another authentication method, using the GPPSignIn button, which has a way to set the actions. However, my application is using multiple other Google API clients (YouTube, YouTube Analytics, and URL Shortener). Mixing the GoogleOpenSource.framework with the other Objective-C libraries causes a conflict. So, I need to use the GTMOAuth2ViewControllerTouch class.
My Authentication Code
GTMOAuth2ViewControllerTouch *viewController =
[GTMOAuth2ViewControllerTouch controllerWithScope:kGTLAuthScopePlusLogin
clientID:kGoogleApiClientId
clientSecret:kGoogleApiClientSecret
keychainItemName:kGooglePlusKeychainName
completionHandler:^(GTMOAuth2ViewControllerTouch *viewController, GTMOAuth2Authentication *auth, NSError *error) {
if (error)
NSLog(#"Error: %#", error.description);
else
app.googlePlusService.authorizer = auth; //this sets a property of my app delegate, to be used elsewhere in the application
}];
[self.navigationController pushViewController:viewController animated:YES];
The code I'm using to insert the "Moment"
NSString *shareUrl = "http://www.google.com"; //just for this example
GTLPlusMoment *moment = [[GTLPlusMoment alloc] init];
moment.type = #"http://schemas.google.com/AddActivity";
GTLPlusItemScope *target = [[GTLPlusItemScope alloc] init];
target.url = shareUrl;
moment.target = target;
GTLQueryPlus *query =
[GTLQueryPlus queryForMomentsInsertWithObject:moment
userId:#"me"
collection:kGTLPlusCollectionVault];
[app.googlePlusService executeQuery:query
completionHandler:^(GTLServiceTicket *ticket,
id object,
NSError *error) {
if (error) {
NSLog(#"Got bad response from plus.moments.insert: %#", error);
} else {
NSLog(#"Moment inserted: %#",moment.identifier);
}
}];
Has anyone out there successfully found the place to add the data-requestvisibleactions parameter to either the authentication call or queryForMomentsInsertWithObject method to allow them to execute the moments.insert action without receiving an error?
Thanks!
You can add data-requestvisibleactions using Java Script code in Authentication. Once you authorized with java script, it will be authorized for all types of insert moments. There is no method in Objective c for adding data-requestvisibleactions in your code. Only the option is possible through Java Script.
For More derails Refer THIS
Related
I need to add a new business place by using the google places API which is not already in google places database. For this we have used addPlace: callback:^ I believe this method once successfully added a new business location that call backs send a response to us and Places API are reviewed and, if approved, added to the global places database.
I have used the same call back method, but can't get any response from it.
My code is below,
GMSPlacesClient *placesClient;
[placesClient addPlace:userAddedPlace callback:^(GMSPlace *place, NSError *error) {
if (error != nil) {
NSLog(#"User Added Place error %#", [error localizedDescription]);
return;
}
NSLog(#"Added place with placeID %#", place.placeID);
NSLog(#"Added Place name %#", place.name);
NSLog(#"Added Place address %#", place.formattedAddress);
}];
We keep the location details in this object userAddedPlace
Is there any issue in this code? help me out why i didn't get the response after call this method. Thanks in advance.
Did you init placesClient object? try GMSPlacesClient *placesClient = [GMSPlacesClient sharedClient];
I saw this question but nobody answer how to change the language using the Google Places Api for iOS (GMSAutocompleteFilter). I need set by code the lenguaje parameter in order to Google api always return the results in english. I saw in the documentation that it's an optional parameter called 'language', but I cant find the way to set it in the iOS api (not as url example in the doc).
if(aQuery.length>0){
GMSAutocompleteFilter *filter = [[GMSAutocompleteFilter alloc] init];
filter.type = kGMSPlacesAutocompleteTypeFilterCity;
// filter.accessibilityLanguage = #"en";
[_placesClient autocompleteQuery:aQuery
bounds:nil
filter:filter
callback:^(NSArray *results, NSError *error) {
if (error != nil) {
NSLog(#"Autocomplete error %#", [error localizedDescription]);
handler(nil);
return;
}
if(results.count>0){
NSMutableArray *arrfinal=[NSMutableArray array];
for (GMSAutocompletePrediction* result in results) {
NSDictionary *aTempDict = [NSDictionary dictionaryWithObjectsAndKeys:result.attributedFullText.string,#"description",result.placeID,#"reference", nil];
PlaceObject *placeObj=[[PlaceObject alloc]initWithPlaceName:[aTempDict objectForKey:#"description"]];
placeObj.userInfo=aTempDict;
[arrfinal addObject:placeObj];
}
handler(arrfinal);
}else{
handler(nil);
}
}];
}else{
handler(nil);
}
You may need to use the Geocoding API to receive these responses in a different language. See here for the Reverse Geocoding article, with the language parameter a few paragraphs down.
You can make an NSURLRequest with the appropriate URL and language parameters. The response is in JSON format, so you should be able to handle this change dynamically within your code.
A cleaner way to do it might be to create a separate page that acts as a sort of web service for you. It accepts two parameters: A language code and an address. It loads the API using the language code requested, and reverse geocodes the address, providing the result. Your page would call this web service-like thing twice, once for each language, and then use the results as desired.
I coding a iOS app using O365-iOS-Connect to connect my app to Office 365. My app can sign in to 365 account. But i can not find some docs how to Fetch/Create calender.
O365-iOS-Connect
Thanks and sorry for my bad english.
Steps to fetch outlook calendars in iOS are:
I use MSGraph SDK & Azure AD v2.0 endpoint(for personal login)
Note: You must know how to install pods and check this link for details: https://graph.microsoft.io/en-us/
Steps:
Register your iOS application on Microsoft Application Registration Portal and it will give you a client-id
Install the following pods :
pod 'MSGraphSDK-NXOAuth2Adapter'
pod 'MSGraphSDK'
Go to your ViewController and define :
#property (strong, nonatomic) MSGraphClient *client;
NSString *clientId = #"<you_clientId>"; // GLOBAL to the class
Now import these files as:
#import <MSGraphSDK/MSGraphSDK.h>
#import <MSGraphSDK-NXOAuth2Adapter/MSGraphSDKNXOAuth2.h>
5.On your button click: First you have use your client-id and define your permissions in the scope as:
[NXOAuth2AuthenticationProvider setClientId:clientId
scopes:#[#"https://graph.microsoft.com/Files.ReadWrite",
#"https://graph.microsoft.com/Calendars.ReadWrite"]];
Now you have to authenticate with your login details and Microsoft login screen automatically opens up:
[[NXOAuth2AuthenticationProvider sharedAuthProvider] loginWithViewController:nil completion:^(NSError *error) {
if (!error) {
[MSGraphClient setAuthenticationProvider:[NXOAuth2AuthenticationProvider sharedAuthProvider]];
self.client = [MSGraphClient client];
//Authenticated successfully
} }];
If there is no error, then error is nil and it will logged in successfully.
Now we can use different APIs using MSGraphClient and for calendars list:
[[[[self.client me] calendars] request] getWithCompletion:^(MSCollection *response, MSGraphUserCalendarsCollectionRequest *nextRequest, NSError *error) {
NSArray *calendars = response.value;
// Here we are getting calendars
}];
Now, get calendars button action look like this:
- (IBAction)getCalendars:(id)sender {
[NXOAuth2AuthenticationProvider setClientId:clientId
scopes:#[#"https://graph.microsoft.com/Files.ReadWrite",
#"https://graph.microsoft.com/Calendars.ReadWrite"]];
[[NXOAuth2AuthenticationProvider sharedAuthProvider] loginWithViewController:nil completion:^(NSError *error) {
if (!error) {
[MSGraphClient setAuthenticationProvider:[NXOAuth2AuthenticationProvider sharedAuthProvider]];
self.client = [MSGraphClient client];
[[[[self.client me] calendars] request] getWithCompletion:^(MSCollection *response, MSGraphUserCalendarsCollectionRequest *nextRequest, NSError *error) {
NSArray *calendars = response.value;
// Here we are getting calendars
}];
} }];
}
we have a couple options in our GitHub code samples that might be of assistance.
One is called O365-iOS- Snippets: https://github.com/OfficeDev/O365-iOS-Snippets. The O365 iOS Snippets project shows you how to do basic operations against the Calendar, Contacts, Mail, and Files service endpoints in Office 365.
For Microsoft Graph, we've also created an iOS snippets project for that - https://github.com/OfficeDev/O365-iOS-Microsoft-Graph-Snippets. This sample shows how to use Microsoft Graph to send email, manage groups, and perform other activities with Office 365 data.
Hope this helps!
Freya H, The Office Newsroom
I have added the announcement app and added few items to it, now i want to fetch the items from my announcement list so I have used the below code
token_Obtained_During_first_time_Login: This is the token that i get when i login for the first time using the acquireTokenWithResource method of ADAuthenticationContext class
- (void)getClientList {
NSString *appToken = [[NSUserDefaults standardUserDefaults]
valueForKey:#"token_Obtained_During_first_time_Login"];
NSString* hostName = #"https://myTenant.sharepoint.com/sites/myApp";
OAuthentication *credentials = [[OAuthentication alloc] initWith:appToken];
ListClient *client = [[ListClient alloc]
initWithUrl:hostName
credentials:credentials];
NSURLSessionTask* task = [client getListItems:#"MyAnnouncements"
callback:^(NSMutableArray *listItems, NSError *error) {
if (error==nil) {
NSLog(#"%#",listItems);
}
}];
[task resume];
}
I have even debugged the 365 code and it provides me the below URL for getListItems: callback method
https://myTenant.sharepoint.com/sites/myApp/_api/lists/GetByTitle('MyAnnouncements')/Items
I have even tried the same using getTokenWith method which comes with the sample code
- (void)getAnnouncementList:(void (^)(ListClient *))callback{
NSString* hostName = #"https://myTenant.sharepoint.com";
[self getTokenWith:hostName :true completionHandler:^(NSString *token) {
OAuthentication *credentials = [[OAuthentication alloc] initWith:token];
callback([[ListClient alloc]initWithUrl:hostName credentials:credentials]);
}];
}
But still no luck i get the list as nil
Please guide on how this can be resolved, I have even verified the rights in the Azure Directory everything seems fine am able to fetch data of one drive, mails and calendar but list is a place where i am stuck.
Every time i call the above code i get the response nil not sure what am passing wrong, my guess is the token.
I resolved this issue by making a change in the apiUrl present in the ListClient.m file of Office 365.
All i did was changed it to
const NSString *apiUrl = #"/sites/mobileApp/_api/web/Lists";
Making the above change did the trick and now i can access all the list data.
So I am trying to allow two users to swap files that each has in their Google Drive. That involves knowing the ID of the other person's file and using the API calls to retrieve it. Both files sit in folders that have been shared to anyone/public.
Trouble is when I execute the code below I am finding that each user can only use the downloadUrl corresponding to the file they own - the others return a 404. In this case either "mine" or "theirs" depending on the account I'm logged into.
// _driveService and its authorizer setup elsewhere
// Retrieve the metadata then the actual data
NSString *mine = #"0B4Pba9IBDsR3T1NVTC1XSGJTenc";
NSString *theirs = #"0B4n9OyY8tqWpNlNaN1dUc3FsNG8";
NSString *get = [NSString stringWithFormat:#"https://www.googleapis.com/drive/v2/files/%#",theirs];
[_driveService fetchObjectWithURL:[NSURL URLWithString:get] completionHandler:^
(GTLServiceTicket *ticket, GTLDriveFile *file, NSError *error)
{
if (error != nil)
NSLog(#"Error retrieving metadata: %#", error);
else
{
// Download the actual data
GTMHTTPFetcher *fetcher = [_driveService.fetcherService fetcherWithURLString:file.downloadUrl];
[fetcher beginFetchWithCompletionHandler:^
(NSData *data, NSError *error)
{
if (error != nil)
NSLog(#"Error retrieving actual data: %#", error);
else
{
NSString *content = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(#"Content: %#", content);
}
}];
}
}];
Error retrieving actual data: Error Domain=com.google.HTTPStatus Code=404 "The operation couldn’t be completed. (com.google.HTTPStatus error 404.)"
What am I doing wrong here? If it's a permissions thing, why am I allowed to get the metadata?
Note this is for an iOS app and both files were created and uploaded from the app using the official client API (rev 353).
Hah, so it seems the devil is in the detail I left out of the question. When creating the authorizer the scope I was providing is kGTLAuthScopeDriveFile, which was the default in an example and I forgot all about it when everything else thus far worked fine. Apparently I need to use kGTLAuthScopeDrive instead (the differences are explained here)
The logic seems a bit flawed here though, I mean I don't want access to other files that weren't created with the app, I just want access to a public file somebody else created with the app...