I've honestly spent hours on this trying to get it to work. Unfortunately Facebook & App Link's documentation is not clear enough. Even the App Links video from F8.
App Requirements:
Progress so far:
I'm using the following code to create the hosted App Link (as I only have mobile content) as per the FB developer's website under Publishing iOS SDK.
NSDictionary *params = [NSDictionary dictionaryWithObjectsAndKeys:
@"{My app name}", @"name",
{custom URL}, @"al:iphone:url",
@"{app store ID}", @"al:iphone:app_store_id",
@"{My app name}", @"al:iphone:app_name",
@"{\"should_fallback\": false}", @"web",
fbAccessToken, @"access_token",
nil
];
/* make the API call */
[FBRequestConnection startWithGraphPath:@"/{FB app id}/app_link_hosts"
parameters:params
HTTPMethod:@"POST"
completionHandler:^(
FBRequestConnection *connection,
id result,
NSError *error
) {
/* handle the result */
NSLog(@"Result = %@",result);
if(error) NSLog(@"error = %@",error);
}];
Next I post the OG story to FB (this is posts fine but without a correct url)
// Create OG object
id<FBGraphObject> object =
[FBGraphObject openGraphObjectForPostWithType:@"{app name}:{FB object_name}"
title:@"Test Link"
image:@"https://cdn3.iconfinder.com/data/icons/picons-social/57/56-apple-512.png" // hosted wallpaper with unique id for background
url:nil // Assuming I need to put the url to the app link host object here??
description:@"Click to on this test link!"];
// Create an action
id<FBOpenGraphAction> action = (id<FBOpenGraphAction>)[FBGraphObject graphObject];
// Link the object to the action
[action setObject:object forKey:@"{FB object name}"];
// Check if the Facebook app is installed and we can present the share dialog
FBOpenGraphActionParams *params = [[FBOpenGraphActionParams alloc] init];
params.action = action;
params.actionType = @"{app name}:{FB action name}";
// If the Facebook app is installed and we can present the share dialog
if([FBDialogs canPresentShareDialogWithOpenGraphActionParams:params]) {
// Show the share dialog
[FBDialogs presentShareDialogWithOpenGraphAction:action
actionType:@"{app name}:{FB action name}"
previewPropertyName:@"{FB object name}"
handler:^(FBAppCall *call, NSDictionary *results, NSError *error) {
if(error) {
// An error occurred, we need to handle the error
// See: https://developers.facebook.com/docs/ios/errors
NSLog(@"Error publishing story: %@", error.description);
} else {
// Success
NSLog(@"result %@", results);
}
}];
}
To handle the incoming URL when someone clicks on the link in the FB OG story I've added the following code to AppDelegate.m as per FB documentation - see Handling incoming links
- (BOOL)application:(UIApplication *)application
openURL:(NSURL *)url
sourceApplication:(NSString *)sourceApplication
annotation:(id)annotation {
BOOL urlWasHandled =
[FBAppCall handleOpenURL:url
sourceApplication:sourceApplication
fallbackHandler:
^(FBAppCall *call) {
// Parse the incoming URL to look for a target_url parameter
NSString *query = [url query];
NSDictionary *params = [self parseURLParams:query];
// Check if target URL exists
NSString *appLinkDataString = [params valueForKey:@"al_applink_data"];
if (appLinkDataString) {
NSError *error = nil;
NSDictionary *applinkData =
[NSJSONSerialization JSONObjectWithData:[appLinkDataString dataUsingEncoding:NSUTF8StringEncoding]
options:0
error:&error];
if (!error &&
[applinkData isKindOfClass:[NSDictionary class]] &&
applinkData[@"target_url"]) {
NSString *targetURLString = applinkData[@"target_url"];
// Show the incoming link in an alert
// Your code to direct the user to the
// appropriate flow within your app goes here
[[[UIAlertView alloc] initWithTitle:@"Received link:"
message:targetURLString
delegate:nil
cancelButtonTitle:@"OK"
otherButtonTitles:nil] show];
}
}
}];
return urlWasHandled;
}
// A function for parsing URL parameters
- (NSDictionary*)parseURLParams:(NSString *)query {
NSArray *pairs = [query componentsSeparatedByString:@"&"];
NSMutableDictionary *params = [[NSMutableDictionary alloc] init];
for (NSString *pair in pairs) {
NSArray *kv = [pair componentsSeparatedByString:@"="];
NSString *val = [[kv objectAtIndex:1]
stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
[params setObject:val forKey:[kv objectAtIndex:0]];
}
return params;
}
Has anyone been able to get this working? I'm still not clear on how the hosted App Link works and where to put it (I'm assuming it should go in the 'url' parameter when calling the FBGraphObject openGraphObjectForPostWithType method.
I really don't want to create a website to store all the urls and add App Link meta tags (I'd have to do all this via the app as each App Link is going to be dynamic and unique for each user that generates it from with in the app).
Please help!
With the help of MingLi from FB I managed to get it working with the following code:
- (void)shareToOpenGraphCountdownInvite
{
NSURL *url = [NSURL URLWithString:@"https://graph.facebook.com/oauth/access_token?grant_type=client_credentials&client_id={insert your FB app ID here}&client_secret={insert client secret here}"];
NSString *fullToken = [NSString stringWithContentsOfURL:url encoding:NSUTF8StringEncoding error:nil];
NSArray *components = [fullToken componentsSeparatedByString:@"="];
FBAppAccessToken = [components objectAtIndex:1];
NSDictionary *paramsForAppLinksHost = [NSDictionary dictionaryWithObjectsAndKeys:
FBAppAccessToken, @"access_token",
@"{your app name}", @"name",
@"{your app's custom url}", @"al:ios:url",
@"{app store ID}", @"al:ios:app_store_id",
@"{your app name}", @"al:ios:app_name",
@"{\"should_fallback\": false}", @"web",
nil
];
[FBRequestConnection startWithGraphPath:@"/{FB app ID}/app_link_hosts"
parameters:paramsForAppLinksHost
HTTPMethod:@"POST"
completionHandler:^(
FBRequestConnection *connection,
id result,
NSError *error
) {
AppLinksHostURL_ID = [result objectForKey:@"id"]; // store this ID in an NSString
[self postOGStoryWithCustomURL];
if(error) NSLog(@"error = %@", error.description);
}];
}
- (void)postOGStoryWithCustomURL
{
NSString *urlString = [NSString stringWithFormat:@"https://fb.me/%@/%@", AppLinksHostURL_ID, customURL];
UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:[self pathForS3ObjectWithFilename:previewImageFilename]]]];
// Create OG object
id<FBGraphObject> object =
[FBGraphObject openGraphObjectForPostWithType:@"timeflyz:countdown_invite"
title:eventBeingShared.eventName
image:image
url:urlString // fb.me app links hosted url here
description:@"{insert description here}"];
// Create an action
id<FBOpenGraphAction> action = (id<FBOpenGraphAction>)[FBGraphObject graphObject];
// Link the object to the action
[action setObject:object forKey:@"countdown_invite"];
// Check if the Facebook app is installed and we can present the share dialog
FBOpenGraphActionParams *params = [[FBOpenGraphActionParams alloc] init];
params.action = action;
params.actionType = @"timeflyz:create";
// If the Facebook app is installed and we can present the share dialog
if([FBDialogs canPresentShareDialogWithOpenGraphActionParams:params]) {
// Show the share dialog
[FBDialogs presentShareDialogWithOpenGraphAction:action
actionType:@"timeflyz:create"
previewPropertyName:@"countdown_invite"
handler:^(FBAppCall *call, NSDictionary *results, NSError *error) {
if(error) {
// An error occurred, we need to handle the error
// See: https://developers.facebook.com/docs/ios/errors
NSLog(@"Error publishing story: %@", error.description);
} else {
// NSLog(@"result %@", results);
if([[results objectForKey:@"completionGesture"] isEqualToString:@"post"]) {
NSLog(@"Posted successfully!");
[[NSNotificationCenter defaultCenter] postNotificationName:@"showShareSuccessfullMessage" object:self userInfo:nil];
} else
NSLog(@"Something else happened - user didn't post");
}
}];
}
Note that "customURL" is an NSString that follows the pattern "?variable1=result1&variable2=result2..."