Skip to content

Deep linking de mensagem no app

Aprenda como fazer deep link dentro de uma mensagem no app para o SDK Braze.

Pré-requisitos

Antes de usar este recurso, você precisará integrar o SDK Android Braze.

Criando um delegado universal

O SDK do Android oferece a capacidade de definir um único objeto delegado para tratar de forma personalizada todos os deep links abertos pela Braze nos Cartões de conteúdo, mensagens no app e notificações por push.

Seu objeto delegado deve implementar a interface IBrazeDeeplinkHandler e ser definido usando BrazeDeeplinkHandler.setBrazeDeeplinkHandler(). Na maioria dos casos, o delegado deve ser definido no Application.onCreate() do seu app.

Veja a seguir um exemplo de substituição do comportamento padrão de UriAction com flags de intent personalizadas e comportamento personalizado para URLs do 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)
  }
}

Deep linking para as configurações do app

Para permitir que deep links abram diretamente as configurações do seu app, você precisará de um BrazeDeeplinkHandler personalizado. No exemplo a seguir, a presença de um par de chave-valor personalizado chamado open_notification_page fará com que o deep link abra a página de configurações do app:

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)
    }
  }
})

Personalizando a atividade WebView

Quando a Braze abre deep links de sites dentro do app, eles são tratados pela BrazeWebViewActivity.

Para mudar isso:

  1. Crie uma nova Activity que trate a URL de destino a partir de Intent.getExtras() com a chave com.braze.Constants.BRAZE_WEBVIEW_URL_EXTRA. Para ver um exemplo, consulte BrazeWebViewActivity.kt.
  2. Adicione essa Activity ao AndroidManifest.xml e defina exported como false.
    1
    2
    3
    
     <activity
         android:name=".MyCustomWebViewActivity"
         android:exported="false" />
    
  3. Defina sua Activity personalizada em um objeto builder de BrazeConfig. Construa o builder e passe-o para Braze.configure() no seu 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)

Solução de problemas

Se os deep links de notificações por push não estiverem funcionando no Android, tente os seguintes passos:

  1. Teste o deep link fora da Braze. Abra a URL do deep link a partir de outro app, como e-mail ou navegador. Se ele não abrir seu app, o deep link pode não estar configurado corretamente no seu AndroidManifest.xml. Para saber mais, consulte a documentação do Android sobre Criar deep links.
  2. Verifique se o tratamento automático de deep links está ativado. Confirme que com_braze_handle_push_deep_links_automatically está definido como true no braze.xml, ou defina essa opção por meio da configuração em tempo de execução. Sem essa configuração, a Braze não abre automaticamente seu app e o destino do deep link quando alguém toca em uma notificação por push.
  3. Verifique o delegado do seu deep link handler. Se você definiu um IBrazeDeeplinkHandler personalizado, confirme que sua implementação de gotoUri trata a URI e não a descarta.
  4. Teste em diferentes canais. Se o mesmo deep link funciona em uma mensagem no app, mas não a partir de push, o problema provavelmente está no tratamento do deep link de push, e não no deep link em si.

Usando Jetpack Compose

Para tratar deep links ao usar Jetpack Compose com NavHost:

  1. Certifique-se de que a Activity que trata seu deep link está registrada no Android Manifest.
    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. No NavHost, especifique quais deep links você deseja que ele trate.
    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. Dependendo da arquitetura do seu app, você também pode precisar tratar o novo intent que é enviado para sua Activity atual.
    1
    2
    3
    4
    5
    6
    7
    
     DisposableEffect(Unit) {
         val listener = Consumer<Intent> {
             navHostController.handleDeepLink(it)
         }
         addOnNewIntentListener(listener)
         onDispose { removeOnNewIntentListener(listener) }
     }
    

Pré-requisitos

Antes de poder usar esse recurso, você precisará integrar o Swift Braze SDK.

Etapa 1: Registrar um esquema

Para lidar com o deep linking, um esquema personalizado deve ser declarado em seu arquivo Info.plist. A estrutura de navegação é definida por uma matriz de dicionários. Cada um desses dicionários contém um vetor de strings.

Use o Xcode para editar seu Info.plist arquivo:

  1. Adicione uma nova chave, URL types. O Xcode fará automaticamente disso um vetor contendo um dicionário chamado Item 0.
  2. Dentro de Item 0, adicione uma chave URL identifier. Defina o valor para seu esquema personalizado.
  3. Dentro de Item 0, adicione uma chave URL Schemes. Isso será automaticamente um vetor contendo uma Item 0 string.
  4. Defina URL Schemes » Item 0 para seu esquema personalizado.

Alternativamente, se você deseja editar seu arquivoInfo.plist diretamente, siga esta especificação:

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>

Etapa 2: Adicionar uma lista de permissão de esquema

Você deve declarar os esquemas de URL que deseja passar para canOpenURL(_:) adicionando a chave LSApplicationQueriesSchemes ao arquivo Info.plist do seu app. Tentar chamar esquemas fora desta lista de permissão fará com que o sistema registre um erro nos logs do dispositivo, e o deep link não abrirá. Um exemplo desse erro é o seguinte:

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

Por exemplo, se uma mensagem no app deve abrir o aplicativo do Facebook ao ser tocada, o app deve ter o esquema personalizado do Facebook (fb) em sua lista de permissões. Caso contrário, o sistema rejeitará o deep link. Os deep linkings que direcionam para uma página ou exibição dentro do seu próprio aplicativo ainda exigem que o esquema personalizado do seu aplicativo seja listado no site Info.plist.

Seu exemplo de lista de permissões pode ser algo como:

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

Para saber mais, consulte a documentação da Apple sobre a tecla LSApplicationQueriesSchemes.

Etapa 3: Implementar um manipulador

Depois de ativar seu app, o iOS chamará o método application:openURL:options:. O argumento importante é o 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;
}

Segurança de Transporte de Aplicativos (ATS)

Conforme definido por Apple, “A Segurança de Transporte de Aplicativos é um recurso que melhora a segurança das conexões entre um app e serviços web.” O recurso consiste em requisitos de conexão padrão que estão em conformidade com as melhores práticas para conexões seguras. Os apps podem substituir esse comportamento padrão e desativar a segurança de transporte.”

O ATS é aplicado por padrão. Requer que todas as conexões usem HTTPS e sejam criptografadas usando TLS 1.2 com sigilo direto. Consulte Requisitos para Conexão Usando ATS para saber mais. Todas as imagens servidas pela Braze para dispositivos finais são gerenciadas por uma rede de entrega de conteúdo (“CDN”) que suporta TLS 1.2 e é compatível com ATS.

A menos que sejam especificados como exceções na Info.plist do seu aplicativo, conexões que não seguem esses requisitos falharão com erros semelhantes aos seguintes.

Exemplo de Erro 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."

Exemplo de Erro 2:

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

A conformidade com ATS é aplicada para links abertos dentro do app móvel (nosso tratamento padrão de links clicados) e não se aplica a sites abertos externamente por meio de um navegador da web.

Trabalhando com ATS

Você pode lidar com ATS de uma das seguintes maneiras, mas recomendamos cumprir os requisitos do ATS.

Sua integração com a Braze pode atender aos requisitos do ATS, garantindo que todos os links existentes para os quais você direciona os usuários (por exemplo, por meio de mensagens no app e campanhas de mensagens) atendam aos requisitos do ATS. Embora existam maneiras de contornar as restrições do ATS, nossa recomendação é garantir que todos os URLs vinculados estejam em conformidade com o ATS. Dada a ênfase crescente da Apple à segurança de aplicativos, as seguintes abordagens para permitir exceções ATS podem não ser compatíveis.

Você pode permitir que um subconjunto de links com determinados domínios ou esquemas sejam tratados como exceções às regras do ATS. Sua integração com o Braze atenderá aos requisitos do ATS se todos os links usados em um canal de envio de mensagens do Braze estiverem em conformidade com o ATS ou forem tratados por uma exceção.

Para adicionar um domínio como exceção do ATS, adicione o seguinte ao arquivo Info.plist do seu app:

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>

Consulte o artigo da Apple sobre [chaves de segurança de transporte de app para saber mais.

Você pode desativar o ATS completamente. Nota que isso não é uma prática recomendada, devido tanto à perda de proteções de segurança quanto à compatibilidade futura com o iOS. Para desativar o ATS, insira o seguinte no arquivo Info.plist do seu app:

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

Decodificando URLs

O SDK codifica os links em porcentagem para criar URLs válidos. Todos os caracteres de link que não são permitidos em um URL devidamente formado, como caracteres Unicode, serão escapados por porcentagem.

Para decodificar um link codificado, use a propriedade String removingPercentEncoding. Você também deve retornar true em BrazeDelegate.braze(_:shouldOpenURL:). Uma chamada para ação é necessária para disparar o tratamento da URL pelo seu aplicativo. Por exemplo:

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;
}

Deep linking para as configurações do app

Você pode aproveitar UIApplicationOpenSettingsURLString para direcionar usuários para as configurações do seu app a partir de notificações push do Braze e mensagens dentro do app.

Para levar os usuários do seu app para as configurações do iOS:

  1. Primeiro, confira se o seu aplicativo está configurado para [links profundos baseados em esquema ou [links universais.
  2. Decida sobre um URI para deep linking para a página de Configurações (por exemplo, myapp://settings ou https://www.braze.com/settings).
  3. Se você estiver usando links profundos baseados em esquemas personalizados, adicione o seguinte código ao seu 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;
}

Opções de personalização

Personalização padrão do WebView

A classe Braze.WebViewController exibe URLs da web abertas pelo SDK, normalmente quando “Abrir URL da Web Dentro do App” é selecionado para um deep link da web.

Você pode personalizar Braze.WebViewController por meio do método delegado BrazeDelegate.braze(_:willPresentModalWithContext:).

O protocolo BrazeDelegate pode ser usado para personalizar o tratamento de URLs, como deep links, URLs da web e links universais. Para definir o delegado durante a inicialização da Braze, defina um objeto delegado na instância Braze. Braze chamará a implementação do seu delegado de shouldOpenURL antes de lidar com qualquer URI.

O Braze oferece suporte a links universais em notificações por push, mensagens no app e cartões de conteúdo. Para ativar o suporte a links universais, configuration.forwardUniversalLinks deve ser definido como true.

Quando ativada, a Braze encaminhará links universais para o AppDelegate do seu app por meio do método application:continueUserActivity:restorationHandler:.

Seu aplicativo também precisa ser configurado para lidar com links universais. Consulte a documentação da Apple para garantir que seu aplicativo esteja configurado corretamente para links universais.

Exemplos

BrazeDelegate

Aqui está um exemplo usando BrazeDelegate. Para mais informações, veja referência do SDK Braze Swift.

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!