¿Cómo podemos cohesionar nuestra página web con nuestra aplicación móvil? ¿Cómo podemos llevar a nuestros usuarios al contenido exacto que quieren ver? ¿Cómo hacemos esto teniendo en cuenta que nuestra base de usuarios utiliza múltiples versiones de iOS?

Lo primero, ¿qué es un deep link y para qué lo necesito?

Un deep link, o enlace profundo, es un tipo de hipervínculo que contiene en sí mismo toda la información necesaria para llegar a un contenido concreto.

Este hecho tan sencillo nos aporta un gran valor frente al usuario. Con un simple clic será transportado automáticamente al contenido que queremos que vea, sin que tenga que lidiar con la labor de navegar entre las múltiples páginas de nuestro sitio web hasta llegar al mismo.

Y esto, ¿qué tiene que ver con las aplicaciones móviles?

Como hemos dicho los deep links son una gran herramienta para transportar, con un simple enlace, a nuestros usuarios a un contenido concreto, pero además nos sirven para cohesionar los contenidos de nuestra página web y nuestras comunicaciones comerciales con las aplicaciones móviles que les distribuimos.

Gracias a ellos, y si el usuario toca el enlace en un dispositivo móvil teniendo nuestra aplicación instalada, somos capaces de llevarles a la sección correcta de la aplicación para que vean el contenido que hemos preparado de una forma totalmente adaptada al tamaño de pantalla que están usando en ese momento. No es la primera vez que hablamos de ellos en el blog: en este post ya os contamos cómo crear links dinámicos con Firebase Dynamic Links.

Ahora que sabemos qué son y para qué nos sirven, vamos a aprender a trabajar con ellos.

Entremos en materia, ¿cómo consigo que los deep links abran mi aplicación?

En el ecosistema iOS este tipo de enlaces se conocen como Universal Links o enlaces universales, e introducirlos en nuestras aplicaciones requiere unos sencillos pasos.

1 Dominios asociados a la aplicación

El primer paso consiste en definir el dominio asociado a la aplicación; esto no es más que la vinculación segura de nuestro dominio con nuestra aplicación.

Esta conexión nos permitirá realizar multitud de desarrollos que mejorarán la usabilidad de nuestra plataforma, consiguiendo así que nuestros usuarios tengan la mejor experiencia posible. Las opciones que nos abre esta conexión van desde guardar credenciales de forma segura, hasta enlazar nuestro contenido web con nuestra aplicación mediante deep links.

La primera parte de esta unión es acudir a la plataforma de desarrolladores de Apple y añadirle al identificador de nuestra aplicación la capacidad de tener dominios asociados.

Lidiando con Deep Links 1

Tras otorgar dicha capacidad al identificador de nuestra aplicación, nos dirigiremos a la sección Signing & Capabilities del proyecto Xcode de nuestra aplicación y añadiremos la capacidad Associated Domains. Una vez hecho esto, introduciremos nuestro dominio.

Lidiando con Deep Links 2

Al introducir el dominio debemos precederlo de la clave applinks: la cual indicará al sistema operativo que la aplicación tiene un dominio asociado para deep links.

2 El fichero apple-app-site-association

En los dispositivos iOS cada vez que una aplicación es instalada, actualizada y aproximadamente una vez a la semana, comprueban si en la configuración de la misma hay definido algún dominio asociado. Si lo hay, realizan una petición a dicho dominio en busca de un fichero concreto, el fichero apple-app-site-association.

La petición en cuestión es enviada contra la URL https://domain.tld/.well-known/apple-app-site-association; analizando la dirección podemos extraer los primeros requisitos:

Además de los requisitos extraídos del análisis de la URL, también es necesario cumplir:

A continuación podemos ver un ejemplo de la estructura del fichero:

{
  "applinks": {
    "details": [
      {
        "appIDs": [
          "ABCDE12345.es.ejemplo.aplicacion"
        ],
        "components": [
          {
            "/": "/ejemplo/privado",
            "exclude": true,
            "comment": "¡No puedes pasar!"
          },
          {
            "/": "/ejemplo/conparametros",
            "?": {
              "parametro1": "?????"
            },
            "comment": "¡Puedes pasar!"
          },
          {
            "/": "/ejemplo/*",
            "comment": "Mi comentario"
          }
        ]
      }
    ]
  }
}

Cómo se puede apreciar, el JSON consta de una estructura y claves concretas, siendo las más importantes:

Además de las claves que acabamos de comentar, existen otras que también nos pueden ser útiles en alguna situación.

A fin de aclarar lo más posible la definición de las reglas, hay que tener en cuenta:

Nota: En lo que concierne a este artículo, únicamente hemos tratado la parte relativa a los deep links pero quiero comentar que este mismo fichero es el que se usa para definir el uso de los servicios Shared Web Credential (almacenaje de credenciales web) y el servicio de App Clips (pequeña parte de una aplicación que se usa para una tarea concreta y que no exige la instalación de la aplicación entera).

3 Capturar, procesar y navegar

Una vez definida la configuración de la aplicación y creado el fichero apple-app-site-association queda realizar el último paso: debemos capturar y tratar los deep links para poder navegar dentro de nuestra aplicación.

En este paso es donde entra en juego la programación. Ahora es cuando crearemos nuestro algoritmo de análisis de los deep links de manera que podamos navegar adecuadamente y llevar al usuario al contenido que desea ver. Cuando la aplicación se abre, el sistema operativo llama al método scene(_:continue:) del UISceneDelegate. Una vez entremos en dicha función podremos acceder a la propiedad webpageURL del parámetro userActivity para obtener el enlace que ha ocasionado la apertura de la aplicación, analizarlo y realizar la navegación adecuada.

func scene(_ scene: UIScene, continue userActivity: NSUserActivity) {
    print(“===>> \(#function)")
    guard let url = userActivity.webpageURL?.absoluteURL else {
        return
    }
    print("===>> Deep Link que ha abierto la aplicación: \(url)”)
    // TODO: Implementar algoritmo de decisión
}

Nota: En lo que concierne a este artículo, únicamente tratamos como capturar el deep link que ha ocasionado la apertura de la aplicación. Para analizar el enlace y ejecutar la navegación hasta el contenido dentro de la aplicación existen múltiples maneras y todas ellas dependen de la aplicación en concreto, la arquitectura implementada, etc., debido a esos factores, el análisis y navegación no se cubren en este artículo.

Peculiaridades por versiones

iOS 14 y posteriores

Todo lo que hemos descrito hasta ahora está totalmente actualizado a iOS 15 (la versión vigente cuando hemos escrito este post), pero hay un detalle que se introdujo en iOS 14 que no hemos comentado.

Anteriormente, explicábamos que el sistema operativo iOS, realiza una comprobación en la configuración de cada aplicación en busca de dominios asociados a la misma, para en caso de encontrarlos, proceder con la descarga del fichero apple-app-site-association. Si bien esto es cierto, tenemos que tener en cuenta que la descarga de dicho fichero en iOS 14 y versiones posteriores se realiza desde el CDN (Content Delivery Network) de Apple, siendo el CDN el encargado capturar la versión más reciente del fichero apple-app-site-association. La captura de la versión más actualizada del fichero por parte del CDN se realiza de manera recurrente cada 24 horas aproximadamente.

Este funcionamiento no debería suponer ningún tipo de problema para las aplicaciones en producción, ya que lo más habitual es que los servidores, a los que dichas aplicaciones atacan, suelen ser accesibles desde cualquier parte del mundo y, por tanto, las peticiones del CDN de Apple llegarán sin ningún problema. Sin embargo, es habitual que además del entorno de producción tengamos el de preproducción y/o desarrollo. En ellos iremos realizando cambios, añadiendo funcionalidades y preparando nuevas versiones y es por ello que, normalmente, el acceso a estos entornos está limitado a un conjunto definido de direcciones IP. En efecto, si el acceso está limitado, el CDN de Apple no podrá recuperar la versión más moderna del fichero de estos entornos preproductivos y, por ende, se nos complica la labor de desarrollo y las pruebas de nuevos deep links que queramos incluir en nuestra aplicación.

Este inconveniente tiene una solución muy sencilla de aplicar. Recordaremos que hemos tenido que añadir el dominio asociado a la configuración de nuestro proyecto Xcode; pues la solución está ahí. Debemos añadir nuevamente el dominio pero esta vez añadiéndole al final ?mode=developer.

Lidiando con Deep Links 3

Al añadir este parámetro query informamos al sistema operativo iOS que no queremos acudir al CDN a recuperar el fichero apple-app-site-association y que, por el contrario, queremos que la petición se realice directamente contra nuestro servidor. Añadiendo esta simple query al dominio solventamos el problema de la descarga del fichero en entornos preproductivos, lo que nos permitirá realizar nuestro desarrollo sin problema.

iOS 12 y anteriores

Es posible que queramos dar soporte con nuestra aplicación a usuarios que aún estén usando iOS 12 o incluso versiones anteriores. Para poder darles este soporte debemos realizar un par de tareas extra.

1 Fichero apple-app-site-association

Con la llegada de iOS 13 se produjo un cambio en la estructura del fichero apple-app-site-association dejando dicha estructura tal y como la hemos visto anteriormente, sin embargo, para las versiones iOS 12 y anteriores la estructura es distinta. A continuación podemos ver un ejemplo de la estructura incluyendo el soporte para iOS 12:

{
  "applinks": {
    "apps": [],
    "details": [
      {
        "appIDs": [
          "ABCDE12345.es.ejemplo.aplicacion"
        ],
        "components": [
          {
            "/": "/ejemplo/privado",
            "exclude": true,
            "comment": "¡No puedes pasar!"
          },
          {
            "/": "/ejemplo/conparametros",
            "?": {
              "parametro1": "?????"
            },
            "comment": "¡Puedes pasar!"
          },
          {
            "/": "/ejemplo/*",
            "comment": "Mi comentario"
          }
        ],
        "appID": "ABCDE12345.es.ejemplo.aplicacion",
        "paths": [
          "NOT /ejemplo/privado",
          "/ejemplo/*"
        ]
      }
    ]
  }
}

Como se puede apreciar, hemos introducido una serie de claves concretas para dar soporte a los usuario de iOS 12:

De estas nuevas claves la más peculiar es la clave paths cuyo contenido cambia bastante respecto a su homóloga components usada a partir de iOS 13. En este caso se trata de una lista de las rutas que activarán la apertura de la aplicación. Analizando cada regla una a una y buscando que actúen igual que sus homólogas en iOS 13 vemos que:

2 Capturar, procesar y navegar

Con iOS 13 llegaron las escenas y apareció el UISceneDelegate. Anteriormente hemos visto que cuando la aplicación es abierta desde un deep link el sistema llama a un método delegado, el cual nos permite capturar el enlace que ha propiciado tal apertura y realizar decisiones basadas en el análisis del mismo, pero ¿cómo haremos esto en iOS 12?

En iOS 12 y anteriores versiones podemos usar el UIAppDelegate, en concreto el método delegado application(_:continue:restorationHandler:) que será llamado cuando la aplicación se abra desde un deep link. Al igual que en el homólogo del UISceneDelegate, podremos acceder a la propiedad webpageURL del parámetro userActivity para obtener el enlace que ha ocasionado la apertura de la aplicación, analizarlo y realizar la navegación adecuada.

func application(_ app: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
    print("===>> \(#function)")
    guard let url = userActivity.webpageURL?.absoluteURL else {
        return false
    }
    print("===>> DeepLink que ha abierto la aplicación: \(url)")
    // TODO: Implementar algoritmo de decisión
    return true
}

Nota: Al igual que en la sección anterior, únicamente tratamos como capturar el deep link que ha ocasionado la apertura de la aplicación. El análisis y navegación no se cubren en este artículo.

Dos trucos para facilitar el desarrollo

1 Abriendo deep links en el simulador

Es bastante habitual que usemos los simuladores para probar nuestra aplicación, comprobar que el código que programamos hace lo que esperamos y que todo funciona de forma correcta. Lógicamente, querremos probar el algoritmo de análisis y navegación que hemos diseñado para tratar los deep links que abran nuestra aplicación. Para ello, se nos puede ocurrir que lo más sencillo es instalar la aplicación en el simulador, ir a Safari, pegar el enlace y… desgraciadamente este método no funciona; el enlace se cargará en el navegador y la aplicación no se abrirá. Esto se debe a que en iOS los enlaces que desencadenan la comprobación de reglas de los deep links deben ser pulsados.

Una vez que sabemos esto, se nos puede ocurrir que una forma de hacerlo es ir a la aplicación Mensajes del simulador, pegar el enlace, enviarlo a la conversación y después hacer clic sobre él para iniciar todo el proceso. En efecto, este proceso funcionará pero es extremadamente laborioso y, por suerte, hay otra forma de hacerlo. Para ello solo necesitamos la terminal de nuestro ordenador para ejecutar xcrun simctl openurl booted $URL. Con esa sencilla línea podremos ordenar a nuestro simulador que abra el enlace que digamos como si hubiéramos pulsado sobre él, desencadenando así todo el proceso de comprobación de reglas y posterior apertura de la aplicación. Desgranando la instrucción anterior:

Con este sencillo comando podremos abrir todos los deep links que queramos en nuestros simuladores a fin de probar nuestro algoritmo de análisis y navegación.

2 No tengo acceso a los servidores

Es posible que durante nuestro desarrollo nos encontremos en la situación de que debemos incluir el tratamiento de un nuevo deep link en nuestra aplicación. En este caso, modificaremos nuestro fichero apple-app-site-association e implementaremos la decisión correspondiente a este nuevo enlace en nuestra aplicación. Una vez hecho esto tenemos que probarlo y para ello es necesario que subamos el fichero al servidor a fin de que iOS se lo descargue cuando instalemos la aplicación en el simulador y poder probar el nuevo deep link. En este punto aparece un conflicto; no tengo acceso a los servidores y por tanto no puedo subir el fichero actualizado.

Bien, ante esta situación tenemos una contramedida llamada Proxyman. Proxyman es una aplicación para MacOS que actúa de “proxy” del sistema que nos permite ver y manipular las peticiones http y https que pasan por él.

Dado que la descarga del fichero apple-app-site-association es una petición https podemos usar Proxyman para interceptarla y cambiar el contenido del cuerpo de la respuesta. En dicha intercepción, podemos añadir esa nueva regla que nos permita probar el nuevo deep link y su correspondiente nueva decisión incluida en el algoritmo de nuestra aplicación. Para ello utilizaremos el módulo Scripting de Proxyman que con un poco de Javascript nos permitirá modificar la respuesta.

Lidiando con Deep Links 4

Conclusiones

A lo largo de todo el artículo hemos visto cómo podemos cohesionar nuestra página web con nuestra aplicación móvil, de manera que demos continuidad total a nuestros usuarios. Todo ello es gracias a los deep links. Son un gran herramienta, pero en lo que se refiere al ecosistema iOS hay que aprender a trabajar con ellos, y las claves son:

Bibliografía

Cuéntanos qué te parece.

Los comentarios serán moderados. Serán visibles si aportan un argumento constructivo. Si no estás de acuerdo con algún punto, por favor, muestra tus opiniones de manera educada.

Suscríbete

Estamos comprometidos.

Tecnología, personas e impacto positivo.