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/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/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/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
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..15aa9b1 100644
--- a/src/AdError.ts
+++ b/src/AdError.ts
@@ -16,19 +16,61 @@
* 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);
}
}