amplify-js icon indicating copy to clipboard operation
amplify-js copied to clipboard

Notifications.PushNotification - Failed to register device for push notifications

Open julian-dotcom opened this issue 1 year ago • 21 comments

Before opening, please confirm:

JavaScript Framework

React Native

Amplify APIs

Authentication, Analytics, Push Notifications

Amplify Version

v6

Amplify Categories

auth, analytics, notifications

Backend

Other

Environment information

# Put output below this line
  System:
    OS: macOS 13.6.1
    CPU: (8) arm64 Apple M1
    Memory: 68.59 MB / 16.00 GB
    Shell: 5.9 - /bin/zsh
  Binaries:
    Node: 18.15.0 - ~/.nvm/versions/node/v18.15.0/bin/node
    Yarn: 1.22.17 - /usr/local/bin/yarn
    npm: 9.7.2 - ~/.nvm/versions/node/v18.15.0/bin/npm
    pnpm: 8.15.4 - ~/.nvm/versions/node/v18.15.0/bin/pnpm
    Watchman: 2024.04.01.00 - /opt/homebrew/bin/watchman
  Browsers:
    Chrome: 125.0.6422.142
    Safari: 16.6
  npmPackages:
    @apollo/client: ^3.7.17 => 3.10.4 
    @apollo/client/cache:  undefined ()
    @apollo/client/core:  undefined ()
    @apollo/client/dev:  undefined ()
    @apollo/client/errors:  undefined ()
    @apollo/client/link/batch:  undefined ()
    @apollo/client/link/batch-http:  undefined ()
    @apollo/client/link/context:  undefined ()
    @apollo/client/link/core:  undefined ()
    @apollo/client/link/error:  undefined ()
    @apollo/client/link/http:  undefined ()
    @apollo/client/link/persisted-queries:  undefined ()
    @apollo/client/link/remove-typename:  undefined ()
    @apollo/client/link/retry:  undefined ()
    @apollo/client/link/schema:  undefined ()
    @apollo/client/link/subscriptions:  undefined ()
    @apollo/client/link/utils:  undefined ()
    @apollo/client/link/ws:  undefined ()
    @apollo/client/react:  undefined ()
    @apollo/client/react/components:  undefined ()
    @apollo/client/react/context:  undefined ()
    @apollo/client/react/hoc:  undefined ()
    @apollo/client/react/hooks:  undefined ()
    @apollo/client/react/internal:  undefined ()
    @apollo/client/react/parser:  undefined ()
    @apollo/client/react/ssr:  undefined ()
    @apollo/client/testing:  undefined ()
    @apollo/client/testing/core:  undefined ()
    @apollo/client/testing/experimental:  undefined ()
    @apollo/client/utilities:  undefined ()
    @apollo/client/utilities/globals:  undefined ()
    @apollo/client/utilities/subscriptions/relay:  undefined ()
    @apollo/client/utilities/subscriptions/urql:  undefined ()
    @aws-amplify/react-native: ^1.1.1 => 1.1.1 
    @aws-amplify/rtn-push-notification: ^1.2.29 => 1.2.29 
    @babel/core: ^7.20.0 => 7.24.7 
    @babel/preset-env: ^7.20.0 => 7.24.7 
    @babel/runtime: ^7.20.0 => 7.24.7 
    @commitlint/cli: ^12.1.4 => 12.1.4 
    @commitlint/config-conventional: ^12.1.4 => 12.1.4 
    @commitlint/cz-commitlint: ^12.1.4 => 12.1.4 
    @datadog/mobile-react-native: ^2.3.2 => 2.3.5 
    @datadog/mobile-react-navigation: ^2.3.2 => 2.3.5 
    @eva-design/eva: 2.0.0 => 2.0.0 
    @graphql-codegen/add: ^4.0.0 => 4.0.1 
    @graphql-codegen/cli: ^3.0.0 => 3.3.1 
    @graphql-codegen/typescript: ^3.0.0 => 3.0.4 
    @graphql-codegen/typescript-operations: ^3.0.0 => 3.0.4 
    @graphql-codegen/typescript-react-apollo: ^3.3.7 => 3.3.7 
    @intercom/intercom-react-native: ^7.1.1 => 7.1.2 
    @onfido/react-native-sdk: ^12.1.0 => 12.1.0 
    @react-native-async-storage/async-storage: ^1.23.1 => 1.23.1 
    @react-native-clipboard/clipboard: ^1.10.0 => 1.14.1 
    @react-native-community/hooks: ^2.8.0 => 2.8.1 
    @react-native-community/push-notification-ios: ^1.10.1 => 1.11.0 
    @react-native-community/slider: ^4.4.2 => 4.5.2 
    @react-native/babel-preset: 0.73.21 => 0.73.21 (0.74.84)
    @react-native/eslint-config: 0.73.2 => 0.73.2 
    @react-native/metro-config: 0.73.5 => 0.73.5 
    @react-native/typescript-config: ^0.75.0-main => 0.75.0-nightly-20240612-fd618819c 
    @react-navigation/bottom-tabs: ^6.5.20 => 6.5.20 
    @react-navigation/drawer: ^6.6.15 => 6.6.15 
    @react-navigation/elements: ^1.3.30 => 1.3.30 
    @react-navigation/native: ^6.1.17 => 6.1.17 
    @react-navigation/stack: ^6.3.29 => 6.3.29 
    @types/bech32: ^1.1.4 => 1.1.4 
    @types/bip21: ^2.0.0 => 2.0.3 
    @types/d3-scale: ^4.0.1 => 4.0.8 
    @types/d3-shape: ^3.0.2 => 3.1.6 
    @types/jest: ^27.4.1 => 27.5.2 
    @types/lodash: ^4.14.170 => 4.17.5 
    @types/react: ^18.2.6 => 18.3.3 
    @types/react-native-push-notification: ^7.3.2 => 7.3.3 
    @types/react-native-snap-carousel: ^3.8.3 => 3.8.11 
    @types/react-native-video: ^5.0.10 => 5.0.20 
    @types/react-test-renderer: ^18.0.0 => 18.3.0 
    @types/semver: ^7.3.10 => 7.5.8 
    @ui-kitten/components: 4.4.1 => 4.4.1 
    @ui-kitten/eva-icons: ^4.4.1 => 4.4.1 
    HelloWorld:  0.0.1 
    apollo-link-timeout: ^4.0.0 => 4.0.0 
    apollo3-cache-persist: ^0.14.1 => 0.14.1 
    aws-amplify: 6.3.4 => 6.3.4 
    aws-amplify/adapter-core:  undefined ()
    aws-amplify/analytics:  undefined ()
    aws-amplify/analytics/kinesis:  undefined ()
    aws-amplify/analytics/kinesis-firehose:  undefined ()
    aws-amplify/analytics/personalize:  undefined ()
    aws-amplify/analytics/pinpoint:  undefined ()
    aws-amplify/api:  undefined ()
    aws-amplify/api/server:  undefined ()
    aws-amplify/auth:  undefined ()
    aws-amplify/auth/cognito:  undefined ()
    aws-amplify/auth/cognito/server:  undefined ()
    aws-amplify/auth/enable-oauth-listener:  undefined ()
    aws-amplify/auth/server:  undefined ()
    aws-amplify/data:  undefined ()
    aws-amplify/data/server:  undefined ()
    aws-amplify/datastore:  undefined ()
    aws-amplify/in-app-messaging:  undefined ()
    aws-amplify/in-app-messaging/pinpoint:  undefined ()
    aws-amplify/push-notifications:  undefined ()
    aws-amplify/push-notifications/pinpoint:  undefined ()
    aws-amplify/storage:  undefined ()
    aws-amplify/storage/s3:  undefined ()
    aws-amplify/storage/s3/server:  undefined ()
    aws-amplify/storage/server:  undefined ()
    aws-amplify/utils:  undefined ()
    aws-appsync-auth-link: ^3.0.4 => 3.0.7 
    axios: ^0.24.0 => 0.24.0 (1.7.2)
    babel-jest: ^29.6.3 => 29.7.0 
    babel-plugin-module-resolver: ^5.0.0 => 5.0.2 
    babel-plugin-transform-remove-console: ^6.9.4 => 6.9.4 
    bech32: ^2.0.0 => 2.0.0 
    bignumber.js: ^9.0.2 => 9.1.2 
    bip21: ^2.0.3 => 2.0.3 
    bitcoin-address-validation: ^2.1.0 => 2.2.3 
    bitcoin-units: ^0.3.0 => 0.3.0 
    commitizen: ^4.2.4 => 4.3.0 
    country-iso-2-to-3: ^1.1.0 => 1.1.0 
    d3-scale: ^4.0.2 => 4.0.2 (2.2.2)
    d3-shape: ^3.0.1 => 3.2.0 
    date-fns: ^2.28.0 => 2.30.0 
    deepl-node: ^1.7.1 => 1.13.0 
    deprecated-react-native-prop-types: ^4.0.0 => 4.2.3 (2.3.0, 5.0.0)
    eslint: ^8.19.0 => 8.57.0 
    eslint-plugin-ft-flow: ^2.0.3 => 2.0.3 
    example:  0.0.1 
    expo: ^50.0.14 => 50.0.19 
    expo-barcode-scanner: 12.9.3 => 12.9.3 
    expo-blur: 12.9.2 => 12.9.2 
    expo-camera: ^14.1.3 => 14.1.3 
    expo-file-system: ^16.0.9 => 16.0.9 
    expo-local-authentication: 13.8.0 => 13.8.0 
    expo-sharing: 11.10.0 => 11.10.0 
    fast-text-encoding: ^1.0.6 => 1.0.6 
    fior-tracking: ^0.1.1 => 0.1.3 
    global: ^4.4.0 => 4.4.0 
    graphql: ^16.6.0 => 16.8.1 (15.8.0)
    graphql-tag: ^2.12.4 => 2.12.6 
    husky: ^6.0.0 => 6.0.0 
    i18next: ^20.3.0 => 20.6.1 
    jest: ^29.6.3 => 29.7.0 
    libphonenumber-js: ^1.10.54 => 1.11.3 
    libphonenumber-js/build:  undefined ()
    libphonenumber-js/core:  undefined ()
    libphonenumber-js/max:  undefined ()
    libphonenumber-js/max/metadata:  undefined ()
    libphonenumber-js/min:  undefined ()
    libphonenumber-js/min/metadata:  undefined ()
    libphonenumber-js/mobile:  undefined ()
    libphonenumber-js/mobile/examples:  undefined ()
    libphonenumber-js/mobile/metadata:  undefined ()
    light-bolt11-decoder: ^3.0.0 => 3.1.1 
    lodash: ^4.17.21 => 4.17.21 
    lottie-react-native: ^6.7.2 => 6.7.2 
    metro-minify-terser: ^0.78.1 => 0.78.1 (0.80.9)
    metro-react-native-babel-preset: ^0.77.0 => 0.77.0 
    metro-react-native-babel-transformer: ^0.77.0 => 0.77.0 
    patch-package: ^6.4.7 => 6.5.1 
    postinstall-postinstall: ^2.1.0 => 2.1.0 
    prettier: 2.8.8 => 2.8.8 
    prompt-sync: ^4.2.0 => 4.2.0 
    proxy-polyfill: ^0.3.2 => 0.3.2 
    query-string: ^7.1.1 => 7.1.3 
    react: 18.2.0 => 18.2.0 
    react-content-loader: ^6.0.3 => 6.2.1 
    react-content-loader/native:  undefined ()
    react-hook-form: ^7.43.1 => 7.51.5 
    react-i18next: ^11.10.0 => 11.18.6 
    react-native: 0.73.8 => 0.73.8 (0.74.2)
    react-native-actions-sheet: ^0.8.29 => 0.8.29 
    react-native-bootsplash: 4.7.5 => 4.7.5 
    react-native-branch: ^6.2.1 => 6.2.2 
    react-native-circular-progress: ^1.3.7 => 1.4.0 
    react-native-cli-bump-version: ^1.5.0 => 1.5.0 
    react-native-code-push: ^8.1.0 => 8.2.2 
    react-native-collapsible: ^1.6.0 => 1.6.1 
    react-native-config: ^1.5.1 => 1.5.1 
    react-native-confirmation-code-field: ^7.1.0 => 7.4.0 
    react-native-device-country: ^1.0.3 => 1.0.4 
    react-native-device-info: ^10.13.2 => 10.14.0 
    react-native-event-listeners: ^1.0.7 => 1.0.7 
    react-native-flags: ^1.0.0 => 1.0.0 
    react-native-gesture-handler: 2.16.0 => 2.16.0 
    react-native-get-random-values: ^1.11.0 => 1.11.0 
    react-native-google-places-autocomplete: ^2.4.1 => 2.5.6 
    react-native-haptic-feedback: ^1.14.0 => 1.14.0 
    react-native-in-app-review: ^4.3.3 => 4.3.3 
    react-native-inappbrowser-reborn: ^3.7.0 => 3.7.0 
    react-native-iphone-x-helper: ^1.3.1 => 1.3.1 
    react-native-keychain: ^8.1.0 => 8.2.0 
    react-native-modal: ^13.0.0 => 13.0.1 
    react-native-push-notification: ^8.1.1 => 8.1.1 
    react-native-reanimated: ^3.9.0 => 3.12.0 
    react-native-safe-area-context: ^4.7.1 => 4.10.4 
    react-native-screens: 3.30.1 => 3.30.1 
    react-native-snap-carousel: ^3.9.1 => 3.9.1 
    react-native-startup-time: ^2.0.0 => 2.1.0 
    react-native-svg: 13.9.0 => 13.9.0 
    react-native-svg-transformer: ^1.1.0 => 1.4.0 
    react-native-toast-message: ^2.2.0 => 2.2.0 
    react-native-video: ^5.2.1 => 5.2.1 
    react-native-wagmi-charts: 2.3.2 => 2.3.2 
    react-navigation-header-buttons: ^7.0.1 => 7.0.2 
    react-query: ^3.33.4 => 3.39.3 
    react-test-renderer: 18.2.0 => 18.2.0 
    recoil: ^0.7.4 => 0.7.7 
    semver: ^7.3.7 => 7.6.2 (6.3.1, 7.3.5, 5.7.2, 7.5.3, 7.3.2)
    typescript: 5.0.4 => 5.0.4 
    url: ^0.11.3 => 0.11.3 
    url-pattern: ^1.0.3 => 1.0.3 
  npmGlobalPackages:
    @aws-amplify/cli: 11.0.3
    corepack: 0.15.3
    create-expo-app: 1.3.3
    expo-cli: 6.3.7
    npm-check: 6.0.1
    npm: 9.7.2
    pnpm: 8.15.4


Describe the bug

When I launch my React Native app in an unauthenticated state, I get the following error: [ERROR] 57:31.569 Notifications.PushNotification - Failed to register device for push notifications [NoCredentials: Credentials should not be empty.]

This happens when I call initializePushNotifications() in my index.js.

When a user is authenticated and I launch the app, the error does NOT show up.

The error also doesn't show up if initializePushNotifications() is commented out.

Expected behavior

Get no error when launching the app in its unauthenticated state.

Reproduction steps

  1. Run npx react-native run-android
  2. Open app

Code Snippet

This is the code for my index.js:

import 'fast-text-encoding';
import 'proxy-polyfill';
import { AppRegistry } from 'react-native';
import PushNotification from 'react-native-push-notification';
import App from './App';
import { name as appName } from './app.json';
import { createNotificationsChannels, options } from './src/common/utils';
import { Amplify } from 'aws-amplify';
import { initializePushNotifications } from 'aws-amplify/push-notifications';

import { AWS_CONFIG } from 'config';
// import { ConsoleLogger } from 'aws-amplify/utils';

// ConsoleLogger.LOG_LEVEL = 'DEBUG';
Amplify.configure(AWS_CONFIG);
initializePushNotifications();

PushNotification.configure(options);
createNotificationsChannels();

AppRegistry.registerComponent(appName, () => App);

Log output

// Put your logs below this line


aws-exports.js

  API: {
    GraphQL: {
      endpoint: Config.AWS_APPSYNC_URL || '',
      region: Config.AWS_REGION || '',
      defaultAuthMode: 'userPool',
    },
  },
  Analytics: {
    Pinpoint: {
      appId: Config.AWS_PINPOINT_APP_ID || '',
      region: Config.AWS_REGION || '',
      bufferSize: 1000,
      flushInterval: 5000,
      flushSize: 100,
      resendLimit: 5,
    },
  },
  Auth: {
    Cognito: {
      identityPoolId: Config.AWS_IDENTITY_POOL_ID || '',
      userPoolClientId: Config.AWS_COGNITO_POOL_CLIENT_ID || '',
      userPoolId: Config.AWS_COGNITO_POOL_ID || '',
    },
  },
  Notifications: {
    PushNotification: {
      Pinpoint: {
        appId: Config.AWS_PINPOINT_APP_ID || '',
        region: Config.AWS_REGION || '',
      },
    },
  },
};

Manual configuration

No response

Additional configuration

No response

Mobile Device

No response

Mobile Operating System

No response

Mobile Browser

No response

Mobile Browser Version

No response

Additional information and screenshots

No response

julian-dotcom avatar Jun 13 '24 08:06 julian-dotcom

@julian-dotcom Thank you for your report! It seems like the application is having trouble when users are unauthenticated. Could you confirm that you've enabled unauthenticated access when setting up your backend? Reference: https://docs.amplify.aws/gen1/react-native/build-a-backend/push-notifications/set-up-push-notifications/#set-up-backend-resources

jimblanc avatar Jun 13 '24 12:06 jimblanc

We only want to send notifications to authenticated users. We never want unauthenticated users to receive notifications.

But as far as I understand initializePushNotifications() has to be called in the index.js.

How do I prevent it from registering the device for push notifications until the user logs in?

julian-dotcom avatar Jun 14 '24 07:06 julian-dotcom

@julian-dotcom Unfortunately this is a use-case that we don't directly support at the moment. However, there is a possible work around you can try: Using identifyUser to mark or unmark a particular device, for example setting optOut: 'ALL' until the user is signed in and resetting it when they sign out.

jimblanc avatar Jun 18 '24 15:06 jimblanc

This doesn't work. When calling identifyUser like so:

import * as PushNotification from 'aws-amplify/push-notifications';

...

    await PushNotification.identifyUser({
      userId: '',
      userProfile: {},
      options: { address: deviceToken.token, optOut: 'ALL' },
    });

identifyUser never finishes executing.

This is because const { credentials, identityId } = await resolveCredentials(); fails in line 28 of node_modules/@aws-amplify/notifications/src/pushNotifications/providers/pinpoint/apis/identifyUser.native.ts

julian-dotcom avatar Jun 19 '24 14:06 julian-dotcom

Please see this ticket: 13504

julian-dotcom avatar Jun 20 '24 07:06 julian-dotcom

@julian-dotcom There are two options here,

  1. Allow guest access to your identityPool so a guest credentials can be fetched by initializePushNotifications when called since endpoint creation needs them. You can immediately call identifyUser with optOut as "ALL" as Jim mentioned so that the guest user does not receive any push notifications pushed through Pinpoint's campaigns. Note: this will not restrict Firebase from sending notifications to the device. When the user authenticates, you may call identifyUser again with optOut as "None".
    identifyUser({
      userId: 'user-id-01',
      userProfile: {name: 'user-test-name'},
      options: {optOut: 'ALL'},
    })
  1. Keep guest access disabled but call initializePushNotifications only in your authenticated route on the app. This API basically initializes all the listeners needed for the library in addition to registering an endpoint (with credentials & auto generated endpointId for the "Push" channel). It is recommended to call as early as possible so as to not miss listening to some events like notification coming in when the app is in background. So, if your authenticated route in your app is the first page to be rendered, calling this API there will also work for your use-case. In this scenario, you would not need to call identifyUser since you are initializing only in the authenticated route of your app.

Samaritan1011001 avatar Jul 02 '24 00:07 Samaritan1011001

I created a patch, because in my estimation this is a bug.

As I commented somewhere else:

I investigated some more and figured out, what goes wrong. To me, it looks like a bug.

When calling initializePushNotifications() in my index.js, the function calls addNativeListeners(), which calls addTokenEventListener(), which calls registerDevice().

The problem is that the register device function fails until a user is authenticated. This is fine and makes sense.

However, the issue is that the exception is not passed on to initializePushNotifications(). This function continues and calls initialize(), setting initialized to true.

This incorrect behavior because the device was never successfully registered, but the code now thinks it's initialized.

Hence, whenever calling initializePushNotifications() after, the code just exits the function early and nothing happens.

In my estimation, this should not happen. We should set initialized to true, ONLY if the device was successfully registered.

export const initializePushNotifications = (): void => {
	if (isInitialized()) {
		logger.info('Push notifications have already been enabled');
		console.log('Push notifications already initialized')
		return;
	}
	addNativeListeners();
	addAnalyticsListeners();
	initialize();
};

Source: node_modules/@aws-amplify/notifications/src/pushNotifications/providers/pinpoint/apis/initializePushNotifications.native.ts

julian-dotcom avatar Jul 10 '24 07:07 julian-dotcom

I created a patch, because in my estimation this is a bug.

As I commented somewhere else:

I investigated some more and figured out, what goes wrong. To me, it looks like a bug.

When calling initializePushNotifications() in my index.js, the function calls addNativeListeners(), which calls addTokenEventListener(), which calls registerDevice().

The problem is that the register device function fails until a user is authenticated. This is fine and makes sense.

However, the issue is that the exception is not passed on to initializePushNotifications(). This function continues and calls initialize(), setting initialized to true.

This incorrect behavior because the device was never successfully registered, but the code now thinks it's initialized.

Hence, whenever calling initializePushNotifications() after, the code just exits the function early and nothing happens.

In my estimation, this should not happen. We should set initialized to true, ONLY if the device was successfully registered.

export const initializePushNotifications = (): void => {
	if (isInitialized()) {
		logger.info('Push notifications have already been enabled');
		console.log('Push notifications already initialized')
		return;
	}
	addNativeListeners();
	addAnalyticsListeners();
	initialize();
};

Source: node_modules/@aws-amplify/notifications/src/pushNotifications/providers/pinpoint/apis/initializePushNotifications.native.ts

Hi julian, what is the patch that you created?, I have the same error, I tried with workarounds that passed here but no success 😬

enzzoperez avatar Jul 16 '24 17:07 enzzoperez

I'm also facing this issue and had some problems patching it. :cry: I have "aws-amplify": "^6.3.8" on my package.json, but the patch is on folder @aws-amplify so I got No such package @aws-amplify when running patch-package

eidson-encora avatar Jul 17 '24 20:07 eidson-encora

I created a patch for this file: node_modules/@aws-amplify/notifications/src/pushNotifications/providers/pinpoint/apis/initializePushNotifications.native.ts

I modify the initializePushNotifications function like so:

let initializedPushNotification = false;
const initializePN = async () => initializedPushNotification = true;
const isInitializedPN = () => initializedPushNotification;


export const initializePushNotifications = (): void => {
	if (isInitialized()) {
		logger.info('Push notifications have already been enabled');
    !isInitializedPN() && registerDevice(getToken());
		return;
	}
	addNativeListeners();
	addAnalyticsListeners();
	initialize();
};

And I add initializePN(); in registerDevice()

const registerDevice = async (address: string): Promise<void> => {
	const { credentials, identityId } = await resolveCredentials();
	const { appId, region } = resolveConfig();
	try {
		await updateEndpoint({
			address,
			appId,
			category: 'PushNotification',
			credentials,
			region,
			channelType: getChannelType(),
			identityId,
			userAgentValue: getPushNotificationUserAgentString(
				PushNotificationAction.InitializePushNotifications,
			),
		});
		initializePN();
		// always resolve inflight device registration promise here even though the promise is only awaited on by
		// `identifyUser` when no endpoint is found in the cache
		resolveInflightDeviceRegistration();
	} catch (underlyingError) {
		rejectInflightDeviceRegistration(underlyingError);
		throw underlyingError;
	}
};

This is the actual patch file @aws-amplify+notifications+2.0.33.patch:

diff --git a/node_modules/@aws-amplify/notifications/src/pushNotifications/providers/pinpoint/apis/initializePushNotifications.native.ts b/node_modules/@aws-amplify/notifications/src/pushNotifications/providers/pinpoint/apis/initializePushNotifications.native.ts
index 2582ada..88ae7b6 100644
--- a/node_modules/@aws-amplify/notifications/src/pushNotifications/providers/pinpoint/apis/initializePushNotifications.native.ts
+++ b/node_modules/@aws-amplify/notifications/src/pushNotifications/providers/pinpoint/apis/initializePushNotifications.native.ts
@@ -40,10 +40,15 @@ const logger = new ConsoleLogger('Notifications.PushNotification');
 
 const BACKGROUND_TASK_TIMEOUT = 25; // seconds
 
+let initializedPushNotification = false;
+const initializePN = async () => initializedPushNotification = true;
+const isInitializedPN = () => initializedPushNotification;
+
+
 export const initializePushNotifications = (): void => {
 	if (isInitialized()) {
 		logger.info('Push notifications have already been enabled');
-
+    !isInitializedPN() && registerDevice(getToken());
 		return;
 	}
 	addNativeListeners();
@@ -159,7 +164,10 @@ const addNativeListeners = (): void => {
 			try {
 				await registerDevice(token);
 			} catch (err) {
-				logger.error('Failed to register device for push notifications', err);
+        if (err.name !== 'NoCredentials') {
+          logger.error('Failed to register device for push notifications', err);
+        }
+
 				throw err;
 			}
 		},
@@ -218,6 +226,7 @@ const registerDevice = async (address: string): Promise<void> => {
 				PushNotificationAction.InitializePushNotifications,
 			),
 		});
+		initializePN();
 		// always resolve inflight device registration promise here even though the promise is only awaited on by
 		// `identifyUser` when no endpoint is found in the cache
 		resolveInflightDeviceRegistration();

julian-dotcom avatar Jul 19 '24 08:07 julian-dotcom

thanks so much @julian-dotcom , it worked

enzzoperez avatar Jul 22 '24 12:07 enzzoperez

I have "aws-amplify": "^6.3.6" on my package.json. you can try:

import {fetchAuthSession} from 'aws-amplify/auth';
import {updateEndpoint} from '@aws-amplify/core/internals/providers/pinpoint';
import {
  Category,
  PushNotificationAction,
  getAmplifyUserAgent,
} from '@aws-amplify/core/internals/utils';


const getPushNotificationUserAgentString = (action: PushNotificationAction) =>
  getAmplifyUserAgent({
    category: Category.PushNotification,
    action,
  });

export const registerEndPoint = async (
  appId: string,
  region: string,
  userId: string,
  fcmToken: string,
) => {
  return new Promise<boolean>(async (resolve, reject) => {
    fetchAuthSession()
      .then(async session => {
        if (session.credentials) {
          updateEndpoint({
            address: fcmToken,
            appId: appId,
            category: 'PushNotification',
            channelType: 'GCM',
            credentials: session.credentials,
            identityId: session.identityId,
            optOut: 'NONE',
            region: region,
            userId: userId,
            userAgentValue: getPushNotificationUserAgentString(
              PushNotificationAction.InitializePushNotifications,
            ),
          })
            .then(async () => {
              resolve(true);
            })
            .catch(async err => {
              reject(err);
            });
        } else {
          reject(undefined);
        }
      })
      .catch(async err => {
        reject(err);
      });
  });
};

@julian-dotcom

guo-pf avatar Jul 26 '24 01:07 guo-pf

@julian-dotcom @cwomack Is there a PR for this?

keithdmoore avatar Aug 12 '24 15:08 keithdmoore

@julian-dotcom @cwomack I also have the same issue. The patch does fix this issue. However, for some reason, I am not getting device token so the OptOut is set to "ALL". I also noticed that the token in the addTokenEventListener is undefined as well.

keithdmoore avatar Aug 12 '24 15:08 keithdmoore

I think this issue would be resolved if https://github.com/aws-amplify/amplify-js/issues/13277 was resolved.

keithdmoore avatar Aug 19 '24 16:08 keithdmoore

@julian-dotcom, want to confirm something on how you're implementing the patch recommended in this comment above. Are you calling initializePushNotifications() twice? Once at the top level of your code (after Amplify.configure()) and again in the code you provided in the comment?

Currently, our documentation for implementing and initializing push notifications implies that the authenticated & unauthenticated with guest access enabled are supported. So this use case of unauthenticated users with guest access disabled for the identityPool is a bit of an edge case.

cwomack avatar Aug 27 '24 20:08 cwomack

When will the patch be merged and released?

georgeplaton7 avatar Sep 08 '24 20:09 georgeplaton7

@georgeplaton7, we don't have a PR for this specifically yet I believe. The workaround/patch that's been mentioned was in @julian-dotcom's comment above (here) that others have reported working for them.

We'd welcome anyone to submit a PR tied to this if they're willing, but since this is a bit of an edge case at this point for the use case of unauthenticated users with guest access being disabled for the identityPool.

cwomack avatar Oct 08 '24 16:10 cwomack

Hi all, we re-evaluated this issue, and we agree with that the patch provided above makes sense. We will be looking into merging the patch soon.

HuiSF avatar Apr 17 '25 19:04 HuiSF

I ran into this on a fresh project yesterday.

It is still a very serious issue, I wasted a whole day on this. I followed the amplify documentation very closely on this point and to be precise it is incorrect due to this bug, but even with the patch the documentation must be updated regarding initialization.

Some notes regarding the permissions required for the identity pool role would be useful in this context as well. The way IAM works with /* /xyz/* etc can be confusing and I spent some time on this as well albeit not as much because I am familiar with it.

I can make a PR for the patch above if anyone would like, it does work.


In a crazy turn of events I discovered something very interesting, the patch suggested by @julian-dotcom actually doesn't even apply because it is a patch to the typescript file! I now suspect that anyone doing this "patch" was not actually modifying anything!

waynenilsen avatar May 16 '25 13:05 waynenilsen

Hi @waynenilsen ,

Thanks for your effort on trying to create a PR in regards to this issue!

As @HuiSF had mentioned, we are looking into merging this patch soon. Once we have it done we will notify the community.

Thanks for your patience!

yuhengshs avatar May 18 '25 01:05 yuhengshs