[94] support BG on iOS
This commit is contained in:
@@ -24,19 +24,16 @@ import 'package:streaming_shared_preferences/streaming_shared_preferences.dart';
|
|||||||
|
|
||||||
import 'firebase_options.dart';
|
import 'firebase_options.dart';
|
||||||
|
|
||||||
|
/// Constructs callback for background notification handling.
|
||||||
|
///
|
||||||
/// Will be invoked from another Isolate, that's why it's required to
|
/// Will be invoked from another Isolate, that's why it's required to
|
||||||
/// initialize everything again:
|
/// initialize everything again:
|
||||||
/// - Firebase
|
/// - Firebase
|
||||||
/// - StreamChatClient
|
/// - StreamChatClient
|
||||||
/// - StreamChatPersistenceClient
|
/// - StreamChatPersistenceClient
|
||||||
///
|
|
||||||
/// This callback is not called on iOS
|
|
||||||
@pragma('vm:entry-point')
|
@pragma('vm:entry-point')
|
||||||
Future<void> _onFirebaseBackgroundMessage(RemoteMessage message) async {
|
Future<void> _onFirebaseBackgroundMessage(RemoteMessage message) async {
|
||||||
// initialize Firebase
|
debugPrint('[onBackgroundMessage] #firebase; message: ${message.toMap()}');
|
||||||
await Firebase.initializeApp(
|
|
||||||
options: DefaultFirebaseOptions.currentPlatform,
|
|
||||||
);
|
|
||||||
final data = message.data;
|
final data = message.data;
|
||||||
// ensure that Push Notification was sent by Stream.
|
// ensure that Push Notification was sent by Stream.
|
||||||
if (data['sender'] != 'stream.chat') {
|
if (data['sender'] != 'stream.chat') {
|
||||||
@@ -46,6 +43,11 @@ Future<void> _onFirebaseBackgroundMessage(RemoteMessage message) async {
|
|||||||
if (data['type'] != 'message.new') {
|
if (data['type'] != 'message.new') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// If you're going to use Firebase services in the background, make sure
|
||||||
|
// you call `initializeApp` before using Firebase services.
|
||||||
|
await Firebase.initializeApp(
|
||||||
|
options: DefaultFirebaseOptions.currentPlatform,
|
||||||
|
);
|
||||||
// read existing user info.
|
// read existing user info.
|
||||||
String? apiKey, userId, token;
|
String? apiKey, userId, token;
|
||||||
if (!kIsWeb) {
|
if (!kIsWeb) {
|
||||||
@@ -57,25 +59,27 @@ Future<void> _onFirebaseBackgroundMessage(RemoteMessage message) async {
|
|||||||
if (userId == null || token == null) {
|
if (userId == null || token == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final client = buildStreamChatClient(apiKey ?? kDefaultStreamApiKey);
|
final chatClient = buildStreamChatClient(apiKey ?? kDefaultStreamApiKey);
|
||||||
final persistenceClient = StreamChatPersistenceClient();
|
try {
|
||||||
|
await chatClient.connectUser(
|
||||||
|
User(id: userId),
|
||||||
|
token,
|
||||||
|
// do not open WS connection
|
||||||
|
connectWebSocket: false,
|
||||||
|
);
|
||||||
|
// initialize persistence with current user
|
||||||
|
if (!chatPersistentClient.isConnected) {
|
||||||
|
await chatPersistentClient.connect(userId);
|
||||||
|
}
|
||||||
|
|
||||||
// initialize persistence with current user
|
final messageId = data['id'];
|
||||||
await persistenceClient.connect(userId);
|
final cid = data['cid'];
|
||||||
|
// pre-cache the new message using client and persistence.
|
||||||
// initialize client with current user
|
final response = await chatClient.getMessage(messageId);
|
||||||
await client.connectUser(
|
await chatPersistentClient.updateMessages(cid, [response.message]);
|
||||||
User(id: userId),
|
} catch (e, stk) {
|
||||||
token,
|
debugPrint('[onBackgroundMessage] #firebase; failed: $e; $stk');
|
||||||
// do not open WS connection
|
}
|
||||||
connectWebSocket: false,
|
|
||||||
);
|
|
||||||
|
|
||||||
final messageId = data['id'];
|
|
||||||
final cid = data['cid'];
|
|
||||||
// pre-cache the new message using client and persistence.
|
|
||||||
final response = await client.getMessage(messageId);
|
|
||||||
await persistenceClient.updateMessages(cid, [response.message]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final chatPersistentClient = StreamChatPersistenceClient(
|
final chatPersistentClient = StreamChatPersistenceClient(
|
||||||
@@ -156,11 +160,14 @@ class _StreamChatSampleAppState extends State<StreamChatSampleApp>
|
|||||||
if (userId != null) {
|
if (userId != null) {
|
||||||
// Requests notification permission.
|
// Requests notification permission.
|
||||||
await FirebaseMessaging.instance.requestPermission();
|
await FirebaseMessaging.instance.requestPermission();
|
||||||
// Sets callback for background messages (it's not called on iOS)
|
// Sets callback for background messages.
|
||||||
FirebaseMessaging.onBackgroundMessage(_onFirebaseBackgroundMessage);
|
FirebaseMessaging.onBackgroundMessage(_onFirebaseBackgroundMessage);
|
||||||
// Sets callback for the notification click event.
|
// Sets callback for the notification click event.
|
||||||
firebaseSubscriptions.add(FirebaseMessaging.onMessageOpenedApp
|
firebaseSubscriptions.add(FirebaseMessaging.onMessageOpenedApp
|
||||||
.listen(_onFirebaseMessageOpenedApp(client)));
|
.listen(_onFirebaseMessageOpenedApp(client)));
|
||||||
|
// Sets callback for foreground messages
|
||||||
|
firebaseSubscriptions.add(FirebaseMessaging.onMessage
|
||||||
|
.listen(_onFirebaseForegroundMessage(client)));
|
||||||
// Sets callback for the token refresh event.
|
// Sets callback for the token refresh event.
|
||||||
firebaseSubscriptions.add(FirebaseMessaging.instance.onTokenRefresh
|
firebaseSubscriptions.add(FirebaseMessaging.instance.onTokenRefresh
|
||||||
.listen(_onFirebaseTokenRefresh(client)));
|
.listen(_onFirebaseTokenRefresh(client)));
|
||||||
@@ -186,6 +193,7 @@ class _StreamChatSampleAppState extends State<StreamChatSampleApp>
|
|||||||
/// Constructs callback for notification click event.
|
/// Constructs callback for notification click event.
|
||||||
OnRemoteMessage _onFirebaseMessageOpenedApp(StreamChatClient client) {
|
OnRemoteMessage _onFirebaseMessageOpenedApp(StreamChatClient client) {
|
||||||
return (message) async {
|
return (message) async {
|
||||||
|
debugPrint('[onMessageOpenedApp] #firebase; message: ${message.toMap()}');
|
||||||
// This callback is getting invoked when the user clicks
|
// This callback is getting invoked when the user clicks
|
||||||
// on the notification in case if notification was shown by OS.
|
// on the notification in case if notification was shown by OS.
|
||||||
final channelType = (message.data['channel_type'] as String?) ?? '';
|
final channelType = (message.data['channel_type'] as String?) ?? '';
|
||||||
@@ -207,11 +215,20 @@ class _StreamChatSampleAppState extends State<StreamChatSampleApp>
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Constructs callback for foreground notification handling.
|
||||||
|
OnRemoteMessage _onFirebaseForegroundMessage(StreamChatClient client) {
|
||||||
|
return (message) async {
|
||||||
|
debugPrint(
|
||||||
|
'[onForegroundMessage] #firebase; message: ${message.toMap()}');
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/// Constructs callback for notification refresh event.
|
/// Constructs callback for notification refresh event.
|
||||||
Future<void> Function(String) _onFirebaseTokenRefresh(
|
Future<void> Function(String) _onFirebaseTokenRefresh(
|
||||||
StreamChatClient client,
|
StreamChatClient client,
|
||||||
) {
|
) {
|
||||||
return (token) async {
|
return (token) async {
|
||||||
|
debugPrint('[onTokenRefresh] #firebase; token: $token');
|
||||||
// This callback is getting invoked when the token got refreshed.
|
// This callback is getting invoked when the token got refreshed.
|
||||||
await client.addDevice(token, PushProvider.firebase);
|
await client.addDevice(token, PushProvider.firebase);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:example/routes/routes.dart';
|
import 'package:example/routes/routes.dart';
|
||||||
import 'package:example/utils/notifications_service.dart';
|
import 'package:example/utils/notifications_service.dart' as pn;
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
|
|
||||||
@@ -36,7 +36,7 @@ class LocalNotificationObserver extends NavigatorObserver {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
showLocalNotification(
|
pn.showLocalNotification(
|
||||||
event,
|
event,
|
||||||
client.state.currentUser!.id,
|
client.state.currentUser!.id,
|
||||||
navigatorKey.currentState!.context,
|
navigatorKey.currentState!.context,
|
||||||
|
|||||||
@@ -74,3 +74,8 @@ void showLocalNotification(
|
|||||||
payload: '${event.channelType}:${event.channelId}',
|
payload: '${event.channelType}:${event.channelId}',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> cancelLocalNotifications() async {
|
||||||
|
final flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
|
||||||
|
await flutterLocalNotificationsPlugin.cancelAll();
|
||||||
|
}
|
||||||
|
|||||||
@@ -12,11 +12,20 @@ dependencies:
|
|||||||
flutter:
|
flutter:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
stream_chat_flutter:
|
stream_chat_flutter:
|
||||||
path: ../../../stream-chat-flutter/packages/stream_chat_flutter
|
git:
|
||||||
|
url: https://github.com/GetStream/stream-chat-flutter.git
|
||||||
|
ref: develop
|
||||||
|
path: packages/stream_chat_flutter
|
||||||
stream_chat_persistence:
|
stream_chat_persistence:
|
||||||
path: ../../../stream-chat-flutter/packages/stream_chat_persistence
|
git:
|
||||||
|
url: https://github.com/GetStream/stream-chat-flutter.git
|
||||||
|
ref: develop
|
||||||
|
path: packages/stream_chat_persistence
|
||||||
stream_chat_localizations:
|
stream_chat_localizations:
|
||||||
path: ../../../stream-chat-flutter/packages/stream_chat_localizations
|
git:
|
||||||
|
url: https://github.com/GetStream/stream-chat-flutter.git
|
||||||
|
ref: develop
|
||||||
|
path: packages/stream_chat_localizations
|
||||||
flutter_local_notifications: ^9.0.0
|
flutter_local_notifications: ^9.0.0
|
||||||
flutter_svg: ^2.0.4
|
flutter_svg: ^2.0.4
|
||||||
flutter_secure_storage: ^6.0.0
|
flutter_secure_storage: ^6.0.0
|
||||||
@@ -37,11 +46,20 @@ dev_dependencies:
|
|||||||
|
|
||||||
dependency_overrides:
|
dependency_overrides:
|
||||||
stream_chat:
|
stream_chat:
|
||||||
path: ../../../stream-chat-flutter/packages/stream_chat
|
git:
|
||||||
|
url: https://github.com/GetStream/stream-chat-flutter.git
|
||||||
|
ref: develop
|
||||||
|
path: packages/stream_chat
|
||||||
stream_chat_flutter_core:
|
stream_chat_flutter_core:
|
||||||
path: ../../../stream-chat-flutter/packages/stream_chat_flutter_core
|
git:
|
||||||
|
url: https://github.com/GetStream/stream-chat-flutter.git
|
||||||
|
ref: develop
|
||||||
|
path: packages/stream_chat_flutter_core
|
||||||
stream_chat_flutter:
|
stream_chat_flutter:
|
||||||
path: ../../../stream-chat-flutter/packages/stream_chat_flutter
|
git:
|
||||||
|
url: https://github.com/GetStream/stream-chat-flutter.git
|
||||||
|
ref: develop
|
||||||
|
path: packages/stream_chat_flutter
|
||||||
|
|
||||||
flutter:
|
flutter:
|
||||||
uses-material-design: true
|
uses-material-design: true
|
||||||
|
|||||||
Reference in New Issue
Block a user