Skip to content

Vinculación en profundidad en mensajes dentro de la aplicación

Aprende a crear vínculos profundos dentro de un mensaje dentro de la aplicación para el SDK de Braze.

Requisitos previos

Antes de poder utilizar esta característica, tendrás que integrar el SDK de Android Braze.

Creación de un delegado universal

El SDK de Android ofrece la posibilidad de establecer un único objeto delegado para gestionar de forma personalizada todos los vínculos profundos abiertos por Braze a través de tarjetas de contenido, mensajes dentro de la aplicación y notificaciones push.

Tu objeto delegado debe implementar la interfaz IBrazeDeeplinkHandler y configurarse mediante la función BrazeDeeplinkHandler.setBrazeDeeplinkHandler(). En la mayoría de los casos, el delegado debe establecerse en la página Application.onCreate() de tu aplicación.

A continuación se muestra un ejemplo de anulación del comportamiento predeterminado UriAction con indicadores de intención personalizados y un comportamiento personalizado para las URL de YouTube:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public class CustomDeeplinkHandler implements IBrazeDeeplinkHandler {
  private static final String TAG = BrazeLogger.getBrazeLogTag(CustomDeeplinkHandler.class);

  @Override
  public void gotoUri(Context context, UriAction uriAction) {
    String uri = uriAction.getUri().toString();
    // Open YouTube URLs in the YouTube app and not our app
    if (!StringUtils.isNullOrBlank(uri) && uri.contains("youtube.com")) {
      uriAction.setUseWebView(false);
    }

    CustomUriAction customUriAction = new CustomUriAction(uriAction);
    customUriAction.execute(context);
  }

  public static class CustomUriAction extends UriAction {

    public CustomUriAction(@NonNull UriAction uriAction) {
      super(uriAction);
    }

    @Override
    protected void openUriWithActionView(Context context, Uri uri, Bundle extras) {
      Intent intent = getActionViewIntent(context, uri, extras);
      intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
      if (intent.resolveActivity(context.getPackageManager()) != null) {
        context.startActivity(intent);
      } else {
        BrazeLogger.w(TAG, "Could not find appropriate activity to open for deep link " + uri + ".");
      }
    }
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class CustomDeeplinkHandler : IBrazeDeeplinkHandler {

  override fun gotoUri(context: Context, uriAction: UriAction) {
    val uri = uriAction.uri.toString()
    // Open YouTube URLs in the YouTube app and not our app
    if (!StringUtils.isNullOrBlank(uri) && uri.contains("youtube.com")) {
      uriAction.useWebView = false
    }

    val customUriAction = CustomUriAction(uriAction)
    customUriAction.execute(context)
  }

  class CustomUriAction(uriAction: UriAction) : UriAction(uriAction) {

    override fun openUriWithActionView(context: Context, uri: Uri, extras: Bundle) {
      val intent = getActionViewIntent(context, uri, extras)
      intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP
      if (intent.resolveActivity(context.packageManager) != null) {
        context.startActivity(intent)
      } else {
        BrazeLogger.w(TAG, "Could not find appropriate activity to open for deep link $uri.")
      }
    }
  }

  companion object {
    private val TAG = BrazeLogger.getBrazeLogTag(CustomDeeplinkHandler::class.java)
  }
}

Vínculo profundo con la configuración de la aplicación

Para permitir que los vínculos profundos abran directamente la configuración de tu aplicación, necesitarás una página personalizada BrazeDeeplinkHandler. En el siguiente ejemplo, la presencia de un par clave-valor personalizado llamado open_notification_page hará que el vínculo profundo abra la página de configuración de la aplicación:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
BrazeDeeplinkHandler.setBrazeDeeplinkHandler(new IBrazeDeeplinkHandler() {
  @Override
  public void gotoUri(Context context, UriAction uriAction) {
    final Bundle extras = uriAction.getExtras();
    if (extras.containsKey("open_notification_page")) {
      Intent intent = new Intent();
      intent.setAction("android.settings.APP_NOTIFICATION_SETTINGS");
      intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

      //for Android 5-7
      intent.putExtra("app_package", context.getPackageName());
      intent.putExtra("app_uid", context.getApplicationInfo().uid);

      // for Android 8 and later
      intent.putExtra("android.provider.extra.APP_PACKAGE", context.getPackageName());
      context.startActivity(intent);
    }
  }
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
BrazeDeeplinkHandler.setBrazeDeeplinkHandler(object : IBrazeDeeplinkHandler {
  override fun gotoUri(context: Context, uriAction: UriAction) {
    val extras = uriAction.extras
    if (extras.containsKey("open_notification_page")) {
      val intent = Intent()
      intent.action = "android.settings.APP_NOTIFICATION_SETTINGS"
      intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK

      //for Android 5-7
      intent.putExtra("app_package", context.packageName)
      intent.putExtra("app_uid", context.applicationInfo.uid)

      // for Android 8 and later
      intent.putExtra("android.provider.extra.APP_PACKAGE", context.packageName)
      context.startActivity(intent)
    }
  }
})

Personalización de la actividad WebView

Cuando Braze abre enlaces profundos de sitios web dentro de la aplicación, los enlaces profundos son gestionados por BrazeWebViewActivity.

Para cambiar esto:

  1. Crea una nueva Actividad que maneje la URL de destino de Intent.getExtras() con la clave com.braze.Constants.BRAZE_WEBVIEW_URL_EXTRA. Por ejemplo, véase BrazeWebViewActivity.kt.
  2. Añade esa actividad a AndroidManifest.xml y establece exported en false.
    1
    2
    3
    
     <activity
         android:name=".MyCustomWebViewActivity"
         android:exported="false" />
    
  3. Configura tu Actividad personalizada en un objeto constructor de BrazeConfig. Crea el constructor y pásalo aBraze.configure() en tu Application.onCreate().
1
2
3
4
5
BrazeConfig brazeConfig = new BrazeConfig.Builder()
    .setCustomWebViewActivityClass(MyCustomWebViewActivity::class)
    ...
    .build();
Braze.configure(this, brazeConfig);
1
2
3
4
5
val brazeConfig = BrazeConfig.Builder()
    .setCustomWebViewActivityClass(MyCustomWebViewActivity::class.java)
    ...
    .build()
Braze.configure(this, brazeConfig)

Uso de Jetpack Compose

Para gestionar enlaces profundos cuando usas Jetpack Compose con NavHost:

  1. Asegúrate de que la actividad que gestiona tu enlace profundo esté registrada en el registro del manifiesto de Android.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    
     <activity
       ...
       <intent-filter>
         <action android:name="android.intent.action.VIEW" />
         <category android:name="android.intent.category.BROWSABLE" />
         <category android:name="android.intent.category.DEFAULT" />
         <data
             android:host="articles"
             android:scheme="myapp" />
       </intent-filter>
     </activity>
    
  2. En NavHost, especifica qué enlaces profundos quieres que gestione.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    
     composableWithCompositionLocal(
         route = "YOUR_ROUTE_HERE",
         deepLinks = listOf(navDeepLink {
             uriPattern = "myapp://articles/{${MainDestinations.ARTICLE_ID_KEY}}"
         }),
         arguments = listOf(
             navArgument(MainDestinations.ARTICLE_ID_KEY) {
                 type = NavType.LongType
             }
         ),
     ) { backStackEntry ->
         val arguments = requireNotNull(backStackEntry.arguments)
         val articleId = arguments.getLong(MainDestinations.ARTICLE_ID_KEY)
         ArticleDetail(
             articleId
         )
     }
    
  3. Dependiendo de la arquitectura de tu aplicación, es posible que también tengas que gestionar la nueva intención que se envía a tu actividad actual.
    1
    2
    3
    4
    5
    6
    7
    
     DisposableEffect(Unit) {
         val listener = Consumer<Intent> {
             navHostController.handleDeepLink(it)
         }
         addOnNewIntentListener(listener)
         onDispose { removeOnNewIntentListener(listener) }
     }
    

Requisitos previos

Antes de poder utilizar esta característica, tendrás que integrar el SDK de Swift Braze.

Manejo de vínculos profundos

Paso 1: Registrar un plan

Para gestionar la vinculación en profundidad, debe indicarse un esquema personalizado en tu archivo Info.plist. La estructura de navegación está definida por una matriz de diccionarios. Cada uno de esos diccionarios contiene una matriz de cadenas.

Utiliza Xcode para editar tu archivo Info.plist:

  1. Añade una nueva clave, URL types. Xcode lo convertirá automáticamente en una matriz que contiene un diccionario llamado Item 0.
  2. Dentro de Item 0, añade una clave URL identifier. Ajusta el valor a tu esquema personalizado.
  3. Dentro de Item 0, añade una clave URL Schemes. Será automáticamente una matriz que contendrá una cadena Item 0.
  4. Configura URL Schemes » Item 0 a tu esquema personalizado.

Alternativamente, si deseas editar tu archivo Info.plist directamente, puedes seguir esta especificación:

1
2
3
4
5
6
7
8
9
10
11
<key>CFBundleURLTypes</key>
<array>
    <dict>
        <key>CFBundleURLName</key>
        <string>YOUR.SCHEME</string>
        <key>CFBundleURLSchemes</key>
        <array>
            <string>YOUR.SCHEME</string>
        </array>
    </dict>
</array>

Paso 2: Añadir una lista de permitidos para el esquema

Debes declarar los esquemas de URL que deseas pasar a canOpenURL(_:) añadiendo la clave LSApplicationQueriesSchemes al archivo Info.plist de tu aplicación. Intentar llamar a esquemas fuera de esta lista permitida hará que el sistema registre un error en los registros del dispositivo, y el vínculo profundo no se abrirá. Un ejemplo de este error tendrá el siguiente aspecto:

1
<Warning>: -canOpenURL: failed for URL: "yourapp://deeplink" – error: "This app is not allowed to query for scheme yourapp"

Por ejemplo, si un mensaje dentro de la aplicación debe abrir la aplicación de Facebook al tocarlo, la aplicación tiene que tener el esquema personalizado de Facebook (fb) en tu lista de permitidos. De lo contrario, el sistema rechazará el deep link. Los vínculos profundos que dirigen a una página o vista dentro de tu propia aplicación siguen requiriendo que el esquema personalizado de tu aplicación aparezca en el sitio Info.plist de tu aplicación.

Tu lista de permitidos de ejemplo podría ser algo así

1
2
3
4
5
6
<key>LSApplicationQueriesSchemes</key>
<array>
    <string>myapp</string>
    <string>fb</string>
    <string>twitter</string>
</array>

Para más información, consulta la documentación de Apple sobre la tecla LSApplicationQueriesSchemes.

Paso 3: Implementa un controlador

Tras activar tu aplicación, iOS llamará al método application:openURL:options:. El argumento importante es el objeto NSURL.

1
2
3
4
5
6
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
  let path = url.path
  let query = url.query
  // Insert your code here to take some action based upon the path and query.
  return true
}
1
2
3
4
5
6
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey, id> *)options {
  NSString *path  = [url path];
  NSString *query = [url query];
  // Insert your code here to take some action based upon the path and query.
  return YES;
}

Seguridad de transporte de aplicaciones (ATS)

Según la definición de Apple, «App Transport Security es una característica que mejora la seguridad de las conexiones entre una aplicación y los servicios Web». La característica consiste en requisitos de conexión predeterminados que se ajustan a las mejores prácticas para conexiones seguras. Las aplicaciones pueden anular este comportamiento predeterminado y desactivar la seguridad del transporte”.

El ATS se aplica por predeterminado. Requiere que todas las conexiones utilicen HTTPS y estén encriptadas mediante TLS 1.2 con confidencialidad directa. Consulta los Requisitos para conectarse mediante ATS para obtener más información. Todas las imágenes servidas por Braze a dispositivos finales son gestionadas por una red de entrega de contenidos (“CDN”) que admite TLS 1.2 y es compatible con ATS.

A menos que se especifiquen como excepciones en la aplicaciónInfo.plist, las conexiones que no cumplan estos requisitos fallarán con errores similares a los siguientes.

Ejemplo de error 1:

1
2
CFNetwork SSLHandshake failed (-9801)
Error Domain=NSURLErrorDomain Code=-1200 "An SSL error has occurred, and a secure connection to the server cannot be made."

Ejemplo de error 2:

1
NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9802)

El cumplimiento de la ATS se aplica a los enlaces abiertos dentro de la aplicación móvil (nuestro tratamiento predeterminado de los enlaces en los que se hace clic) y no se aplica a los sitios abiertos externamente a través de un navegador web.

Trabajar con ATS

Puedes gestionar los ATS de cualquiera de las siguientes maneras, pero te recomendamos que cumplas con los requisitos de los ATS.

Tu integración con Braze puede satisfacer los requisitos de ATS asegurándote de que cualquier enlace existente al que dirijas a los usuarios (por ejemplo, mediante campañas de mensajería dentro de la aplicación y notificaciones push) satisfaga los requisitos de ATS. Aunque hay formas de eludir las restricciones de la ATS, nuestra recomendación es que te asegures de que todas las URL enlazadas cumplen la ATS. Dado el creciente énfasis de Apple en la seguridad de las aplicaciones, no está garantizado que Apple admita los siguientes enfoques para permitir excepciones ATS.

Puedes permitir que un subconjunto de enlaces con determinados dominios o esquemas sean tratados como excepciones a las normas ATS. Tu integración Braze satisfará los requisitos de ATS si cada enlace que utilices en un canal de mensajería Braze es compatible con ATS o se gestiona mediante una excepción.

Para añadir un dominio como excepción del ATS, añade lo siguiente al archivo Info.plist de tu aplicación:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<key>NSAppTransportSecurity</key>
<dict>
    <key>NSAllowsArbitraryLoads</key>
    <true/>
    <key>NSExceptionDomains</key>
    <dict>
        <key>example.com</key>
        <dict>
            <key>NSExceptionAllowsInsecureHTTPLoads</key>
            <false/>
            <key>NSIncludesSubdomains</key>
            <true/>
        </dict>
    </dict>
</dict>

Consulta el artículo de Apple sobre las claves de seguridad para el transporte de aplicaciones para obtener más información.

Puedes desactivar ATS por completo. Ten en cuenta que no es una práctica recomendada, tanto por la pérdida de protecciones de seguridad como por la futura compatibilidad con iOS. Para desactivar ATS, inserta lo siguiente en el archivo Info.plist de tu aplicación:

1
2
3
4
5
<key>NSAppTransportSecurity</key>
<dict>
    <key>NSAllowsArbitraryLoads</key>
    <true/>
</dict>

Descodificación de URL

El SDK codifica porcentualmente los enlaces para crear URL válidos. Todos los caracteres de enlace que no estén permitidos en una URL correctamente formada, como los caracteres Unicode, se escaparán en porcentaje.

Para descodificar un enlace codificado, utiliza la propiedad String removingPercentEncoding. También debes devolver true en la dirección BrazeDelegate.braze(_:shouldOpenURL:). Se necesita una llamada a la acción para desencadenar el manejo de la URL por parte de tu aplicación. Por ejemplo:

1
2
3
4
5
  func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
    let urlString = url.absoluteString.removingPercentEncoding
    // Handle urlString
    return true
  }
1
2
3
4
5
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url options:(NSDictionary<NSString *, id> *)options {
  NSString *urlString = [url.absoluteString stringByRemovingPercentEncoding];
  // Handle urlString
  return YES;
}

Vinculación en profundidad con la configuración de la aplicación

Puedes aprovecharUIApplicationOpenSettingsURLString para dirigir a los usuarios a la configuración de tu aplicación desde las notificaciones push y los mensajes dentro de la aplicación de Braze.

Para llevar a los usuarios de tu aplicación a la configuración de iOS:

  1. En primer lugar, asegúrate de que tu aplicación está configurada para enlaces profundos basados en esquemas o enlaces universales.
  2. Decide un URI para la vinculación en profundidad a la página de configuración (por ejemplo, myapp://settings o https://www.braze.com/settings).
  3. Si utilizas vínculos profundos personalizados basados en esquemas, añade el siguiente código a tu método application:openURL:options::
1
2
3
4
5
6
7
func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool {
  let path = url.path
  if (path == "settings") {
    UIApplication.shared.openURL(URL(string:UIApplication.openSettingsURLString)!)
  }
  return true
}
1
2
3
4
5
6
7
8
9
10
- (BOOL)application:(UIApplication *)app
            openURL:(NSURL *)url
            options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {
  NSString *path  = [url path];
  if ([path isEqualToString:@"settings"]) {
    NSURL *settingsURL = [NSURL URLWithString:UIApplicationOpenSettingsURLString];
    [[UIApplication sharedApplication] openURL:settingsURL];
  }
  return YES;
}

Opciones de personalización

Personalización predeterminada de WebView

La clase Braze.WebViewController muestra las URL web abiertas por el SDK, normalmente, cuando se selecciona “Abrir URL web dentro de la aplicación” para un vínculo profundo a la web.

Puedes personalizar el Braze.WebViewController mediante el método delegado BrazeDelegate.braze(_:willPresentModalWithContext:).

Personalización de la gestión de enlaces

El protocolo BrazeDelegate puede utilizarse para personalizar el tratamiento de las URL, como los vínculos profundos, las URL web y los vínculos universales. Para configurar el delegado durante la inicialización de Braze, establece un objeto delegado en la instancia de Braze. A continuación, Braze llamará a la implementación de shouldOpenURL de tu delegado antes de gestionar cualquier URI.

Braze admite enlaces universales en notificaciones push, mensajes dentro de la aplicación y tarjetas de contenido. Para habilitar la compatibilidad con el enlace universal, configuration.forwardUniversalLinks debe estar configurado en true.

Cuando esté habilitado, Braze reenviará los enlaces universales a la página AppDelegate de tu aplicación mediante el método application:continueUserActivity:restorationHandler: método.

Tu aplicación también debe estar configurada para gestionar enlaces universales. Consulta la documentación de Apple para asegurarte de que tu aplicación está configurada correctamente para los enlaces universales.

Ejemplos

BrazeDelegate

Aquí tienes un ejemplo utilizando BrazeDelegate. Para obtener más información, consulta la referencia de Braze SWIFT SDK.

1
2
3
4
5
6
7
8
func braze(_ braze: Braze, shouldOpenURL context: Braze.URLContext) -> Bool {
  if context.url.host == "MY-DOMAIN.com" {
    // Custom handle link here
    return false
  }
  // Let Braze handle links otherwise
  return true
}
1
2
3
4
5
6
7
8
- (BOOL)braze:(Braze *)braze shouldOpenURL:(BRZURLContext *)context {
  if ([[context.url.host lowercaseString] isEqualToString:@"MY-DOMAIN.com"]) {
    // Custom handle link here
    return NO;
  }
  // Let Braze handle links otherwise
  return YES;
}
New Stuff!