push_service_client 1.0.0 copy "push_service_client: ^1.0.0" to clipboard
push_service_client: ^1.0.0 copied to clipboard

Cliente Flutter para o Push Service — regista devices sozinho (estilo OneSignal) e recebe push notifications (FCM/APNs).

example/lib/main.dart

import 'dart:async';

import 'package:flutter/material.dart';

import 'package:push_service_client/push_service_client.dart';

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();

  // TODO: substituir pelo App ID público da tua app no Push Service
  // (painel → Aplicações → API → App ID). Não é secreto.
  final push = PushService(
    appId: 'UUID-PUBLICO-DA-TUA-APP',
  );

  final device = await push.initialize(
    tags: {'app': 'exemplo'},
    onOpened: (notification) {
      debugPrint('Push aberto: ${notification.title} — ${notification.data}');
    },
    onReceived: (notification) {
      debugPrint('Push recebido: ${notification.title}');
    },
  );

  // Guarda device.subscriptionId no teu backend — é o id para enviar pushes.
  debugPrint('Subscription ID: ${device.subscriptionId}');

  runApp(PushServiceExampleApp(push: push));
}

class PushServiceExampleApp extends StatefulWidget {
  const PushServiceExampleApp({super.key, required this.push});

  final PushService push;

  @override
  State<PushServiceExampleApp> createState() => _PushServiceExampleAppState();
}

/// Envia atividade (sessões e tempo de uso) para o Push Service quando a app
/// vai para segundo plano, para o painel mostrar dados reais.
class _ActivityTracker extends WidgetsBindingObserver {
  _ActivityTracker(this.push);

  final PushService push;

  DateTime? _foregroundSince;
  bool _sessionSent = false;

  /// Marca o início da sessão no servidor (primeira sessão incluída).
  Future<void> start() async {
    final device = push.device;
    if (device == null || _sessionSent) return;
    _sessionSent = true;

    _foregroundSince = DateTime.now();

    try {
      await push.trackActivity(
        sessions: 1,
        firstSessionAt: device.firstSessionAt ?? DateTime.now(),
      );
    } catch (_) {
      // Sem rede — tenta na próxima mudança de estado.
    }
  }

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    final device = push.device;
    if (device == null) return;

    if (state == AppLifecycleState.resumed) {
      _foregroundSince = DateTime.now();
      return;
    }

    if (state == AppLifecycleState.inactive ||
        state == AppLifecycleState.paused ||
        state == AppLifecycleState.hidden ||
        state == AppLifecycleState.detached) {
      final since = _foregroundSince;
      final duration = since != null
          ? DateTime.now().difference(since).inSeconds
          : 0;

      if (duration > 0) {
        unawaited(() async {
          try {
            await push.trackActivity(
              usageDuration: duration,
              sessionDuration: duration,
              sessionStartedAt: since,
              sessionEndedAt: DateTime.now(),
            );
          } catch (_) {
            // Sem rede — tenta na próxima mudança de estado.
          }
        }());
      }
    }
  }
}

class _PushServiceExampleAppState extends State<PushServiceExampleApp> {
  late final _ActivityTracker _tracker;

  @override
  void initState() {
    super.initState();
    _tracker = _ActivityTracker(widget.push);
    WidgetsBinding.instance.addObserver(_tracker);
    _tracker.start();
  }

  @override
  void dispose() {
    WidgetsBinding.instance.removeObserver(_tracker);
    super.dispose();
  }

  String get _status => widget.push.device != null
      ? 'Device registado!'
      : 'A registar...';

  Future<void> _unsubscribe() async {
    if (widget.push.device == null) return;

    try {
      await widget.push.unsubscribe();
      if (!mounted) return;
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(content: Text('Device desativado (não recebe pushes).')),
      );
    } catch (e) {
      if (!mounted) return;
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('Erro: $e')),
      );
    }
  }

  @override
  Widget build(BuildContext context) {
    final device = widget.push.device;

    return MaterialApp(
      title: 'Push Service Exemplo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(
          seedColor: const Color(0xFF576CDB),
          brightness: Brightness.light,
        ),
        useMaterial3: true,
      ),
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Push Service — Exemplo'),
          backgroundColor: const Color(0xFF576CDB),
          foregroundColor: Colors.white,
        ),
        body: Padding(
          padding: const EdgeInsets.all(24),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.stretch,
            children: [
              Card(
                child: Padding(
                  padding: const EdgeInsets.all(16),
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      const Text('Estado',
                          style: TextStyle(fontWeight: FontWeight.bold)),
                      const SizedBox(height: 8),
                      Text(_status),
                      if (device != null) ...[
                        const SizedBox(height: 8),
                        Text(
                            'Subscription ID: ${device.subscriptionId}'),
                        Text('Plataforma: ${device.platform}'),
                        Text('Subscrito: ${device.subscribed}'),
                      ],
                    ],
                  ),
                ),
              ),
              const SizedBox(height: 16),
              OutlinedButton.icon(
                onPressed: device == null ? null : _unsubscribe,
                icon: const Icon(Icons.notifications_off),
                label: const Text('Desativar notificações'),
              ),
              const Spacer(),
              const Text(
                'Configura o App ID público da tua app no ficheiro main.dart '
                'para ligar ao teu Push Service. Não te esqueças de adicionar '
                'o google-services.json (Android) ou GoogleService-Info.plist (iOS).',
                style: TextStyle(fontSize: 12, color: Colors.grey),
              ),
            ],
          ),
        ),
      ),
    );
  }
}
0
likes
150
points
315
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

Cliente Flutter para o Push Service — regista devices sozinho (estilo OneSignal) e recebe push notifications (FCM/APNs).

Homepage

License

MIT (license)

Dependencies

device_info_plus, firebase_core, firebase_messaging, flutter, flutter_timezone, http, package_info_plus

More

Packages that depend on push_service_client