Skip to content

Commit b37722d

Browse files
authored
feat(messaging, web): add support for custom service worker script path in getToken method (#18290)
1 parent 3b77147 commit b37722d

8 files changed

Lines changed: 63 additions & 12 deletions

File tree

packages/firebase_messaging/firebase_messaging/lib/src/messaging.dart

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,11 +114,17 @@ class FirebaseMessaging extends FirebasePluginPlatform {
114114
/// Returns the default FCM token for this device.
115115
///
116116
/// On web, a [vapidKey] is required.
117+
///
118+
/// On web, a custom messaging service worker can be registered with
119+
/// [serviceWorkerScriptPath]. This must point to a JavaScript file in the
120+
/// root of the app's `web` directory.
117121
Future<String?> getToken({
118122
String? vapidKey,
123+
String? serviceWorkerScriptPath,
119124
}) {
120125
return _delegate.getToken(
121126
vapidKey: vapidKey,
127+
serviceWorkerScriptPath: serviceWorkerScriptPath,
122128
);
123129
}
124130

packages/firebase_messaging/firebase_messaging/test/firebase_messaging_test.dart

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -99,12 +99,35 @@ void main() {
9999
group('getToken', () {
100100
test('verify delegate method is called with correct args', () async {
101101
const vapidKey = 'test-vapid-key';
102-
when(kMockMessagingPlatform.getToken(vapidKey: anyNamed('vapidKey')))
103-
.thenAnswer((_) => Future.value(''));
102+
when(kMockMessagingPlatform.getToken(
103+
vapidKey: anyNamed('vapidKey'),
104+
serviceWorkerScriptPath: anyNamed('serviceWorkerScriptPath'),
105+
)).thenAnswer((_) => Future.value(''));
104106

105107
await messaging!.getToken(vapidKey: vapidKey);
106108

107-
verify(kMockMessagingPlatform.getToken(vapidKey: vapidKey));
109+
verify(kMockMessagingPlatform.getToken(
110+
vapidKey: vapidKey,
111+
serviceWorkerScriptPath: null,
112+
));
113+
});
114+
115+
test('verify delegate method is called with service worker path',
116+
() async {
117+
const serviceWorkerScriptPath = 'custom-messaging-sw.js';
118+
when(kMockMessagingPlatform.getToken(
119+
vapidKey: anyNamed('vapidKey'),
120+
serviceWorkerScriptPath: anyNamed('serviceWorkerScriptPath'),
121+
)).thenAnswer((_) => Future.value(''));
122+
123+
await messaging!.getToken(
124+
serviceWorkerScriptPath: serviceWorkerScriptPath,
125+
);
126+
127+
verify(kMockMessagingPlatform.getToken(
128+
vapidKey: null,
129+
serviceWorkerScriptPath: serviceWorkerScriptPath,
130+
));
108131
});
109132
});
110133

packages/firebase_messaging/firebase_messaging/test/mock.dart

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,9 +96,12 @@ class MockFirebaseMessaging extends Mock
9696
}
9797

9898
@override
99-
Future<String> getToken({String? vapidKey}) {
99+
Future<String> getToken({String? vapidKey, String? serviceWorkerScriptPath}) {
100100
return super.noSuchMethod(
101-
Invocation.method(#getToken, [], {#vapidKey: vapidKey}),
101+
Invocation.method(#getToken, [], {
102+
#vapidKey: vapidKey,
103+
#serviceWorkerScriptPath: serviceWorkerScriptPath
104+
}),
102105
returnValue: Future<String>.value(''),
103106
returnValueForMissingStub: Future<String>.value(''));
104107
}

packages/firebase_messaging/firebase_messaging_platform_interface/lib/src/method_channel/method_channel_messaging.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,7 @@ class MethodChannelFirebaseMessaging extends FirebaseMessagingPlatform {
240240
@override
241241
Future<String?> getToken({
242242
String? vapidKey, // not used yet; web only property
243+
String? serviceWorkerScriptPath, // web only property
243244
}) async {
244245
await _APNSTokenCheck();
245246

packages/firebase_messaging/firebase_messaging_platform_interface/lib/src/platform_interface/platform_interface_messaging.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,7 @@ abstract class FirebaseMessagingPlatform extends PlatformInterface {
173173
/// Returns the default FCM token for this device and optionally [senderId].
174174
Future<String?> getToken({
175175
String? vapidKey,
176+
String? serviceWorkerScriptPath,
176177
}) {
177178
throw UnimplementedError('getToken() is not implemented');
178179
}

packages/firebase_messaging/firebase_messaging_web/lib/firebase_messaging_web.dart

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,8 @@ class FirebaseMessagingWeb extends FirebaseMessagingPlatform {
112112
}
113113

114114
@override
115-
Future<String?> getToken({String? vapidKey}) async {
115+
Future<String?> getToken(
116+
{String? vapidKey, String? serviceWorkerScriptPath}) async {
116117
_delegate;
117118

118119
if (!_initialized) {
@@ -121,7 +122,8 @@ class FirebaseMessagingWeb extends FirebaseMessagingPlatform {
121122
}
122123

123124
return convertWebExceptions(
124-
() => _delegate.getToken(vapidKey: vapidKey),
125+
() => _delegate.getToken(
126+
vapidKey: vapidKey, serviceWorkerScriptPath: serviceWorkerScriptPath),
125127
);
126128
}
127129

packages/firebase_messaging/firebase_messaging_web/lib/src/interop/messaging.dart

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import 'dart:async';
99
import 'dart:js_interop';
1010

1111
import 'package:firebase_core_web/firebase_core_web_interop.dart';
12-
12+
import 'package:web/web.dart' as web;
1313
import 'messaging_interop.dart' as messaging_interop;
1414

1515
export 'messaging_interop.dart';
@@ -43,15 +43,24 @@ class Messaging extends JsObjectWrapper<messaging_interop.MessagingJsImpl> {
4343

4444
/// After calling [requestPermission] you can call this method to get an FCM registration token
4545
/// that can be used to send push messages to this user.
46-
Future<String> getToken({String? vapidKey}) async {
46+
Future<String> getToken(
47+
{String? vapidKey, String? serviceWorkerScriptPath}) async {
4748
try {
49+
web.ServiceWorkerRegistration? serviceWorkerRegistration;
50+
if (serviceWorkerScriptPath != null) {
51+
serviceWorkerRegistration = await web.window.navigator.serviceWorker
52+
.register(serviceWorkerScriptPath.toJS)
53+
.toDart;
54+
}
4855
final token = (await messaging_interop
4956
.getToken(
5057
jsObject,
51-
vapidKey == null
58+
vapidKey == null && serviceWorkerRegistration == null
5259
? null
5360
: messaging_interop.GetTokenOptions(
54-
vapidKey: vapidKey.toJS))
61+
vapidKey: vapidKey?.toJS,
62+
serviceWorkerRegistration: serviceWorkerRegistration,
63+
))
5564
.toDart)
5665
.toDart;
5766
return token;
@@ -62,7 +71,10 @@ class Messaging extends JsObjectWrapper<messaging_interop.MessagingJsImpl> {
6271
if (err.toString().toLowerCase().contains('no active service worker') &&
6372
firstGetTokenCall) {
6473
firstGetTokenCall = false;
65-
return getToken(vapidKey: vapidKey);
74+
return getToken(
75+
vapidKey: vapidKey,
76+
serviceWorkerScriptPath: serviceWorkerScriptPath,
77+
);
6678
}
6779
rethrow;
6880
}

packages/firebase_messaging/firebase_messaging_web/lib/src/interop/messaging_interop.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
library;
1010

1111
import 'dart:js_interop';
12+
import 'package:web/web.dart' as web;
1213

1314
import 'package:firebase_core_web/firebase_core_web_interop.dart';
1415

@@ -50,8 +51,10 @@ extension type GetTokenOptions._(JSObject _) implements JSObject {
5051
external factory GetTokenOptions({
5152
JSString? vapidKey,
5253
/*dynamic serviceWorkerRegistration */
54+
web.ServiceWorkerRegistration? serviceWorkerRegistration,
5355
});
5456
external JSString get vapidKey;
57+
external web.ServiceWorkerRegistration get serviceWorkerRegistration;
5558
}
5659

5760
extension type NotificationPayloadJsImpl._(JSObject _) implements JSObject {

0 commit comments

Comments
 (0)