diff --git a/packages/notifications/push/amplify_push_notifications/android/src/main/kotlin/com/amazonaws/amplify/amplify_push_notifications/AmplifyLifecycleObserver.kt b/packages/notifications/push/amplify_push_notifications/android/src/main/kotlin/com/amazonaws/amplify/amplify_push_notifications/AmplifyLifecycleObserver.kt index f2dd09c24c..8a750e6bd7 100644 --- a/packages/notifications/push/amplify_push_notifications/android/src/main/kotlin/com/amazonaws/amplify/amplify_push_notifications/AmplifyLifecycleObserver.kt +++ b/packages/notifications/push/amplify_push_notifications/android/src/main/kotlin/com/amazonaws/amplify/amplify_push_notifications/AmplifyLifecycleObserver.kt @@ -23,8 +23,4 @@ class AmplifyLifecycleObserver : DefaultLifecycleObserver { isAppLaunch = false super.onResume(owner) } - override fun onCreate(owner: LifecycleOwner) { - refreshToken() - super.onCreate(owner) - } } diff --git a/packages/notifications/push/amplify_push_notifications/android/src/main/kotlin/com/amazonaws/amplify/amplify_push_notifications/AmplifyPushNotificationsPlugin.kt b/packages/notifications/push/amplify_push_notifications/android/src/main/kotlin/com/amazonaws/amplify/amplify_push_notifications/AmplifyPushNotificationsPlugin.kt index 256c6b9d33..731d93fd50 100644 --- a/packages/notifications/push/amplify_push_notifications/android/src/main/kotlin/com/amazonaws/amplify/amplify_push_notifications/AmplifyPushNotificationsPlugin.kt +++ b/packages/notifications/push/amplify_push_notifications/android/src/main/kotlin/com/amazonaws/amplify/amplify_push_notifications/AmplifyPushNotificationsPlugin.kt @@ -185,6 +185,10 @@ class AmplifyPushNotificationsPlugin( return } + override fun requestInitialToken() { + refreshToken() + } + override fun getPermissionStatus(result: PushNotificationsHostApiBindings.Result) { val resultBuilder = PushNotificationsHostApiBindings.GetPermissionStatusResult.Builder() val permission = PushNotificationPermission(applicationContext) diff --git a/packages/notifications/push/amplify_push_notifications/android/src/main/kotlin/com/amazonaws/amplify/amplify_push_notifications/PushNotificationsHostApiBindings.java b/packages/notifications/push/amplify_push_notifications/android/src/main/kotlin/com/amazonaws/amplify/amplify_push_notifications/PushNotificationsHostApiBindings.java index bc0b6582a9..72f3c538f4 100644 --- a/packages/notifications/push/amplify_push_notifications/android/src/main/kotlin/com/amazonaws/amplify/amplify_push_notifications/PushNotificationsHostApiBindings.java +++ b/packages/notifications/push/amplify_push_notifications/android/src/main/kotlin/com/amazonaws/amplify/amplify_push_notifications/PushNotificationsHostApiBindings.java @@ -1,7 +1,7 @@ // // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 -// Autogenerated from Pigeon (v9.2.4), do not edit directly. +// Autogenerated from Pigeon (v9.2.5), do not edit directly. // See also: https://pub.dev/packages/pigeon package com.amazonaws.amplify.amplify_push_notifications; @@ -326,6 +326,8 @@ protected void writeValue(@NonNull ByteArrayOutputStream stream, Object value) { /** Generated interface from Pigeon that represents a handler of messages from Flutter. */ public interface PushNotificationsHostApi { + void requestInitialToken(); + void getPermissionStatus(@NonNull Result result); void requestPermissions(@NonNull PermissionsOptions withPermissionOptions, @NonNull Result result); @@ -346,6 +348,28 @@ public interface PushNotificationsHostApi { } /**Sets up an instance of `PushNotificationsHostApi` to handle messages through the `binaryMessenger`. */ static void setup(@NonNull BinaryMessenger binaryMessenger, @Nullable PushNotificationsHostApi api) { + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.PushNotificationsHostApi.requestInitialToken", getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + ArrayList wrapped = new ArrayList(); + try { + api.requestInitialToken(); + wrapped.add(0, null); + } + catch (Throwable exception) { + ArrayList wrappedError = wrapError(exception); + wrapped = wrappedError; + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } { BasicMessageChannel channel = new BasicMessageChannel<>( diff --git a/packages/notifications/push/amplify_push_notifications/ios/Classes/AmplifyPushNotificationsPlugin.swift b/packages/notifications/push/amplify_push_notifications/ios/Classes/AmplifyPushNotificationsPlugin.swift index d81aadfe82..42a7435510 100644 --- a/packages/notifications/push/amplify_push_notifications/ios/Classes/AmplifyPushNotificationsPlugin.swift +++ b/packages/notifications/push/amplify_push_notifications/ios/Classes/AmplifyPushNotificationsPlugin.swift @@ -32,6 +32,10 @@ public class AmplifyPushNotificationsPlugin: NSObject, FlutterPlugin, PushNotifi registrar.addApplicationDelegate(pluginInstance) } + public func requestInitialTokenWithError(_ error: AutoreleasingUnsafeMutablePointer) { + UIApplication.shared.registerForRemoteNotifications() + } + public func getPermissionStatus(completion: @escaping (GetPermissionStatusResult?, FlutterError?) -> Void) { Task { switch await AUNotificationPermissions.status { diff --git a/packages/notifications/push/amplify_push_notifications/ios/Classes/PushNotificationsNativePlugin.h b/packages/notifications/push/amplify_push_notifications/ios/Classes/PushNotificationsNativePlugin.h index 35be11c00a..f0f2980b16 100644 --- a/packages/notifications/push/amplify_push_notifications/ios/Classes/PushNotificationsNativePlugin.h +++ b/packages/notifications/push/amplify_push_notifications/ios/Classes/PushNotificationsNativePlugin.h @@ -1,7 +1,7 @@ // // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 -// Autogenerated from Pigeon (v9.2.4), do not edit directly. +// Autogenerated from Pigeon (v9.2.5), do not edit directly. // See also: https://pub.dev/packages/pigeon #import @@ -54,6 +54,7 @@ NSObject *PushNotificationsFlutterApiGetCodec(void); NSObject *PushNotificationsHostApiGetCodec(void); @protocol PushNotificationsHostApi +- (void)requestInitialTokenWithError:(FlutterError *_Nullable *_Nonnull)error; - (void)getPermissionStatusWithCompletion:(void (^)(GetPermissionStatusResult *_Nullable, FlutterError *_Nullable))completion; - (void)requestPermissionsWithPermissionOptions:(PermissionsOptions *)withPermissionOptions completion:(void (^)(NSNumber *_Nullable, FlutterError *_Nullable))completion; - (nullable NSDictionary *)getLaunchNotificationWithError:(FlutterError *_Nullable *_Nonnull)error; diff --git a/packages/notifications/push/amplify_push_notifications/ios/Classes/PushNotificationsNativePlugin.m b/packages/notifications/push/amplify_push_notifications/ios/Classes/PushNotificationsNativePlugin.m index f3242efb9e..5430c80d8e 100644 --- a/packages/notifications/push/amplify_push_notifications/ios/Classes/PushNotificationsNativePlugin.m +++ b/packages/notifications/push/amplify_push_notifications/ios/Classes/PushNotificationsNativePlugin.m @@ -1,7 +1,7 @@ // // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 -// Autogenerated from Pigeon (v9.2.4), do not edit directly. +// Autogenerated from Pigeon (v9.2.5), do not edit directly. // See also: https://pub.dev/packages/pigeon #import "PushNotificationsNativePlugin.h" @@ -229,6 +229,23 @@ - (FlutterStandardReader *)readerWithData:(NSData *)data { } void PushNotificationsHostApiSetup(id binaryMessenger, NSObject *api) { + { + FlutterBasicMessageChannel *channel = + [[FlutterBasicMessageChannel alloc] + initWithName:@"dev.flutter.pigeon.PushNotificationsHostApi.requestInitialToken" + binaryMessenger:binaryMessenger + codec:PushNotificationsHostApiGetCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(requestInitialTokenWithError:)], @"PushNotificationsHostApi api (%@) doesn't respond to @selector(requestInitialTokenWithError:)", api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + FlutterError *error; + [api requestInitialTokenWithError:&error]; + callback(wrapResult(nil, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } { FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] diff --git a/packages/notifications/push/amplify_push_notifications/lib/src/amplify_push_notifications_impl.dart b/packages/notifications/push/amplify_push_notifications/lib/src/amplify_push_notifications_impl.dart index b65803ec36..8cffe2b4d3 100644 --- a/packages/notifications/push/amplify_push_notifications/lib/src/amplify_push_notifications_impl.dart +++ b/packages/notifications/push/amplify_push_notifications/lib/src/amplify_push_notifications_impl.dart @@ -335,14 +335,26 @@ abstract class AmplifyPushNotifications Future _registerDeviceWhenConfigure() async { late String deviceToken; + try { - deviceToken = await _bufferedTokenStream.peek; + await _hostApi.requestInitialToken(); + deviceToken = + await _bufferedTokenStream.peek.timeout(const Duration(seconds: 5)); } on PlatformException catch (error) { // the error mostly like is the App doesn't have corresponding // capability to request a push notification device token throw PushNotificationException( - 'Error occurred awaiting for device token', - recoverySuggestion: 'Please review the underlying exception', + 'Error occurred awaiting for device token.', + recoverySuggestion: 'Review the underlying exception.', + underlyingException: error, + ); + } on TimeoutException catch (error) { + throw PushNotificationException( + 'Timed out awaiting for device token.', + recoverySuggestion: + 'This may happen when the native apps have not been correctly configured' + ' for push notifications, review push notification configurations' + ' of the native iOS and Android apps of your Flutter project.', underlyingException: error, ); } diff --git a/packages/notifications/push/amplify_push_notifications/lib/src/native_push_notifications_plugin.g.dart b/packages/notifications/push/amplify_push_notifications/lib/src/native_push_notifications_plugin.g.dart index 8c4773ab7c..2dcb8df388 100644 --- a/packages/notifications/push/amplify_push_notifications/lib/src/native_push_notifications_plugin.g.dart +++ b/packages/notifications/push/amplify_push_notifications/lib/src/native_push_notifications_plugin.g.dart @@ -1,7 +1,7 @@ // // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 -// Autogenerated from Pigeon (v9.2.4), do not edit directly. +// Autogenerated from Pigeon (v9.2.5), do not edit directly. // See also: https://pub.dev/packages/pigeon // ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, unused_shown_name, unnecessary_import @@ -186,6 +186,28 @@ class PushNotificationsHostApi { static const MessageCodec codec = _PushNotificationsHostApiCodec(); + Future requestInitialToken() async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.PushNotificationsHostApi.requestInitialToken', + codec, + binaryMessenger: _binaryMessenger); + final List? replyList = await channel.send(null) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else { + return; + } + } + Future getPermissionStatus() async { final BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.PushNotificationsHostApi.getPermissionStatus', diff --git a/packages/notifications/push/amplify_push_notifications/pigeons/native_push_notification_plugin.dart b/packages/notifications/push/amplify_push_notifications/pigeons/native_push_notification_plugin.dart index 4d1fc9fb27..8444cfa2c1 100644 --- a/packages/notifications/push/amplify_push_notifications/pigeons/native_push_notification_plugin.dart +++ b/packages/notifications/push/amplify_push_notifications/pigeons/native_push_notification_plugin.dart @@ -59,6 +59,8 @@ abstract class PushNotificationsFlutterApi { @HostApi() abstract class PushNotificationsHostApi { + void requestInitialToken(); + @async GetPermissionStatusResult getPermissionStatus(); diff --git a/packages/notifications/push/amplify_push_notifications/test/amplify_push_noitfications_impl_test.dart b/packages/notifications/push/amplify_push_notifications/test/amplify_push_noitfications_impl_test.dart index c6e80c267b..81045425f5 100644 --- a/packages/notifications/push/amplify_push_notifications/test/amplify_push_noitfications_impl_test.dart +++ b/packages/notifications/push/amplify_push_notifications/test/amplify_push_noitfications_impl_test.dart @@ -1,6 +1,7 @@ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 +import 'dart:async'; import 'dart:convert'; import 'package:amplify_core/amplify_core.dart'; @@ -99,6 +100,7 @@ void main() { config: config, ); + verify(mockPushNotificationsHostApi.requestInitialToken()).called(1); verify( mockServiceProviderClient.recordNotificationEvent( eventType: PinpointEventType.notificationOpened, @@ -118,6 +120,8 @@ void main() { authProviderRepo: authProviderRepo, config: config, ); + + verify(mockPushNotificationsHostApi.requestInitialToken()).called(1); verify(mockServiceProviderClient.registerDevice('123')).called(1); void tokenHandler(String token) { @@ -264,6 +268,23 @@ void main() { }, ); }); + + test('configure should fail if timed out awaiting for device token', + () async { + expect( + plugin.configure( + authProviderRepo: authProviderRepo, + config: config, + ), + throwsA( + isA().having( + (o) => o.underlyingException, + 'underlyingException', + isA(), + ), + ), + ); + }); }); test('should fail configure when registering device is unsuccessful', () async { diff --git a/packages/notifications/push/amplify_push_notifications/test/amplify_push_noitfications_impl_test.mocks.dart b/packages/notifications/push/amplify_push_notifications/test/amplify_push_noitfications_impl_test.mocks.dart index f8431bd5e3..a65c332bc6 100644 --- a/packages/notifications/push/amplify_push_notifications/test/amplify_push_noitfications_impl_test.mocks.dart +++ b/packages/notifications/push/amplify_push_notifications/test/amplify_push_noitfications_impl_test.mocks.dart @@ -68,6 +68,15 @@ class MockPushNotificationsHostApi extends _i1.Mock _i1.throwOnMissingStub(this); } + @override + _i5.Future requestInitialToken() => (super.noSuchMethod( + Invocation.method( + #requestInitialToken, + [], + ), + returnValue: _i5.Future.value(), + returnValueForMissingStub: _i5.Future.value(), + ) as _i5.Future); @override _i5.Future<_i2.GetPermissionStatusResult> getPermissionStatus() => (super.noSuchMethod(