import 'dart:async'; import 'dart:typed_data'; import 'package:flutter/foundation.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:package_info_plus/package_info_plus.dart'; import '../network/dio_provider.dart'; import 'notification_permission.dart'; import 'umeng_push_service.dart'; class DevicePushRegistrar { DevicePushRegistrar(this._read); final T Function(ProviderListenable) _read; StreamSubscription? _subscription; String? _lastToken; bool? _lastPermission; int _attempt = 0; void start() { _subscription ??= UmengPushService.onDeviceToken.listen(_register); UmengPushService.emitCachedToken(); } Future stop() async => _subscription?.cancel(); Future refresh() => UmengPushService.refreshDeviceToken(); void forceRegisterCurrentToken() { _lastToken = null; _lastPermission = null; UmengPushService.emitCachedToken(); } Future _register(String token) async { final permission = await NotificationPermission.isGranted(); if (token == _lastToken && permission == _lastPermission) return; try { final package = await PackageInfo.fromPlatform(); await _read(dioProvider).post>( '/api/v1/push/devices', data: _PushRegisterRequest( token: token, platform: defaultTargetPlatform == TargetPlatform.iOS ? 1 : 2, version: package.version, permission: permission, ).toBytes(), options: protobufOptions(), ); _lastToken = token; _lastPermission = permission; _attempt = 0; } catch (_) { if (_attempt++ >= 3) return; await Future.delayed(Duration(seconds: 1 << (_attempt - 1))); await _register(token); } } } class _PushRegisterRequest { const _PushRegisterRequest({ required this.token, required this.platform, required this.version, required this.permission, }); final String token; final int platform; final String version; final bool permission; Uint8List toBytes() { final bytes = BytesBuilder(copy: false); void putInt(int value) { while (value > 0x7f) { bytes.addByte((value & 0x7f) | 0x80); value >>= 7; } bytes.addByte(value); } void putString(int tag, String value) { final raw = value.codeUnits; putInt((tag << 3) | 2); putInt(raw.length); bytes.add(raw); } putString(1, token); putInt(2 << 3); putInt(platform); putString(3, version); putInt(4 << 3); putInt(permission ? 1 : 0); return bytes.toBytes(); } }