适用于IOS和Android应用程序的Deeplink解决方案适用于Facebook

Mus*_*lar 8 facebook deep-linking applinks ios-universal-links deeplink

有太多深层链接(通用链接或应用链接)教程.但其中大多数都展示了如何在Android或IOS应用中启用它.此外还有付费云解决方案,但它们提供了许多功能.但是我在现实生活中面临三个主要问题:

  1. 某些浏览器不允许App Links工作.例如,您可以将http://example.com配置为在应用程序中捕获,但如果用户通过Facebook应用程序单击此链接则不会处理,并且Facebook浏览器会显示该网站.
  2. 没有独特的标准解决方案来处理Android和IOS应用程序的链接.
  3. 如果应用程序未安装在移动设备上且用户单击App Link,则无法提供实用的解决方案.

我写了这个Q&A,这是我学习的结果(花了太多时间),以便有一个独特的,适用于所有案例的解决方案.

代码来自我的工作解决方案,但我删除了一些部分只是为了表明这个想法.如果存在一些编译问题,请按照算法编写自己的代码

这是解决方案,即使你知道一些步骤也要一步一步,因为代码中有技巧.还有一些解释在代码部分的注释行中,请阅读它们.

示例是使用最终的参数处理Android和IOS应用程序的深层链接http://example.com/v/,例如http://example.com/v/id-of-user?key=value.

1.配置Android

1.1将活动信息添加到AndroidManifest.xml文件中:

<activity
android:name=".appLinkHandlerActivity">

<intent-filter>
    <action android:name="android.intent.action.VIEW" />
    <category android:name="android.intent.category.DEFAULT" />
    <category android:name="android.intent.category.BROWSABLE" />

    <data
        android:host="example.com"
        android:pathPrefix="/v/"
        android:scheme="http" />
</intent-filter>

<intent-filter>
    <action android:name="android.intent.action.VIEW" />
    <category android:name="android.intent.category.DEFAULT" />
    <category android:name="android.intent.category.BROWSABLE" />

<!—this intent is needed to handle links to myapp://share, I will explain later why we need it -->
    <data
        android:host="share"
        android:scheme="myapp" />
</intent-filter>
Run Code Online (Sandbox Code Playgroud)

1.2创建名为appLinkHandlerActivity的活动,该活动将处理单击的链接

    public class appLinkHandlerActivity extends AppCompatActivity {


    /* assume that user is clicked http://example.com/v/my-user-id   
    actCode will be “v”, pCode will be “my-user-id” */
    String actCode="", pCode="";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);


        // ATTENTION: This was auto-generated to handle app links.
        Intent appLinkIntent = getIntent();
        String appLinkAction = appLinkIntent.getAction();
        Uri appLinkData = appLinkIntent.getData();



        String code = null;
        try {
            code = getIntent().getData().getLastPathSegment();
        } catch (Exception e) {

        }

        if (code == null) {
            Intent i = new Intent(this, {your main activity.class});
            startActivity(i);
        }

        List<String> params=appLinkData.getPathSegments();


        if (params.size()>0)
            actCode=params.get(0);

        if (params.size()>=2)
            pCode=params.get(1);

        /* assume that user is clicked http://example.com/v/my-user-id actCode is “v”, pCode is “my-user-id”  Do now whatever you need. */
    } 
 }
Run Code Online (Sandbox Code Playgroud)

2.配置IOS

这比Android更复杂,我将在这里解释必要的要点.请参阅文档:https: //developer.apple.com/library/content/documentation/General/Conceptual/AppSearch/UniversalLinks.html#//apple_ref/doc/uid/TP40016308-CH12-SW1

https://www.raywenderlich.com/128948/universal-links-make-connection

2.1在Apple Developer Portal上创建App ID时,您必须启用Associated Domains.重要问题:您需要购买Apple开发者帐户才能启用此选项,这意味着无需购买开发者帐户,就无法在IOS项目上尝试使用AppLinks.

2.2在XCode项目中,打开"Capabilites"选项卡并将Associated Domains切换为On.如果您未在Apple Developer Portal App ID部分中启用Associated Domains,则可能无法选择通过单击Associated Domains选项下的+按钮添加权利,请写入"applinks:example.com".

2.3在您的Web服务器上创建一个名为"apple-app-site-association"的文件,该文件必须通过https://example.com/apple-app-site-association访问HTTPS是强制性的,如果它不是有效的SSL证书App Link可能无法正常工作.将以下行添加到apple-app-site-association文件中:

{
    "applinks": {
        "apps": [],
        "details": [
            {
                "appID": "6HY7TF56.com.example.app",
                "paths": [ "/ios/*", "/v/*" ]
            }
        ]
    }
}
Run Code Online (Sandbox Code Playgroud)

appID是{"团队ID"."应用程序的捆绑ID"}的格式.您可以在Developer Portal的"成员身份详细信息"部分下找到您的teamID.

我们处理链接http://example.com/v/parameters,但是在这里您可以看到"/ ios/*"的另一个路径配置.需要绕过不支持的浏览器,我稍后会解释.

2.4在AppDelegate.m文件中添加两个方法来处理用户在example.com上的点击

-(BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void (^)(NSArray * _Nullable))restorationHandler{
    if ([userActivity.activityType isEqualToString: NSUserActivityTypeBrowsingWeb]) {

        NSURL *url = userActivity.webpageURL;
          [self parseUrl:url];

    }
return YES;
}


- (void) parseUrl:(NSURL * )handledUrl {
    NSString *urlStr=@"";
    NSString *pCode=@"";
    NSString *handledUrlStr=[handledUrl parameterString];

    NSString *handledUrlQueryPart;

    NSArray<NSString *> *pathsArray= [handledUrl pathComponents];

    //remember that we only added paths “/v/*” and “/ios/*” to handle in apple-app-site-association file. If you want to handle more subpaths you can add them into apple-app-site-association file, then below if-else conditions. Don’t touch to config and code for “/ios/*” path, it is needed to bypass unsopported browsers.
    if ([pathsArray[1]  isEqual: @"v"]){
        //sample url= http://example.com/v/menu?aaa=bbb
        pCode = pathsArray[2];
        handledUrlQueryPart=[handledUrl query];
    } else if ([pathsArray[1]  isEqual: @"ios"]){
        //sample url= http://example.com/ios/deeplink-ios.php?/v/menu?aaa=bbb
        NSArray *uriArray = [[handledUrl query] componentsSeparatedByString:@"?"];
           NSArray *queryPathsArray = [uriArray[0] componentsSeparatedByString:@"/"];
        if ([queryPathsArray count] > 2)
            pCode = queryPathsArray[2];

        if ([uriArray count] > 1 ){
            handledUrlQueryPart=uriArray[1];
        }
    }

    /* here pCode is the parameter what is passed from user. If the link clicked is http://example.com/v/menu it is “menu”. If the link clicked is http://example.com/v/menu?aaa=bbb it is “menu?aaa=bbb”. So you can do now what ever you need. */    
}
Run Code Online (Sandbox Code Playgroud)

3.管理令人不快的点击.

3.1好的,您的Android和IOS应用程序应该处理链接http://example.com/v/blabla上的点击,并将"blabla"参数传递给我展示的方法中使用的pCode变量.但是像Facebook应用程序这样的浏览器可能会禁用App Links.在这种情况下,用户单击将转到您的Web服务器,浏览器会尝试显示http://example.com/v/blabla的内容,该内容可能是404 Page Not Found.为了处理这些点击,我们将配置Apache Web服务器并将用户重定向到您的应用程序.如果您使用IIS或其他,我不知道如何操作,但您可以将其作为示例并使用相同的algortihm来配置您的Web服务器.

3.2在example.com根目录的.htaccess文件中写下以下行

#redirect to deeplink
<IfModule mod_rewrite.c>

#if there is a request to example.com/v/any-sub-path, redirect them to example.com/deeplink.php file. This rule is for both IOS and Android
RewriteRule ^(v)/.* /deeplink.php [L]

#if there is a request to example.com/ios/any-sub-path, redirect them to app installation page. That means your app is not installed on IOS device. This rule is for IOS devices only
RewriteRule ^(ios)/.* http://itunes.apple.com/install-of-your-app [L] 
</IfModule>  
Run Code Online (Sandbox Code Playgroud)

4.将用户重定向到应用程序

4.1步骤3中显示的.htaccess文件中的重定向规则将用户重定向到deeplink.php文件.以下是将用户重定向到您的应用程序的文件内容.

 <?php

$request_uri=$_SERVER[REQUEST_URI];

$ua = strtolower($_SERVER['HTTP_USER_AGENT']);
if(stripos($ua,'android') == true){
//if user device is android, redirect it to intent url which is handled by Android.
        $redir_tag="<meta http-equiv='refresh' content='0;url=intent://share$request_uri/#Intent;scheme=myapp;S.browser_fallback_url=http%3A%2F%2Fexample.com%2Fget-app%2F;package=com.example.app;end' />";
//scheme=myapp and host named “share” is configured in AndroidManifest.xml file to be handled by the activity.
//fallback url is the url, if your app is not installed on android device, so you can redirect them to a page to install android app. In some cases users are redirected to Play Store directly for application id of com.example.app
}

else if ( (stripos($ua,'iPhone') == true) || (stripos($ua,'iPad') == true) ) {
        //if user device is IOS, redirect them to a web page to see. There will be a link here to the another handled link: http://example.com/ios/blabla.
        // due to my experience there is no way to redirect IOS to app directly at this stage, user must click a link on browser and that link must be different than the link which was shown and clicked at first.
        // another experience taught me ther ecan be problems if we redirect users to a web page under example.com which is configured as applink, so I redirect users to a page under deep.example.com here
        $redir_tag="<meta http-equiv='refresh' content='0;url=http://deep.example.com/deeplink-ios.php?$request_uri' />";
}

else {
//If the device is neither IOS nor Android, redirect users to a web page which gives information that this link is for Android and IOS only
        $redir_tag="<meta http-equiv='refresh' content='0;url=http://example.com/non-mobile' />";
}


?>



<html>
    <head>

        <!— add tags for no-caching, this is important, the date below is my son’s birth time and date, he is now 6, so you can use it as a date in the past -->
        <meta http-equiv="cache-control" content="max-age=0" />
        <meta http-equiv="cache-control" content="no-cache" />
        <meta http-equiv="expires" content="-1" />
        <meta http-equiv="expires" content="Tue, 31 May 2011 10:15:00 GMT+3" />
        <meta http-equiv="pragma" content="no-cache" />


        <?php echo $redir_tag; ?>

    </head>
</html>
Run Code Online (Sandbox Code Playgroud)

5.向IOS用户显示单击链接

5.1以下是http://deep.example.com/deeplink-ios.php文件的内容.用户将看到如下页面,当他们点击链接时,该请求应由您的IOS应用程序处理.

<?php
//we create a link to http://example.com/ios/… which is configure to be handled by IOS app. IOS needs to be a user click in some cases to handle the request, that is why this page is shown to the user
$request_uri=$_SERVER[REQUEST_URI];
$link="<div class='w3-container w3-card'><h1><a href='http://example.com/ios$request_uri'>Click here to open MyApp</a></h1></div>";
?>

<html>
    <head>

        <!—adding no-cache tags is also important here-->
        <meta http-equiv="cache-control" content="max-age=0" />
        <meta http-equiv="cache-control" content="no-cache" />
        <meta http-equiv="expires" content="-1" />
        <meta http-equiv="expires" content="Tue, 31 May 2011 10:15:00 GMT+3" />
        <meta http-equiv="pragma" content="no-cache" />
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3mobile.css">

    </head>
<body>

<?php echo $link ?>

</body>
</html>
Run Code Online (Sandbox Code Playgroud)

6.案例分析:

6.1 Android

6.1.1案例1 - 应用程序安装在设备上
•浏览器请求http://example.com/v/blabla•Android
捕获链接并创建清单文件中配置的活动

6.1.2案例2 - 应用程序安装在设备上
•浏览器请求http://example.com/v/blabla•Android
无法捕获链接.
•浏览器连接到Web服务器,请求/ v/blabla
•由于.htaccess文件中的配置,它被重定向到deeplink.php?/ v/blabla
•deeplink.php得知它是android,并重定向到:intent:// share/v/blabla/#Intnt; scheme = myapp; S.browser_fallback_url = http%3A%2F%2Fexample.com%2Fget-app%2F; package = com.example.app
•Android捕获for意图的请求: //,所以由于清单文件中的配置,myapp:// share/v/blabla由活动处理

6.1.3案例3 - 未安装应用程序
•浏览器请求http://example.com/v/blabla•Android
无法捕获链接.
•浏览器连接到Web服务器,请求/ v/blabla
•由于.htaccess文件中的配置,它被重定向到deeplink.php?/ v/blabla
•deeplink.php得知它是android,并重定向到:intent:// share/v/blabla/#Intnt; scheme = myapp; S.browser_fallback_url = http%3A%2F%2Fexample.com%2Fget-app%2F; package = com.example.app
•Android捕获for意图的请求: //,但没有为id:com.example.app安装应用程序.在某些情况下,它会将浏览器重定向并重定向到您的应用的http://example.com/get-app或Play商店安装页面

6.2 IOS

6.2.1案例1 - 应用程序安装在设备上
•浏览器请求http://example.com/v/blabla•IOS
捕获链接并调用AppDelegate.m中的continueUserActivity方法

6.2.2案例2 - 应用程序安装在设备上
•浏览器请求http://example.com/v/blabla•IOS
无法捕获链接.
•浏览器连接到Web服务器,请求/ v/blabla
•由于.htaccess文件中的配置,它被重定向到deeplink.php?/ v/blabla
•deeplink.php得知它是IOS,并重定向到:http:// deep.example.com/deeplink-ios.php?/v/blabla•deeplink-ioos.php
文件显示用户的URL.URL为:http://lify.me/ios/v/blabla•
用户点击URL,浏览器请求http://lify.me/ios/v/blabla•IOS
因路径配置而捕获请求/ ios/*"在apple-app-site-association文件中并调用AppDelegate.m中的continueUserActivity方法
•如果IOS因任何原因无法捕获http://lify.me/ios/v/blabla的请求,它将表现为设备上未安装应用程序.看那个案子.

6.2.3案例2 - 设备上未安装应用程序
•浏览器请求http://example.com/v/blabla•IOS
无法捕获链接.
•浏览器连接到Web服务器,请求/ v/blabla
•由于.htaccess文件中的配置,它被重定向到deeplink.php?/ v/blabla
•deeplink.php得知它是IOS,并重定向到:http:// deep.example.com/deeplink-ios.php?/v/blabla•deeplink-ioos.php
文件显示用户的URL.URL为:http://lify.me/ios/v/blabla•
用户点击URL和浏览器请求http://lify.me/ios/v/blabla•
如果IOS无法捕获http的请求://lify.me/ios/v/blabla•
浏览器连接到Web服务器,请求/ ios/v/blabla
•它被重定向到http://itunes.apple.com/install-of-your-app到期在Web服务器上的.htaccess文件中进行配置

6.3在非Android或IOS设备上单击App Link
•浏览器请求http://example.com/v/blabla•
设备操作系统无法捕获链接.
•浏览器连接到Web服务器,请求/ v/blabla
•由于.htaccess文件中的配置,它被重定向到deeplink.php?/ v/blabla
•deeplink.php得知它既不是IOS也不是IOS,并重定向到:http ://example.com/non-mobile