Flutter Web permission/display/click smoke를 반복 검증할 수 있도록 테스트 호스트 UI와 위젯 테스트를 갱신한다. 리뷰 완료 산출물을 archive로 이동해 마일스톤 test-host 완료 근거를 남긴다.
194 lines
6.4 KiB
Dart
194 lines
6.4 KiB
Dart
import 'dart:async';
|
|
|
|
import 'package:firebase_core/firebase_core.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:nexo_messaging/nexo_messaging.dart';
|
|
|
|
Future<void> main() async {
|
|
WidgetsFlutterBinding.ensureInitialized();
|
|
await Firebase.initializeApp();
|
|
runApp(const MyApp());
|
|
}
|
|
|
|
class MyApp extends StatefulWidget {
|
|
const MyApp({super.key, this.initializePlugin = true});
|
|
|
|
final bool initializePlugin;
|
|
|
|
@override
|
|
State<MyApp> createState() => _MyAppState();
|
|
}
|
|
|
|
class _MyAppState extends State<MyApp> {
|
|
String? _deviceToken;
|
|
String? _lastNotification;
|
|
String? _lastOpened;
|
|
String? _lastNavigation;
|
|
NexoMessagingWebNotificationStatus? _webNotificationStatus;
|
|
NexoMessagingWebNotificationDisplayResult? _lastWebDisplay;
|
|
StreamSubscription<Map<String, dynamic>>? _notificationSubscription;
|
|
StreamSubscription<NotificationOpenedEvent>? _openedSubscription;
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
final plugin = NexoMessagingPlugin.instance;
|
|
plugin.onDeviceTokenReady = (token) {
|
|
if (!mounted) return;
|
|
setState(() => _deviceToken = token);
|
|
};
|
|
plugin.onNavigateToChannel = (serverUrl, channelId) {
|
|
if (!mounted) return;
|
|
setState(() => _lastNavigation = 'channel:$serverUrl/$channelId');
|
|
};
|
|
plugin.onNavigateToThread = (serverUrl, rootId) {
|
|
if (!mounted) return;
|
|
setState(() => _lastNavigation = 'thread:$serverUrl/$rootId');
|
|
};
|
|
_notificationSubscription = plugin.onNotification.listen((event) {
|
|
if (!mounted) return;
|
|
setState(() => _lastNotification = _formatMap(event));
|
|
});
|
|
_openedSubscription = plugin.onNotificationOpened.listen((event) {
|
|
if (!mounted) return;
|
|
setState(() => _lastOpened = _formatOpened(event));
|
|
});
|
|
if (widget.initializePlugin) {
|
|
unawaited(_initializePlugin(plugin));
|
|
}
|
|
}
|
|
|
|
Future<void> _initializePlugin(NexoMessagingPlugin plugin) async {
|
|
try {
|
|
await _configureSmokeAuthToken(plugin);
|
|
await plugin.initialize();
|
|
} catch (error, stackTrace) {
|
|
debugPrint('[NexoClient] Failed to initialize messaging plugin: $error');
|
|
debugPrintStack(stackTrace: stackTrace);
|
|
}
|
|
}
|
|
|
|
Future<void> _configureSmokeAuthToken(NexoMessagingPlugin plugin) async {
|
|
const serverUrl = String.fromEnvironment('NEXO_SMOKE_SERVER_URL');
|
|
const authToken = String.fromEnvironment('NEXO_SMOKE_AUTH_TOKEN');
|
|
const identifier = String.fromEnvironment('NEXO_SMOKE_SERVER_IDENTIFIER');
|
|
if (serverUrl.isEmpty || authToken.isEmpty) return;
|
|
|
|
await plugin.setAuthToken(
|
|
serverUrl,
|
|
authToken,
|
|
identifier: identifier.isEmpty ? null : identifier,
|
|
);
|
|
debugPrint('[NexoClient] Smoke auth token configured');
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
_notificationSubscription?.cancel();
|
|
_openedSubscription?.cancel();
|
|
final plugin = NexoMessagingPlugin.instance;
|
|
plugin.onDeviceTokenReady = null;
|
|
plugin.onNavigateToChannel = null;
|
|
plugin.onNavigateToThread = null;
|
|
super.dispose();
|
|
}
|
|
|
|
String _formatMap(Map<String, dynamic> map) {
|
|
return map.entries.map((e) => '${e.key}: ${e.value}').join(', ');
|
|
}
|
|
|
|
String _formatOpened(NotificationOpenedEvent event) {
|
|
return 'server_url: ${event.serverUrl}, channel_id: ${event.channelId}, root_id: ${event.rootId}, is_crt_enabled: ${event.isCRTEnabled}';
|
|
}
|
|
|
|
String _formatWebSupport() {
|
|
if (_webNotificationStatus == null) return 'unknown';
|
|
return _webNotificationStatus!.isSupported ? 'yes' : 'no';
|
|
}
|
|
|
|
String _formatWebPermission() {
|
|
if (_webNotificationStatus == null) return 'unknown';
|
|
return _webNotificationStatus!.permission.name;
|
|
}
|
|
|
|
String _formatWebDisplay() {
|
|
if (_lastWebDisplay == null) return 'none';
|
|
if (!_lastWebDisplay!.isSupported) return 'unsupported';
|
|
if (!_lastWebDisplay!.permissionGranted) return 'permission denied';
|
|
return _lastWebDisplay!.success ? 'shown' : 'failed';
|
|
}
|
|
|
|
Future<void> _refreshWebNotificationStatus(NexoMessagingPlugin plugin) async {
|
|
try {
|
|
final status = await plugin.getWebNotificationPermissionStatus();
|
|
if (!mounted) return;
|
|
setState(() => _webNotificationStatus = status);
|
|
} catch (e) {
|
|
debugPrint('[NexoClient] Web permission refresh failed: $e');
|
|
}
|
|
}
|
|
|
|
Future<void> _requestWebNotificationPermission(
|
|
NexoMessagingPlugin plugin,
|
|
) async {
|
|
try {
|
|
final status = await plugin.requestWebNotificationPermission();
|
|
if (!mounted) return;
|
|
setState(() => _webNotificationStatus = status);
|
|
} catch (e) {
|
|
debugPrint('[NexoClient] Web permission request failed: $e');
|
|
}
|
|
}
|
|
|
|
void _showWebSmokeNotification(NexoMessagingPlugin plugin) {
|
|
final result = plugin.showWebForegroundNotification({
|
|
'title': 'Nexo Smoke',
|
|
'body': 'Web notification smoke test',
|
|
'server_url': 'https://nexo.example.com',
|
|
'channel_id': 'smoke-channel',
|
|
});
|
|
setState(() => _lastWebDisplay = result);
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final plugin = NexoMessagingPlugin.instance;
|
|
return MaterialApp(
|
|
home: Scaffold(
|
|
appBar: AppBar(title: const Text('Nexo client')),
|
|
body: ListView(
|
|
padding: const EdgeInsets.all(16),
|
|
children: [
|
|
Text('Device token: ${_deviceToken ?? 'pending'}'),
|
|
Text('Last notification: ${_lastNotification ?? 'none'}'),
|
|
Text('Last opened: ${_lastOpened ?? 'none'}'),
|
|
Text('Last navigation: ${_lastNavigation ?? 'none'}'),
|
|
Text('Web notification support: ${_formatWebSupport()}'),
|
|
Text(
|
|
'Web notification permission: ${_formatWebPermission()}',
|
|
key: const Key('web-permission-status'),
|
|
),
|
|
Text(
|
|
'Last web display: ${_formatWebDisplay()}',
|
|
key: const Key('web-display-status'),
|
|
),
|
|
ElevatedButton(
|
|
onPressed: () =>
|
|
unawaited(_refreshWebNotificationStatus(plugin)),
|
|
child: const Text('Refresh web permission'),
|
|
),
|
|
ElevatedButton(
|
|
onPressed: () =>
|
|
unawaited(_requestWebNotificationPermission(plugin)),
|
|
child: const Text('Request web permission'),
|
|
),
|
|
ElevatedButton(
|
|
onPressed: () => _showWebSmokeNotification(plugin),
|
|
child: const Text('Show web smoke notification'),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|