Слишком много руководств по глубоким ссылкам (универсальные ссылки или ссылки на приложения). Но большинство из них показывает, как включить его в приложениях для Android или IOS. Также есть платные облачные решения, но они предлагают много возможностей. Но есть три основные проблемы, с которыми я столкнулся в реальной жизни:
- Некоторые браузеры не позволяют работать ссылкам на приложения. Например, вы можете настроить http://example.com так, чтобы он попадал в приложение, но если пользователь щелкает эту ссылку через приложение Facebook, она не обрабатывается, и браузер Facebook показывает веб-сайт.
- Не существует единого стандартного решения для обработки ссылок как для приложений Android, так и для IOS.
- Нет практического решения, если приложение не установлено на мобильном устройстве, а пользователь щелкает ссылку на приложение.
Я написал этот вопрос и ответ, который является результатом моих исследований (потратил слишком много часов), чтобы найти уникальное и работающее решение для всех случаев.
Коды взяты из моего рабочего решения, но я удалил некоторые части, чтобы показать идею. Если есть проблемы с компиляцией, следуйте алгоритму и напишите свой код
Вот решение, идите шаг за шагом, даже если вы знаете некоторые шаги, потому что в кодах есть хитрости. Также некоторые пояснения находятся в строках комментариев к частям кода, прочтите их.
Например, для обработки глубокой ссылки 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/немобильный