Rastreamento de desinstalação
Acompanhe as desinstalações de aplicativos para medir a retenção de usuários e otimizar campanhas de reengajamento integrando serviços de notificação por push com o SDK Singular.
Importante: o Google descontinuou as APIs do GCM em abril de 2018. Use o Firebase Cloud Messaging (FCM) para todas as implementações de rastreamento de desinstalação do Android.
Rastreamento de desinstalação do Android
Pré-requisitos
Antes de implementar o rastreamento de desinstalação em seu aplicativo Flutter, configure seu aplicativo na plataforma Singular seguindo o guia Configurando o rastreamento de desinstalação do Android.
Requisitos do sistema
O rastreamento de desinstalação requer o Firebase Cloud Messaging e configurações específicas do dispositivo.
Requisitos do FCM(fonte):
- Versão do Android: Os dispositivos devem executar o Android 4.1 (API 16) ou superior
- Serviços do Google Play: Os dispositivos devem ter o aplicativo Google Play Store instalado
- Suporte de emulador: São suportados emuladores Android 4.1+ com APIs do Google
- Distribuição: As aplicações podem ser distribuídas fora da Google Play Store, continuando a suportar o controlo de desinstalações
Nota: Os utilizadores de versões do Android não suportadas ou de dispositivos sem o Google Play Services não serão rastreados para desinstalações.
Etapas de implementação
Etapa 1: Instalar os pacotes do Firebase
Adicione as dependências do Firebase ao seu arquivo pubspec.yaml para obter a funcionalidade principal e o suporte a mensagens.
dependencies:
flutter:
sdk: flutter
firebase_core: ^2.24.2
firebase_messaging: ^14.7.10
singular_flutter_sdk: ^1.8.0
Depois de adicionar as dependências, execute flutter pub get para instalar os pacotes.
Etapa 2: configurar o Firebase
Adicione arquivos de configuração do Firebase ao seu projeto Flutter para Android.
- Registre seu aplicativo Android no seu projeto do Firebase Console
- Baixe
google-services.jsone coloque-o emandroid/app/ - Verifique se as dependências de mensagens do Firebase foram adicionadas ao seu projeto
Para obter instruções detalhadas de configuração, consulte Adicionar o Firebase ao seu aplicativo Flutter.
Etapa 3: inicializar o Firebase
Inicialize o Firebase antes de executar seu aplicativo Flutter para habilitar os serviços de mensagens.
import 'package:flutter/material.dart';
import 'package:firebase_core/firebase_core.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
// Initialize Firebase
await Firebase.initializeApp();
runApp(MyApp());
}
Etapa 4: solicitar permissão de notificação
Solicite permissões de notificação do usuário (necessário para Android 13+) antes de recuperar o token FCM.
import 'package:firebase_messaging/firebase_messaging.dart';
import 'dart:io';
Future<bool> requestNotificationPermission() async {
if (Platform.isAndroid) {
// Android 13+ requires explicit permission request
// Note: firebase_messaging handles this automatically via requestPermission
final FirebaseMessaging messaging = FirebaseMessaging.instance;
final NotificationSettings settings = await messaging.requestPermission(
alert: true,
badge: true,
sound: true,
);
return settings.authorizationStatus == AuthorizationStatus.authorized ||
settings.authorizationStatus == AuthorizationStatus.provisional;
}
// iOS permission handled separately
return true;
}
Passo 5: Recuperar e registar o token FCM
Obtenha o token de dispositivo FCM e registe-o no Singular utilizando registerDeviceTokenForUninstall() após solicitar as permissões.
import 'package:flutter/material.dart';
import 'package:singular_flutter_sdk/singular.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'dart:io';
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
@override
void initState() {
super.initState();
if (Platform.isAndroid) {
initializeAndroidUninstallTracking();
}
}
Future<void> initializeAndroidUninstallTracking() async {
try {
// Request notification permission
final hasPermission = await requestNotificationPermission();
if (!hasPermission) {
print('Notification permission denied - uninstall tracking unavailable');
return;
}
// Get FCM token
final token = await FirebaseMessaging.instance.getToken();
if (token != null) {
// Register token with Singular for uninstall tracking
Singular.registerDeviceTokenForUninstall(token);
print('FCM token registered with Singular: $token');
} else {
print('No FCM token available');
}
} catch (error) {
print('Error setting up uninstall tracking: $error');
}
}
Future<bool> requestNotificationPermission() async {
final messaging = FirebaseMessaging.instance;
final settings = await messaging.requestPermission(
alert: true,
badge: true,
sound: true,
);
return settings.authorizationStatus == AuthorizationStatus.authorized ||
settings.authorizationStatus == AuthorizationStatus.provisional;
}
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: MyHomePage(),
);
}
}
Assinatura do método:
static void registerDeviceTokenForUninstall(String token)
Para obter a documentação completa do método, consulte a referência registerDeviceTokenForUninstall.
Etapa 6: lidar com a atualização do token
Atualize o token FCM com o Singular sempre que ele for atualizado para manter o rastreamento preciso da desinstalação.
import 'package:flutter/material.dart';
import 'package:singular_flutter_sdk/singular.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'dart:io';
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
@override
void initState() {
super.initState();
if (Platform.isAndroid) {
setupTokenRefreshListener();
}
}
void setupTokenRefreshListener() {
// Listen for token refresh events
FirebaseMessaging.instance.onTokenRefresh.listen((String token) {
print('FCM token refreshed: $token');
// Update Singular with new token
Singular.registerDeviceTokenForUninstall(token);
});
}
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: MyHomePage(),
);
}
}
Melhores práticas: Os tokens FCM podem ser atualizados a qualquer momento (atualizações de aplicativos, restauração de dispositivos, etc.). Sempre assine o fluxo onTokenRefresh para manter o Singular atualizado com o token mais recente.
Rastreamento de desinstalação do iOS
Pré-requisitos
Configure seu aplicativo iOS na plataforma Singular seguindo o guia Configurando o rastreamento de desinstalação do iOS.
O rastreamento de desinstalação no iOS é baseado na tecnologia do serviço de notificação por push da Apple (APNs). Se o seu aplicativo não for compatível com notificações por push, consulte o guia da Apple para Registrar seu aplicativo com APNs.
Passos de implementação
Etapa 1: Configurar o projeto iOS
Adicione a configuração do Firebase e ative os recursos de notificação por push no seu projeto iOS.
- Registre seu aplicativo iOS no seu projeto do Console do Firebase
- Baixe
GoogleService-Info.pliste adicione-o à pasta Xcode Runner - Nas configurações do projeto Xcode, ative o recurso Notificações por push
- Habilite Modos em segundo plano e marque Notificações remotas
Etapa 2: solicitar autorização de notificação do iOS
Solicite permissões de notificação ao utilizador e recupere o token do dispositivo APNS.
import 'package:firebase_messaging/firebase_messaging.dart';
import 'dart:io';
Future<bool> requestIOSNotificationPermission() async {
if (!Platform.isIOS) {
return false;
}
try {
final FirebaseMessaging messaging = FirebaseMessaging.instance;
final NotificationSettings settings = await messaging.requestPermission(
alert: true,
badge: true,
sound: true,
provisional: false,
);
final authorized =
settings.authorizationStatus == AuthorizationStatus.authorized ||
settings.authorizationStatus == AuthorizationStatus.provisional;
if (authorized) {
print('iOS notification authorization status: ${settings.authorizationStatus}');
return true;
}
return false;
} catch (error) {
print('Error requesting iOS notification permission: $error');
return false;
}
}
Passo 3: Recuperar e registar o Token APNS
Obtenha o token do dispositivo APNS e registe-o na Singular utilizando registerDeviceTokenForUninstall() após a autorização ser concedida.
import 'package:flutter/material.dart';
import 'package:singular_flutter_sdk/singular.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'dart:io';
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
@override
void initState() {
super.initState();
if (Platform.isIOS) {
initializeIOSUninstallTracking();
}
}
Future<void> initializeIOSUninstallTracking() async {
try {
// Request notification authorization
final hasPermission = await requestIOSNotificationPermission();
if (!hasPermission) {
print('Notification permission denied - uninstall tracking unavailable');
return;
}
// Get APNS token
final apnsToken = await FirebaseMessaging.instance.getAPNSToken();
if (apnsToken != null) {
// Register token with Singular for uninstall tracking
Singular.registerDeviceTokenForUninstall(apnsToken);
print('APNS token registered with Singular: $apnsToken');
} else {
print('No APNS token available');
}
} catch (error) {
print('Error setting up iOS uninstall tracking: $error');
}
}
Future<bool> requestIOSNotificationPermission() async {
final messaging = FirebaseMessaging.instance;
final settings = await messaging.requestPermission(
alert: true,
badge: true,
sound: true,
);
return settings.authorizationStatus == AuthorizationStatus.authorized ||
settings.authorizationStatus == AuthorizationStatus.provisional;
}
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: MyHomePage(),
);
}
}
Formato do token: O token APNS recuperado de getAPNSToken() já está formatado como uma cadeia hexadecimal, que é o formato correto para o Singular.
Etapa 4: lidar com a atualização do token (iOS)
Atualize o token APNS com o Singular se ele for alterado durante o ciclo de vida do aplicativo.
import 'package:flutter/material.dart';
import 'package:singular_flutter_sdk/singular.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'dart:io';
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
@override
void initState() {
super.initState();
if (Platform.isIOS) {
setupIOSTokenRefreshListener();
}
}
void setupIOSTokenRefreshListener() {
// Listen for token refresh events
FirebaseMessaging.instance.onTokenRefresh.listen((String token) {
print('APNS token refreshed: $token');
// Update Singular with new token
Singular.registerDeviceTokenForUninstall(token);
});
}
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: MyHomePage(),
);
}
}
Implementação completa entre plataformas
Configuração unificada do rastreamento de desinstalação
Implemente o rastreamento de desinstalação para as plataformas Android e iOS com tratamento adequado de erros e lógica de atualização de token.
import 'package:flutter/material.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:singular_flutter_sdk/singular.dart';
import 'package:singular_flutter_sdk/singular_config.dart';
import 'dart:io';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
// Initialize Firebase
await Firebase.initializeApp();
runApp(MyApp());
}
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
@override
void initState() {
super.initState();
// Initialize Singular SDK
initializeSingularSDK();
// Setup uninstall tracking
initializeUninstallTracking();
// Setup token refresh listener
setupTokenRefreshListener();
}
void initializeSingularSDK() {
final config = SingularConfig(
'YOUR_SDK_KEY',
'YOUR_SDK_SECRET'
);
Singular.start(config);
}
Future<void> initializeUninstallTracking() async {
try {
if (Platform.isAndroid) {
await setupAndroidUninstallTracking();
} else if (Platform.isIOS) {
await setupIOSUninstallTracking();
}
} catch (error) {
print('Error initializing uninstall tracking: $error');
}
}
Future<void> setupAndroidUninstallTracking() async {
print('Setting up Android uninstall tracking');
// Request notification permission
final messaging = FirebaseMessaging.instance;
final settings = await messaging.requestPermission(
alert: true,
badge: true,
sound: true,
);
if (settings.authorizationStatus != AuthorizationStatus.authorized &&
settings.authorizationStatus != AuthorizationStatus.provisional) {
print('Android notification permission denied');
return;
}
// Get and register FCM token
final token = await messaging.getToken();
if (token != null) {
Singular.registerDeviceTokenForUninstall(token);
print('Android FCM token registered: $token');
} else {
print('Failed to retrieve Android FCM token');
}
}
Future<void> setupIOSUninstallTracking() async {
print('Setting up iOS uninstall tracking');
// Request iOS notification authorization
final messaging = FirebaseMessaging.instance;
final settings = await messaging.requestPermission(
alert: true,
badge: true,
sound: true,
);
final authorized =
settings.authorizationStatus == AuthorizationStatus.authorized ||
settings.authorizationStatus == AuthorizationStatus.provisional;
if (!authorized) {
print('iOS notification permission denied');
return;
}
// Get and register APNS token
final apnsToken = await messaging.getAPNSToken();
if (apnsToken != null) {
Singular.registerDeviceTokenForUninstall(apnsToken);
print('iOS APNS token registered: $apnsToken');
} else {
print('Failed to retrieve iOS APNS token');
}
}
void setupTokenRefreshListener() {
// Listen for token refresh events (works for both platforms)
FirebaseMessaging.instance.onTokenRefresh.listen((String token) {
print('${Platform.operatingSystem.toUpperCase()} token refreshed: $token');
Singular.registerDeviceTokenForUninstall(token);
});
}
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: Scaffold(
appBar: AppBar(
title: Text('Uninstall Tracking Demo'),
),
body: Center(
child: Text('Uninstall tracking initialized'),
),
),
);
}
}
Notas específicas da plataforma
- iOS: Certifique-se de que seu aplicativo tenha os direitos de notificação por push necessários e que os APNs estejam configurados corretamente na sua conta de desenvolvedor da Apple
-
Android: Verifique se o FCM está configurado no seu console do Firebase e se o arquivo
google-services.jsonestá incluído no seu projeto emandroid/app/
Verificação e solução de problemas
Verificar a implementação
Confirme se o rastreamento de desinstalação está funcionando corretamente antes de implantar na produção.
- Verifique os logs: Verifique se o registro do token aparece nos logs do console com o formato correto
- Teste a geração de tokens: Certifique-se de que os tokens sejam gerados na primeira inicialização do aplicativo após a concessão de permissões
- Monitorar o painel: Verifique o painel do Singular para obter dados de rastreamento de desinstalação após 24-48 horas
- Testar atualização de token: Limpar os dados do aplicativo e verificar se o token é atualizado corretamente quando o aplicativo é reiniciado
Problemas comuns
-
Token não gerado: Verifique se as dependências do Firebase estão instaladas corretamente e se o Firebase está configurado no seu projeto Flutter. Execute
flutter pub getdepois de adicionar dependências - Permissão negada: Verifique se os usuários concederam permissões de notificação. Para Android 13+, é necessária uma solicitação de permissão explícita. Para iOS, os usuários devem autorizar as notificações
-
O token não está sendo atualizado: Certifique-se de que subscreveu o fluxo
onTokenRefreshpara ambas as plataformas. O ouvinte deve ser configurado na inicialização do seu aplicativo - Dados ausentes: Confirme se os dispositivos cumprem os requisitos da plataforma (Android 4.1+ com Google Play Services, iOS com suporte para APNs). Os dispositivos sem estes serviços não podem ser monitorizados
- Erro de configuração: Verifique se o rastreamento de desinstalação está ativado nas configurações da plataforma Singular para seu aplicativo. Siga os guias de configuração específicos da plataforma vinculados em Pré-requisitos
-
Configuração do Firebase: Para Android, verifique se
google-services.jsonestá emandroid/app/. Para iOS, verifique seGoogleService-Info.plistfoi adicionado à pasta Runner do projeto Xcode -
Inicialização do SDK: Confirme se o Singular SDK foi inicializado antes de chamar
registerDeviceTokenForUninstall(). O registro do token deve ocorrer após a inicialização do SDK -
Deteção de plataforma: Use
Platform.isAndroidePlatform.isIOSdedart:iopara garantir que o código específico da plataforma seja executado na plataforma correta
Recursos adicionais: Para obter uma solução de problemas detalhada, consulte o Guia de configuração de rastreamento de desinstalação do Android, o Guia de configuração de rastreamento de desinstalação do iOS e a Documentação de configuração do Flutter Firebase.
Práticas recomendadas
Gerenciamento de token
- Registro antecipado: Solicite permissões e registre tokens o mais cedo possível no ciclo de vida do aplicativo, de preferência durante a primeira inicialização do aplicativo
- Tratamento de erros: Implemente um tratamento de erros robusto em torno da recuperação e do registo de tokens para lidar com falhas de forma graciosa
- Atualização de token: Sempre implemente ouvintes de atualização de token para manter o Singular atualizado quando os tokens forem alterados
- Experiência do utilizador: Solicitar permissões de notificação no contexto, explicando por que o aplicativo precisa delas para melhorar as taxas de concessão de permissão
Estratégia de teste
- Teste de desenvolvimento: Teste em dispositivos Android e iOS físicos, pois os emuladores podem ter suporte limitado a notificações por push
- Fluxos de permissão: Testar cenários em que os utilizadores negam permissões e verificar se a aplicação lida com isso de forma graciosa
- Persistência de tokens: Verificar se os tokens persistem durante as reinicializações da aplicação e se são actualizados corretamente na atualização
- Registo: Ativar o registo detalhado durante o desenvolvimento para acompanhar a geração e o registo de tokens