Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

React Native – "identifyUser" function does not work on launch #13504

Closed
3 tasks done
julian-dotcom opened this issue Jun 18, 2024 · 7 comments
Closed
3 tasks done

React Native – "identifyUser" function does not work on launch #13504

julian-dotcom opened this issue Jun 18, 2024 · 7 comments
Assignees
Labels
Push Notifications Related to Push Notification components question General question React Native React Native related issue

Comments

@julian-dotcom
Copy link

Before opening, please confirm:

JavaScript Framework

React Native

Amplify APIs

Analytics, Push Notifications

Amplify Version

v6

Amplify Categories

notifications

Backend

None

Environment information

# Put output below this line
  System:
    OS: macOS 13.6.1
    CPU: (8) arm64 Apple M1
    Memory: 48.81 MB / 16.00 GB
    Shell: 5.9 - /bin/zsh
  Binaries:
    Node: 20.13.1 - ~/.nvm/versions/node/v20.13.1/bin/node
    Yarn: 1.22.17 - /usr/local/bin/yarn
    npm: 10.8.0 - ~/.nvm/versions/node/v20.13.1/bin/npm
    pnpm: 8.15.6 - /opt/homebrew/bin/pnpm
    Watchman: 2024.04.01.00 - /opt/homebrew/bin/watchman
  Browsers:
    Chrome: 125.0.6422.176
    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:
    corepack: 0.28.0
    npm: 10.8.0


Describe the bug

identifyUser from aws-amplify/push-notifications never successfully saves the endpoint with the address on first launch.

It never registers the endpoint, until I close the app and restart it with the user already authenticated. On second launch, it succesfully submits the endpoint on Android, but never does on iOS.

Expected behavior

I sign in and upon sign in, the identifyUser registers the endpoint on first call, allowing me to receive notifications.

Reproduction steps

unexpected behavior arises when I call identifyUser

Code Snippet

My index.js

Amplify.configure(AWS_CONFIG);
initializePushNotifications();

How I register the device token:

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

  // in my custom hook function, called after user is authenticated
  const registerDeviceToken = useCallback(async () => {
    try {
      const deviceToken = await getSavedDeviceTokenState();

      if (!deviceToken?.token) {
        return;
      }

      const userAttributes = await authService.getUserAttributes();

      if (userAttributes?.sub && userAttributes?.locale && deviceToken.token) {
        await PushNotification.identifyUser({
          userId: userAttributes.sub,
          userProfile: {
            customProperties: {
              locale: [userAttributes.locale],
            },
          },
          options: { address: deviceToken.token, optOut: 'NONE' },
        });
      }
    } catch (error) {
      console.log('Registering device token request error', error);
    }
  }, []);

identifyUser call the function in this file /node_modules/@aws-amplify/notifications/src/pushNotifications/providers/pinpoint/apis/identifyUser.native.ts where unfortunately, await getEndpointId(appId, 'Analytics') returns undefined

Log output

// Put your logs below this line


aws-exports.js

import Config from 'react-native-config';
import { ResourcesConfig } from 'aws-amplify';

export const AWS_CONFIG: ResourcesConfig = {
  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 julian-dotcom added the pending-triage Issue is pending triage label Jun 18, 2024
@julian-dotcom
Copy link
Author

julian-dotcom commented Jun 18, 2024

As an update, if I comment out / remove this if statement if (!(await getEndpointId(appId, 'PushNotification'))) { the endpoint creation works as expected.

node_modules/@aws-amplify/notifications/src/pushNotifications/providers/pinpoint/apis/identifyUser.native.ts

export const identifyUser: IdentifyUser = async ({
	userId,
	userProfile,
	options,
}) => {
	assertIsInitialized();
	const { credentials, identityId } = await resolveCredentials();
	const { appId, region } = resolveConfig();
	const { address, optOut, userAttributes } = options ?? {};

	if (!(await getEndpointId(appId, 'PushNotification'))) {
		// if there is no cached endpoint id, wait for successful endpoint creation before continuing
		await getInflightDeviceRegistration();
	}

	await updateEndpoint({
		address,
		channelType: getChannelType(),
		optOut,
		appId,
		category: 'PushNotification',
		credentials,
		identityId,
		region,
		userAttributes,
		userId,
		userProfile,
		userAgentValue: getPushNotificationUserAgentString(
			PushNotificationAction.IdentifyUser,
		),
	});
};

So it seems like the getInflightDeviceRegistration function fails, but it never throws an error or informs the developer what goes wrong.

@chrisbonifacio chrisbonifacio added React Native React Native related issue Push Notifications Related to Push Notification components labels Jun 18, 2024
@cwomack cwomack self-assigned this Jun 18, 2024
@julian-dotcom
Copy link
Author

As an update, I tried logging from the resolveInflightDeviceRegistration and rejectInflightDeviceRegistration but they are never called by the getInflightDeviceRegistration in node_modules/@aws-amplify/notifications/src/pushNotifications/providers/pinpoint/utils/inflightDeviceRegistration.ts

import { PushNotificationError } from '../../../errors';
import {
	InflightDeviceRegistration,
	InflightDeviceRegistrationResolver,
} from '../types';

const inflightDeviceRegistrationResolver: InflightDeviceRegistrationResolver =
	{};

let inflightDeviceRegistration: InflightDeviceRegistration = new Promise<void>(
	(resolve, reject) => {
		inflightDeviceRegistrationResolver.resolve = resolve;
		inflightDeviceRegistrationResolver.reject = reject;
	},
);

export const getInflightDeviceRegistration = () => inflightDeviceRegistration;

export const resolveInflightDeviceRegistration = () => {
	inflightDeviceRegistrationResolver.resolve?.();
	// release promise from memory
	inflightDeviceRegistration = undefined;
};

export const rejectInflightDeviceRegistration = (underlyingError: unknown) => {
	inflightDeviceRegistrationResolver.reject?.(
		new PushNotificationError({
			name: 'DeviceRegistrationFailed',
			message: 'Failed to register device for push notifications.',
			underlyingError,
		}),
	);
	// release promise from memory
	inflightDeviceRegistration = undefined;
};

@julian-dotcom
Copy link
Author

julian-dotcom commented Jun 20, 2024

I investigated some more and figured 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
Copy link
Author

julian-dotcom commented Jun 20, 2024

It seems like the ticket is related to my other open issue. We should continue the conversation in this thread for simplicity.

@haverchuck
Copy link
Contributor

@julian-dotcom per your suggestions above, closing this in favor of your other issue.

@julian-dotcom
Copy link
Author

Sorry for the confusion/misunderstanding, but I think we should continue in this thread right here, and close the other one.

@adirsation
Copy link

As an update, if I comment out / remove this if statement if (!(await getEndpointId(appId, 'PushNotification'))) { the endpoint creation works as expected.

node_modules/@aws-amplify/notifications/src/pushNotifications/providers/pinpoint/apis/identifyUser.native.ts

export const identifyUser: IdentifyUser = async ({
	userId,
	userProfile,
	options,
}) => {
	assertIsInitialized();
	const { credentials, identityId } = await resolveCredentials();
	const { appId, region } = resolveConfig();
	const { address, optOut, userAttributes } = options ?? {};

	if (!(await getEndpointId(appId, 'PushNotification'))) {
		// if there is no cached endpoint id, wait for successful endpoint creation before continuing
		await getInflightDeviceRegistration();
	}

	await updateEndpoint({
		address,
		channelType: getChannelType(),
		optOut,
		appId,
		category: 'PushNotification',
		credentials,
		identityId,
		region,
		userAttributes,
		userId,
		userProfile,
		userAgentValue: getPushNotificationUserAgentString(
			PushNotificationAction.IdentifyUser,
		),
	});
};

So it seems like the getInflightDeviceRegistration function fails, but it never throws an error or informs the developer what goes wrong.

Also experienced this issue and after commenting out the getInflightDeviceRegistration function, I was able to use identifyUser and it was not stuck.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Push Notifications Related to Push Notification components question General question React Native React Native related issue
Projects
None yet
Development

No branches or pull requests

5 participants