Решение Deeplink для приложений IOS и Android работает в Facebook

Слишком много руководств по глубоким ссылкам (универсальные ссылки или ссылки на приложения). Но большинство из них показывает, как включить его в приложениях для Android или IOS. Также есть платные облачные решения, но они предлагают много возможностей. Но есть три основные проблемы, с которыми я столкнулся в реальной жизни:

  1. Некоторые браузеры не позволяют работать ссылкам на приложения. Например, вы можете настроить http://example.com так, чтобы он попадал в приложение, но если пользователь щелкает эту ссылку через приложение Facebook, она не обрабатывается, и браузер Facebook показывает веб-сайт.
  2. Не существует единого стандартного решения для обработки ссылок как для приложений Android, так и для IOS.
  3. Нет практического решения, если приложение не установлено на мобильном устройстве, а пользователь щелкает ссылку на приложение.

Я написал этот вопрос и ответ, который является результатом моих исследований (потратил слишком много часов), чтобы найти уникальное и работающее решение для всех случаев.

Коды взяты из моего рабочего решения, но я удалил некоторые части, чтобы показать идею. Если есть проблемы с компиляцией, следуйте алгоритму и напишите свой код

Вот решение, идите шаг за шагом, даже если вы знаете некоторые шаги, потому что в кодах есть хитрости. Также некоторые пояснения находятся в строках комментариев к частям кода, прочтите их.

Например, для обработки глубокой ссылки http://example.com/v/ вашими приложениями Android и IOS с аргументом в конце, например, 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>

1.2 Create an activity named appLinkHandlerActivity which will handle the links clicked

    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. */
    } 
 }

<сильный>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. Важная проблема: вам необходимо иметь приобретенную учетную запись разработчика Apple, чтобы включить эту опцию, что означает, что без покупки учетной записи разработчика вы не сможете попробовать AppLinks в своем проекте IOS.

2.2 В проекте XCode откройте вкладку «Возможности» и установите для параметра «Связанные домены» значение «Вкл.». Если вы не включили «Связанные домены» в разделе «Идентификатор приложения» на портале разработчиков Apple, это может быть невозможно выбрать. Добавьте право, нажав кнопку «+» в разделе «Связанные домены», напишите «applinks:example.com».

2.3 Создайте на своем веб-сервере файл с именем «apple-app-site-association». Доступ к этому файлу должен осуществляться через https://example.com/apple-app-site-association. Ссылка на приложение SSL-сертификата может не работать. Добавьте следующие строки в файл apple-app-site-association:

{
    "applinks": {
        "apps": [],
        "details": [
            {
                "appID": "6HY7TF56.com.example.app",
                "paths": [ "/ios/*", "/v/*" ]
            }
        ]
    }
}

appID — это формат {"Team ID", "Bundle ID вашего приложения"}. Вы можете найти свой 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. */    
}

<сильный>3. Управление неперехваченными кликами.

3.1 Хорошо. Ваши приложения для Android и IOS должны обрабатывать клики по ссылке http://example.com/v/blabla и передавать параметр «blabla» в переменную pCode, используемую в методах, которые я показал. Но некоторые браузеры, такие как приложение Facebook, могут отключать ссылки на приложения для работы. В этом случае пользовательский клик переходит на ваш веб-сервер, и браузер пытается отобразить содержимое http://example.com/v/blabla, которое, вероятно, является 404 Страница не найдена. Для обработки этих кликов мы настроим веб-сервер Apache и перенаправим пользователей в ваше приложение. Если вы используете IIS или другой, я не знаю, как это сделать, но вы можете взять это как пример и использовать тот же алгоритм для настройки вашего веб-сервера.

3.2 Запишите следующие строки в файл .htaccess в корневом каталоге example.com.

#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>  

<сильный>4. Перенаправить пользователей в приложения

4.1 Правила перенаправления в файле .htaccess, показанные на шаге 3, перенаправляют пользователей в файл 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>

<сильный>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>

<сильный>6. Анализ случая:

6.1 Андроид

6.1.1 Случай 1. Приложение установлено на устройстве
• Браузер запрашивает http://example.com/v/blabla
• Android перехватывает ссылку и создает действие, настроенное в файле манифеста.

6.1.2 Случай 2 – приложение установлено на устройстве
• Браузер запрашивает http://example.com/v/blabla
• Android не может поймать ссылку.
• Браузер подключается к Интернету. сервер, запрос на /v/blabla
• Он перенаправляется на deeplink.php?/v/blabla из-за конфигурации в файле .htaccess
• deeplink.php узнает, что это андроид, и перенаправляет на: намерение:/ /share/v/blabla/#Intent;scheme=myapp;S.browser_fallback_url=http%3A%2F%2Fexample.com%2Fget-app%2F;package=com.example.app
• Android перехватывает запрос, который для намерения://, поэтому из-за конфигурации в файле манифеста myapp://share/v/blabla обрабатывается действием

6.1.3 Вариант 3 – приложение не установлено
• Браузер запрашивает http://example.com/v/blabla
• Android не может поймать ссылку.
• Браузер подключается к веб-серверу. , запрос на /v/blabla
• Он перенаправляется на deeplink.php?/v/blabla из-за конфигурации в файле .htaccess
• deeplink.php узнает, что это Android, и перенаправляет на: намерение: // share/v/blabla/#Intent;scheme=myapp;S.browser_fallback_url=http%3A%2F%2Fexample.com%2Fget-app%2F;package=com.example.app
• Android перехватывает запрос, который для намерения://, но для id: com.example.app не установлено приложение. В некоторых случаях он перенаправляет браузер на http://example.com/get-app или на страницу установки вашего приложения в Play Store.

6.2 ИОС

6.2.1 Случай 1 — приложение установлено на устройстве
• Браузер запрашивает http://example.com/v/blabla
• IOS перехватывает ссылку и вызывает метод continueUserActivity в AppDelegate.m

6.2.2 Случай 2 — приложение установлено на устройстве
• Браузер запрашивает http://example.com/v/blabla
• IOS не может поймать ссылку.
• Браузер подключается к Интернету. сервер, запрос на /v/blabla
• Он перенаправляется на deeplink.php?/v/blabla из-за конфигурации в файле .htaccess
• deeplink.php узнает, что это IOS, и перенаправляет на: http:/ /deep.example.com/deeplink-ios.php?/v/blabla
• Файл deeplink-ios.php показывает пользователю URL. URL-адрес: http://lify.me/ios/v/blabla
• Пользователь щелкает URL-адрес, и браузер запрашивает http://lify.me/ios/v/blabla
• IOS перехватывает запрос из-за конфигурации пути «/ios/*» в файле apple-app-site-association и вызова метода continueUserActivity в AppDelegate.m
• Если IOS не может перехватить запрос на http://lify.me/ ios/v/blabla по любой причине, он будет вести себя так, как будто приложение не установлено на устройстве. Смотрите тот случай.

6.2.3 Вариант 2: приложение не установлено на устройстве
• Браузер запрашивает http://example.com/v/blabla
• IOS не может поймать ссылку.
• Браузер подключается к веб-сервер, запрос на /v/blabla
• Он перенаправляется на deeplink.php?/v/blabla из-за конфигурации в файле .htaccess
• deeplink.php узнает, что это IOS, и перенаправляет на: http: //deep.example.com/deeplink-ios.php?/v/blabla
• Файл deeplink-ios.php показывает пользователю URL. URL-адрес: http://lify.me/ios/v/blabla
• Пользователь щелкает URL-адрес, и браузер запрашивает http://lify.me/ios/v/blabla
• Если IOS может' не перехватывает запрос на http://lify.me/ios/v/blabla
• Браузер подключается к веб-серверу, запрос на /ios/v/blabla
• Он перенаправляется на http://itunes. apple.com/install-of-your-app из-за конфигурации в файле .htaccess на веб-сервере

6.3 Ссылка на приложение нажата на устройстве, отличном от Android или IOS
• Браузер запрашивает http://example.com/v/blabla
• ОС устройства не может поймать ссылку.
• Браузер подключается к Интернету. сервер, запрос на /v/blabla
• Он перенаправляется на deeplink.php?/v/blabla из-за конфигурации в файле .htaccess
• deeplink.php узнает, что это ни IOS, ни Android, и перенаправляет на: http://example.com/немобильный


person Mustafa Atalar    schedule 17.09.2017    source источник
comment
Существуют бесплатные решения для реализации диплинков. Моя команда работает над динамическими ссылками Firebase. Я знаю по крайней мере об одном конкуренте, который также является бесплатным. Не уверен, что вы имеете в виду, но они предлагают множество функций. Вы можете игнорировать функции, которые вам не нужны.   -  person Oleksiy Ivanov    schedule 18.09.2017
comment
Я уверен, что вы уже провели исследование, но Branch и Firebase делают это бесплатно. Эти продукты, особенно Branch, сосредоточены на обработке всех этих крайних случаев, чтобы вам не приходилось этого делать. Нет причин создавать все это самостоятельно, когда исходный код уже открыт.   -  person clayjones94    schedule 18.09.2017
comment
динамическое связывание firebase не работает с приложениями facebook и d messenger.   -  person tabebqena    schedule 02.10.2019
comment
@clayjones94 не уверен, что Бранч был бесплатным в то время, когда вы писали комментарий, но сейчас это точно не так.   -  person MAS    schedule 29.06.2020
comment
После установки приложения, как мне прочитать реферальные параметры в iOS? Пересылает ли iOS эти параметры из ссылки для установки. Может ли кто-нибудь направить меня.   -  person Mohamed Jaleel Nazir    schedule 19.06.2021
comment
Спасибо за руководство. Это полезно для регионов, где продукты Firebase/Google заблокированы. Насчет Бранча не уверен.   -  person Leonardo Vinsen    schedule 27.06.2021