Skip to content

Commit 22b9d2d

Browse files
fix: add firebase-messaging gradle dependency to app module
The native module declares firebase-messaging as an `implementation` dependency, which is private to the library module. Since the generated FirebaseMessagingService lives in the app module, it needs firebase-messaging on its own compile classpath. Conditionally adds the dependency to app/build.gradle if not already present. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent d797b38 commit 22b9d2d

2 files changed

Lines changed: 59 additions & 0 deletions

File tree

__tests__/withAndroidPushNotifications.test.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,26 @@ function createMockConfig(packageName?: string) {
4040
describe('withAndroidPushNotifications', () => {
4141
let mkdirSyncSpy: jest.SpyInstance;
4242
let writeFileSyncSpy: jest.SpyInstance;
43+
let readFileSyncSpy: jest.SpyInstance;
44+
45+
const fakeBuildGradle = `
46+
android {
47+
compileSdkVersion 34
48+
}
49+
50+
dependencies {
51+
implementation("com.facebook.react:react-native:+")
52+
}
53+
`;
4354

4455
beforeEach(() => {
4556
mkdirSyncSpy = jest.spyOn(fs, 'mkdirSync').mockReturnValue(undefined);
4657
writeFileSyncSpy = jest
4758
.spyOn(fs, 'writeFileSync')
4859
.mockReturnValue(undefined);
60+
readFileSyncSpy = jest
61+
.spyOn(fs, 'readFileSync')
62+
.mockReturnValue(fakeBuildGradle);
4963
});
5064

5165
afterEach(() => {
@@ -139,6 +153,32 @@ describe('withAndroidPushNotifications', () => {
139153
});
140154
});
141155

156+
describe('Gradle dependency', () => {
157+
test('adds firebase-messaging when not present', () => {
158+
const config = createMockConfig('com.example.myapp');
159+
withAndroidPushNotifications(config as any, {} as any);
160+
161+
const gradleWriteCall = writeFileSyncSpy.mock.calls.find(
162+
(call: any[]) => (call[0] as string).includes('build.gradle')
163+
);
164+
expect(gradleWriteCall).toBeDefined();
165+
expect(gradleWriteCall[1]).toContain('firebase-messaging');
166+
});
167+
168+
test('skips adding firebase-messaging when already present', () => {
169+
readFileSyncSpy.mockReturnValue(
170+
'dependencies {\n implementation("com.google.firebase:firebase-messaging:23.0.0")\n}'
171+
);
172+
const config = createMockConfig('com.example.myapp');
173+
withAndroidPushNotifications(config as any, {} as any);
174+
175+
const gradleWriteCall = writeFileSyncSpy.mock.calls.find(
176+
(call: any[]) => (call[0] as string).includes('build.gradle')
177+
);
178+
expect(gradleWriteCall).toBeUndefined();
179+
});
180+
});
181+
142182
describe('AndroidManifest service registration', () => {
143183
test('adds service entry with correct attributes', () => {
144184
const config = createMockConfig('com.example.myapp');

src/expo-plugins/withAndroidPushNotifications.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,25 @@ const writeFirebaseService: ConfigPlugin<IntercomPluginProps> = (_config) =>
7474
'utf-8'
7575
);
7676

77+
// The native module declares firebase-messaging as an `implementation`
78+
// dependency, which keeps it private to the library. Since our generated
79+
// service lives in the app module, we need firebase-messaging on the
80+
// app's compile classpath too.
81+
const buildGradlePath = path.join(
82+
projectRoot,
83+
'android',
84+
'app',
85+
'build.gradle'
86+
);
87+
const buildGradle = fs.readFileSync(buildGradlePath, 'utf-8');
88+
if (!buildGradle.includes('firebase-messaging')) {
89+
const updatedBuildGradle = buildGradle.replace(
90+
/dependencies\s*\{/,
91+
`dependencies {\n implementation("com.google.firebase:firebase-messaging:24.1.2")`
92+
);
93+
fs.writeFileSync(buildGradlePath, updatedBuildGradle, 'utf-8');
94+
}
95+
7796
return config;
7897
},
7998
]);

0 commit comments

Comments
 (0)