Skip to content

[messaging] Enhance Expo notification icon configuration support and documentation #8618

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

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions docs/messaging/usage/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,66 @@ you can follow the manual installation steps for [iOS](/messaging/usage/installa

# Expo

## Notification Icons and Colors

The @react-native-firebase/messaging package includes an Expo config plugin that automatically configures Firebase notification icons and colors when using Expo managed workflow.

### Android Configuration

For Android, add notification configuration to your `app.json` or `app.config.js`:

```json
{
"expo": {
"name": "Your App",
"slug": "your-app",
"notification": {
"icon": "./assets/notification-icon.png",
"color": "#FF0000"
}
}
}
```

The plugin will automatically:
- Configure `com.google.firebase.messaging.default_notification_icon` in your Android manifest
- Configure `com.google.firebase.messaging.default_notification_color` in your Android manifest
- Use Expo's standard notification icon handling (requires a pure white PNG icon)

> **Note**: Android notifications require a pure white icon for proper display. The notification icon should be a white silhouette on a transparent background. For more information, see [Expo's notification documentation](https://docs.expo.dev/versions/latest/config/app/#notification).

### iOS Configuration

iOS uses the app icon for notifications by default and doesn't require separate notification icon configuration. However, you can customize notification appearance through iOS-specific settings in your `app.json`:

```json
{
"expo": {
"ios": {
"icon": "./assets/ios-icon.png"
}
}
}
```

### Manual Setup

If you need to manually configure the plugin, add it to your `app.json` or `app.config.js`:

```json
{
"expo": {
"plugins": [
"@react-native-firebase/messaging"
]
}
}
```

### No Configuration Warning

If no notification configuration is detected, the plugin will display a warning message encouraging you to add proper notification icon configuration for Android compatibility.

## iOS - Notifications entitlement

Since Expo SDK51, Notifications entitlement is no longer always added to iOS projects during prebuild. If your project uses push notifications, you may need to add the aps-environment entitlement to your app config:
Expand Down
96 changes: 96 additions & 0 deletions packages/messaging/EXPO_EXAMPLE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# @react-native-firebase/messaging Expo Configuration Example

This example demonstrates how to configure Firebase Cloud Messaging notification icons and colors in an Expo managed workflow project.

## Configuration

Add the following to your `app.json` or `app.config.js`:

```json
{
"expo": {
"name": "Firebase Messaging Example",
"slug": "firebase-messaging-example",
"version": "1.0.0",
"orientation": "portrait",
"icon": "./assets/icon.png",
"userInterfaceStyle": "light",
"splash": {
"image": "./assets/splash.png",
"resizeMode": "contain",
"backgroundColor": "#ffffff"
},
"notification": {
"icon": "./assets/notification-icon.png",
"color": "#FF6B35"
},
"assetBundlePatterns": [
"**/*"
],
"ios": {
"supportsTablet": true
},
"android": {
"adaptiveIcon": {
"foregroundImage": "./assets/adaptive-icon.png",
"backgroundColor": "#FFFFFF"
}
},
"web": {
"favicon": "./assets/favicon.png"
},
"plugins": [
"@react-native-firebase/messaging"
]
}
}
```

## Key Points

1. **Notification Icon**: Must be a pure white PNG icon on a transparent background
2. **Notification Color**: Hex color code that will be used to tint notification elements
3. **Plugin**: The `@react-native-firebase/messaging` plugin is automatically applied when the package is installed
4. **Android Only**: iOS uses the app icon for notifications by default

## Creating the Notification Icon

Your notification icon should be:
- **Pure white** silhouette on a transparent background
- **Square** aspect ratio
- **High resolution** (recommended 192x192px or higher)
- **Simple design** that's recognizable at small sizes

Example using ImageMagick to convert a regular icon:
```bash
convert your-icon.png -colorspace Gray -threshold 50% -negate notification-icon.png
```

## Verification

When you run `expo prebuild`, you should see these messages:
```
[@react-native-firebase/messaging] Android notification icon configured from app.json
[@react-native-firebase/messaging] Android notification color configured from app.json
```

If you don't have notification configuration, you'll see a warning with instructions on how to add it.

## Testing

Send a test notification to verify your configuration:
```javascript
import messaging from '@react-native-firebase/messaging';

// Request permission (iOS)
await messaging().requestPermission();

// Get FCM token
const token = await messaging().getToken();
console.log('FCM Token:', token);

// Listen for messages
messaging().onMessage(async remoteMessage => {
console.log('Received message:', remoteMessage);
});
```
20 changes: 20 additions & 0 deletions packages/messaging/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,26 @@ Requires `@react-native-firebase/app` to be installed.
yarn add @react-native-firebase/messaging
```

## Expo Configuration

This package includes an Expo config plugin for automatic configuration in Expo managed workflow. To configure notification icons and colors, add the following to your `app.json`:

```json
{
"expo": {
"notification": {
"icon": "./assets/notification-icon.png",
"color": "#FF0000"
},
"plugins": [
"@react-native-firebase/messaging"
]
}
}
```

> **Note**: Android requires a pure white notification icon. See the [full documentation](https://rnfirebase.io/messaging/usage#expo) for details.

## Documentation

- [Quick Start](https://rnfirebase.io/messaging/usage)
Expand Down
131 changes: 131 additions & 0 deletions packages/messaging/plugin/__tests__/enhanced.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
import { describe, expect, it } from '@jest/globals';
import { setFireBaseMessagingAndroidManifest } from '../src/android/setupFirebaseNotifationIcon';
import { ExpoConfig } from '@expo/config-types';
import { ManifestApplication } from '@expo/config-plugins/build/android/Manifest';

// Test to understand current functionality and identify improvements needed
describe('Enhanced Firebase Messaging Plugin Tests', function () {

// Test case 1: Standard Expo notification configuration
it('handles standard Expo notification configuration', async function () {
const config: ExpoConfig = {
name: 'Test App',
slug: 'test-app',
notification: {
icon: './assets/notification-icon.png',
color: '#FF0000'
}
};

const manifestApplication: ManifestApplication = {
$: { 'android:name': '' },
'meta-data': []
};

setFireBaseMessagingAndroidManifest(config, manifestApplication);

// Should set notification icon
expect(manifestApplication['meta-data']).toContainEqual({
$: {
'android:name': 'com.google.firebase.messaging.default_notification_icon',
'android:resource': '@drawable/notification_icon',
},
});

// Should set notification color
expect(manifestApplication['meta-data']).toContainEqual({
$: {
'android:name': 'com.google.firebase.messaging.default_notification_color',
'android:resource': '@color/notification_icon_color',
'tools:replace': 'android:resource',
},
});
});

// Test case 2: Custom icon path
it('handles different icon path formats', async function () {
const config: ExpoConfig = {
name: 'Test App',
slug: 'test-app',
notification: {
icon: './custom/path/icon.png'
}
};

const manifestApplication: ManifestApplication = {
$: { 'android:name': '' },
'meta-data': []
};

setFireBaseMessagingAndroidManifest(config, manifestApplication);

// Currently hardcodes to @drawable/notification_icon regardless of path
expect(manifestApplication['meta-data']).toContainEqual({
$: {
'android:name': 'com.google.firebase.messaging.default_notification_icon',
'android:resource': '@drawable/notification_icon',
},
});
});

// Test case 3: Missing notification config
it('warns when notification config is missing', async function () {
const warnOrig = console.warn;
const logOrig = console.log;
let warnCalled = false;
let warnMessage = '';
console.warn = (message: string) => {
warnCalled = true;
warnMessage = message;
};
console.log = () => {}; // Suppress log messages

const config: ExpoConfig = {
name: 'Test App',
slug: 'test-app'
// No notification config
};

const manifestApplication: ManifestApplication = {
$: { 'android:name': '' },
'meta-data': []
};

setFireBaseMessagingAndroidManifest(config, manifestApplication);

expect(warnCalled).toBeTruthy();
expect(warnMessage).toContain('[@react-native-firebase/messaging]');
expect(warnMessage).toContain('notification configuration');
console.warn = warnOrig;
console.log = logOrig;
});

// Test case 4: Successful configuration with logging
it('logs successful configuration', async function () {
const logOrig = console.log;
let logMessages: string[] = [];
console.log = (message: string) => {
logMessages.push(message);
};

const config: ExpoConfig = {
name: 'Test App',
slug: 'test-app',
notification: {
icon: './assets/notification-icon.png',
color: '#FF0000'
}
};

const manifestApplication: ManifestApplication = {
$: { 'android:name': '' },
'meta-data': []
};

setFireBaseMessagingAndroidManifest(config, manifestApplication);

expect(logMessages.some(msg => msg.includes('notification icon configured'))).toBeTruthy();
expect(logMessages.some(msg => msg.includes('notification color configured'))).toBeTruthy();
console.log = logOrig;
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,16 @@ export function setFireBaseMessagingAndroidManifest(
// This warning is important because the notification icon can only use pure white on Android. By default, the system uses the app icon as the notification icon, but the app icon is usually not pure white, so you need to set the notification icon
// eslint-disable-next-line no-console
console.warn(
'For Android 8.0 and above, it is necessary to set the notification icon to ensure correct display. Otherwise, the notification will not show the correct icon. For more information, visit https://docs.expo.dev/versions/latest/config/app/#notification',
'[@react-native-firebase/messaging] For Android, it is necessary to set a notification icon to ensure correct display. Add notification configuration to your app.json:\n' +
'{\n' +
' "expo": {\n' +
' "notification": {\n' +
' "icon": "./assets/notification-icon.png",\n' +
' "color": "#FF0000"\n' +
' }\n' +
' }\n' +
'}\n' +
'For more information, visit https://docs.expo.dev/versions/latest/config/app/#notification',
);
return config;
}
Expand All @@ -56,6 +65,11 @@ export function setFireBaseMessagingAndroidManifest(
'android:resource': '@drawable/notification_icon',
},
});

// eslint-disable-next-line no-console
console.log(
'[@react-native-firebase/messaging] Android notification icon configured from app.json',
);
}

if (
Expand All @@ -71,6 +85,11 @@ export function setFireBaseMessagingAndroidManifest(
'tools:replace': 'android:resource',
},
});

// eslint-disable-next-line no-console
console.log(
'[@react-native-firebase/messaging] Android notification color configured from app.json',
);
}

return application;
Expand Down