Skip to content

Mensagens no app com deep link

Aprenda como usar 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 pelo 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 UriAction com sinalizadores de intenção personalizados 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)
  }
}

Para permitir que os 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 o Braze abre links profundos de sites dentro do app, os links profundos são tratados por BrazeWebViewActivity.

Para mudar isso:

  1. Crie uma nova atividade que manipule o direcionamento do URL de Intent.getExtras() com a chave com.braze.Constants.BRAZE_WEBVIEW_URL_EXTRA. Para um exemplo, veja BrazeWebViewActivity.kt.
  2. Adicione essa atividade a 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 do construtor BrazeConfig. Construa o construtor 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)

Usando Jetpack Compose

Para tratar links profundos ao usar Jetpack Compose com NavHost:

  1. Certifique-se de que a atividade que trata seu link profundo está registrada no Manifesto do 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. No NavHost, especifique quais links profundos 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ê pode precisar tratar a nova intenção que é enviada para sua atividade atual também.
    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.

Manuseio de deep linking

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

App Transport Security (ATS)

Conforme definido pela Apple, “o App Transport Security é um recurso que melhora a segurança das conexões entre um aplicativo e os serviços da 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 especificadas como exceções no site Info.plist do seu aplicativo, as conexões que não seguirem 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 o ATS de uma das seguintes maneiras, mas recomendamos que você cumpra 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>

Decodificação de 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 o UIApplicationOpenSettingsURLString para fazer um deep link dos usuários para as configurações do seu app a partir das notificações por push e mensagens no app do Braze.

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

Veja um exemplo usando BrazeDelegate. Para saber mais, consulte a referência do 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!