En una aplicación de Android podemos definir plantillas de URI que asignan URI a actividades mediante filtros de intención.
Para saber más al respecto recomendamos leer esta documentación proporcionada por Google https://developer.android.com/training/app-links
Una vez que hayamos definido qué URI maneja nuestra aplicación en nuestro manifiesto, podemos inspeccionar el URI de las intenciones de los enlaces entrantes y decidir cómo actuar en consecuencia.
La API Deep Linking se encarga de gestionar los enlaces entrantes asignando patrones de URI a comandos.
Estos comandos luego se pueden usar para iniciar una actividad, mostrar un fragmento, mostrar alguna otra interfaz de usuario o cualquier otra cosa que pueda hacer en el contexto de la actividad que maneja sus enlaces profundos.
El enfoque está inspirado en el patrón Front Controller de Martin Fowler.
Agregar dependencias
Paso 1. Agrega el repositorio JitPack a tu archivo de compilación
todos los proyectos { repositorio { … maven { url ‘https://jitpack.io’ } } }
Paso 2. Agrega la dependencia
dependencias {implementación ‘com.github.justeatakeaway:android-deep-links:1.0.0’ }
guía de usuario
Primero debemos designar una actividad que manejará los enlaces profundos entrantes y agregar los filtros de intención necesarios para la actividad en nuestro AndroidManifest.xml de la siguiente manera.
actividad android:name=”.examples.simple.ExampleDeepLinkActivity” android:excludeFromRecents=”true” android:exported=”true” android:launchMode=”singleTask”> herramientas de filtrado intent:ignore=”AppLinkUrlError”> acción android:name = “android.intent.action.VIEW” /> categoría android:name=”android.intent.category.DEFAULT” /> datos android:scheme=”https” /> datos android:host=”simple.site.com” / > filtro de intención > actividad >
Con nuestro filtro de intención definido, podemos definir nuestro enrutamiento; para el enfoque más simple, usamos la función de extensión deepLinkRouter para realizar la mayor parte de la configuración por nosotros.
clase EjemploDeepLinkActivity: ComponentActivity() { anular diversión onCreate(savedInstanceState: ¿Paquete?) { super.onCreate(savedInstanceState) deepLinkRouter { esquemas(“https”) host(“simple.site.com”) “/home” mapTo { HomeCommand() } “/productos/[a-zA-Z0-9]*” mapTo { ProductCommand() } }.route(intent.data?: Uri.EMPTY) } }
En el ejemplo asignamos las rutas /home a un HomeCommand y también a /product/[a-zA-Z0-9]* respectivamente a un ProductCommand.
La parte de la ruta es lo que sigue a la parte del host del URI como https://simple.site.com/products/123 y en nuestro mapeo la definimos como Regex.
Para ProductCommand lo asignamos a una expresión regular que corresponde a un ID de producto del modelo. [a-zA-Z0-9]*
Comandos
Con nuestro mapeo definido y asignado a comandos, necesitamos hacer que nuestros comandos hagan algo.
Normalmente, un comando simplemente inicia una tarea, sin embargo, puede hacer más (más sobre esto más adelante).
El siguiente comando es para el patrón de ruta /home.
clase HomeCommand: Comando() { anular diversión ejecutar() = navegar { contexto -> contexto.startActivity(Intent(context, HomeActivity::class.java)) } }
Si observa el ejemplo de HomeCommand, observará el bloque navegar { .. }.
Los comandos deben terminar con un bloque de navegación {}, y el bloque debe definir lo que debe suceder una vez que se completa el comando. La razón de esto es que los comandos pueden funcionar con corrutinas (más sobre esto más adelante) y, a veces, un comando puede tardar más en completarse y también pasar por cambios de configuración de Android. El bloque de navegación {} se llamará en el momento en que sea seguro hacerlo en el ciclo de vida de la interfaz de usuario de Android y dado el contexto actual para que pueda realizar de forma segura cosas como la navegación por intención.
Aparte de la larga explicación del bloque de navegación, un comando es en su mayoría simple y todo lo que hace es redirigir a una actividad, en este caso HomeActivity.
El siguiente ejemplo es ProductCommand asignado al patrón /products/[a-zA-Z0-9]*
clase ProductCommand: Command() { valor privado productId por pathSegment(1) anular diversión ejecutar() = navegar { contexto -> contexto.startActivity( Intent(context, ProductActivity::class.java) .putExtra(“productId”, productId) ) } }
Este comando extrae un segmento de ruta desde la posición 1 en el URI, que es la parte coincidente. [a-zA-Z0-9]* proporcionándonos su ID de producto. Logramos esto utilizando el conveniente delegado de propiedad pathSegment(index).
Al igual que con pathSegment(index), también podemos usar queryParam(name) para obtener los parámetros de consulta del URI; si eso no es suficiente, puede acceder a una propiedad uri que le proporcionará android.net.Uri.
ProductCommand finaliza con la navegación { } que crea una intención para ProductActivity al pasar el ID del producto extraído del Uri como una intención adicional.
Pruebe sus enlaces directos
Para probar los atajos, puede usar un comando de shell ADB para iniciar su aplicación y proporcionarle un atajo; el siguiente ejemplo muestra cómo iniciarla con un atajo asignado a HomeCommand.
adb shell soy inicio -W -a android.intent.action.VIEW -d “https://simple.site.com/home” com.jet.android.links
En el comando especificamos qué aplicación iniciar usando el nombre del paquete com.jet.android.links.
Puedes leer más al respecto en los documentos oficiales para desarrolladores de Android. https://developer.android.com/training/app-links/deep-linking#testing-filters
De manera similar, para asignar ProductCommand, podemos usar el patrón URI con ID de producto de la siguiente manera.
adb shell soy inicio -W -a android.intent.action.VIEW -d “https://simple.site.com/products/abcd1234” com.jet.android.links
Requisitos de comando
Interceptar un enlace profundo y pasarlo a un comando es útil; podemos inspeccionar el enlace profundo y enrutarlo en la aplicación a una tarea o lo que sea. A veces, sin embargo, podemos necesitar más información del usuario que se conecta directamente a la aplicación o podemos exigirle que cumpla con un estado particular, como autenticación o geolocalización.
Para manejar estas situaciones podemos usar Requisitos de comando, una manera elegante de suspender un comando hasta que se cumplan los requisitos.
El siguiente ejemplo muestra cómo lograr esto usando las funciones require() y satisface(Any) de Link API.
class OrderDetailsCommand: Command() { val privado orderId por pathSegment(1) var privado loginResult: LoginResult? = nulo anular diversión ejecutar() { lanzar { loginResult = require() } navegar { contexto -> contexto.startActivity( Intent(context, OrderDetailsActivity::class.java) .putExtra(“orderId”, orderId) .putExtra(“loginName “, loginResult!!.nombre) ) } } }
En el comando anterior, cuando presionamos la línea loginResult = require() nuestro comando se detendrá y esperará el valor de require().
Para que el comando continúe, debemos indicarle al enrutador/controlador que cumpla (cualquiera) el requisito.
El siguiente ejemplo muestra una configuración de enrutador de enlace directo que asigna un enlace directo entrante al patrón de ruta /orders/[a-zA-Z0-9]* al comando OrderDertails. Esto corresponderá a un enlace directo como https://requirements.site.com/orders/abcd1234
clase EjemploDeepLinkActivity: ComponentActivity() { enrutador de valor privado por lazy { deepLinkRouter { esquemas(“https”) host(“requirements.site.com”) “/home” mapTo { HomeCommand() } “/orders/[a-zA-Z0-9]*” mapTo { OrderDetailsCommand() } } } val privado loginForResult = RegisterForActivityResult(StartActivityForResult()) { val loginName = it.data!!.getStringExtra(“loginName”)!! router.satisfy(LoginResult(nombre = loginName)) } anular diversión onCreate(savedInstanceState: ¿Paquete?) { super.onCreate(savedInstanceState) router.onRequirement(this) { if (it == LoginResult::class.java) { startLoginActivity() } } router.route(intent.data?: Uri.EMPTY) } diversión privada startLoginActivity() { loginForResult.launch(Intent(this, LoginActivity::class.java)) } }
Usamos la API de resultados de actividad para iniciar una nueva actividad de inicio de sesión, el usuario ingresa su nombre y regresa con un botón de inicio de sesión. Cuando el usuario regresa a ExampleDeepLinkActivity, extraemos el argumento loginName del resultado de Intent (el nombre que ingresaron en el campo de nombre en la pantalla de inicio de sesión) y luego llamamos a router.satisfy(LoginResult(name = loginName)) pasando el nombre de inicio de sesión.
Para iniciar LoginActivity necesitamos decirle al enrutador qué hacer cuando un comando cumple con un requisito
router.onRequirement(this) { if (it == LoginResult::class.java) { startLoginActivity() } }
Logramos esto llamando a onRequirement y si hemos probado el requisito de LoginResult y si es verdadero, iniciamos la actividad de inicio de sesión usando startLoginActivity() que simplemente inicia LoginActivity.
Finalización del comando
Cuando se completa un comando, el comportamiento predeterminado al usar la función de extensión deepLinkRouter para configurar un enrutador llamará a la función de navegación (Contexto) de los comandos y luego llamará a terminar() en la tarea.
Si desea hacer algo diferente, puede proporcionar su propia devolución de llamada de finalización de comando.
router.onCommandComplete(this) { cuando (it) { es DeepLinkRouter.Result.Complete -> { // TODO hacer algo antes de navegar.navigate(this) // TODO hacer algo después de navegar final() } es DeepLinkRouter.Result. Cancelado -> { // TODO maneja la cancelación del comando } } }
Mirando el ejemplo, llamamos a onCommpandComplete(LifecycleOwner, (DeepLinkRouter.Result) -> Unit) con una devolución de llamada que puede manejar el resultado y luego debemos llamarlo.navigate(this) para ejecutar manualmente la función de navegación de comandos. Luego puedes finalizar() la tarea (el patrón habitual) o hacer otra cosa.
Además de gestionar la finalización del comando, también podemos definir qué sucede cuando se cancela el comando, esto sucederá si se cancela la rutina de trabajo del comando.
Referencias
LICENCIA
Copyright 2022 Sólo come comida para llevar
Licenciado bajo la Licencia Apache, Versión 2.0 (la “Licencia”); no puede utilizar este archivo excepto de acuerdo con la Licencia. Puede obtener una copia de la licencia en
http://www.apache.org/licenses/LICENSE-2.0
A menos que lo exija la ley aplicable o se acuerde por escrito, el software distribuido bajo la Licencia se distribuye “TAL CUAL”, SIN GARANTÍAS NI CONDICIONES DE NINGÚN TIPO, expresas o implícitas. Consulte la Licencia para conocer el idioma específico que rige los permisos y limitaciones de la Licencia.