Conformidade com as leis de privacidade de dados
Implementar a recolha de dados em conformidade com a privacidade, notificando a Singular das escolhas de consentimento do utilizador para GDPR, CCPA, COPPA e outros regulamentos de privacidade do consumidor.
Quando os utilizadores consentirem ou recusarem a partilha das suas informações com terceiros, utilize os métodos de privacidade da Singular para comunicar a sua escolha. Isto assegura a conformidade com regulamentos como o California Consumer Privacy Act (CCPA) e permite que os parceiros respeitem as preferências de privacidade dos utilizadores.
Saiba mais: Consulte Privacidade do usuário e Limitar compartilhamento de dados para obter informações detalhadas sobre como a Singular processa o consentimento de privacidade.
Limitar a partilha de dados
Controlar o compartilhamento de dados de terceiros
Notificar a Singular se os usuários consentiram em compartilhar seus dados pessoais com parceiros terceiros usando o método limitDataSharing().
Assinatura do método:
static void limitDataSharing(bool shouldLimitDataSharing)
Parâmetros:
- false: O utilizador optou e consentiu a partilha dos seus dados
- true: O utilizador optou por não participar e não consente a partilha dos seus dados
Importante: Embora opcional, este método afecta a partilha de dados de atribuição. Alguns parceiros só partilham informações de atribuição completas quando são explicitamente notificados de que os utilizadores optaram por participar.
Para obter a documentação completa do método, consulte a referência limitDataSharing.
Exemplos de utilização
Implementar controlos de partilha de dados com base nas preferências de privacidade do utilizador.
import 'package:singular_flutter_sdk/singular.dart';
// User has opted in to share their data
void onUserOptedInToDataSharing() {
Singular.limitDataSharing(false);
print('Data sharing enabled');
}
// User has opted out and declined to share their data
void onUserOptedOutOfDataSharing() {
Singular.limitDataSharing(true);
print('Data sharing limited');
}
// Set based on user preference
void handlePrivacyConsent(bool userConsented) {
// Pass inverse: false = opted in, true = opted out
Singular.limitDataSharing(!userConsented);
print('Data sharing: ${userConsented ? 'Enabled' : 'Limited'}');
}
Como funciona:
A Singular usa essa configuração em Postbacks de privacidade do usuárioe a passa para parceiros que a exigem para conformidade regulatória.
Métodos de conformidade com o GDPR
Gerencie o consentimento de rastreamento do usuário e controle a funcionalidade do SDK para estar em conformidade com o GDPR (Regulamento Geral de Proteção de Dados) e outros regulamentos de privacidade.
Gestão do consentimento de rastreio
TrackingOptIn
Regista o consentimento explícito do utilizador para o rastreio, enviando um evento GDPR opt-in para os servidores Singular.
Assinatura do método:
static void trackingOptIn()
Quando usar:
- Conformidade com o GDPR: Chamar quando os usuários consentirem explicitamente com o rastreamento em regiões regulamentadas pelo GDPR
- Registro de consentimento: Marca os usuários como tendo fornecido consentimento GDPR nos sistemas da Singular
- Comportamento padrão: Sem esta chamada, o SDK continua a rastrear mas não regista especificamente o consentimento
Para obter a documentação completa do método, consulte a referência trackingOptIn.
Exemplo de implementação
Chame trackingOptIn() depois de os utilizadores aceitarem o consentimento de rastreio através da caixa de diálogo de consentimento da sua aplicação.
import 'package:flutter/material.dart';
import 'package:singular_flutter_sdk/singular.dart';
import 'package:shared_preferences/shared_preferences.dart';
class GDPRManager extends StatefulWidget {
@override
_GDPRManagerState createState() => _GDPRManagerState();
}
class _GDPRManagerState extends State<GDPRManager> {
bool? hasConsent;
@override
void initState() {
super.initState();
checkStoredConsent();
}
Future<void> checkStoredConsent() async {
final prefs = await SharedPreferences.getInstance();
final consent = prefs.getString('gdpr_consent');
if (consent == null) {
// Show consent dialog
showGDPRConsentDialog();
} else {
setState(() {
hasConsent = consent == 'true';
});
}
}
void showGDPRConsentDialog() {
showDialog(
context: context,
barrierDismissible: false,
builder: (context) => AlertDialog(
title: Text('Privacy Consent'),
content: Text(
'We would like your permission to track app usage and improve your experience.'
),
actions: [
TextButton(
onPressed: () {
Navigator.of(context).pop();
setState(() {
hasConsent = false;
});
},
child: Text('Decline'),
),
ElevatedButton(
onPressed: () async {
Navigator.of(context).pop();
await onUserAcceptedTracking();
},
child: Text('Accept'),
),
],
),
);
}
Future<void> onUserAcceptedTracking() async {
// Record user consent
Singular.trackingOptIn();
print('User opted in to tracking');
// Save preference
final prefs = await SharedPreferences.getInstance();
await prefs.setString('gdpr_consent', 'true');
setState(() {
hasConsent = true;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: hasConsent != null
? Text('Privacy Status: ${hasConsent! ? 'Opted In' : 'Declined'}')
: CircularProgressIndicator(),
),
);
}
}
Métodos de controlo de rastreio
StopAllTracking
Desactiva completamente todas as actividades de rastreio do SDK para o utilizador atual neste dispositivo.
Assinatura do método:
static void stopAllTracking()
Crítico Aviso: Este método desactiva permanentemente o SDK até que resumeAllTracking() seja chamado. O estado de desativação persiste durante as reinicializações da aplicação e só pode ser revertido programaticamente.
Comportamento:
- Efeito imediato: Interrompe todo o rastreamento, relatório de eventos e coleta de dados instantaneamente
- Estado persistente: Permanece desativado mesmo depois de a aplicação ser fechada e reaberta
-
Sem reinicialização automática: Tem de chamar explicitamente
resumeAllTracking()para voltar a ativar
Para obter a documentação completa do método, consulte a referência stopAllTracking.
Exemplo de implementação
Parar o rastreio quando os utilizadores recusam o consentimento ou optam por sair através das definições de privacidade.
import 'package:singular_flutter_sdk/singular.dart';
import 'package:shared_preferences/shared_preferences.dart';
// User declined all tracking
Future<void> onUserDeclinedTracking() async {
Singular.stopAllTracking();
print('All tracking stopped');
// Store preference
final prefs = await SharedPreferences.getInstance();
await prefs.setBool('tracking_enabled', false);
}
// Handle user opt-out from settings menu
void handlePrivacySettingsChange(bool trackingEnabled) {
if (!trackingEnabled) {
Singular.stopAllTracking();
print('Privacy settings: Tracking disabled');
}
}
RetomarTudoRastreio
Reativar o rastreio depois de ter sido interrompido com stopAllTracking().
Assinatura do método:
static void resumeAllTracking()
Casos de utilização:
- Alteração de consentimento: O utilizador altera as preferências de privacidade e volta a optar pelo rastreio
- Definições de privacidade: O utilizador actualiza o consentimento através do menu de definições da aplicação
- Conformidade regional: Reativar o rastreio quando o utilizador se desloca para regiões não regulamentadas
Para obter a documentação completa do método, consulte a referência resumeAllTracking.
Exemplo de implementação
Retomar o rastreio quando os utilizadores optarem por voltar a participar ou actualizarem as suas preferências de privacidade.
import 'package:singular_flutter_sdk/singular.dart';
import 'package:shared_preferences/shared_preferences.dart';
// User opted back in to tracking
Future<void> onUserResumedTracking() async {
Singular.resumeAllTracking();
print('Tracking resumed');
// Update stored preference
final prefs = await SharedPreferences.getInstance();
await prefs.setBool('tracking_enabled', true);
}
// Handle consent update from settings
void handlePrivacySettingsChange(bool trackingEnabled) {
if (trackingEnabled) {
Singular.resumeAllTracking();
print('Privacy settings: Tracking enabled');
}
}
IsAllTrackingStopped
Verificar se o rastreio foi desativado para o utilizador atual.
Assinatura do método:
static Future<bool> isAllTrackingStopped()
Retorna:
-
Future<true>: O rastreamento está atualmente parado via
stopAllTracking() - Future<false>: O rastreio está ativo (nunca parou ou foi retomado)
Para obter a documentação completa do método, consulte a referência isAllTrackingStopped.
Exemplo de implementação
Verificar o estado do rastreio para sincronizar o estado da IU com o estado do rastreio do SDK.
import 'package:flutter/material.dart';
import 'package:singular_flutter_sdk/singular.dart';
class PrivacySettingsUI extends StatefulWidget {
@override
_PrivacySettingsUIState createState() => _PrivacySettingsUIState();
}
class _PrivacySettingsUIState extends State<PrivacySettingsUI> {
bool trackingEnabled = false;
String statusText = 'Checking...';
@override
void initState() {
super.initState();
updatePrivacyUI();
}
// Check current tracking status
Future<bool> isTrackingEnabled() async {
final isStopped = await Singular.isAllTrackingStopped();
return !isStopped;
}
// Display privacy status in settings
Future<String> getPrivacyStatusText() async {
final isStopped = await Singular.isAllTrackingStopped();
return isStopped ? 'Tracking: Disabled' : 'Tracking: Enabled';
}
// Sync UI with tracking state
Future<void> updatePrivacyUI() async {
final isStopped = await Singular.isAllTrackingStopped();
final status = await getPrivacyStatusText();
setState(() {
trackingEnabled = !isStopped;
statusText = status;
});
print('Current tracking state: ${isStopped ? 'Stopped' : 'Active'}');
}
// Handle toggle change from UI
Future<void> onTrackingToggleChanged(bool enabled) async {
if (enabled) {
Singular.resumeAllTracking();
} else {
Singular.stopAllTracking();
}
await updatePrivacyUI();
}
@override
Widget build(BuildContext context) {
return Column(
children: [
Text(statusText),
Switch(
value: trackingEnabled,
onChanged: onTrackingToggleChanged,
),
],
);
}
}
Proteção da privacidade das crianças
TrackingUnder13
Notifica a Singular de que o utilizador tem menos de 13 anos de idade para cumprir a COPPA (Children's Online Privacy Protection Act) e outros regulamentos de privacidade infantil.
Assinatura do método:
static void trackingUnder13()
Requisitos de conformidade:
- Conformidade com a COPPA: Necessário para aplicações que recolhem dados de crianças com menos de 13 anos nos Estados Unidos
- Conteúdo com restrição de idade: Utilizar quando os utilizadores se identificam como tendo menos de 13 anos durante o registo ou a verificação da idade
- Rastreio restrito: Limita a recolha de dados para cumprir as leis de proteção da privacidade das crianças
Para obter a documentação completa do método, consulte a referência trackingUnder13.
Exemplo de implementação
Chame trackingUnder13() imediatamente após determinar que o utilizador tem menos de 13 anos através da verificação da idade.
import 'package:flutter/material.dart';
import 'package:singular_flutter_sdk/singular.dart';
import 'package:singular_flutter_sdk/singular_config.dart';
import 'package:shared_preferences/shared_preferences.dart';
class COPPAManager extends StatefulWidget {
@override
_COPPAManagerState createState() => _COPPAManagerState();
}
class _COPPAManagerState extends State<COPPAManager> {
final TextEditingController ageController = TextEditingController();
// User identified as under 13
Future<void> onUserUnder13() async {
Singular.trackingUnder13();
print('COPPA mode enabled for user under 13');
// Store age category for app restart
final prefs = await SharedPreferences.getInstance();
await prefs.setString('user_age_category', 'under_13');
}
// Call after age verification
Future<void> onAgeVerified(int userAge) async {
final prefs = await SharedPreferences.getInstance();
if (userAge < 13) {
Singular.trackingUnder13();
print('COPPA restrictions applied');
// Also limit advertising identifiers
Singular.limitDataSharing(true);
await prefs.setString('user_age_category', 'under_13');
showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text('Child Account'),
content: Text('Special privacy protections have been applied.'),
actions: [
TextButton(
onPressed: () => Navigator.of(context).pop(),
child: Text('OK'),
),
],
),
);
} else {
await prefs.setString('user_age_category', 'adult');
print('Adult account - standard tracking');
}
}
void handleAgeSubmit() {
final userAge = int.tryParse(ageController.text);
if (userAge == null || userAge < 1 || userAge > 120) {
showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text('Invalid Age'),
content: Text('Please enter a valid age.'),
actions: [
TextButton(
onPressed: () => Navigator.of(context).pop(),
child: Text('OK'),
),
],
),
);
return;
}
onAgeVerified(userAge);
}
@override
Widget build(BuildContext context) {
return Column(
children: [
TextField(
controller: ageController,
decoration: InputDecoration(
hintText: 'Enter your age',
),
keyboardType: TextInputType.number,
),
ElevatedButton(
onPressed: handleAgeSubmit,
child: Text('Submit'),
),
],
);
}
@override
void dispose() {
ageController.dispose();
super.dispose();
}
}
Importante: Chame este método o mais cedo possível depois de determinar que o utilizador tem menos de 13 anos, idealmente durante a inicialização da aplicação ou imediatamente após a verificação da idade. Isso garante que todo o rastreamento subsequente respeite os regulamentos de privacidade das crianças.
Configuração de LimitAdvertisingIdentifiers
Restringe a coleta e o uso de identificadores de publicidade (GAID no Android, IDFA no iOS) durante a inicialização do SDK para aplicativos que atendem a crianças.
Propriedade de configuração:
bool? limitAdvertisingIdentifiers
Parâmetros:
- true: Ativar o modo de identificadores de publicidade limitados (restringir a recolha)
- false: Desativar o modo de identificadores de publicidade limitados (recolha normal)
Casos de uso:
- Aplicações direcionadas para crianças: Aplicações concebidas principalmente para utilizadores com menos de 13 anos
- Aplicações de público misto: Aplicações que servem tanto adultos como crianças, em que a idade é determinada antes da inicialização do SDK
- Aplicações com prioridade à privacidade: Aplicar limitações de identificadores de publicidade desde o início
Para obter a documentação de configuração completa, consulte a referência limitAdvertisingIdentifiers.
Exemplo de configuração
Defina limitações de identificadores de publicidade durante a inicialização do SDK para aplicativos que conhecem os requisitos de privacidade desde o início.
import 'package:singular_flutter_sdk/singular.dart';
import 'package:singular_flutter_sdk/singular_config.dart';
// Limit advertising identifiers at initialization
void initializeSingular() {
final config = SingularConfig(
'YOUR_SDK_KEY',
'YOUR_SDK_SECRET'
);
// Enable limited advertising identifiers mode
config.limitAdvertisingIdentifiers = true;
Singular.start(config);
print('SDK initialized with advertising identifier restrictions');
}
Abordagem combinada: Para aplicações que servem crianças, combine trackingUnder13() com limitAdvertisingIdentifiers = true para garantir uma conformidade abrangente com a COPPA.
Melhores práticas de implementação
Exemplo de gestão de privacidade completa
Implemente controlos de privacidade abrangentes que respeitem as preferências do utilizador e cumpram os regulamentos.
import 'package:flutter/material.dart';
import 'package:singular_flutter_sdk/singular.dart';
import 'package:singular_flutter_sdk/singular_config.dart';
import 'package:shared_preferences/shared_preferences.dart';
const String PREF_USER_CONSENT = 'privacy_user_consent';
const String PREF_DATA_SHARING = 'privacy_data_sharing';
const String PREF_AGE_CATEGORY = 'user_age_category';
/// Initialize privacy settings on app startup based on stored preferences
Future<void> initializePrivacySettings() async {
final hasUserConsent = await getUserConsent();
final allowDataSharing = await getDataSharingPreference();
final ageCategory = await getAgeCategory();
// Apply age-based restrictions first
if (ageCategory == 'under_13') {
Singular.trackingUnder13();
print('COPPA restrictions applied on startup');
}
// Apply stored tracking preference
if (hasUserConsent) {
Singular.trackingOptIn();
Singular.resumeAllTracking();
print('Privacy initialized: Tracking enabled with consent');
} else {
Singular.stopAllTracking();
print('Privacy initialized: Tracking disabled');
}
// Set data sharing preference (inverse logic)
Singular.limitDataSharing(!allowDataSharing);
print('Privacy initialized: consent=$hasUserConsent, sharing=$allowDataSharing');
}
/// User accepts tracking via consent dialog
Future<void> onUserAcceptedTracking() async {
await saveUserConsent(true);
Singular.trackingOptIn();
Singular.resumeAllTracking();
print('User accepted tracking');
}
/// User declines tracking
Future<void> onUserDeclinedTracking() async {
await saveUserConsent(false);
Singular.stopAllTracking();
print('User declined tracking');
}
/// User updates data sharing preference
Future<void> setDataSharingEnabled(bool enabled) async {
await saveDataSharingPreference(enabled);
// Note: limitDataSharing uses inverse logic
// false = data sharing enabled, true = data sharing limited
Singular.limitDataSharing(!enabled);
print('Data sharing: ${enabled ? 'Enabled' : 'Limited'}');
}
/// Check if tracking is currently enabled
Future<bool> isTrackingEnabled() async {
final isStopped = await Singular.isAllTrackingStopped();
return !isStopped;
}
/// Get current privacy status as readable text
Future<String> getPrivacyStatus() async {
final isEnabled = await isTrackingEnabled();
final dataSharingEnabled = await getDataSharingPreference();
final ageCategory = await getAgeCategory();
String status = 'Tracking: ${isEnabled ? 'Enabled' : 'Disabled'}
';
status += 'Data Sharing: ${dataSharingEnabled ? 'Enabled' : 'Limited'}';
if (ageCategory == 'under_13') {
status += '
COPPA: Restrictions Applied';
}
return status;
}
// Private helper methods for SharedPreferences
Future<bool> getUserConsent() async {
final prefs = await SharedPreferences.getInstance();
return prefs.getBool(PREF_USER_CONSENT) ?? false;
}
Future<void> saveUserConsent(bool consent) async {
final prefs = await SharedPreferences.getInstance();
await prefs.setBool(PREF_USER_CONSENT, consent);
}
Future<bool> getDataSharingPreference() async {
final prefs = await SharedPreferences.getInstance();
return prefs.getBool(PREF_DATA_SHARING) ?? false;
}
Future<void> saveDataSharingPreference(bool enabled) async {
final prefs = await SharedPreferences.getInstance();
await prefs.setBool(PREF_DATA_SHARING, enabled);
}
Future<String?> getAgeCategory() async {
final prefs = await SharedPreferences.getInstance();
return prefs.getString(PREF_AGE_CATEGORY);
}
// Flutter widget to initialize privacy on app startup
class PrivacyInitializer extends StatefulWidget {
final Widget child;
const PrivacyInitializer({Key? key, required this.child}) : super(key: key);
@override
_PrivacyInitializerState createState() => _PrivacyInitializerState();
}
class _PrivacyInitializerState extends State<PrivacyInitializer> {
@override
void initState() {
super.initState();
initializePrivacySettings();
}
@override
Widget build(BuildContext context) {
return widget.child;
}
}
Principais diretrizes de implementação
Melhores práticas:
- Armazenamento persistente: Guarde as preferências do utilizador utilizando SharedPreferences ou uma solução de armazenamento seguro
- Inicialização antecipada: Aplicar configurações de privacidade antes da inicialização do SDK, quando possível
-
Sincronização da IU: Manter as configurações da interface do usuário sincronizadas com o estado real do SDK usando
isAllTrackingStopped() - Comunicação clara: Fornecer controlos de privacidade claros e acessíveis nas definições da aplicação
-
Lógica inversa: Lembre-se de que
limitDataSharing(false)significa que a partilha de dados está activada, enquantotruesignifica que está limitada -
Prioridade COPPA: Aplicar as protecções de privacidade das crianças (
trackingUnder13()) antes de outras definições de privacidade - Documentação de conformidade: Manter registos de quando e como os utilizadores fornecem ou revogam o consentimento