React Native e Expo
O pacote @atalia-ia/react-native-chat leva os SDKs nativos de Android e iOS para o seu app React Native: é o mesmo chat, com os mesmos recursos, chamado pelo JavaScript. Funciona com Expo e com React Native puro.
Como qualquer pacote com código nativo, o SDK precisa de um development build: npx expo run:android, npx expo run:ios ou um build do EAS. No Expo Go o pacote não carrega.
Testado com Expo SDK 58 (React Native 0.88), na nova arquitetura.
1. Instalar
Num app Expo:
npx expo install @atalia-ia/react-native-chat
Num app React Native sem Expo, instale antes o suporte a módulos do Expo (uma vez por projeto) e depois o pacote:
npx install-expo-modules@latest
npm install @atalia-ia/react-native-chat
cd ios && pod install
2. Configurar pelo plugin
O plugin grava o token do canal e as permissões nos arquivos nativos. Com ele, o SDK já nasce configurado quando o app abre, antes do JavaScript: é isso que faz o toque numa notificação, com o app fechado, abrir a conversa certa.
{
"expo": {
"plugins": [
["@atalia-ia/react-native-chat", { "channelToken": "<token-do-canal>" }]
]
}
}
O token fica em Configurações › Canais › Editar canal › Instalação › Token do widget, no painel da Atalia. Depois de mudar o plugin, gere os projetos nativos de novo (npx expo prebuild ou o próximo npx expo run:*).
| Opção | Padrão | Para quê |
|---|---|---|
channelToken | nenhum | Token do canal. Sem ele, chame configure pelo JavaScript |
baseUrl | https://chat.atalia.ai | Outra origem: homologação ou o domínio próprio do canal |
customDomain | false | true quando baseUrl é o domínio próprio vinculado ao canal |
cameraPermission | "Para enviar fotos no chat de atendimento." | Texto do pedido de câmera no iOS. A chave é obrigatória: sem ela o iOS fecha o app quando o visitante escolhe tirar foto |
microphonePermission | "Para gravar mensagens de voz no chat de atendimento." | Texto do pedido de microfone, ou false para não pedir (o chat avisa o visitante) |
notifications | true | Android 13+: declara a permissão POST_NOTIFICATIONS |
notificationIcon | nenhum | Android: PNG branco com fundo transparente (96×96) para o ícone das notificações. Veja Notificações push |
Sem o plugin (React Native puro), configure pelo JavaScript quando o app inicia. O toque numa notificação com o app fechado só abre a conversa depois desse configure.
import Atalia from '@atalia-ia/react-native-chat';
Atalia.configure('<token-do-canal>');
As opções do configure são as de AtaliaOptions, na referência. Chamar o configure com o plugin já configurado só troca as opções.
3. Abrir o chat
import Atalia from '@atalia-ia/react-native-chat';
<Button title="Falar com a gente" onPress={() => Atalia.open()} />
Atalia.openConversation(id) abre direto numa conversa. A tela do chat é nativa e abre numa folha que sobe sobre o app (arrastar a alça fecha); presentationStyle: 'fullScreen' no configure abre em tela cheia. No iOS, Atalia.close() fecha.
4. Não lidas e estado
O hook atualiza sozinho:
import { useAtaliaState } from '@atalia-ia/react-native-chat';
function MenuSuporte() {
const { unreadCount, isIdentified, isChatOpen } = useAtaliaState();
return <Text>Suporte {unreadCount > 0 ? `(${unreadCount})` : ''}</Text>;
}
Para só o número, useAtaliaUnreadCount(). Fora de componente, await Atalia.getState().
5. Identificar o usuário logado
try {
const contact = await Atalia.identify(tokenDoSeuBackend);
} catch (error) {
console.warn(error.code); // EXPIRED, INVALID_SIGNATURE...
}
// no logout do app:
await Atalia.logout();
O JWT é assinado pelo seu backend com o segredo do canal, nunca no app. Regras e códigos de erro em Identificar o usuário logado.
6. Eventos
import { useAtaliaEvent } from '@atalia-ia/react-native-chat';
useAtaliaEvent((event) => {
if (event.type === 'messageReceived') analytics.track('mensagem_suporte');
});
Fora de componente, Atalia.addListener(listener) devolve um objeto com remove(). Os eventos estão na referência.
7. Botão flutuante
Opcional: o SDK não desenha nada sobre o app sem você pedir. O botão fica por cima de todas as telas, com a aparência do painel.
Atalia.showLauncher({ bottomMargin: 72 }); // acima da barra de abas
Atalia.hideLauncher();
As opções (side, horizontalMargin, bottomMargin, text, subtitle, color, collapse, collapseAfter, draggable, dockable, preloadChat) estão na referência e o comportamento, em Botão flutuante. Chamar showLauncher de novo troca as opções.
8. Notificações push
A regra de quando notificar é da Atalia, como no app nativo: o painel e o comportamento estão em Notificações push. Aqui, o que fazer no projeto React Native.
Qual biblioteca de push usar
| Biblioteca | Android | iOS |
|---|---|---|
@react-native-firebase/messaging (recomendada) | Sim | Sim |
expo-notifications | Sim | Só pelo modo webhook |
No iOS, a Atalia envia pelo Firebase do app, e o Firebase só entrega a quem registrou o token dele. O expo-notifications entrega o token do APNs, que serve ao seu backend no modo webhook. Use uma das duas bibliotecas: no iOS, as duas tentam tratar as notificações do app.
Com o Firebase
1. Prepare o Firebase e o painel. No projeto do Firebase, crie o app Android e o app iOS e baixe o google-services.json e o GoogleService-Info.plist. Para o iOS, envie a chave do APNs ao Firebase (passos, aba iOS). No painel da Atalia, ligue as notificações e envie a conta de serviço (passos).
2. Instale as bibliotecas.
npx expo install @react-native-firebase/app @react-native-firebase/messaging expo-build-properties
3. Configure o app.
{
"expo": {
"android": {
"googleServicesFile": "./google-services.json"
},
"ios": {
"googleServicesFile": "./GoogleService-Info.plist",
"entitlements": { "aps-environment": "development" }
},
"plugins": [
["@atalia-ia/react-native-chat", {
"channelToken": "<token-do-canal>",
"notificationIcon": "./assets/notificacao.png"
}],
"@react-native-firebase/app",
"@react-native-firebase/messaging",
["expo-build-properties", { "ios": { "useFrameworks": "dynamic" } }]
]
}
}
googleServicesFile: os arquivos que você baixou do Firebase.aps-environment: liga a capability Push Notifications no iOS, como o Xcode faz. O valor édevelopment; na exportação para o TestFlight e a App Store, a assinatura passa a usarproduction.useFrameworks: "dynamic": o@react-native-firebase27 exige no iOS, porque o Firebase só é distribuído pelo Swift Package Manager. Versões anteriores pediamstatic: siga o que a versão instalada pede.notificationIcon: o ícone pequeno das notificações no Android, um PNG branco com fundo transparente de 96×96. Vale para as notificações que o sistema mostra (app em segundo plano) e para as que o SDK mostra (app aberto). Sem ele, o Android usa o ícone do app, que aparece como um quadrado branco.
Depois de mudar o app.json, gere os projetos nativos de novo: npx expo prebuild --clean.
4. Peça a permissão e ligue ao SDK. Chame quando o app inicia (no componente raiz, por exemplo) ou no momento em que o seu app pede a permissão de notificação.
import Atalia from '@atalia-ia/react-native-chat';
import {
getInitialNotification,
getMessaging,
getToken,
onMessage,
onNotificationOpenedApp,
onTokenRefresh,
requestPermission,
} from '@react-native-firebase/messaging';
import { PermissionsAndroid, Platform } from 'react-native';
export async function ligarPush() {
const messaging = getMessaging();
// Sem a permissão nada aparece: no iOS, pelo Firebase; no Android 13 ou mais novo, pelo sistema.
if (Platform.OS === 'ios') await requestPermission(messaging);
else if (Platform.OS === 'android' && Platform.Version >= 33) {
await PermissionsAndroid.request(PermissionsAndroid.PERMISSIONS.POST_NOTIFICATIONS);
}
Atalia.setPushToken(await getToken(messaging));
onTokenRefresh(messaging, Atalia.setPushToken);
// App aberto: o Firebase não mostra nada sozinho. No Android o SDK mostra (menos com o chat na tela).
onMessage(messaging, async (message) => {
if (!(await Atalia.handleNotification(message))) {
// ...as notificações do seu app
}
});
// Toque com o app em segundo plano e com o app fechado.
onNotificationOpenedApp(messaging, (message) => Atalia.handleNotificationTap(message));
const initial = await getInitialNotification(messaging);
if (initial) Atalia.handleNotificationTap(initial);
}
No iOS, com o app aberto, o @react-native-firebase não mostra a notificação (é o padrão dele), e o handleNotification só atualiza as não lidas. Com o app em segundo plano, quem mostra é o sistema, nas duas plataformas.
Com o expo-notifications
No Android, o expo-notifications também usa o Firebase: coloque o google-services.json em android.googleServicesFile. O ícone pode vir do plugin dele, que grava o mesmo ícone que o SDK usa:
["expo-notifications", { "icon": "./assets/notificacao.png" }]
import Atalia from '@atalia-ia/react-native-chat';
import * as Notifications from 'expo-notifications';
import { Platform } from 'react-native';
// App aberto: sem banner quando a notificação é da Atalia e o chat já está na tela.
Notifications.setNotificationHandler({
handleNotification: async (notification) => {
const show = await Atalia.shouldShowNotification(notification);
return { shouldShowBanner: show, shouldShowList: show, shouldPlaySound: show, shouldSetBadge: false };
},
});
export async function ligarPush() {
const { granted } = await Notifications.requestPermissionsAsync();
if (!granted) return;
const { data } = await Notifications.getDevicePushTokenAsync();
if (Platform.OS === 'android') Atalia.setPushToken(data);
else Atalia.setAPNsToken(data, __DEV__ ? 'sandbox' : 'production'); // modo webhook
Notifications.addNotificationResponseReceivedListener((response) => Atalia.handleNotificationTap(response));
const last = await Notifications.getLastNotificationResponseAsync();
if (last) Atalia.handleNotificationTap(last);
}
Comportamento
handleNotification, handleNotificationTap e shouldShowNotification aceitam o objeto que cada biblioteca entrega (a RemoteMessage do Firebase, a Notification ou a resposta do expo-notifications) ou só o data. Notificação de outra origem devolve false (ou true, no shouldShowNotification): trate como as suas.
O número no ícone, a limpeza das notificações lidas e o comportamento no login e no logout são os do SDK nativo: veja Notificações push. No iOS, appBadge: false no configure deixa o número no ícone com o app.
Para testar, deixe o app em segundo plano e use Enviar teste na lista Aparelhos com o app, no painel.
Testar com o app de exemplo
O repositório tem um app Expo em react-native/example, com o token do canal numa variável de ambiente:
cd react-native && npm install
cd example && npm install
ATALIA_CHANNEL_TOKEN=<token-do-canal> npx expo run:android