59992af778
The local notifications plugin was initialised without iOS settings, so flutter_local_notifications threw "iOS settings must be set" before the app registered with Apple, and restoreMode swallowed the error. iPhones never sent the relay an APNs token for message wake-ups or a VoIP token for calls. - add DarwinInitializationSettings and request iOS permission explicitly - register with Apple before asking for notification permission (silent wake-ups do not need it) - send the VoIP token on its own (PLATFORM_APNS with an empty endpoint) when no APNs token is available yet - record a failed registration so the chat list shows it instead of failing silently - drop the force cast of rootViewController in AppDelegate and the unused SceneDelegate
131 lines
3.9 KiB
Dart
131 lines
3.9 KiB
Dart
import 'dart:convert';
|
|
|
|
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:sepot/core/push/push_service.dart';
|
|
import 'package:sepot/core/services/messaging_service.dart';
|
|
import 'package:sepot/core/storage/secure_storage.dart';
|
|
import 'package:sepot/proto/sepot.pb.dart' as pb;
|
|
|
|
/// iPhony relayi neposílaly APNs ani VoIP token: init lokálních notifikací
|
|
/// na iOS házel výjimku, ta zastavila registraci u Apple a restoreMode ji
|
|
/// spolkl. Tady se hlídá pořadí kroků a skládání registrace bez iPhonu.
|
|
class _FakeMessaging extends MessagingService {
|
|
_FakeMessaging() : super(storage: SecureStorageService());
|
|
|
|
final registrations = <pb.RegisterPush>[];
|
|
|
|
@override
|
|
void registerPush(pb.RegisterPush registration) =>
|
|
registrations.add(registration);
|
|
}
|
|
|
|
class _FakeIos extends IosPushPlatform {
|
|
_FakeIos({
|
|
this.apns,
|
|
this.voip,
|
|
this.permissionFails = false,
|
|
this.registerFails = false,
|
|
});
|
|
|
|
final String? apns;
|
|
final String? voip;
|
|
final bool permissionFails;
|
|
final bool registerFails;
|
|
final calls = <String>[];
|
|
bool? failedFlag;
|
|
String? mode;
|
|
|
|
@override
|
|
bool get isIOS => true;
|
|
|
|
@override
|
|
Future<void> registerApns() async {
|
|
calls.add('register');
|
|
if (registerFails) throw StateError('apns channel');
|
|
}
|
|
|
|
@override
|
|
Future<String?> apnsToken() async => apns;
|
|
|
|
@override
|
|
Future<String?> voipToken() async => voip;
|
|
|
|
@override
|
|
Future<void> requestPermission() async {
|
|
calls.add('permission');
|
|
if (permissionFails) {
|
|
throw ArgumentError('iOS settings must be set');
|
|
}
|
|
}
|
|
|
|
@override
|
|
Future<void> writeMode(String m) async => mode = m;
|
|
|
|
@override
|
|
Future<void> setRegistrationFailed(bool failed) async => failedFlag = failed;
|
|
}
|
|
|
|
void main() {
|
|
setUp(() => FlutterSecureStorage.setMockInitialValues({}));
|
|
|
|
String text(List<int> bytes) => utf8.decode(bytes);
|
|
|
|
group('apnsRegistration', () {
|
|
test('APNs i VoIP v jedné registraci', () {
|
|
final reg = PushService.apnsRegistration(
|
|
apnsToken: 'ab12',
|
|
voipToken: 'cd34',
|
|
)!;
|
|
expect(reg.platform, pb.RegisterPush_Platform.PLATFORM_APNS);
|
|
expect(text(reg.endpoint), 'ab12');
|
|
expect(text(reg.voipToken), 'cd34');
|
|
});
|
|
|
|
test('samotný VoIP token jde s prázdným endpointem', () {
|
|
final reg = PushService.apnsRegistration(voipToken: 'cd34')!;
|
|
expect(reg.platform, pb.RegisterPush_Platform.PLATFORM_APNS);
|
|
expect(reg.endpoint, isEmpty);
|
|
expect(text(reg.voipToken), 'cd34');
|
|
});
|
|
|
|
test('bez tokenů se nic neposílá', () {
|
|
expect(PushService.apnsRegistration(), isNull);
|
|
});
|
|
});
|
|
|
|
test(
|
|
'selhané oprávnění nezastaví registraci u Apple ani token pro relay',
|
|
() async {
|
|
final messaging = _FakeMessaging();
|
|
final ios = _FakeIos(apns: 'ab12', voip: 'cd34', permissionFails: true);
|
|
await PushService(messaging, ios: ios).restoreMode();
|
|
|
|
expect(ios.calls, [
|
|
'register',
|
|
'permission',
|
|
], reason: 'registrace u Apple před dotazem na oprávnění');
|
|
expect(ios.mode, 'apns');
|
|
expect(ios.failedFlag, isFalse);
|
|
final reg = messaging.registrations.single;
|
|
expect(text(reg.endpoint), 'ab12');
|
|
expect(text(reg.voipToken), 'cd34');
|
|
},
|
|
);
|
|
|
|
test('VoIP token odejde, i když APNs token ještě nepřišel', () async {
|
|
final messaging = _FakeMessaging();
|
|
final push = PushService(messaging, ios: _FakeIos(voip: 'cd34'));
|
|
await push.refreshVoipToken();
|
|
final reg = messaging.registrations.single;
|
|
expect(reg.endpoint, isEmpty);
|
|
expect(text(reg.voipToken), 'cd34');
|
|
});
|
|
|
|
test('selhaná registrace se nespolkne — stav pushů ukáže chybu', () async {
|
|
final ios = _FakeIos(registerFails: true);
|
|
await PushService(_FakeMessaging(), ios: ios).restoreMode();
|
|
expect(ios.failedFlag, isTrue);
|
|
});
|
|
}
|