Skip to content

Commit

Permalink
fix(messaging): Throw exception if APNS token is not yet available (#…
Browse files Browse the repository at this point in the history
…11400)

Co-authored-by: Kevin Cheung <kevinthecheung@users.noreply.github.com>
  • Loading branch information
russellwheatley and kevinthecheung committed Aug 23, 2023
1 parent 071adde commit 346d602
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 1 deletion.
14 changes: 13 additions & 1 deletion docs/cloud-messaging/client.md
Expand Up @@ -144,8 +144,20 @@ To retrieve the current registration token for an app instance, call
ask the user for notification permissions. Otherwise, it returns a token or
rejects the future due to an error.

Warning: In iOS SDK 10.4.0 and higher, it is a requirement that the APNs token
is available before making API requests. The APNs token is not guaranteed to have been received
before making FCM plugin API requests.

```dart
final fcmToken = await FirebaseMessaging.instance.getToken();
// You may set the permission requests to "provisional" which allows the user to choose what type
// of notifications they would like to receive once the user receives a notification.
final notificationSettings = await FirebaseMessaging.instance.requestPermission(provisional: true);
// For apple platforms, ensure the APNS token is available before making any FCM plugin API calls
final apnsToken = await FirebaseMessaging.instance.getAPNSToken();
if (apnsToken != null) {
// APNS token is available, make FCM plugin API requests...
}
```

On web platforms, pass your VAPID public key to `getToken()`:
Expand Down
Expand Up @@ -4,6 +4,7 @@
// BSD-style license that can be found in the LICENSE file.

import 'dart:async';
import 'dart:io' show Platform;
import 'dart:ui';

import 'package:firebase_core/firebase_core.dart';
Expand Down Expand Up @@ -126,6 +127,24 @@ class MethodChannelFirebaseMessaging extends FirebaseMessagingPlatform {
static StreamController<String> tokenStreamController =
StreamController<String>.broadcast();

// Created this to check APNS token is available before certain Apple Firebase
// Messaging requests. See this issue:
// https://github.com/firebase/flutterfire/issues/10625
Future<void> _APNSTokenCheck() async {
if (Platform.isMacOS || Platform.isIOS) {
String? token = await getAPNSToken();

if (token == null) {
throw FirebaseException(
plugin: 'firebase_messaging',
code: 'apns-token-not-set',
message:
'APNS token has not been set yet. Please ensure the APNS token is available by calling `getAPNSToken()`.',
);
}
}
}

@override
FirebaseMessagingPlatform delegateFor({required FirebaseApp app}) {
return MethodChannelFirebaseMessaging(app: app);
Expand Down Expand Up @@ -189,6 +208,8 @@ class MethodChannelFirebaseMessaging extends FirebaseMessagingPlatform {

@override
Future<void> deleteToken() async {
await _APNSTokenCheck();

try {
await channel
.invokeMapMethod('Messaging#deleteToken', {'appName': app.name});
Expand Down Expand Up @@ -220,6 +241,8 @@ class MethodChannelFirebaseMessaging extends FirebaseMessagingPlatform {
Future<String?> getToken({
String? vapidKey, // not used yet; web only property
}) async {
await _APNSTokenCheck();

try {
Map<String, String?>? data =
await channel.invokeMapMethod<String, String>('Messaging#getToken', {
Expand Down Expand Up @@ -364,6 +387,8 @@ class MethodChannelFirebaseMessaging extends FirebaseMessagingPlatform {

@override
Future<void> subscribeToTopic(String topic) async {
await _APNSTokenCheck();

try {
await channel.invokeMapMethod('Messaging#subscribeToTopic', {
'appName': app.name,
Expand All @@ -376,6 +401,8 @@ class MethodChannelFirebaseMessaging extends FirebaseMessagingPlatform {

@override
Future<void> unsubscribeFromTopic(String topic) async {
await _APNSTokenCheck();

try {
await channel.invokeMapMethod('Messaging#unsubscribeFromTopic', {
'appName': app.name,
Expand Down

0 comments on commit 346d602

Please sign in to comment.