A solução Deeplink para aplicativos IOS e Android funciona no Facebook

Existem muitos tutoriais de Deep Linking (Universal Links ou App Links). Mas a maioria deles mostra como ativá-lo nos aplicativos Android ou IOS. Também existem soluções em nuvem pagas, mas elas oferecem muitos recursos. Mas há três problemas principais que enfrentei na vida real:

Alguns navegadores não permitem que os Links de aplicativos funcionem. Por exemplo, você pode configurar o http://example.com para ser capturado no aplicativo, mas se esse link for clicado pelo usuário pelo aplicativo do Facebook, ele não será tratado e o navegador do Facebook mostrará o site.Não existe uma solução padrão exclusiva para lidar com links para aplicativos Android e IOS.Nenhuma solução prática se o aplicativo não estiver instalado no dispositivo móvel e o usuário clicar em um link do aplicativo.

Eu escrevi esta sessão de perguntas e respostas, que é o resultado dos meus estudos (gastei muitas horas) para ter uma solução única e funcionando para todos os casos.

Os códigos são provenientes da minha solução de trabalho, mas removi algumas partes apenas para mostrar a ideia. Se houver algum problema de compilação, siga o algoritmo e escreva seu próprio código

Aqui está a solução, vá passo a passo, mesmo se você souber alguns passos, porque existem truques nos códigos. Além disso, algumas explicações estão nas linhas de comentários das partes do código, por favor, leia-as.

Os exemplos são lidar com deeplink http://example.com/v/ pelos seus aplicativos Android e IOS com um argumento no final, por exemplo http://example.com/v/id-of-user?key=value.

1. Configurando o Android

1.1 Adicione informações de atividade ao seu arquivo 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 Crie uma atividade chamada appLinkHandlerActivity que manipulará os links clicados

    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. Configurando o IOS

Isso é mais complexo que o Android, explicarei os pontos necessários aqui. Por favor, consulte os documentos: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 Você deve habilitar os domínios associados ao criar um ID do aplicativo no Apple Developer Portal. Problema importante: você precisa ter uma conta de desenvolvedor Apple comprada para ativar esta opção, ou seja, sem comprar uma conta de desenvolvedor, não é possível experimentar o AppLinks no seu projeto IOS.

2.2 No projeto XCode, abra a guia "Capabilites" e alterne Domínios Associados para Ativado. Se você não ativou Domínios Associados na seção ID do Aplicativo do Apple Developer Portal, isso pode não ser selecionável. Adicione um direito clicando no botão + na opção Domínios Associados, escreva "applinks: example.com".

2.3 Crie um arquivo no servidor da Web chamado “apple-app-site-association” e esse arquivo deve ser acessado por https://example.com/apple-app-site-association HTTPS é obrigatório e se não for válido Certificado SSL O App Link pode não funcionar. Adicione as seguintes linhas ao arquivo apple-app-site-association:

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

appID é o formato de {"Team ID". "ID do pacote do seu aplicativo"}. Você pode encontrar seu teamID na seção Detalhes da associação no Developer Portal.

Lidamos com o link http://example.com/v/parameters, mas aqui você vê que há outra configuração de caminho para “/ ios / *”. É necessário ignorar navegadores não suportados, explicarei mais adiante.

2.4 No arquivo AppDelegate.m, adicione dois métodos para manipular os cliques do usuário em 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. Gerenciando os cliques não capturados.

3.1 Ok, seus aplicativos para Android e IOS devem lidar com os cliques no link http://example.com/v/blabla e passar o parâmetro "blabla" para a variável pCode usada nos métodos mostrados. Mas algumas sobrancelhas, como o aplicativo do Facebook, podem desativar os Links do aplicativo para funcionar. Nesse caso, o clique do usuário acessa o servidor da Web e o navegador tenta mostrar o conteúdo de http://example.com/v/blabla, que provavelmente é 404 Página não encontrada. Para lidar com esses cliques, configuraremos o servidor da web Apache e redirecionaremos os usuários para o seu aplicativo. Se você usa o IIS ou outro, não sei como fazê-lo, mas você pode usar isso como exemplo e usar o mesmo algoritmo para configurar seu servidor da web.

3.2 Escreva as linhas abaixo no arquivo .htaccess no diretório raiz de 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. Redirecione usuários para aplicativos

4.1 As regras de redirecionamento no arquivo .htaccess mostradas na etapa 3 redirecionam os usuários para o arquivo deeplink.php. Então, aqui está o conteúdo desse arquivo para redirecionar os usuários ao seu aplicativo.

 <?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. Mostre aos usuários do IOS um link para clicar

5.1 Aqui está o conteúdo do arquivo http://deep.example.com/deeplink-ios.php. Os usuários verão uma página como abaixo, quando clicaram no link, essa solicitação deve ser tratada pelo seu aplicativo 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. Análise de Caso:

6.1 Android

6.1.1 Caso 1 - o aplicativo está instalado no dispositivo
• Solicitações do navegador para http://example.com/v/blabla
• Android pega o link e cria a atividade configurada no seu arquivo de manifesto

6.1.2 Caso-2 - o aplicativo está instalado no dispositivo
• Solicitações do navegador para http://example.com/v/blabla
• O Android não consegue capturar o link.
• O navegador se conecta ao servidor da Web, solicite / v / blabla
• Ele é redirecionado para deeplink.php? / V / blabla devido à configuração no arquivo .htaccess
• deeplink.php descobre que é android e redireciona para: intent: // share / v / blabla / # Intent; schema = myapp; S.browser_fallback_url = http% 3A% 2F% 2Fexample.com% 2Fget-app% 2F; package = com.example.app
• O Android captura a solicitação com a intenção: //, portanto, devido à configuração no arquivo de manifesto myapp: // share / v / blabla é tratado pela atividade

6.1.3 Caso-3 - o aplicativo não está instalado
• Solicitações do navegador para http://example.com/v/blabla
• O Android não consegue capturar o link.
• O navegador se conecta ao servidor da Web, solicite / v / blabla
• Ele é redirecionado para deeplink.php? / V / blabla devido à configuração no arquivo .htaccess
• deeplink.php descobre que é android e redireciona para: intent: // share / v / blabla / # Intent; schema = myapp; S.browser_fallback_url = http% 3A% 2F% 2Fexample.com% 2Fget-app% 2F; package = com.example.app
• O Android captura a solicitação com a intenção: //, mas não há aplicativo instalado para o id: com.example.app. Ele falha e redireciona o navegador para http://example.com/get-app ou página de instalação da Play Store do seu aplicativo em alguns casos

6.2 IOS

6.2.1 Caso 1 - o aplicativo está instalado no dispositivo
• Solicitações do navegador para http://example.com/v/blabla
• O IOS captura o link e chama o método continueUserActivity em AppDelegate.m

6.2.2 Caso 2 - o aplicativo está instalado no dispositivo
• Solicitações do navegador para http://example.com/v/blabla
• O iOS não consegue capturar o link.
• O navegador se conecta ao servidor da Web, solicite / v / blabla
• Ele é redirecionado para deeplink.php? / V / blabla devido à configuração no arquivo .htaccess
• deeplink.php descobre que é o IOS e redireciona para: http://deep.example.com/deeplink-ios.php?/v/blabla
• O arquivo deeplink-ios.php mostra uma URL para o usuário. O URL é: http://lify.me/ios/v/blabla
• O usuário clica no URL e solicitações do navegador para http://lify.me/ios/v/blabla
• O IOS captura a solicitação devido à configuração do caminho “/ ios / *” no arquivo de associação de aplicativo de aplicativo da Apple e chama o método continueUserActivity em AppDelegate.m
• Se o IOS não conseguir capturar a solicitação de http://lify.me/ios/v/blabla por qualquer motivo, ele se comportará porque o aplicativo não está instalado no dispositivo. Veja esse caso.

6.2.3 Caso 2 - o aplicativo não está instalado no dispositivo
• Solicitações do navegador para http://example.com/v/blabla
• O iOS não consegue capturar o link.
• O navegador se conecta ao servidor da Web, solicite / v / blabla
• Ele é redirecionado para deeplink.php? / V / blabla devido à configuração no arquivo .htaccess
• deeplink.php descobre que é o IOS e redireciona para: http://deep.example.com/deeplink-ios.php?/v/blabla
• O arquivo deeplink-ios.php mostra uma URL para o usuário. O URL é: http://lify.me/ios/v/blabla
• O usuário clica no URL e solicitações do navegador para http://lify.me/ios/v/blabla
• Se o IOS não conseguir capturar a solicitação de http://lify.me/ios/v/blabla
• O navegador se conecta ao servidor da Web, solicite / ios / v / blabla
• Ele é redirecionado para http://itunes.apple.com/install-of-your-app devido à configuração no arquivo .htaccess no servidor da web

6.3 O link do aplicativo é clicado em um dispositivo não Android ou IOS
• Solicitações do navegador para http://example.com/v/blabla
• O SO do dispositivo não consegue capturar o link.
• O navegador se conecta ao servidor da Web, solicite / v / blabla
• Ele é redirecionado para deeplink.php? / V / blabla devido à configuração no arquivo .htaccess
• deeplink.php descobre que não é nem iOS nem Android, e redireciona para: http://example.com/non-mobile

questionAnswers(0)

yourAnswerToTheQuestion