From 75461eec9dc6821614c84ca0faec2c228c3312eb Mon Sep 17 00:00:00 2001 From: Jerome Bonfort Date: Mon, 30 Mar 2026 15:43:45 +0200 Subject: [PATCH 1/3] Enhance error handling in ad loading across platforms - Improved error messages in both iOS and Android implementations to include SDK-specific details and raw values for better debugging. - Updated AdError class to support additional properties for enhanced error reporting. - Modified Banner and Interstitial components to display more informative error messages, improving user feedback during ad loading failures. --- .../adversport/rnaps/RNAPSAdLoaderModule.java | 25 +++++++-- example/src/Banner.component.tsx | 29 ++++++++-- example/src/Interstitial.component.tsx | 25 +++++++-- ios/RNAPS/RNAPSAdLoaderModule.swift | 17 ++++-- src/AdError.ts | 53 +++++++++++++++++-- 5 files changed, 130 insertions(+), 19 deletions(-) diff --git a/android/src/main/java/com/adversport/rnaps/RNAPSAdLoaderModule.java b/android/src/main/java/com/adversport/rnaps/RNAPSAdLoaderModule.java index 182211c..7412c69 100644 --- a/android/src/main/java/com/adversport/rnaps/RNAPSAdLoaderModule.java +++ b/android/src/main/java/com/adversport/rnaps/RNAPSAdLoaderModule.java @@ -103,9 +103,26 @@ public void onFailure(AdError adError) { break; } + String sdkCodeName = errorCode.name(); + String sdkMessage = adError.getMessage(); + if (sdkMessage == null) { + sdkMessage = ""; + } + String composedMessage = + "Failed to load APS ad (mapped: " + + code + + ", SDK: " + + sdkCodeName + + ", ordinal: " + + errorCode.ordinal() + + ")" + + (sdkMessage.isEmpty() ? "" : " — " + sdkMessage); + WritableMap userInfoMap = Arguments.createMap(); userInfoMap.putString("code", code); - userInfoMap.putString("message", adError.getMessage()); + userInfoMap.putString("message", composedMessage); + userInfoMap.putString("sdkCode", sdkCodeName); + userInfoMap.putInt("rawValue", errorCode.ordinal()); WritableMap payload = Arguments.createMap(); payload.putInt("loaderId", loaderId); @@ -116,8 +133,10 @@ public void onFailure(AdError adError) { // Créer une copie pour promise.reject car userInfoMap est déjà utilisé WritableMap userInfoCopy = Arguments.createMap(); userInfoCopy.putString("code", code); - userInfoCopy.putString("message", adError.getMessage()); - promise.reject(code, adError.getMessage(), userInfoCopy); + userInfoCopy.putString("message", composedMessage); + userInfoCopy.putString("sdkCode", sdkCodeName); + userInfoCopy.putInt("rawValue", errorCode.ordinal()); + promise.reject(code, composedMessage, userInfoCopy); promise = null; } } diff --git a/example/src/Banner.component.tsx b/example/src/Banner.component.tsx index cbffe12..8b16348 100644 --- a/example/src/Banner.component.tsx +++ b/example/src/Banner.component.tsx @@ -53,7 +53,9 @@ export default function BannerDemo() { (error) => { setApsBidError(error); setBidComplete(true); - addEvent(`APS bid failed (code: ${error.code})`); + addEvent( + `APS bid failed (${error.formatShortLabel()}) — ${error.message}` + ); } ); @@ -70,7 +72,9 @@ export default function BannerDemo() { : new AdError('unknown', String(error?.message ?? error)); setApsBidError(adError); setBidComplete(true); - addEvent(`APS bid failed (code: ${adError.code})`); + addEvent( + `APS bid failed (${adError.formatShortLabel()}) — ${adError.message}` + ); }); addEvent('APS bid requested'); @@ -116,10 +120,15 @@ export default function BannerDemo() { Won ) : ( - + - Failed ({apsBidError?.code ?? '?'}) + Failed ({apsBidError?.formatShortLabel() ?? '?'}) + {!!apsBidError?.message && ( + + {apsBidError.message} + + )} )} @@ -257,6 +266,18 @@ const styles = StyleSheet.create({ badgeError: { backgroundColor: '#fef2f2', }, + badgeErrorStack: { + flexDirection: 'column', + alignItems: 'flex-end', + maxWidth: '78%', + gap: 4, + }, + badgeTextErrorDetail: { + fontSize: 11, + color: '#b91c1c', + fontWeight: '400', + textAlign: 'right', + }, badgeTextLoading: { fontSize: 13, color: '#6366f1', diff --git a/example/src/Interstitial.component.tsx b/example/src/Interstitial.component.tsx index a36f1c0..a376012 100644 --- a/example/src/Interstitial.component.tsx +++ b/example/src/Interstitial.component.tsx @@ -57,7 +57,9 @@ export default function InterstitialDemo() { .catch((error) => { if (isAdError(error)) { setApsBidError(error); - addEvent(`APS bid failed (code: ${error.code})`); + addEvent( + `APS bid failed (${error.formatShortLabel()}) — ${error.message}` + ); } const interstitial = GAMInterstitialAd.createForAdRequest( TestIds.GAM_INTERSTITIAL @@ -137,10 +139,15 @@ export default function InterstitialDemo() { Won ) : apsBidError ? ( - + - Failed ({apsBidError.code}) + Failed ({apsBidError.formatShortLabel()}) + {!!apsBidError.message && ( + + {apsBidError.message} + + )} ) : ( @@ -280,6 +287,18 @@ const styles = StyleSheet.create({ badgeError: { backgroundColor: '#fef2f2', }, + badgeErrorStack: { + flexDirection: 'column', + alignItems: 'flex-end', + maxWidth: '78%', + gap: 4, + }, + badgeTextErrorDetail: { + fontSize: 11, + color: '#b91c1c', + fontWeight: '400', + textAlign: 'right', + }, badgeTextLoading: { fontSize: 13, color: '#6366f1', diff --git a/ios/RNAPS/RNAPSAdLoaderModule.swift b/ios/RNAPS/RNAPSAdLoaderModule.swift index 65d1bf8..6d19ec9 100644 --- a/ios/RNAPS/RNAPSAdLoaderModule.swift +++ b/ios/RNAPS/RNAPSAdLoaderModule.swift @@ -119,10 +119,19 @@ class RNAPSAdLoaderModule: RCTEventEmitter { default: // Use simple default to ensure exhaustiveness code = "unknown" } - let message = String(format: "Failed to load APS ad with code: %@", code) - var userInfo = Dictionary() - userInfo["code"] = code - userInfo["message"] = message + let sdkLabel = String(describing: error) + let message = String( + format: "Failed to load APS ad (mapped: %@, APS: %@, rawValue: %d)", + code, + sdkLabel, + error.rawValue + ) + let userInfo: [String: Any] = [ + "code": code, + "message": message, + "sdkCode": sdkLabel, + "rawValue": error.rawValue, + ] adLoaderModule.sendEvent(name: RNAPSAdLoaderModule.EVENT_FAILURE, body: [ "loaderId": loaderId, "userInfo": userInfo diff --git a/src/AdError.ts b/src/AdError.ts index fd85fec..a6db6ed 100644 --- a/src/AdError.ts +++ b/src/AdError.ts @@ -16,19 +16,62 @@ * along with Foobar. If not, see . */ +export type AdErrorExtras = { + /** Amazon SDK error label (e.g. iOS `String(describing:)`, Android `ErrorCode.name()`). */ + sdkCode?: string; + /** Raw / ordinal value from the native SDK when available. */ + rawValue?: number; +}; + /** - * AdError class - * + * AdError class — normalized `code` from the bridge, plus optional native details for debugging. */ export class AdError extends Error { - constructor(readonly code: string, message: string) { + readonly code: string; + readonly sdkCode?: string; + readonly rawValue?: number; + + constructor(code: string, message: string, extras?: AdErrorExtras) { super(message); this.name = 'AdError'; + this.code = code; + this.sdkCode = extras?.sdkCode; + this.rawValue = extras?.rawValue; + } + + /** Compact label for UI (badge, logs). */ + formatShortLabel(): string { + const parts = [this.code]; + if (this.sdkCode) { + parts.push(this.sdkCode); + } + if (this.rawValue !== undefined) { + parts.push(`#${this.rawValue}`); + } + return parts.join(' · '); } static fromNativeError(error: any): AdError { - const { code, message } = error.userInfo; - return new AdError(code, message); + const ui = error?.userInfo; + const code = typeof ui?.code === 'string' ? ui.code : 'unknown'; + const message = + typeof ui?.message === 'string' ? ui.message : String(ui?.message ?? ''); + const sdkCode = + typeof ui?.sdkCode === 'string' ? ui.sdkCode : undefined; + let rawValue: number | undefined; + if (typeof ui?.rawValue === 'number' && !Number.isNaN(ui.rawValue)) { + rawValue = ui.rawValue; + } else if (typeof ui?.rawValue === 'string' && ui.rawValue !== '') { + const n = Number(ui.rawValue); + if (!Number.isNaN(n)) { + rawValue = n; + } + } + const extras = + sdkCode !== undefined || rawValue !== undefined + ? { sdkCode, rawValue } + : undefined; + return new AdError(code, message, extras); } } From 8fd97f4f6b54da6bc7edc1f650dd3ff56b9527e1 Mon Sep 17 00:00:00 2001 From: Jerome Bonfort Date: Mon, 30 Mar 2026 16:04:14 +0200 Subject: [PATCH 2/3] chore: update react-native-google-mobile-ads dependency to version 15.8.3 - Upgraded the react-native-google-mobile-ads package from version 14.2.0 to 15.8.3 in package.json and yarn.lock for improved functionality and performance. --- example/package.json | 2 +- example/yarn.lock | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/example/package.json b/example/package.json index 1693291..bdd4af9 100644 --- a/example/package.json +++ b/example/package.json @@ -13,7 +13,7 @@ "react": "18.3.1", "react-native": "0.77.3", "react-native-aps": "link:../", - "react-native-google-mobile-ads": "^14.2.0" + "react-native-google-mobile-ads": "15.8.3" }, "devDependencies": { "@babel/core": "^7.25.2", diff --git a/example/yarn.lock b/example/yarn.lock index 2ba2645..4f67f40 100644 --- a/example/yarn.lock +++ b/example/yarn.lock @@ -4841,7 +4841,7 @@ __metadata: react: "npm:18.3.1" react-native: "npm:0.77.3" react-native-aps: "link:../" - react-native-google-mobile-ads: "npm:^14.2.0" + react-native-google-mobile-ads: "npm:15.8.3" typescript: "npm:^5.0.4" languageName: unknown linkType: soft @@ -4852,9 +4852,9 @@ __metadata: languageName: node linkType: soft -"react-native-google-mobile-ads@npm:^14.2.0": - version: 14.11.0 - resolution: "react-native-google-mobile-ads@npm:14.11.0" +"react-native-google-mobile-ads@npm:15.8.3": + version: 15.8.3 + resolution: "react-native-google-mobile-ads@npm:15.8.3" dependencies: "@iabtcf/core": "npm:^1.5.3" use-deep-compare-effect: "npm:^1.8.1" @@ -4863,7 +4863,7 @@ __metadata: peerDependenciesMeta: expo: optional: true - checksum: 10c0/5d424081fc14f1da9d495cdf26109fb0d55c5d1599fb651d5117f36357eab0334e61701557046e1f58b84e4cafa480dcf6ac13071641188950fcdcf10f00e2c4 + checksum: 10c0/444adaa3a852a2acbe799802ba5e1b4cf9b94c5ff07c2e2d0a403084a85120060b5426046e613fe90efe92b222949dbbe5dcd38fd4d25cce70d7e46bad9af8c7 languageName: node linkType: hard From 2444a9c626f7973395268b4f2272f9122d210b88 Mon Sep 17 00:00:00 2001 From: Jerome Bonfort Date: Mon, 30 Mar 2026 16:08:39 +0200 Subject: [PATCH 3/3] refactor: clean up AdError class code for improved readability - Removed unnecessary line breaks in the AdError class to enhance code clarity and maintainability. --- src/AdError.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/AdError.ts b/src/AdError.ts index a6db6ed..15aa9b1 100644 --- a/src/AdError.ts +++ b/src/AdError.ts @@ -56,8 +56,7 @@ export class AdError extends Error { const code = typeof ui?.code === 'string' ? ui.code : 'unknown'; const message = typeof ui?.message === 'string' ? ui.message : String(ui?.message ?? ''); - const sdkCode = - typeof ui?.sdkCode === 'string' ? ui.sdkCode : undefined; + const sdkCode = typeof ui?.sdkCode === 'string' ? ui.sdkCode : undefined; let rawValue: number | undefined; if (typeof ui?.rawValue === 'number' && !Number.isNaN(ui.rawValue)) { rawValue = ui.rawValue;