Pular para o conteúdo

Visão geral ​

notti-android é o SDK nativo oficial de Android para notificações push do Notti (FCM). Ele cuida do registro de dispositivo, identidade do usuário, tags, eventos de engajamento (received / opened / clicked) e mensagens in-app, para que a integração nunca precise montar chamadas REST manualmente contra a API de Devices. É escrito em Kotlin, pode ser chamado de Java e é publicado no Maven Central como br.com.zeeplabs:notti-android.

A versão 0.2.0 (lançada em 2026-11-04) é a versão atual. A 0.1.0 portou o react-native-notti 0.8.0 para um SDK nativo de Android, com mensagens in-app incluídas, o mesmo contrato com o backend e o mesmo armazenamento no dispositivo; a 0.2.0 adiciona o sdk_name que o dispositivo informa. Veja Limitações conhecidas.

Por padrão, o SDK se comunica com o Notti (https://app.zeepnotti.app), então Notti.initialize só precisa do ID do seu app e da chave de cliente.

Requisitos ​

  • minSdk 24 ou superior e compileSdk 34 ou superior (o AAR declara minCompileSdk 34).
  • Kotlin 2.0 ou mais recente se o seu app tem código Kotlin (o POM declara kotlin-stdlib 2.0.21). Apps somente Java não precisam de nada extra.
  • Um projeto Firebase com o seu app registrado, e o respectivo google-services.json, com as credenciais FCM configuradas no seu App do Notti.
  • Um App do Notti e seus ID do app/chave de cliente - veja Primeiros passos com o Notti para criar um.
  • Um backend do Notti que aceite o que o SDK envia: v0.10.0 ou mais recente para os campos de perfil do dispositivo, v0.11.0 ou mais recente para o evento opened, v0.23.0 ou mais recente para mensagens in-app e v0.24.0 ou mais recente para a desvinculação no logout (veja Limitações conhecidas). Um backend mais antigo rejeita esses campos ou eventos e o SDK os descarta.

Instalação ​

O artefato está no Maven Central:

kotlin
// settings.gradle.kts
dependencyResolutionManagement {
    repositories {
        google()
        mavenCentral()
    }
}

// app/build.gradle.kts
dependencies {
    implementation("br.com.zeeplabs:notti-android:0.2.0")
}

O SDK traz firebase-messaging como dependência api, além de okhttp, androidx.core, androidx.activity, androidx.lifecycle-process e androidx.annotation, nas versões que o react-native-notti 0.8.0 resolve, então ele não força upgrades no seu app. Uma versão mais nova no seu app prevalece.

Configuração do Firebase ​

Coloque o google-services.json do seu app no módulo do app e aplique o plugin Google Services nele (nunca em uma biblioteca):

kotlin
// build.gradle.kts (root)
plugins {
    id("com.google.gms.google-services") version "4.5.0" apply false
}

// app/build.gradle.kts
plugins {
    id("com.android.application")
    id("com.google.gms.google-services")
}

Sem isso o Firebase não inicia: o SDK registra por que não consegue obter o token de push, o dispositivo nunca se registra e o seu app continua rodando. Mantenha o google-services.json fora do controle de versão se a sua política o trata como configuração.

Inicializando e pedindo permissão ​

Chame Notti.initialize uma vez, o mais cedo possível, idealmente em Application.onCreate, com o ID do seu app e a chave de cliente (nunca a chave REST - veja a Referência da API de Apps para entender por quê):

kotlin
class MyApplication : Application() {
    override fun onCreate() {
        super.onCreate()
        Notti.initialize(this, "YOUR_APP_ID", "YOUR_CLIENT_KEY")
    }
}

Sem opções, o SDK se comunica com o host de produção https://app.zeepnotti.app. Para apontar para outro host, passe o seu:

kotlin
Notti.initialize(this, "YOUR_APP_ID", "YOUR_CLIENT_KEY", NottiOptions(baseUrl = "https://push.example.invalid"))

NottiOptions tem dois campos: baseUrl (null para o host padrão) e opensInAppUrls (padrão true, veja Mensagens in-app). O SDK guarda apenas o contexto da aplicação. Chamar initialize de novo com os mesmos valores não faz nada; com valores diferentes, o dispositivo se registra de novo. IDs em branco ou null e uma URL base inválida são registrados no log e ignorados. Nenhuma chamada do SDK lança exceção, nem com argumentos de texto, mapa ou lista null vindos de Java (argumentos de listener e de callback não podem ser null).

Depois, peça permissão quando fizer sentido para o seu usuário:

kotlin
Notti.Notifications.requestPermission { granted -> /* update your UI */ }

POST_NOTIFICATIONS é declarada pelo SDK. No Android 13+, a solicitação mostra o diálogo do sistema a partir da Activity em primeiro plano e informa a resposta. Com o app em segundo plano, ou antes de uma Activity ter sido retomada, ela responde false sem diálogo, e a solicitação não conta como feita (um botão push_permission posterior ainda mostra o prompt). Abaixo do Android 13 não existe permissão em tempo de execução e a solicitação responde true. O SDK informa o estado da permissão ao backend (permission_status) quando ele muda.

SDKs wrapper ​

Notti.initializeForWrapper existe apenas para SDKs wrapper construídos sobre este, como o react-native-notti: é o initialize mais o nome e a versão do SDK que o dispositivo informa (sdk_name, sdk_version) no lugar de android e da versão deste SDK. Ele é marcado com @NottiWrapperApi, então quem chama em Kotlin precisa aceitar com @OptIn(NottiWrapperApi::class) (chamadas Java não são verificadas), e está fora da promessa de versionamento semântico: pode mudar ou desaparecer em qualquer versão. Apps chamam Notti.initialize.

Identidade e tags ​

login vincula o dispositivo ao seu próprio ID de usuário. E-mail, telefone e tags são opcionais e só são enviados quando você os define. logout limpa o ID de usuário externo no dispositivo, envia external_user_id: null para desvinculá-lo no backend e limpa e-mail e telefone no dispositivo (cada limpeza também é enviada ao backend); as tags e a assinatura permanecem.

  • A desvinculação fica guardada no dispositivo até o backend confirmá-la: um logout feito offline, antes de Notti.initialize, ou cuja requisição falhou, é enviado de novo no próximo registro (um login posterior o substitui).
  • Chamadas de login, de tags e de setSubscription feitas antes de Notti.initialize são ignoradas, cada uma com uma linha de erro no log: chame-as depois de initialize. E-mail, telefone, compartilhamento de localização e logout são mantidos e enviados no primeiro registro. Isso exige o NottiInitProvider (o padrão): se você o removeu, toda chamada anterior ao primeiro initialize é descartada com uma linha WARN, que o nível padrão ERROR esconde.
  • Desvincular no backend exige o backend do Notti v0.24.0 ou mais recente: veja Limitações conhecidas.
kotlin
Notti.login("user-123")
Notti.User.addTag("plan", "premium")
Notti.User.addTags(mapOf("tier" to "gold", "region" to "south"))
Notti.User.removeTag("plan")
Notti.User.removeTags(listOf("tier", "region"))
Notti.User.setEmail("user@example.invalid")
Notti.User.setPhone("+5511900000000")
Notti.User.clearEmail()
Notti.User.clearPhone()
Notti.setSubscription(false)            // stop push delivery to this device
Notti.setLocationSharingEnabled(true)   // opt-in country targeting, default off
Notti.logout()

O compartilhamento de localização envia apenas o código do país, resolvido no dispositivo. O SDK nunca pede a permissão de localização: com o compartilhamento ligado e a permissão já concedida pelo seu app, ele lê o país no próximo início de sessão. Desligá-lo também limpa o país no backend.

Tratando eventos de notificação ​

Os listeners recebem o payload de um push que chegou com o app em execução (received) e de um toque (clicked). O SDK nunca abre uma URL ou deep link de push: o data do push chega ao seu código intacto e você decide o que um link significa. (As mensagens in-app são diferentes: o SDK abre uma ação url http/https de mensagem in-app e, para um botão push_permission, as configurações de notificação: veja Mensagens in-app.)

kotlin
val received = Notti.Notifications.addReceivedListener { notification ->
    // A push arrived while the app runs: notification.title, notification.body, notification.data
}
val clicked = Notti.Notifications.addClickedListener { notification ->
    // A notification was tapped: route with notification.data
}
received.remove() // when the listener is no longer needed

val removeDeviceId = Notti.addDeviceIdChangedListener { id -> /* the backend assigned a new device id */ }
val current: String? = Notti.deviceId // null until the first registration

Todo listener e callback roda na main thread. Um push recebido sem listener não é reenviado depois. Enquanto não existe listener de clique, o SDK guarda o último toque e Notti.Notifications.takeInitialClick() o retorna uma vez. Adicione o listener de clique em Application.onCreate, antes de initialize, para receber o toque que abriu o app como um evento; takeInitialClick() então retorna null.

Um toque reporta dois eventos ao Notti, opened e clicked, sob o ID da notificação. Os eventos de entrega (received, opened, clicked) ficam em fila no dispositivo e são reenviados com backoff (veja a política de retentativas em Limitações conhecidas).

Notificações em primeiro plano ​

Enquanto o seu app está em primeiro plano, o Firebase não exibe um push do tipo notification. O SDK reporta received e chama os seus listeners de recebimento; exibir a notificação fica por sua conta.

Activities singleTop e singleTask ​

Um toque em uma notificação com o app em execução entrega um novo Intent em onNewIntent. O SDK lê o Intent atual da Activity, então chame setIntent:

kotlin
override fun onNewIntent(intent: Intent) {
    super.onNewIntent(intent)
    setIntent(intent)
}

Sem isso, toques "a quente" em uma Activity singleTop/singleTask não são reportados (igual ao react-native-notti 0.8.0).

Mensagens in-app ​

Links. Por padrão, o SDK abre no navegador uma ação url de mensagem in-app cujo valor é um link http ou https, depois que os seus listeners de clique rodaram: não abra o link de novo no listener. Ele nunca abre um deeplink, nem uma url com qualquer outro esquema (tel:, mailto:, esquemas próprios): esses ficam com você, pelo listener de clique. Sem listener, um toque nesse botão ainda reporta click ao Notti e fecha a mensagem, nada é aberto e o SDK registra um aviso. Para abrir links web por conta própria, passe NottiOptions(opensInAppUrls = false) para Notti.initialize.

As mensagens são criadas no painel do Notti (veja Mensagens in-app) e exigem o backend do Notti v0.23.0 ou mais recente. Elas são exibidas pelo SDK sobre a Activity atual, com Views do Android. Uma vez por sessão em foreground, depois que este processo registrou o dispositivo, o SDK pergunta ao backend quais mensagens este dispositivo pode ver (POST /v1/apps/<appId>/in-app-messages/eligible). Ele exibe a primeira mensagem session_start imediatamente e mantém as mensagens event em memória até que o seu app reporte um evento correspondente. No máximo uma mensagem fica visível, e cada mensagem aparece no máximo uma vez por sessão. Se ela aparece de novo em uma sessão posterior é decisão do backend. O lado do servidor dessa troca está descrito no contrato de mensagens in-app.

kotlin
// Before Notti.initialize, so a message shown right after launch already has a listener.
val inAppClicks = Notti.InAppMessages.addClickListener { click ->
    // null for a `push_permission` button and for a button without a valid action.
    val action = click.action ?: return@addClickListener
    when (action.type) {
        NottiInAppAction.Type.DEEPLINK -> { /* route action.value inside the app */ }
        NottiInAppAction.Type.URL -> { /* opened by the SDK after this listener returns */ }
        else -> { /* a type added in a later version */ }
    }
}

// Shows the oldest waiting message whose trigger is this event name (exact, case-sensitive).
Notti.trackEvent("checkout_completed")

inAppClicks.remove()
  • Notti.trackEvent compara apenas no dispositivo: o nome nunca é enviado, armazenado nem registrado no log. Um nome em branco não faz nada. Uma chamada antes de initialize, ou em segundo plano depois que uma sessão terminou, é ignorada. Uma chamada depois de initialize e antes de a primeira sessão abrir é lembrada para essa sessão (até 32 nomes distintos). Pode ser chamada de qualquer thread.
  • O listener de clique roda na main thread, antes de a mensagem fechar, para um toque em um botão, em uma imagem tocável, ou no corpo de uma mensagem top ou bottom que tem botões (ele age como o primeiro botão). NottiInAppClick traz messageId, buttonId (image para a imagem) e action: uma NottiInAppAction com type (URL ou DEEPLINK) e o value intacto, ou null. Os enums públicos (NottiInAppAction.Type, NottiLogLevel) podem ganhar valores em uma versão minor, então mantenha um ramo else. Listeners adicionados antes de initialize são mantidos; um clique sem listener não é reenviado depois.
  • Links web. Com opensInAppUrls verdadeiro (o padrão), depois que os listeners rodaram e a mensagem fechou, o SDK dispara um Intent ACTION_VIEW para uma ação url cujo valor é uma URL http ou https (qualquer combinação de maiúsculas e minúsculas) com host e sem espaços, a partir da Activity em primeiro plano (ou em uma nova task quando não há nenhuma). Qualquer outro valor não é aberto; uma abertura que falha (sem navegador) registra um aviso fixo e não é repetida. O SDK nunca registra o link no log. Todo initialize válido define a opção com o valor que ele traz, como baseUrl, sem registrar de novo: uma chamada posterior com NottiOptions() a liga de volta, então passe as mesmas opções em toda chamada.
  • Botões push_permission rodam o fluxo de permissão em vez de um link: o listener recebe o clique com action == null, a mensagem fecha, e então o SDK mostra o prompt do sistema se nunca perguntou (Android 13+), abre as configurações de notificação do app se as notificações estão desligadas e ele já perguntou (ou abaixo do Android 13), e não faz nada se elas estão ligadas. O Android não distingue "nunca perguntado" de "negado permanentemente": depois que o SDK mostrou o prompt uma vez, os toques seguintes abrem as configurações.
  • Eventos. O SDK reporta impression, click (com o ID do botão) e dismiss (com o motivo). Eles ficam em fila no dispositivo, são enviados em ordem e descartados após 7 dias; acima de 100 eventos na fila, o mais antigo é descartado.
  • Apresentação. Barras top e bottom (o app por baixo continua interativo), um card center sobre um fundo escurecido e full dentro da área segura. Sempre há um controle de fechar; as barras também fecham com um deslize, center com um toque no fundo, e um temporizador opcional de fechamento automático fecha a mensagem sozinho. Título e corpo são texto simples. O controle de fechar tem rótulo em inglês e em português do Brasil, e o texto acompanha a escala de fonte do sistema.
  • Imagens. A imagem de uma mensagem é baixada pelo dispositivo a partir do host do autor: somente https, sem chave de cliente, token ou cookies, no máximo 5 MiB e 10 s, mantida apenas em memória.

Ícone e cor da notificação ​

As notificações push são desenhadas pelo Firebase Messaging, não pelo SDK. Defina o ícone pequeno, a cor de destaque e o canal padrão com os meta-data do próprio Firebase no manifest do seu app:

xml
<application>
    <meta-data
        android:name="com.google.firebase.messaging.default_notification_icon"
        android:resource="@drawable/ic_notification" />
    <meta-data
        android:name="com.google.firebase.messaging.default_notification_color"
        android:resource="@color/notification_accent" />
    <meta-data
        android:name="com.google.firebase.messaging.default_notification_channel_id"
        android:value="@string/default_notification_channel_id" />
</application>

Sem um ícone, o Android usa o ícone do app, que aparece como um quadrado liso na maioria dos aparelhos. Um push com imagem a mostra na notificação expandida (quem a desenha é o Firebase).

Integração com o Android ​

Configuração automática ​

O manifest do SDK é mesclado ao do seu app e traz:

  • NottiFirebaseMessagingService (com.google.firebase.MESSAGING_EVENT, não exportado): renovações do token FCM e pushes recebidos com o app em execução (eventos received).
  • NottiInitProvider (authority ${applicationId}.com.zeeplabs.notti.initprovider, não exportado): um hook de início de processo que detecta toques em notificações (opened + clicked, incluindo o toque que abriu o app) e inicia os observadores de foreground e de rede. Ele não faz trabalho de rede.
  • NottiPermissionActivity (translúcida, não exportada): hospeda o diálogo de permissão de notificação do Android 13+ a partir da Activity que estiver em primeiro plano.
  • android.permission.POST_NOTIFICATIONS.

Nenhum código de FirebaseMessagingService ou de Activity é necessário.

Seu app já tem um FirebaseMessagingService ​

O Android entrega as mensagens FCM a um serviço por app. Remova o serviço do SDK e encaminhe a partir do seu:

xml
<!-- AndroidManifest.xml of your app (xmlns:tools="http://schemas.android.com/tools") -->
<service
    android:name="com.zeeplabs.notti.NottiFirebaseMessagingService"
    tools:node="remove" />
kotlin
class MyMessagingService : FirebaseMessagingService() {
    override fun onNewToken(token: String) {
        // your own handling
        NottiBridge.onNewToken(token)
    }

    override fun onMessageReceived(remoteMessage: RemoteMessage) {
        // your own handling
        NottiBridge.onMessageReceived(remoteMessage)
    }
}

Os métodos de NottiBridge são estáticos para quem chama de Java (NottiBridge.onNewToken(token)) e não fazem nada, com segurança, antes de o SDK ter iniciado. O repositório do SDK tem um exemplo compilável, example-manual-fcm/.

Removendo o hook de início de processo ​

Você pode remover com.zeeplabs.notti.NottiInitProvider com tools:node="remove". O Notti.initialize então instala os mesmos hooks (detecção de toques, observadores de foreground e de rede), uma vez por processo. Até essa primeira chamada não existe estado do SDK, então toda outra chamada (incluindo e-mail, telefone, compartilhamento de localização e logout) é descartada com uma linha WARN; chame initialize antes de qualquer outra coisa. O ponto onde você o chama decide se o toque que abriu o app é visto:

  • Em Application.onCreate: igual a com o provider.
  • No onCreate da Activity de lançamento: o toque de lançamento é detectado quando a Activity é retomada, e reabrir o app pelos Recentes não é reportado como um toque.
  • Mais tarde (depois de a primeira Activity ter sido retomada): o toque de lançamento se perde; os toques seguintes são detectados.

Sem o provider, quando o Android restaura uma Activity depois de matar o processo, o toque de lançamento dela não se distingue de um novo quando a Activity é retomada, então ele é reportado de novo (opened + clicked). Mantenha o provider, ou chame initialize em Application.onCreate, para evitar isso.

R8 ​

Nenhuma regra é necessária. O AAR traz um consumer-rules.pro vazio: o R8 mantém os componentes do manifest pelas próprias regras do AGP, e o seu código referencia NottiBridge diretamente.

Java ​

Todo membro é estático:

java
Notti.initialize(this, "YOUR_APP_ID", "YOUR_CLIENT_KEY", new NottiOptions());
Notti.initialize(this, "YOUR_APP_ID", "YOUR_CLIENT_KEY", new NottiOptions(null, false)); // you open web links
Notti.login("user-123");
Notti.User.addTag("plan", "premium");
NottiSubscription clicked = Notti.Notifications.addClickedListener(notification -> { });
Notti.Notifications.requestPermission(granted -> { });
NottiSubscription inApp = Notti.InAppMessages.addClickListener(click -> { });
Notti.trackEvent("checkout_completed");
Notti.setLogLevel(NottiLogLevel.DEBUG);
String deviceId = Notti.getDeviceId();

Argumentos de texto, mapa e lista aceitam null: a chamada é registrada no log pelo nome do método e ignorada, e chaves, valores ou itens de lista null são descartados. Argumentos de listener e de callback não podem ser null.

Logs ​

Notti.logLevel = NottiLogLevel.DEBUG (níveis VERBOSE, DEBUG, INFO, WARN, ERROR, NONE; padrão ERROR, NONE silencia o SDK). Os logs vão para o logcat sob a tag Notti e nunca contêm e-mail, telefone, token de push, ID de usuário, país, valores de tags ou URLs; os erros são registrados por classe ou código, não por mensagem. Uma exceção: uma baseUrl inválida é registrada como foi informada, para explicar por que o initialize foi ignorado. É configuração sua, não dado de usuário; mantenha credenciais fora dela.

Privacidade, Play Data safety e LGPD ​

Esta seção descreve o que o SDK faz. Isto não é aconselhamento jurídico e não afirma que o seu uso está em conformidade com a LGPD - valide com o seu próprio time jurídico/DPO antes de publicar.

Enviado ao backend do Notti ​

As requisições vão para /v1/apps/<appId>/devices (registro), /v1/apps/<appId>/devices/<deviceId> (toda atualização posterior, então o ID do dispositivo viaja no caminho), /v1/apps/<appId>/notifications/<id>/events, /v1/apps/<appId>/in-app-messages/eligible e /v1/apps/<appId>/in-app-messages/<messageId>/events, autenticadas com a sua chave de cliente. Toda atualização de dispositivo também carrega o token de push.

QuandoCampos
Registrotoken (token de push FCM), platform (android)
login, logoutexternal_user_id (null no logout)
setEmail, setPhone, clearEmail, clearPhone, logoutemail, phone (null em uma limpeza)
addTag, addTags, removeTag, removeTagstags (seus próprios pares chave/valor)
Permissão e setSubscriptionpermission_status, subscribed, last_unsubscribed_at
Perfil do dispositivo, sincronizado quando mudaapp_version, sdk_version, sdk_name (android), device_os, device_model, timezone_id, language
Sessõesfirst_session_at, last_session_at, session_count, session_time_seconds
Compartilhamento de localização ligado, e o seu app já tem permissão de localizaçãoapenas country (null quando você desliga o compartilhamento)
Um push é recebido, aberto ou clicadodelivery_id, type (received, opened, clicked), token, reportado sob o ID da notificação
Busca in-app, uma vez por sessão em foregrounddevice_id, token
Uma mensagem in-app é exibida, tocada ou fechadadevice_id, token, event_id, type (impression, click, dismiss), occurred_at, button_id (apenas em click, o ID do autor), reason (apenas em dismiss, um valor fixo), reportado sob o ID da mensagem

Não coloque dados pessoais em chaves ou valores de tags a menos que a sua própria base legal de tratamento os cubra. O país é resolvido no dispositivo com o Geocoder do Android a partir de uma localização que a permissão do seu app já permite; o SDK nunca pede permissão de localização e envia apenas o código do país. O geocoding pode usar um serviço de rede fornecido pelo dispositivo.

Armazenado no dispositivo ​

O SDK guarda seu estado no arquivo SharedPreferences notti_prefs, sem criptografia, no armazenamento privado do seu app, com o mesmo nome de arquivo e os mesmos nomes de chave do react-native-notti 0.8.0 (mais notti_last_synced_sdk_name, adicionada na 0.2.0), então um app que migra do módulo React Native mantém o ID do dispositivo, as tags e os eventos pendentes. Isso inclui e-mail, telefone, ID de usuário externo e tags. A lista completa de chaves está no README do SDK. Se o arquivo entra no backup segue o allowBackup e as regras de backup do seu app; o SDK não define nenhuma.

O que o seu app declara no Google Play Data safety ​

A tabela abaixo é o que o SDK implica, com base nos dados acima. Cabe ao dono do app confirmá-la: o formulário do seu app também precisa cobrir a sua própria coleta, e se um tipo se aplica depende de quais chamadas você faz.

Tipo de dado do PlayColetado quandoFinalidade
Device or other IDssempre (ID de dispositivo do Notti, token de push FCM)App functionality
Personal info: User IDsvocê chama loginApp functionality
Personal info: Email addressvocê chama setEmailApp functionality
Personal info: Phone numbervocê chama setPhoneApp functionality
Location: Approximate locationvocê ativa o compartilhamento de localização (apenas país)App functionality
App activity: App interactionssempre (push received/opened/clicked, in-app impression/click/dismiss, contagem de sessões)App functionality, Analytics
App activity: Other actionsvocê define tagsApp functionality
App info and performance: Other app performance datasempre (versão do app, nome e versão do SDK, versão do SO, modelo do aparelho, fuso horário, idioma)App functionality
  • Criptografado em trânsito: sim com o host padrão ou qualquer URL base https. O SDK também aceita uma URL base http; não use uma em produção.
  • Compartilhado com terceiros: os dados vão para o seu backend do Notti, que os trata por você; se isso conta como compartilhamento no seu formulário depende do seu contrato com o operador do Notti. O SDK não envia nada a outras partes (o Firebase recebe apenas o que o próprio Firebase Messaging precisa para entregar os pushes).
  • Opcional ou obrigatório: o ID do dispositivo, o token de push, as interações e as informações do app são necessários para a entrega de push; ID de usuário, e-mail, telefone, tags e localização são opcionais e só são coletados quando o seu app os define.
  • Exclusão: o SDK não tem chamada de exclusão. Pedidos de exclusão são tratados no seu backend do Notti.

LGPD ​

Antes de publicar, peça aos seus times jurídico e de privacidade que revisem os dados acima, a base legal, o aviso exibido aos usuários e a retenção e exclusão no seu backend do Notti. Essa revisão inclui as mensagens in-app: cada requisição in-app carrega o ID do dispositivo e o token de push, e cada mensagem que o usuário vê, toca ou fecha vira um evento vinculado ao registro do dispositivo. Os nomes de trackEvent ficam no dispositivo.

O SDK não tem API de consentimento na 0.2.0: controle você mesmo Notti.initialize e Notti.login.

Limitações conhecidas ​

  • Ainda sem API de consentimento. Não há chamada para segurar a coleta até o usuário consentir. Controle você mesmo Notti.initialize e Notti.login, e chame login depois de initialize: antes disso, o login é ignorado.
  • Dados pessoais em SharedPreferences sem criptografia. E-mail, telefone, ID de usuário externo e tags são armazenados sem criptografia em notti_prefs, no armazenamento privado do seu app.
  • logout e o novo registro exigem o backend do Notti v0.24.0 ou mais recente. A partir dessa versão, PATCH com external_user_id: null desvincula o dispositivo, e um registro que omite external_user_id e tags os mantém. Contra um backend mais antigo, a desvinculação responde 2xx mas o backend mantém o valor guardado, então o dispositivo continua vinculado ao usuário anterior até o próximo lançamento; o SDK conta o 2xx como entregue e não repete. Um backend mais antigo também zera external_user_id e tags a cada registro no lançamento, então chame login e addTags de novo a cada lançamento. O react-native-notti 0.8.0 tem os mesmos limites.
  • As tags sobrevivem ao logout. O logout não limpa as tags no backend; limpe-as você mesmo (removeTags) se elas descrevem o usuário.
  • Sem Retry-After nas requisições de dispositivo. Uma requisição de dispositivo ou de evento de push é tentada até 5 vezes, com esperas de 2, 4, 8 e 16 segundos. Erros de rede, 5xx, 408 e 429 são repetidos; os demais 4xx são definitivos. Um header Retry-After é ignorado ali (o cliente in-app o respeita).
  • Nenhuma notificação exibida em primeiro plano. Veja Notificações em primeiro plano.
  • setIntent para toques a quente. Uma Activity singleTop/singleTask que não chama setIntent em onNewIntent perde os toques a quente (veja Activities singleTop e singleTask).
  • Remover o NottiInitProvider muda quais toques de lançamento são vistos e pode reportar duas vezes o toque de lançamento de uma Activity restaurada (veja Removendo o hook de início de processo).
  • Um link web aberto duas vezes. Com opensInAppUrls verdadeiro, um listener de clique que também abre uma ação url a abre uma segunda vez. Abra-a no listener somente com NottiOptions(opensInAppUrls = false).
  • Sem limite de tamanho em pixels para imagens in-app. Os downloads têm teto de 5 MiB e 10 s, mas um arquivo pequeno que decodifica para um bitmap muito grande não é rejeitado.
  • Ao lado do react-native-notti. Os pacotes diferem (com.zeeplabs.notti aqui, com.notti lá) e as authorities dos providers diferem, então os dois compilam em um mesmo app, mas o Android entrega o FCM a um único serviço: não rode os dois SDKs no mesmo app.
  • Kotlin 2.0 ou mais recente. O POM declara kotlin-stdlib 2.0.21 em escopo de compilação; um app que compila com Kotlin 1.9 ou anterior não é suportado.

Código-fonte e changelog ​