I'm using Braintree for Payment process in my application
[BTPaymentViewController paymentViewControllerWithVenmoTouchEnabled:NO];and use this method for encryption
`
(void)paymentViewController:(BTPaymentViewController *)paymentViewController
didSubmitCardWithInfo:(NSDictionary *)cardInfo
andCardInfoEncrypted:(NSDictionary *)cardInfoEncrypted {
NSDictionary *dict=[self encryptFormData:cardInfo];
[self savePaymentInfoToServer:dict];
}
-(NSDictionary *) encryptFormData:(NSDictionary *) formData {
BTEncryption *braintree = [[BTEncryption alloc] initWithPublicKey: PUBLIC_KEY];
NSMutableDictionary *encryptedParams = [[NSMutableDictionary alloc] init];
[formData enumerateKeysAndObjectsUsingBlock:^(id key, id object, BOOL *stop) {
[encryptedParams setObject: [braintree encryptString: object] forKey: key];
}];
return encryptedParams;
}
call to this method to post the data to localhost server for testing
- (void) savePaymentInfoToServer:(NSDictionary *)paymentInfo {
NSURL *url = [NSURL URLWithString: [NSString stringWithFormat:#"%#/card", SAMPLE_CHECKOUT_BASE_URL]];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
// You need a customer id in order to save a card to the Braintree vault.
// Here, for the sake of example, we set customer_id to device id.
// In practice, this is probably whatever user_id your app has assigned to this user.
// NSString *customerId = [[UIDevice currentDevice] identifierForVendor].UUIDString;
AppDelegate *appdelegate=(AppDelegate *) [[UIApplication sharedApplication]delegate];
[paymentInfo setValue:appdelegate.referenceId forKey:#"bookingRefId"];
[paymentInfo setValue:appdelegate.passengerId forKey:#"passengerId"];
request.HTTPBody = [self postDataFromDictionary:paymentInfo];
request.HTTPMethod = #"POST";
[NSURLConnection sendAsynchronousRequest:request
queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse *response, NSData *body, NSError *requestError)
{
NSError *err = nil;
if (!response && requestError) {
NSLog(#"requestError: %#", requestError);
[self.paymentViewController showErrorWithTitle:#"Error" message:#"Unable to reach the network."];
return;
}
NSDictionary *<b>responseDictionary</b> = [NSJSONSerialization JSONObjectWithData:body options:kNilOptions error:&err];
NSLog(#"saveCardToServer: paymentInfo: %# response: %#, error: %#", paymentInfo, responseDictionary, requestError);
if ([[responseDictionary valueForKey:#"success"] isEqualToNumber:#1]) { // Success!
// Don't forget to call the cleanup method,
// `prepareForDismissal`, on your `BTPaymentViewController`
[self.paymentViewController prepareForDismissal];
// Now you can dismiss and tell the user everything worked.
[self dismissViewControllerAnimated:YES completion:^(void) {
[[[UIAlertView alloc] initWithTitle:#"Success" message:#"Saved your card!" delegate:nil
cancelButtonTitle:#"OK" otherButtonTitles:nil] show];
}];
} else { // The card did not save correctly, so show the error from server with convenenience method `showErrorWithTitle`
[self.paymentViewController showErrorWithTitle:#"Error saving your card" message:[self messageStringFromResponse:responseDictionary]];
}
}];
}`
contain responseDictionary is null and error is null how to fix the issue can any one help me
where are you sending the paymentInfo dictionary to (i.e. what is SAMPLE_CHECKOUT_BASE_URL)? The example project built by Braintree simulates a backend as if you had one yourself. You will want to replace that URL with your backend's URL.
The BTPaymentViewController provides a client-side credit card checkout page, but your backend still has to execute the transaction. For your backend to execute that transaction, you'll have to send that paymentInfo dictionary to your servers.
If you haven't yet built a backend for your iOS app, you can quickly get set up and approved in minutes with Braintree to process your payments.
Related
My question is predicated on Jason Clark’s statement at f8 2014 that app links is designed to sit side by side well with deep linking technologies. I have a word game app published in 2013 to Canada and Australia using Facebook’s authentication but without deep linking. For the US market launch my intent was to add Facebook deep linking. Managed with the request and feed dialogs to send the Match Identifier UUID for both initiating a match and then bragging about the match (FriendSmash example) at that time to open the game on that match. My day job got in the way and I did not have time to finish QA and support a launch to the US. Last summer I upgraded SDKs (Facebook 3.14) and the url query no longer contained the string ‘notif’ to allow me to parse for the match Id. Therefore, I switched from using [FBSession.activeSession handleOpenURL:url] to the current [FBAppCall handleOpenURL:url …] and some other code from the new FriendSmash example. However, the url passed from the Facebook app no longer contains the ‘ref’ and therefore not the ‘notif’ which was the method documented to utilize my deep linking content. I have since updated my project to Facebook iOS SDK 3.21 (predicated in part by other SDKs, e.g. AWS not supporting arm64).
I currently use the following code to send the brag
- (void) sendBrag
{
// This function will invoke the Feed Dialog to post to a user's Timeline and News Feed
// It will attemnt to use the Facebook Native Share dialog
// If that's not supported we'll fall back to the web based dialog.
NSArray *friend = [[NSArray alloc] initWithObjects: bragMatch.opponentFacebookId, nil];
NSString *linkURL = [NSString stringWithFormat:#"http://www.ruleofwords.com/?deeplink_matchno=%#", bragMatch.initiatorMatchNo];
//NSString *linkURL = [NSString stringWithFormat:#"http://www.ruleofwords.com"];
NSString *pictureURL = #"https://pacific-castle-1361.herokuapp.com/rowappicon.png";
NSMutableString *msg = [[NSMutableString alloc]
initWithString:#"Just scored 0 points in Rule of Words. Good luck trying to beat that."];
[msg replaceOccurrencesOfString:#"0" withString:bragMatch.initiatorMatchPoints
options:NSBackwardsSearch range: NSMakeRange(0, [msg length])];
// Prepare the native share dialog parameters
FBLinkShareParams *shareParams = [[FBLinkShareParams alloc] init];
shareParams.friends = friend;
shareParams.link = [NSURL URLWithString:linkURL];
shareParams.name = #"Rule of Words Bragging Rights";
shareParams.caption= msg;
shareParams.picture= [NSURL URLWithString:pictureURL];
shareParams.linkDescription = #"Rule of Words, the contagious photography word social game on iPhone.";
if ([FBDialogs canPresentShareDialogWithParams:shareParams]){
[FBDialogs presentShareDialogWithParams:shareParams
clientState:nil
handler:^(FBAppCall *call, NSDictionary *results, NSError *error) {
if(error) {
NSLog(#"Error publishing story.");
} else if (results[#"completionGesture"] && [results[#"completionGesture"] isEqualToString:#"cancel"]) {
NSLog(#"User canceled story publishing.");
} else {
NSLog(#"Story published.");
}
}];
} else {
// Prepare the web dialog parameters
NSDictionary *params = #{
#"to": bragMatch.opponentFacebookId,
#"name" : shareParams.name,
#"caption" : shareParams.caption,
#"description" : shareParams.linkDescription,
#"picture" : pictureURL,
#"link" : linkURL
};
// Invoke the dialog
[FBWebDialogs presentFeedDialogModallyWithSession:nil
parameters:params
handler:
^(FBWebDialogResult result, NSURL *resultURL, NSError *error) {
if (error) {
NSLog(#"Error publishing story %#.", error);
} else {
if (result == FBWebDialogResultDialogNotCompleted) {
NSLog(#"User canceled story publishing.");
} else {
NSLog(#"Story published.");
}
}}];
}
}
(Aside - In my stepping through the sendBrag code the FBDialogs canPresentShareDialogWithParams always fails so that every time it defaults to a feed dialog. Anyone know what is the state is where the share dialog works? )
Then in my AppDelegate I have…
- (BOOL)application:(UIApplication *)application
openURL:(NSURL *)url
sourceApplication:(NSString *)sourceApplication
annotation:(id)annotation {
NSLog(#"app is %# and url is %# and sourceApp is %#", application, url, sourceApplication);
// attempt to extract a token from the url
return [FBAppCall handleOpenURL:url
sourceApplication:sourceApplication
fallbackHandler:^(FBAppCall *call) {
// If there is an active session
if (FBSession.activeSession.isOpen) {
// Check the incoming link
[self handleAppLinkData:call.appLinkData];
} else {
NSLog(#"Access Token is %#", call.accessTokenData);
if (call.accessTokenData) {
// If token data is passed in and there's
// no active session.
if ([self handleAppLinkToken:call.accessTokenData]) {
// Attempt to open the session using the
// cached token and if successful then
// check the incoming link
[self handleAppLinkData:call.appLinkData];
}
}
}
}];
- (void) handleAppLinkData:(FBAppLinkData *)appLinkData {
NSURL *targetURL = appLinkData.targetURL;
if (targetURL) {
//NSURL *targetURL = [NSURL URLWithString:targetURLString];
NSDictionary *targetParams = [self parseURLParams:[targetURL query]];
NSString *ref = [targetParams valueForKey:#"ref"];
// Check if ref parm is among incoming news feed link, otw attribution link
if ([ref isEqualToString:#"notif"]) {
// Get the request id
NSString *requestIDParam = targetParams[#"request_ids"];
NSArray *requestIDs = [requestIDParam
componentsSeparatedByString:#","];
// Get data (of last request) from Graph API call to request id endpoint
//
[self notificationGet:requestIDs[[requestIDs count]-1]];
}
}
}
- (void) notificationGet:(NSString *)requestid {
__block NSString *title;
__block NSString *message;
[FBRequestConnection startWithGraphPath:requestid
completionHandler:^(FBRequestConnection *connection,
id result,
NSError *error) {
if (! error) {
if (result[#"data"])
{
title = [NSString stringWithFormat:
#"%# requests a match!", result[#"from"][#"name"]];
NSString *jsonString = result[#"data"];
NSData *jsonData = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
if (!jsonData) {
NSLog(#"JSON decode error: %#", error);
return;
}
NSError *jsonError = nil;
NSDictionary *requestData =[NSJSONSerialization JSONObjectWithData:jsonData options:0
error:&jsonError];
if (jsonError) {
NSLog(#"JSON decode error: %#", error);
return;
}
message = [NSString stringWithFormat:#"Match #: %#, Flashes: %#",
requestData[#"deeplink_matchno"],
requestData[#"flashes_gifted"]];
// set global opponentFacebookId for bragging
[[rowGlobals sharedGlobalVars] setRowGlobal:requestData[#"deeplink_matchno"]
forKey:#"deeplink_matchno"] ;
// Set up FB Deep Link Notification
// homeViewController is registered for notification
[[NSNotificationCenter defaultCenter]
postNotificationName:FBDeepLinkNotification
object:requestData[#"deeplink_matchno"]];
NSLog(#"successfully posted DeepLink notification") ;
} else {
title = [NSString stringWithFormat:#"%# sent you a request", result[#"from"][#"name"]];
message = result[#"message"];
}
// Delete the request notification
[self notificationClear:result[#"id"]];
} else {
title = #"General Deep Link Error" ;
message = #"Error occured with Facebook FBRequest Connection. This Facebook notification likely has been previously processed." ;
}
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:title
message:message
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil,
nil];
[alert show];
}];
}
Now I recognize I have some clean up to align the dialog setup with how I parse appLinkData to get the matchId UUID for my NSNotification to open on the game, but I am not getting that far to bother cleaning it up.
I have tried many meta tags on my site but at the moment I am just using
<meta property=”al:ios:url” content=”ruleofwords”>
where ruleofwords is a custom URL I added to my app’s plist.
but I cannot seem to put together any URL other than
NSString *linkURL = [NSString stringWithFormat:#"http://www.ruleofwords.com"];
which will launch my game by clicking on the Facebook link…
When I use anything like
NSString *urlLink = [NSString stringWithFormat:#"https://www.ruleofwords.com/?deeplink_matchNo=%#", bragMatch.initiatorMatchNo];
Then Facebook will only launch my web page without the custom URL link to my game.
Moreover, Facebook no longer launches it directly; it brings up my web page with an added link displayed as the offset brackets app Links logo.(Although not explicit it does technically follow the Facebook flow diagram). Touching this app Link logo does launch my game. This seems to be the case whether I have the meta tag on my website or not (now I may have other problems since we are only using Godaddy website builder).
Previously with the request dialog I had the ability to populate values such as #”data” with things like my match Id and gifts
NSData *jsonData = [NSJSONSerialization
dataWithJSONObject:#{
#"deeplink_matchno": bragMatch.initiatorMatchNo,
#"flashes_gifted": #"0"}
options:0
error:&error];
if (!jsonData) {
NSLog(#"JSON error: %#", error);
return;
}
NSString *challengeStr = [[NSString alloc]
initWithData:jsonData
encoding:NSUTF8StringEncoding];
NSMutableDictionary *params =
[NSMutableDictionary dictionaryWithObjectsAndKeys:
bragMatch.opponentFacebookId, #"to",
#"Rule of Words Bragging", #"name",
msg, #"caption",
#"Rule of Words, the contagious photography word social game on iPhone.",
#"description",
urlLink, #"link",
#"https://pacific-castle-6969.herokuapp.com/rowappicon.png", #"picture",
challengeStr, #"data",
nil];
// Invoke the dialog
//[self.facebook dialog:#"feed" andParams:params andDelegate:self];
//[FBWebDialogs presentFeedDialogModallyWithSession:nil
[FBWebDialogs presentRequestsDialogModallyWithSession:nil
message:msg
title:nil
parameters:params
handler:
^(FBWebDialogResult result, NSURL *resultURL, NSError *error) {
if (error) {
// Case A: Error launching the dialog or publishing story.
NSString *errormsg = [NSString stringWithFormat:#"Error encountered posting Facebook brag with error %#", error.localizedDescription];
NSLog(#"%#", errormsg);
UIAlertView *alert = [[UIAlertView alloc]
initWithTitle:#"Facebook Brag Error"
message:errormsg
delegate:nil
cancelButtonTitle:#"Ok"
otherButtonTitles: nil];
[alert show];
} else {
if (result == FBWebDialogResultDialogNotCompleted) {
// Case B: User clicked the "x" icon
NSLog(#"Player canceled Facebook brag post via x icon.");
} else {
// Case C: Dialog shown and the user clicks Cancel or Share
NSDictionary *urlParams = [self parseURLParams:[resultURL query]];
//if (![urlParams valueForKey:#"post_id"]) {
if ([urlParams valueForKey:#"error_code"]) {
// User clicked the Cancel button
NSLog(#"error message is %#", [urlParams valueForKey:#"error_message"]);
NSLog(#"Player canceled Facebook brag post via Cancel button.");
} else {
// User clicked the Share button
//NSString *postID = [urlParams valueForKey:#"post_id"];
NSString *postID = [urlParams valueForKey:#"request"];
NSLog(#"Player Successfuly Posted RoW Match via Facebook brag, id: %#", postID);
}
}
}
}];
However, I no longer have al_applink_data in the passed URL for this request dialog, it just has an access_token with the original custom URL.
url is fb407545862655947://authorize/#access_token=CAAFyqSpfj8sBAGxahmdTCl1D9fs5hZBt3OfKP2MHCtM8STHadqEjlyFnXDTNHScjsxZCI6q0H8ZAppNSqJIJt83uN4LemkfklLjOdPTv3JZBtg3xTVZBKOhzdOMaZCGob5x2FPddZBzmaZBhIaE8dIgNqPfi9IlEuwQ2oHq6tEgA1w1pNESnHuDyK9gD7vswAC93nO7cCmCT4KBgxI22UDB3nINYZA058g8AZD&expires_in=3600 and sourceApp is com.facebook.Facebook
When I add the #”data” param with
[FBWebDialogs presentFeedDialogModallyWithSession:…]
although this argument is accepted by the feed dialog I the url does not get my match UUID or anything extra from my #”data” param…
url is ruleofwords:///?al_applink_data=%7B%22target_url%22%3A%22http%3A%5C%2F%5C%2Fwww.ruleofwords.com%5C%2F%22%2C%22extras%22%3A%7B%22fb_ref%22%3A%22Default%22%7D%2C%22referer_app_link%22%3A%7B%22url%22%3A%22fb%3A%5C%2F%5C%2F%5C%2F%3Fbacktrack_id%3Ddlr5p6iu_6a-OeUn%22%2C%22app_name%22%3A%22Facebook%22%7D%7D and sourceApp is com.facebook.Facebook
So I am at a loss how I am supposed to inject content specific information so that I can open my game with the match, which the opponent has requested or bragged about. I probably would have given up a long time ago but I did once have deep linking working (SDK 3.5?). I am wondering if I should be at another release level of the SDK for deep linking. It seems like the Facebook platform has significantly changed how it packages appLinkData. And although Facebook’s documentation has improved over the past two years, many of the examples which are required to put this all together do not seem to be referring to the same level of SDK. So Facebook how do I inject content into appLinkData so I can support deep linking with SDK 3.21? I thought about adding the Bolts framework but Jason implied it was designed for outlinking apps, which is not my case.
I can directly type in my iPhone Safari something like ‘ruleofwords://matchId=UUID’ and get the app delegate to parse out the [url query] so I could probably implement deep linking with push notifications, but I still like the ability to have a Facebook user tap on a link and launch the specific match directly.
Trying to Authenticate with Azure Active Directory and fetch mail, calendar data, accessToken is returned successfully:
authority = #"https://login.windows.net/common/oauth2/authorize";
redirectUriString = #"http://xxxxxx.xxxxxxx.com/oauth";
resourceId = #"https://outlook.office365.com";
clientId = #"xxxxxxx-xxxxx-xxx";
-(void) getToken : (BOOL) clearCache completionHandler:(void (^) (NSString*))completionBlock;
{
ADAuthenticationError *error;
authContext = [ADAuthenticationContext authenticationContextWithAuthority:authority
error:&error];
[authContext setValidateAuthority:YES];
NSURL *redirectUri = [NSURL URLWithString:redirectUriString];
if(clearCache){
[authContext.tokenCacheStore removeAllWithError:&error];
if (error) {
NSLog(#"Error: %#", error);
}
}
[authContext acquireTokenWithResource:resourceId
clientId:clientId
redirectUri:redirectUri
completionBlock:^(ADAuthenticationResult *result) {
if (AD_SUCCEEDED != result.status){
// display error on the screen
[self showError:result.error.errorDetails];
}
else{
completionBlock(result.accessToken);
}
}];
}
-(NSArray*)getEventsList
{
__block NSMutableArray * todoList;
[self getToken:YES completionHandler:^(NSString* accessToken){
NSURL *todoRestApiURL = [[NSURL alloc]initWithString:#"https://outlook.office365.com/api/v1.0/me/folders/inbox/messages?$top=2"];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc]initWithURL:todoRestApiURL];
NSString *authHeader = [NSString stringWithFormat:#"Bearer %#", #""];
[request addValue:authHeader forHTTPHeaderField:#"Authorization"];
[request addValue:#"application/json; odata.metadata=none" forHTTPHeaderField:#"accept"];
[request addValue:#"fbbadfe-9211-1234-9654-fe435986a1d6" forHTTPHeaderField:#"client-request-id"];
[request addValue:#"Presence-Propelics/1.0" forHTTPHeaderField:#"User-Agent"];
//[request addValue:#"true" forHTTPHeaderField:#"return-client-request-id"];
NSOperationQueue *queue = [[NSOperationQueue alloc]init];
[NSURLConnection sendAsynchronousRequest:request queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
if (error == nil){
NSArray *scenarios = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
todoList = [[NSMutableArray alloc]initWithArray:scenarios];
//each object is a key value pair
NSDictionary *keyVauePairs;
for(int i =0; i < todoList.count; i++)
{
keyVauePairs = [todoList objectAtIndex:i];
NSLog(#"%#", keyVauePairs);
}
}
NSLog(#"Finished");
//[delegate updateTodoList:TodoList];
}];
}];
return nil; }
Error is returned in response object:
{
error = {
code = ErrorAccessDenied;
message = "Access is denied. Check credentials and try again.";
};
}
I know its late to answer this but it might be helpful for someone like me who was struggling to get the same thing done
I have done this using the office 365 SDK for iOS which has all the inbuilt classes to do your work.
If you download their sample code it will provide you all the details you require to do certain operations (mail, calendar, contacts, one drive).
Before using the SDK make sure you login to Azure AD and register your application and add permissions so that you do not get 403 error code or any access denied message.
I am using the below code to fetch my events details from outlook calendar
[self getClientEvents:^(MSOutlookClient *client) {
NSURLSessionDataTask *task = [[[client getMe] getEvents] read:^(NSArray<MSOutlookEvent> *events, MSODataException *error) {
if (error==nil) {
if (events.count!=0) {
dispatch_async(dispatch_get_main_queue(), ^{
for(MSOutlookEvent *calendarEvent in events){
NSLog(#"name = %#",calendarEvent.Subject);
}
});
}else{
NSLog(#"No events found for today");
}
}
}];
[task resume];
}];
getClientEvents is a method which gives call to the Office 365 SDK and fetches the event details of the user but it first fetches the token for the resource and then makes the call with the acquired token
-(void)getClientEvents : (void (^) (MSOutlookClient* ))callback{
[self getTokenWith : #"https://outlook.office365.com" :true completionHandler:^(NSString *token) {
MSODataDefaultDependencyResolver* resolver = [MSODataDefaultDependencyResolver alloc];
MSODataOAuthCredentials* credentials = [MSODataOAuthCredentials alloc];
[credentials addToken:token];
MSODataCredentialsImpl* credentialsImpl = [MSODataCredentialsImpl alloc];
[credentialsImpl setCredentials:credentials];
[resolver setCredentialsFactory:credentialsImpl];
[[resolver getLogger] log:#"Going to call client API" :(MSODataLogLevel *)INFO];
callback([[MSOutlookClient alloc] initWithUrl:#"https://outlook.office365.com/api/v1.0" dependencyResolver:resolver]);
}];
}
getTokenWith method fetches the token for a resource first and then with the acquired token makes the necessary calls to fetch the events, but before fetching the token it checks in the cache to see if there are any tokens available for the same resource.
// fetch tokens for resources
- (void) getTokenWith :(NSString *)resourceId : (BOOL) clearCache completionHandler:(void (^) (NSString *))completionBlock;
{
// first check if the token for the resource is present or not
if([self getCacheToken : resourceId completionHandler:completionBlock]) return;
ADAuthenticationError *error;
authContext = [ADAuthenticationContext authenticationContextWithAuthority:[[NSUserDefaults standardUserDefaults] objectForKey:#"authority"] error:&error];
NSURL *redirectUri = [NSURL URLWithString:#"YOUR_REDIRECT_URI"];
[authContext acquireTokenWithResource:resourceId
clientId:[[NSUserDefaults standardUserDefaults] objectForKey:#"clientID"]
redirectUri:redirectUri
completionBlock:^(ADAuthenticationResult *result) {
if (AD_SUCCEEDED != result.status){
[self showError:result.error.errorDetails];
}
else{
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
[userDefaults setObject:result.tokenCacheStoreItem.userInformation.userId forKey:#"LogInUser"];
[userDefaults synchronize];
completionBlock(result.accessToken);
}
}];
}
getCacheToken method: Checks if there are any reusable token for any resources.
-(BOOL)getCacheToken : (NSString *)resourceId completionHandler:(void (^) (NSString *))completionBlock {
ADAuthenticationError * error;
id<ADTokenCacheStoring> cache = [ADAuthenticationSettings sharedInstance].defaultTokenCacheStore;
NSArray *array = [cache allItemsWithError:&error];
if([array count] == 0) return false;
ADTokenCacheStoreItem *cacheItem;
for (ADTokenCacheStoreItem *item in array) {
if([item.resource isEqualToString:resourceId]){
cacheItem = item;
break;
}
}
ADUserInformation *user = cacheItem.userInformation;
if(user == nil) return false;
if([cacheItem isExpired]){
return [self refreshToken:resourceId completionHandler:completionBlock];
}
else
{
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
[userDefaults setObject:user.userId forKey:#"LogInUser"];
[userDefaults synchronize];
completionBlock(cacheItem.accessToken);
return true;
}
}
Using this code and Office 365 SDK in place you can get the outlook events for a particular user, before that make sure you have full permissions in the Azure AD else you may get 0 events as response.
Please note all the methods are from the SDK example apart from the first method to view how to fetch the events i would recommend to download the exchange example from the github.
You can also use MSGraph SDK to fetch calendars and events:
Check this link: Configuration process is same, only fetching events is different(see given code for fetching events):
How to Fetch/Create calender by O365-iOS-Connect?
Note: Above link is used to fetch calendars from outlook the process is same for this but you should use this code after authentication and completed get events action look like this:
- (IBAction)getCalendarsEvents:(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];
// Authentication done
[[[[_client me] events] request] getWithCompletion:^(MSCollection *response, MSGraphUserEventsCollectionRequest *nextRequest, NSError *error){
NSArray *arr = response.value;
MSGraphEvent *event = arr.firstObject;
// Here you will getting outlook events
}];
}
}];
}
Creating first app with webservices, I am using AFNetworking for webservices. Everything is working fine but i have no idea , that how to fetch data out from block which i am getting in response. This is what i have done so far
+(WebServices *)sharedManager{
static WebServices *managerServices = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
managerServices = [[self alloc] init];
});
return managerServices;
}
-(NSArray *)firstPostService{
//1
NSURL *url = [NSURL URLWithString:BaseURLString];
//2
AFHTTPSessionManager *manager = [[AFHTTPSessionManager alloc] initWithBaseURL:url];
manager.responseSerializer = [AFHTTPResponseSerializer serializer];
NSDictionary *param = #{#"request" : #"get_pull_down_menu" , #"data" : #"0,0,3,1"};
[manager POST:#"person.php" parameters:param success:^(NSURLSessionDataTask *task, id responseObject) {
[self methodUsingJsonFromSuccessBlock:responseObject];
} failure:^(NSURLSessionDataTask *task, NSError *error) {
UIAlertView *av = [[UIAlertView alloc] initWithTitle:#"Error retrieving data" message:[error localizedDescription] delegate:nil cancelButtonTitle:#"Ok" otherButtonTitles:nil, nil];
[av show];
}];
if (list.count == 0) {
NSLog(#"Nothing in array yet!!");
}
else{
NSLog(#"Object 1 is : %#", [list objectAtIndex:1]);
}
return list;
}
- (void)methodUsingJsonFromSuccessBlock:(id)json {
// use the json
NSString *string = [NSString stringWithUTF8String:[json bytes]];
NSLog(#"This is data : %#", string);
list = [string componentsSeparatedByString:#"\n"];
NSLog(#"After sepration first object: %#", [list objectAtIndex:1]);
//NSLog(#"json from the block : %#", json);
}
What i understand reading from different blogs and tuts, that block is a separate thread and what every i do finishes with it. I read some where that this is normally use for it
dispatch_async(dispatch_get_main_queue(), ^{
data = [string componentsSeparatedByString:#"\n"];
//WHERE DATA IS __block NSArray * data = [[NSArray alloc] init];
});
and i was returning it in the of the function(firstPostService) but nothing happen. i still get an empty array outside the block. Kindly help me , suggest me some good reading stuff. Thanking you all in advance.
You say:
I need this data to my view controller i am trying to return in dispatch part but it is not allowing. Is it possible to get data into my viewcontroller class ?
Yes, it's possible. But, no, firstPostService should not return the results. It can't because it returns immediately, but the POST completion blocks won't be called until much later. There's nothing to return by the time firstPostService returns.
At the end of your original question, you said:
What i understand reading from different blogs and tuts, that block is a separate thread and what every i do finishes with it. I read some where that this is normally use for it
dispatch_async(dispatch_get_main_queue(), ^{
data = [string componentsSeparatedByString:#"\n"];
//WHERE DATA IS __block NSArray * data = [[NSArray alloc] init];
});
This is not the appropriate pattern of __block local variable. You generally use that __block pattern when dealing with some block that runs synchronously (for example the block of an enumeration method). But while you can use __block variable with asynchronous block, you almost never do (and it doesn't quite make sense to even try to do it). When you use appropriate completion block patterns, there's no need for any __block variable.
So, let's go back to your original code sample: So, you should take a page from AFNetworking and employ completion blocks yourself. When the AFNetworking POST method wanted to return data to your code asynchonously, it used a completion block pattern, instead. Thus, if your own firstPostService wants to pass back data asynchronously, it should do the same.
For example:
#interface WebServices ()
#property (nonatomic, strong) AFHTTPSessionManager *manager;
#end
#implementation WebServices
// note, use `instancetype` rather than actually referring to WebServices
// in the `sharedManager` method
+ (instancetype)sharedManager
{
static id sharedMyManager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedMyManager = [[self alloc] init];
});
return sharedMyManager;
}
// I'd also suggest that you init the `AFHTTPSessionManager` only once when this
// object is first instantiated, rather than doing it when `firstPostService` is
// called
- (instancetype)init
{
self = [super init];
if (self) {
NSURL *url = [NSURL URLWithString:BaseURLString];
self.manager = [[AFHTTPSessionManager alloc] initWithBaseURL:url];
self.manager.responseSerializer = [AFHTTPResponseSerializer serializer];
}
return self;
}
// Notice:
//
// 1. This now has a return type of `void`, because when it instantly returns,
// there is no data to return.
//
// 2. In order to pass the data back, we use the "completion handler" pattern.
- (void)firstPostServiceWithCompletionHandler:(void (^)(NSArray *list, NSError *error))completionHandler {
NSDictionary *param = #{#"request" : #"get_pull_down_menu" , #"data" : #"0,0,3,1"};
[self.manager POST:#"person.php" parameters:param success:^(NSURLSessionDataTask *task, id responseObject) {
NSArray *list = [self methodUsingJsonFromSuccessBlock:responseObject];
if (completionHandler) {
completionHandler(list, nil);
}
} failure:^(NSURLSessionDataTask *task, NSError *error) {
[[[UIAlertView alloc] initWithTitle:#"Error retrieving data" message:[error localizedDescription] delegate:nil cancelButtonTitle:#"Ok" otherButtonTitles:nil, nil] show];
if (completionHandler) {
completionHandler(nil, error);
}
}];
// // none of this code belongs here!!! You are dealing with asynchronous methods.
// // the `list` has not been returned by the time you get here!!! You shouldn't even
// // be using instance variable anyway!
//
// if (list.count == 0) {
//
// NSLog(#"Nothing in array yet!!");
// }
// else{
// NSLog(#"Object 1 is : %#", [list objectAtIndex:1]);
//
// }
// return list;
}
- (NSArray *)methodUsingJsonFromSuccessBlock:(NSData *)data {
// note, do not use `stringWithUTF8String` with the `bytes` of the `NSData`
// this is the right way to convert `NSData` to `NSString`:
NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(#"This is string representation of the data : %#", string);
// Note, retire the `list` instance variable, and instead use a local variable
NSArray *list = [string componentsSeparatedByString:#"\n"];
NSLog(#"After sepration first object: %#", [list objectAtIndex:1]);
return list;
}
#end
Then, you could invoke that like so:
[[WebServices sharedManager] firstPostServiceWithCompletionHandler:^(NSArray *list, NSError *error) {
if (error) {
// handle the error here
} else {
// use the `list` results here
}
}];
// NOTE, DO NOT USE `list` HERE. By the time you get here, `list` has not been
// returned. Only use it in the above block.
//
// In fact, you can see that if you put a `NSLog` or breakpoint here, and again, above
// where it says "use the `list` results` here", you'll see that it's running the code
// inside that block _after_ this code down here!
I'd suggest you tackle the above first, to first make sure you completely understand the proper asynchronous technique of the completion block pattern. We don't want to complicate things quite yet. Make sure you're getting the sort of data you wanted before you proceed to what I will describe below.
But, once you've grokked the above, it's time to look at your JSON parsing. You make several reference to JSON, but if that's what it really is, then using componentsSeparatedByString is not the right way to parse it. You should use NSJSONSerialization. Or even better, you can let AFNetworking do that for you (right now, you're making it more complicated than it needs to be and your results will not be formatted correctly).
Above, I kept your methodUsingJsonFromSuccessBlock in the process, but if you're really dealing with JSON, you should eliminate that method entirely. Let AFNetworking do this for you.
You should eliminate the line that says:
responseSerializer = [AFHTTPResponseSerializer serializer];
The default serializer is AFJSONResponseSerializer which is what you want to use if handling JSON requests.
The methodUsingJsonFromSuccessBlock is then no longer needed because AFNetworking will do the JSON conversion for you. So firstPostServiceWithCompletionHandler should look like:
- (void)firstPostServiceWithCompletionHandler:(void (^)(NSArray *list, NSError *error))completionHandler {
NSDictionary *param = #{#"request" : #"get_pull_down_menu" , #"data" : #"0,0,3,1"};
[self.manager POST:#"person.php" parameters:param success:^(NSURLSessionDataTask *task, id responseObject) {
if (completionHandler) {
completionHandler(responseObject, nil);
}
} failure:^(NSURLSessionDataTask *task, NSError *error) {
[[[UIAlertView alloc] initWithTitle:#"Error retrieving data" message:[error localizedDescription] delegate:nil cancelButtonTitle:#"Ok" otherButtonTitles:nil, nil] show];
if (completionHandler) {
completionHandler(nil, error);
}
}];
}
I use a facebook api to connect to facebook and send request via native dialogs provided by the api.
I followed the sample posted in the docs on developers.facebook.com
But I have following problem sending requests :
1. The requests are not shown in notifications - only in application center - In this case i think that it is a problem of that the app is in sandbox and not posted to APPSTORE
I succesfully send request to facebook server with right fbUser id. But when I want to receive the notification in app here comes the problem :
Following the docs as an authorized user I should se
this in open url method:
fb[APP_ID]://authorize#expires_in=[ACCESS_TOKEN_EXPIRATION]
&access_token=[USER_ACCESS_TOKEN]
&target_url=https://apps.facebook.com/[APP_NAME_SPACE]/?request_ids=
[COMMA_SEPARATED_REQUESTIDs]&ref=notif&app_request_type=user_to_user
But i can see only plain login without targer url .... I can see session expiration date, fb app id, access token and so on. But no target url?
So basically what the target_url is?
How it should be set?
What i have to include when sending request?
In addition :
application handle open url method is called properly.
checkRequests method is also called properly after app becomes active.
Please do not link me to the docs. I have read it moreless 50 times and didn't find any reasonable solution...
- (BOOL)application:(UIApplication *)application
openURL:(NSURL *)url
sourceApplication:(NSString *)sourceApplication
annotation:(id)annotation {
// attempt to extract a token from the url
self.openedURL = url;
NSLog(#"%#",url);
return [FBSession.activeSession handleOpenURL:url];
}
- (void)sendRequest {
FBSBJSON *jsonWriter = [FBSBJSON new];
NSDictionary *gift = [NSDictionary dictionaryWithObjectsAndKeys:
#"5", #"points",
#"1", #"badge",
nil];
NSString *giftStr = [jsonWriter stringWithObject:gift];
NSMutableDictionary* params =
[NSMutableDictionary dictionaryWithObjectsAndKeys:
#"Hi from test app", #"message",
giftStr, #"data",
nil];
[self.facebook dialog:#"apprequests"
andParams:params
andDelegate:self];
}
// Handle the request call back
- (void)dialogCompleteWithUrl:(NSURL *)url {
NSDictionary *params = [self parseURLParams:[url query]];
NSString *requestID = [params valueForKey:#"request"];
NSLog(#"Request ID: %#", requestID);
}
-(FBSession*)returnSession{
return self.session;
}
/*
* Helper function to get the request data
*/
- (void) notificationGet:(NSString *)requestid {
[FBRequestConnection startWithGraphPath:requestid
completionHandler:^(FBRequestConnection *connection,
id result,
NSError *error) {
if (!error) {
NSString *title;
NSString *message;
if ([result objectForKey:#"data"]) {
title = [NSString
stringWithFormat:#"%# sent you a gift",
[[result objectForKey:#"from"]
objectForKey:#"name"]];
FBSBJSON *jsonParser = [FBSBJSON new];
NSDictionary *requestData =
[jsonParser
objectWithString:[result objectForKey:#"data"]];
message =
[NSString stringWithFormat:#"Badge: %#, Karma: %#",
[requestData objectForKey:#"badge"],
[requestData objectForKey:#"points"]];
} else {
title = [NSString
stringWithFormat:#"%# sent you a request",
[[result objectForKey:#"from"] objectForKey:#"name"]];
message = [NSString stringWithString:
[result objectForKey:#"message"]];
}
UIAlertView *alert = [[UIAlertView alloc]
initWithTitle:title
message:message
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil,
nil];
[alert show];
// Delete the request notification
[self notificationClear:[result objectForKey:#"id"]];
}
}];
}
/*
* Helper function to check incoming URL
*/
- (void) checkIncomingNotification {
if (self.openedURL) {
NSString *query = [self.openedURL fragment];
if (!query) {
query = [self.openedURL query];
}
NSDictionary *params = [self parseURLParams:query];
for (NSString * str in [params allKeys]) {
NSLog(#"key %#", str);
}
// Check target URL exists
NSString *targetURLString = [params valueForKey:#"target_url"];
if (targetURLString) {
NSURL *targetURL = [NSURL URLWithString:targetURLString];
NSDictionary *targetParams = [self parseURLParams:[targetURL query]];
NSString *ref = [targetParams valueForKey:#"ref"];
// Check for the ref parameter to check if this is one of
// our incoming news feed link, otherwise it can be an
// an attribution link
if ([ref isEqualToString:#"notif"]) {
// Get the request id
NSString *requestIDParam = [targetParams
objectForKey:#"request_ids"];
NSArray *requestIDs = [requestIDParam
componentsSeparatedByString:#","];
// Get the request data from a Graph API call to the
// request id endpoint
[self notificationGet:[requestIDs objectAtIndex:0]];
}
}
// Clean out to avoid duplicate calls
self.openedURL = nil;
}
}
Is there any way that these problems are caused by the way that the app is not published on Appstore (Appstore id is not set neither for iPhone nor iPad)?
Here are code snippets showing using of the fb api:
Thank you very much for the time.
Enable deep linking in Facebook app settings
Facebook sdk 3.5 requests not working
I think this link will help you,configure App on Facebook as well
I have found a services from Google which provides to access to Google APIs for various Google Services. I could set up a project in iPhone and create API access for iOS applications (via OAuth2.0) and native applications. I wanted to use the native API for my iPhone app. It API gives me email,fullname,firstname,lastname,google_id,gender,dob,profile_image. How do I use these in my iPhone Application, Any sample apps, snippets available?
Please help me.
Here is my code :
-(void) loadGmail_Login
{
NSString *keychainItemName = nil;
if ([self shouldSaveInKeychain]) {
keychainItemName = kKeychainItemName;
}
// For GTM applications, the scope is available as
NSString *scope = #"http://www.google.com/m8/feeds/";
// ### Important ###
// GTMOAuthViewControllerTouch is not designed to be reused. Make a new
// one each time you are going to show it.
// Display the autentication view.
GTMOAuthAuthentication *auth;
auth = [GTMOAuthViewControllerTouch authForGoogleFromKeychainForName:kKeychainItemName];
GTMOAuthViewControllerTouch *viewController = [[[GTMOAuthViewControllerTouch alloc]
initWithScope:scope
language:nil
appServiceName:keychainItemName
delegate:self
finishedSelector:#selector(viewController:finishedWithAuth:error:)] autorelease];
// You can set the title of the navigationItem of the controller here, if you want.
// Optional: display some html briefly before the sign-in page loads
NSString *html = #"<html><body bgcolor=silver><div align=center>Loading sign-in page...</div></body></html>";
[viewController setInitialHTMLString:html];
[[self navigationController] pushViewController:viewController animated:YES];
}
- (void)viewController:(GTMOAuthViewControllerTouch *)viewController
finishedWithAuth:(GTMOAuthAuthentication *)auth
error:(NSError *)error
{
if (error != nil)
{
// Authentication failed (perhaps the user denied access, or closed the
// window before granting access)
NSLog(#"Authentication error: %#", error);
NSData *responseData = [[error userInfo] objectForKey:#"data"]; // kGTMHTTPFetcherStatusDataKey
if ([responseData length] > 0) {
// show the body of the server's authentication failure response
NSString *str = [[[NSString alloc] initWithData:responseData
encoding:NSUTF8StringEncoding] autorelease];
NSLog(#"%#", str);
}
[self setAuthentication:nil];
}
else
{
// save the authentication object
[self setAuthentication:auth];
// Just to prove we're signed in, we'll attempt an authenticated fetch for the
// signed-in user
[self doAnAuthenticatedAPIFetch];
}
}
- (void)doAnAuthenticatedAPIFetch
{
NSString *urlStr;
// Google Contacts feed
//
// https://www.googleapis.com/oauth2/v2/userinfo
urlStr = #"http://www.google.com/m8/feeds/contacts/default/thin";
NSURL *url = [NSURL URLWithString:urlStr];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[mAuth authorizeRequest:request];
NSError *error = nil;
NSURLResponse *response = nil;
NSData *data = [NSURLConnection sendSynchronousRequest:request
returningResponse:&response
error:&error];
if (data) {
// API fetch succeeded
NSString *str = [[[NSString alloc] initWithData:data
encoding:NSUTF8StringEncoding] autorelease];
NSLog(#"API response: %#", str);
GGCXml_Adaptor *localAlphabetXMLParser = [[GGCXml_Adaptor alloc] init];
[localAlphabetXMLParser processBooksXML:data];
[localAlphabetXMLParser release];
// [self updateUI];
} else {
// fetch failed
NSLog(#"API fetch error: %#", error);
}
}
- (void)setAuthentication:(GTMOAuthAuthentication *)auth {
[mAuth autorelease];
mAuth = [auth retain];
}
First you will need to get token from Google API, For this 1st step you will have to follow this tutorial and in the end of this link there is whole source code for iOS for getting token from google API
http://technogerms.com/login-with-google-using-oauth-2-0-for-ios-xcode-objective-c/
Then in the next step you have to send that token to Google API to request user Data, I just needed the first step So I am sharing my searchings
Try this Tutorial and Source code Link.. It's works fine for me.
1. Tutorial Reference: http://technogerms.com/login-with-google-using-oauth-2-0-for-ios-xcode-objective-c/
2. Api Reference : https://code.google.com/apis/console/
3. Source code: https://github.com/emysa341/Login-with-gmail-google-g--using-oath-2.0-protocol/archive/master.zip
i think this will help anybody else
Follow the below steps to integrate gmail with your application .
1.Add following classes to you project .
GTMHTTPFetcher.h , GTMHTTPFetcher.m ,GTMOAuth2Authentication.h, GTMOAuth2Authentication.m,GTMOAuth2SignIn.h,GTMOAuth2SignIn.m,GTMOAuth2ViewControllerTouch.h,GTMOAuth2ViewControllerTouch.m,GTMOAuth2ViewTouch.xib,SBJSON.h , SBJSON.m
you will get these classes here : https://github.com/jonmountjoy/Force.com-iOS-oAuth-2.0-Example
Note : if you are working under ARC Environment then you have to disable the ARC for following files :
GTMHTTPFetcher.m , GTMOAuth2Authentication.m , GTMOAuth2SignIn.m, GTMOAuth2ViewControllerTouch.m
To disable ARC for source files in Xcode 4, select the project and the target in Xcode. Under the target "Build Phases" tab, expand the Compile Sources build phase, select the library source files, then press Enter to open an edit field, and type -fno-objc-arc as the compiler flag for those files.
2. add the following frameworks
security.framework , systemConfiguration.framework
3. Register your app to google api console …. here : https://code.google.com/apis/console
Then go to ApiAccess section , create client id for iOS app .
then you will get clientID, ClientSecret and RedirectUrl
**4. Now it's time for coding . . . .**
create a signIn button in your controller and set the action for that . Here when the user click the button SignInGoogleButtonClicked method gets called .
//import GTMOAuth2Authentication , GTMOAuth2ViewControllerTouch
#define GoogleClientID #"paster your client id"
#define GoogleClientSecret #"paste your client secret"
#define GoogleAuthURL #"https://accounts.google.com/o/oauth2/auth"
#define GoogleTokenURL #"https://accounts.google.com/o/oauth2/token"
-(void) SignInGoogleButtonClicked
{
NSURL * tokenURL = [NSURL URLWithString:GoogleTokenURL];
NSString * redirectURI = #"urn:ietf:wg:oauth:2.0:oob";
GTMOAuth2Authentication * auth;
auth = [GTMOAuth2Authentication authenticationWithServiceProvider:#"google"
tokenURL:tokenURL
redirectURI:redirectURI
clientID:GoogleClientID
clientSecret:GoogleClientSecret];
auth.scope = #"https://www.googleapis.com/auth/plus.me";
GTMOAuth2ViewControllerTouch * viewcontroller = [[GTMOAuth2ViewControllerTouch alloc] initWithAuthentication:auth
authorizationURL:[NSURL URLWithString:GoogleAuthURL]
keychainItemName:#"GoogleKeychainName" delegate:self
finishedSelector:#selector(viewController:finishedWithAuth:error:)];
[self.navigationController pushViewController:viewcontroller animated:YES];
}
//this method is called when authentication finished
- (void)viewController:(GTMOAuth2ViewControllerTouch * )viewController finishedWithAuth:(GTMOAuth2Authentication * )auth error:(NSError * )error
{
if (error != nil) {
UIAlertView * alert = [[UIAlertView alloc] initWithTitle:#"Error Authorizing with Google"
message:[error localizedDescription]
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
}
else
{
UIAlertView * alert = [[UIAlertView alloc] initWithTitle:#"Alert !"
message:#"success"
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
}
}