Cannot get the new AppLinks to work on iOS or Android

三世轮回 提交于 2019-11-29 23:50:40

I was having the same problem with AppLinks and decided to just forego them altogether and just use facebook's app link host: https://developers.facebook.com/docs/applinks/hosting-api

My app is really mobile only, and I misunderstood how AppLinks worked at first. I thought I could just put the al_ios_* meta tags on a single, universal web page but this is wrong. There would need to be a separate page for every piece of content on my site, and each one of those pages needs to have its own AppLinks meta tags to send a URL for that specific content back to my app.

When I was doing it wrong, when I tapped on my OpenGraph story in facebook, it would open my site in the web browser and there was an action icon in the bottom toolbar that I could tap and have the option to open my app. Or I would have to precision-tap the name of my app in the OpenGraph story. Either of those fast-switch to my app, but the URL would not be specific to the content I want my app to navigate to. Also, both of those options suck -- I just want to tap anywhere on the story and go straight to my app, which is why we're all here.

The solution

I am going to use an OpenGraph story with the share dialog as an example.

First, you need to create a hosted app link on your server, not in the app. Before creating your OpenGraph story or whatever is being shared, make a call to your server to accomplish 2 things:

1.) Make an API call to create a new facebook app link, which will give you back an ID

2.) Use that ID to make a 2nd API call to get the URL to your hosted app link

This has to be done on the server because these API calls require an app access token, not a user access token. This token has app level permissions, not user level permissions. You cannot and should not store your facebook app secret anywhere in your mobile application because someone could decompile your app and make changes to your facebook app. No good. Use your server because it can safely know your app secret.

My server side is in PHP so here is an example of how to accomplish this. Dealing with the API wasn't a particularly pleasant experience, so I'll share in hopes that it helps someone else with formatting the requests:

# create a new facebook app link using cURL
$metadata = <what to handle in AppDelegate application:openURL:sourceApplication:annotation>;
$url = "https://graph.facebook.com/v2.1/app/app_link_hosts";
$ch = curl_init($url);

# create form post data
$deepLinkURL = "<myApp>://" . $metadata;
$iosArray = json_encode(array(array("url"          => $deepLinkURL,
                                    "app_store_id" => <appStoreId (number)>,
                                    "app_name"     => "<myAppName>")
                              )
                       );
$webFallbackArray = json_encode(array("should_fallback" => false));

$formQuery = http_build_query(array("access_token" => "<appId>|<appSecret>",
                                    "name"         => $metadata,
                                    "ios"          => $iosArray,
                                    "web"          => $webFallbackArray)
                              );

# options
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $formQuery);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

# get response
$responseJson = curl_exec($ch);
curl_close($ch);

# decode response from facebook
$jsonResponse = json_decode($responseJson, true);
$appLinkId = "";

# get appLinkId
foreach ($jsonResponse as $key => $val) {

    # get status
    if($key == "id") {
        $appLinkId = $val;
    }
}

# if response is good, need to request canonical URL from appLinkId
$errorMessage = "";
$canonicalUrl = "";

if(!empty($appLinkId)) {

    # create another instance of cURL to get the appLink object from facebook using the ID generated by the previous post request
    $getAppLinkUrl = "https://graph.facebook.com/" . $appLinkId;
    $ch2 = curl_init();

    # cURL options
    $queryString = http_build_query(array("access_token" => "<appId>|<appSecret>",
                                          "fields"       => "canonical_url",
                                          "pretty"       => true)
                                    );
    curl_setopt($ch2, CURLOPT_URL, $getAppLinkUrl . "?" . $queryString);
    curl_setopt($ch2, CURLOPT_RETURNTRANSFER, true);

    # get response
    $urlResponseJson = curl_exec($ch2);
    curl_close($ch2);

    # decode response from facebook
    $urlJsonResponse = json_decode($urlResponseJson, true);

    # parse response to get canonical URL
    foreach ($urlJsonResponse as $key => $val) {
        # get canonical URL
        if($key == "canonical_url") {
            $canonicalUrl = $val;
        }
    }

    # check for result
    if(empty($canonicalUrl)) {
        $errorMessage = "Unable to retreive URL.";
    }

} else {
    $errorMessage = "Unable to publish appLink.";
}

# encode response back to your app
if(empty($errorMessage)) {
    $response = json_encode(array("result"        => "success",
                                  "canonical_url" => $canonicalUrl));
} else {
    $response = json_encode(array("result" => "failed",
                                  "errorMessage" => $errorMessage));
}

#send response back to your app

Back in your app, once you confirm a good response, put the canonical URL you get back as the url parameter in [FBGraphObject openGraphObjectForPostWithType: below. Now when you click on your story in the facebook app, it will go straight to your app. No web nonsense.

// Create an action
id<FBOpenGraphAction> action = (id<FBOpenGraphAction>)[FBGraphObject graphObject];

// Create an object
id<FBGraphObject> object;

// set shareDialog parameters
FBOpenGraphActionParams *params = [[FBOpenGraphActionParams alloc] init];
params.action = action;
params.actionType = @"<myApp>:<myAction>";
params.previewPropertyName = @"<key>";
object = [FBGraphObject openGraphObjectForPostWithType:@"<myApp>:<myObject>"
                                                 title:<title>
                                                 image:<urlToPic>
                                                   url:<fb.me/xyz canonical URL>
                                           description:<someDescription>];

[action setObject:object forKey:@"<key>"];

etc...

When I was working on my app, Sweep, I put a pay/share wall after a certain amount of time spent in the app. I faced the same problem where AppLinks really sucked at actually linking off of Facebook, despite the promise. Based on this problem, I built a service called branch.io that hosts the links for me, plus automatically inserts the correct AppLinks metatags for Android/iOS. The links actually work as expected, as crazy as that is. It uses a combination of client side JS with the AppLinks to make them properly redirect in every webview and native browser

Here's a high level guide to creating the share links on iOS:

  1. To get started, you just need to configure the location of your app in either store on the dashboard at dashboard.branch.io. Once it's all setup, you get your Branch app key.

  2. pod "Branch" or you can clone the open source repo here: https://github.com/BranchMetrics/Branch-iOS-SDK

  3. Add the Branch key to your plist file as a String with the key 'branch_key'

  4. Add the following code to your AppDelegate in the appropriate methods

In the didFinishLaunchingWithOptions:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // your other init code
    Branch *branch = [Branch getInstance];
    [branch initSessionWithLaunchOptions:launchOptions andRegisterDeepLinkHandler:^(NSDictionary *params, NSError *error) {     // previously initUserSessionWithCallback:withLaunchOptions:
        if (!error) {
            // params are the deep linked params associated with the link that the user clicked before showing up
            // params will be empty if no data found

            // here is the data from the example below if a new user clicked on Joe's link and installed the app
            NSString *name = [params objectForKey:@"user"]; // returns Joe
            NSString *profileUrl = [params objectForKey:@"profile_pic"]; // returns https://s3-us-west-1.amazonaws.com/myapp/joes_pic.jpg
            NSString *description = [params objectForKey:@"description"]; // returns Joe likes long walks on the beach...

            // route to a profile page in the app for Joe
            // show a customer welcome
        }
    }];
}

In the openUrl for handling URI calls:

- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {
    // pass the url to the handle deep link call
    // if handleDeepLink returns YES, and you registered a callback in initSessionAndRegisterDeepLinkHandler, the callback will be called with the data associated with the deep link
    if (![[Branch getInstance] handleDeepLink:url]) {
        // do other deep link routing for the Facebook SDK, Pinterest SDK, etc
    }
    return YES;
}
  1. Lastly, to create the hosted links, it's very simple. You just need to call getShortUrl to dynamically create one. You can put as many keys and values in the links as possible (to be retrieved in the initSession callback)

You can put this snippet anywhere you want to create a link:

NSMutableDictionary *params = [[NSMutableDictionary alloc] init];

[params setObject:@"Joe" forKey:@"user"];
[params setObject:@"url.to.picture/mypic.png" forKey:@"profile_pic"];
[params setObject:@"Joe likes long walks on the beach..." forKey:@"description"];

// Customize the display of the link
[params setObject:@"Joe's MyApp Referral" forKey:@"$og_title"];
[params setObject:@"url.to.picture/mypic.png" forKey:@"$og_image_url"];
[params setObject:@"Join Joe in MyApp - it's awesome" forKey:@"$og_description"];

// Customize the redirect performance
[params setObject:@"http://myapp.com/desktop_splash" forKey:@"$desktop_url"];

Branch *branch = [Branch getInstance];
[branch getShortURLWithParams:params andCallback:^(NSString *url, NSError *error) {
    // show the link to the user or share it immediately
}];

Android is very similar in method calls and functionality and can be found on the site.

sorry if my answer is not exactly what you expect but just to share what we did on our websites and apps.

For instance, I know we had to add more tags to make it works with twitter cards and here is the list of the meta properties we have in our pages:

meta property="twitter:card" content=""
meta property="twitter:title" content=""
meta property="twitter:description" content=""
meta property="twitter:image:src" content=""
meta property="twitter:app:id:iphone" content=""
meta property="twitter:app:name:iphone" content="Marmiton"
meta property="twitter:app:url:iphone" content=""
meta property="twitter:app:id:googleplay" content=""
meta property="twitter:app:name:googleplay" content=""
meta property="twitter:app:url:googleplay" content=""

and the metha you also have:

meta property="al:iphone:app_store_id" content=""
meta property="al:iphone:app_name" content=""
meta property="al:iphone:url" content=""
meta property="al:android:package" content=""
meta property="al:android:app_name" content=""
meta property="al:android:url" content=""

we also have the facebook opengraph meta defined such as fb:app_id. I mention that because when you receive the deeplink in your app, you also have the facebook app id in the applinks link.

And from what we tested:

  • facebook does not open the deeplink directly on iOS whereas Android gives you the app choice. It sometimes shows up the blue popup at the bottom of the screen and sometimes you just have a link added in the actionsheet you have when you tap on the share button in the facebook (safari) webview (only at first load)-> this presentation of the link depends on how the content was shared on facebook.

  • twitter add a link to the app inside the card on iOS.

Don't know what I can add more.

Hope it helps a bit.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!