invertase / invertase/react-native-google-mobile-ads
[🐛] `NativeAd` paid event type exposes `currencyCode`, but the bridge sends `currency`
- Dominant language
- TypeScript
- Stars
- 1k
- Forks
- 229
- Avg merge
- 3d 5h
- Merged PRs (30d)
- 7
Description
### What happened?
## Summary
`NativeAd.addAdEventListener(NativeAdEventType.PAID, ...)` exposes a payload type
with `currencyCode`, but both native implementations emit the JavaScript payload
key as `currency`.
TypeScript accepts `payload.currencyCode`, but that property is `undefined` at
runtime. The actual value is available at `payload.currency`.
## Evidence
The NativeAd TypeScript payload declares `currencyCode`:
```ts
export type NativeAdPaidEventPayload = {
value: number;
precision: number;
currencyCode: string;
};
```
https://discord.com/channels/295953187817521152/1059856784308850709/1539547481434492958
### Platforms
Android, but have not tested behavior on iOS
### React Native Info
```Shell
System:
OS: Windows 11 10.0.26200
CPU: "(12) x64 AMD Ryzen 5 5600H with Radeon Graphics "
Memory: 1.60 GB / 15.35 GB
Binaries:
Node:
version: 24.15.0
path: C:\Program Files\nodejs\node.EXE
Yarn:
version: 4.10.3
path: C:\Users\Sanjay Sargam\AppData\Roaming\npm\yarn.CMD
npm:
version: 11.8.0
path: C:\rngma\node_modules\.bin\npm.CMD
Watchman: Not Found
SDKs:
Android SDK:
API Levels:
- "33"
- "34"
- "35"
- "36"
- "36"
- "37"
Build Tools:
- 34.0.0
- 35.0.0
- 36.0.0
- 36.1.0
- 37.0.0
System Images:
- android-33 | Google Play Intel x86_64 Atom
- android-35 | ARM 64 v8a
- android-35 | Google Play ARM 64 v8a
- android-35 | Google Play Intel x86_64 Atom
- android-35 | Google Play Tablet Intel x86_64 Atom
- android-37.0 | 16 KB Page Size Google Play Intel x86_64 Atom
- android-37.1 | 16 KB Page Size Google APIs Intel x86_64 Atom
Android NDK: Not Found
Windows SDK:
AllowDevelopmentWithoutDevLicense: Enabled
IDEs:
Android Studio: AI-261.26222.65.2613.16025427
Visual Studio: Not Found
Languages:
Java:
version: 21.0.10
path: C:\Users\Sanjay Sargam\.jdks\jbr-21.0.10\bin\javac.EXE
Ruby: Not Found
npmPackages:
"@react-native-community/cli":
installed: 20.1.0
wanted: 20.1.0
react:
installed: 19.2.3
wanted: 19.2.3
react-native:
installed: 0.86.0
wanted: 0.86.0
react-native-windows: Not Found
npmGlobalPackages:
"*react-native*": Not Found
Android:
hermesEnabled: false
newArchEnabled: true
iOS:
hermesEnabled: Not found
newArchEnabled: Not found
```
### Are your using Typescript?
- [x] My project is using Typescript
### package.json
```JSON
{
"name": "RNGoogleMobileAdsExample",
"version": "0.0.1",
"private": true,
"scripts": {
"android": "react-native run-android",
"build:android": "npm run mkdist && react-native bundle --entry-file index.js --platform android --dev true --bundle-output dist/main.android.jsbundle --assets-dest dist/res",
"build:ios": "npm run mkdist && react-native bundle --entry-file index.js --platform ios --dev true --bundle-output dist/main.ios.jsbundle --assets-dest dist",
"ios": "react-native run-ios",
"lint": "eslint .",
"mkdist": "node -e \"require('node:fs').mkdirSync('dist', { recursive: true, mode: 0o755 })\"",
"start": "react-native start",
"test": "jest"
},
"dependencies": {
"@react-native/new-app-screen": "0.83.1",
"react": "19.2.3",
"react-native": "0.86.0",
"react-native-google-mobile-ads": "portal:../",
"react-native-safe-area-context": "^5.5.2"
},
"devDependencies": {
"@babel/core": "^7.25.2",
"@babel/preset-env": "^7.25.3",
"@babel/runtime": "^7.25.0",
"@react-native-community/cli": "20.1.0",
"@react-native-community/cli-platform-android": "20.1.0",
"@react-native-community/cli-platform-ios": "20.1.0",
"@react-native/babel-preset": "0.86.0",
"@react-native/eslint-config": "0.86.0",
"@react-native/metro-config": "0.86.0",
"@react-native/typescript-config": "0.86.0",
"@rnx-kit/metro-config": "^2.2.4",
"@types/jest": "^29.5.13",
"@types/react": "^19.1.1",
"@types/react-test-renderer": "^19.1.0",
"eslint": "^8.19.0",
"jest": "^29.6.3",
"jet": "https://github.com/invertase/jet#@mikehardy/jet-next",
"prettier": "2.8.8",
"react-native-test-app": "^5.4.0",
"react-test-renderer": "19.2.3",
"typescript": "^5.8.3"
},
"engines": {
"node": ">= 22.11.0"
}
}
```
### app.json
```JSON
{
"name": "RNGoogleMobileAdsExample",
"displayName": "RNGoogleMobileAdsExample",
"singleApp": "RNGoogleMobileAdsExample",
"components": [
{
"appKey": "RNGoogleMobileAdsExample",
"displayName": "RNGoogleMobileAdsExample",
"slug": "RNGoogleMobileAdsExample"
}
],
"resources": {
"android": [
"dist/res",
"dist/main.android.jsbundle"
],
"ios": [
"dist/assets",
"dist/main.ios.jsbundle"
],
"macos": [
"dist/assets",
"dist/main.macos.jsbundle"
],
"visionos": [
"dist/assets",
"dist/main.visionos.jsbundle"
],
"windows": [
"dist/assets",
"dist/main.windows.bundle"
]
},
"react-native-google-mobile-ads": {
"android_app_id": "ca-app-pub-3940256099942544~3347511713",
"ios_app_id": "ca-app-pub-3940256099942544~1458002511",
"delay_app_measurement_init": false,
"user_tracking_usage_description": "This identifier will be used to deliver personalized ads to you.",
"sk_ad_network_items": [
"cstr6suwn9.skadnetwork",
"4fzdc2evr5.skadnetwork",
"2fnua5tdw4.skadnetwork",
"ydx93a7ass.skadnetwork",
"p78axxw29g.skadnetwork",
"v72qych5uu.skadnetwork",
"ludvb6z3bs.skadnetwork",
"cp8zw746q7.skadnetwork",
"3sh42y64q3.skadnetwork",
"c6k4g5qg8m.skadnetwork",
"s39g8k73mm.skadnetwork",
"wg4vff78zm.skadnetwork",
"3qy4746246.skadnetwork",
"f38h382jlk.skadnetwork",
"hs6bdukanm.skadnetwork",
"mlmmfzh3r3.skadnetwork",
"v4nxqhlyqp.skadnetwork",
"wzmmz9fp6w.skadnetwork",
"su67r6k2v3.skadnetwork",
"yclnxrl5pm.skadnetwork",
"t38b2kh725.skadnetwork",
"7ug5zh24hu.skadnetwork",
"gta9lk7p23.skadnetwork",
"vutu7akeur.skadnetwork",
"y5ghdn5j9k.skadnetwork",
"v9wttpbfk9.skadnetwork",
"n38lu8286q.skadnetwork",
"47vhws6wlr.skadnetwork",
"kbd757ywx3.skadnetwork",
"9t245vhmpl.skadnetwork",
"a2p9lx4jpn.skadnetwork",
"22mmun2rn5.skadnetwork",
"44jx6755aq.skadnetwork",
"k674qkevps.skadnetwork",
"4468km3ulz.skadnetwork",
"2u9pt9hc89.skadnetwork",
"8s468mfl3y.skadnetwork",
"klf5c3l5u5.skadnetwork",
"ppxm28t8ap.skadnetwork",
"kbmxgpxpgc.skadnetwork",
"uw77j35x4d.skadnetwork",
"578prtvx9j.skadnetwork",
"4dzt52r2t5.skadnetwork",
"tl55sbb4fm.skadnetwork",
"c3frkrj4fj.skadnetwork",
"e5fvkxwrpn.skadnetwork",
"8c4e2ghe7u.skadnetwork",
"3rd42ekr43.skadnetwork",
"97r2b46745.skadnetwork",
"3qcr597p9d.skadnetwork"
]
}
}
```
### ios/Podfile
```Ruby
```
### android/build.gradle
```Groovy
```
### android/app/build.gradle
```Groovy
```
### android/settings.gradle
```Groovy
```
### AndroidManifest.xml
```XML
```
Contributor guide
Research direction
Start by searching for NativeAdPaidEventPayload and the NativeAd.addAdEventListener PAID entry point, then trace the Android and iOS bridge emitters that build the event payload. Make the declared and emitted currency property consistent on both platforms, and verify the PAID callback exposes the same value at runtime as the TypeScript type.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- android, ios, react-native, typescript
- Domain
- api, mobile
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 68/100