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
minSdk24 ou superior ecompileSdk34 ou superior (o AAR declaraminCompileSdk34).- Kotlin 2.0 ou mais recente se o seu app tem código Kotlin (o POM declara
kotlin-stdlib2.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 nologout(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:
// 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):
// 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ê):
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:
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:
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
logoutfeito offline, antes deNotti.initialize, ou cuja requisição falhou, é enviado de novo no próximo registro (umloginposterior o substitui). - Chamadas de
login, de tags e desetSubscriptionfeitas antes deNotti.initializesão ignoradas, cada uma com uma linha de erro no log: chame-as depois deinitialize. E-mail, telefone, compartilhamento de localização elogoutsão mantidos e enviados no primeiro registro. Isso exige oNottiInitProvider(o padrão): se você o removeu, toda chamada anterior ao primeiroinitializeé descartada com uma linhaWARN, que o nível padrãoERROResconde. - Desvincular no backend exige o backend do Notti v0.24.0 ou mais recente: veja Limitações conhecidas.
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.)
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 registrationTodo 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:
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
urlde mensagem in-app cujo valor é um linkhttpouhttps, depois que os seus listeners de clique rodaram: não abra o link de novo no listener. Ele nunca abre umdeeplink, nem umaurlcom qualquer outro esquema (tel:,mailto:, esquemas próprios): esses ficam com você, pelo listener de clique. Sem listener, um toque nesse botão ainda reportaclickao Notti e fecha a mensagem, nada é aberto e o SDK registra um aviso. Para abrir links web por conta própria, passeNottiOptions(opensInAppUrls = false)paraNotti.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.
// 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.trackEventcompara apenas no dispositivo: o nome nunca é enviado, armazenado nem registrado no log. Um nome em branco não faz nada. Uma chamada antes deinitialize, ou em segundo plano depois que uma sessão terminou, é ignorada. Uma chamada depois deinitializee 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
topoubottomque tem botões (ele age como o primeiro botão).NottiInAppClicktrazmessageId,buttonId(imagepara a imagem) eaction: umaNottiInAppActioncomtype(URLouDEEPLINK) e ovalueintacto, ounull. Os enums públicos (NottiInAppAction.Type,NottiLogLevel) podem ganhar valores em uma versão minor, então mantenha um ramoelse. Listeners adicionados antes deinitializesão mantidos; um clique sem listener não é reenviado depois. - Links web. Com
opensInAppUrlsverdadeiro (o padrão), depois que os listeners rodaram e a mensagem fechou, o SDK dispara um IntentACTION_VIEWpara uma açãourlcujo valor é uma URLhttpouhttps(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. Todoinitializeválido define a opção com o valor que ele traz, comobaseUrl, sem registrar de novo: uma chamada posterior comNottiOptions()a liga de volta, então passe as mesmas opções em toda chamada. - Botões
push_permissionrodam o fluxo de permissão em vez de um link: o listener recebe o clique comaction == 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) edismiss(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
topebottom(o app por baixo continua interativo), um cardcentersobre um fundo escurecido efulldentro da área segura. Sempre há um controle de fechar; as barras também fecham com um deslize,centercom 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:
<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 (eventosreceived).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:
<!-- AndroidManifest.xml of your app (xmlns:tools="http://schemas.android.com/tools") -->
<service
android:name="com.zeeplabs.notti.NottiFirebaseMessagingService"
tools:node="remove" />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
onCreateda 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:
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.
| Quando | Campos |
|---|---|
| Registro | token (token de push FCM), platform (android) |
login, logout | external_user_id (null no logout) |
setEmail, setPhone, clearEmail, clearPhone, logout | email, phone (null em uma limpeza) |
addTag, addTags, removeTag, removeTags | tags (seus próprios pares chave/valor) |
Permissão e setSubscription | permission_status, subscribed, last_unsubscribed_at |
| Perfil do dispositivo, sincronizado quando muda | app_version, sdk_version, sdk_name (android), device_os, device_model, timezone_id, language |
| Sessões | first_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ção | apenas country (null quando você desliga o compartilhamento) |
| Um push é recebido, aberto ou clicado | delivery_id, type (received, opened, clicked), token, reportado sob o ID da notificação |
| Busca in-app, uma vez por sessão em foreground | device_id, token |
| Uma mensagem in-app é exibida, tocada ou fechada | device_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 Play | Coletado quando | Finalidade |
|---|---|---|
| Device or other IDs | sempre (ID de dispositivo do Notti, token de push FCM) | App functionality |
| Personal info: User IDs | você chama login | App functionality |
| Personal info: Email address | você chama setEmail | App functionality |
| Personal info: Phone number | você chama setPhone | App functionality |
| Location: Approximate location | você ativa o compartilhamento de localização (apenas país) | App functionality |
| App activity: App interactions | sempre (push received/opened/clicked, in-app impression/click/dismiss, contagem de sessões) | App functionality, Analytics |
| App activity: Other actions | você define tags | App functionality |
| App info and performance: Other app performance data | sempre (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 basehttp; 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.initializeeNotti.login, e chamelogindepois deinitialize: antes disso, ologiné ignorado. - Dados pessoais em
SharedPreferencessem criptografia. E-mail, telefone, ID de usuário externo e tags são armazenados sem criptografia emnotti_prefs, no armazenamento privado do seu app. logoute o novo registro exigem o backend do Notti v0.24.0 ou mais recente. A partir dessa versão,PATCHcomexternal_user_id: nulldesvincula o dispositivo, e um registro que omiteexternal_user_idetagsos 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 zeraexternal_user_ide tags a cada registro no lançamento, então chamelogineaddTagsde novo a cada lançamento. Oreact-native-notti0.8.0 tem os mesmos limites.- As tags sobrevivem ao
logout. Ologoutnão limpa as tags no backend; limpe-as você mesmo (removeTags) se elas descrevem o usuário. - Sem
Retry-Afternas 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 headerRetry-Afteré ignorado ali (o cliente in-app o respeita). - Nenhuma notificação exibida em primeiro plano. Veja Notificações em primeiro plano.
setIntentpara toques a quente. Uma ActivitysingleTop/singleTaskque não chamasetIntentemonNewIntentperde os toques a quente (veja ActivitiessingleTopesingleTask).- Remover o
NottiInitProvidermuda 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
opensInAppUrlsverdadeiro, um listener de clique que também abre uma açãourla abre uma segunda vez. Abra-a no listener somente comNottiOptions(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.nottiaqui,com.nottilá) 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-stdlib2.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
- Código-fonte, README e apps de exemplo: github.com/zeeplabs/zeep-notti-android-sdk
- CHANGELOG, incluindo notas de migração a partir do
react-native-notti - Checklist de dispositivo