cloudx-react-native 3.10.1 → 3.11.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/android/build.gradle +1 -1
- package/android/src/main/java/com/cloudxreactnative/CloudXAdEvents.kt +9 -0
- package/android/src/main/java/com/cloudxreactnative/CloudXAdInfo.kt +76 -0
- package/android/src/main/java/com/cloudxreactnative/CloudXModuleImpl.kt +110 -0
- package/android/src/main/java/com/cloudxreactnative/CloudXNativeAdHolder.kt +184 -0
- package/android/src/main/java/com/cloudxreactnative/CloudXNativeAdView.kt +209 -70
- package/android/src/main/java/com/cloudxreactnative/CloudXNativeAdViewManagerImpl.kt +6 -0
- package/android/src/newarch/com/cloudxreactnative/CloudXModule.kt +9 -0
- package/android/src/newarch/com/cloudxreactnative/CloudXNativeAdViewManager.kt +2 -0
- package/android/src/oldarch/com/cloudxreactnative/CloudXModule.kt +14 -0
- package/android/src/oldarch/com/cloudxreactnative/CloudXNativeAdViewManager.kt +3 -0
- package/android/src/test/java/com/cloudxreactnative/CloudXNativeAdPreloadTest.kt +351 -0
- package/android/src/test/java/com/cloudxreactnative/FakeReadable.kt +2 -2
- package/cloudx-react-native.podspec +1 -1
- package/ios/CloudX.h +12 -0
- package/ios/CloudX.mm +94 -1
- package/ios/CloudXNativeAdHolder.h +66 -0
- package/ios/CloudXNativeAdHolder.mm +247 -0
- package/ios/CloudXNativeAdView.h +9 -0
- package/ios/CloudXNativeAdView.mm +308 -64
- package/ios/CloudXNativeAdViewManager.mm +7 -0
- package/lib/commonjs/CloudXNativeAd.js +178 -0
- package/lib/commonjs/CloudXNativeAd.js.map +1 -0
- package/lib/commonjs/CloudXNativeAdView.js +58 -11
- package/lib/commonjs/CloudXNativeAdView.js.map +1 -1
- package/lib/commonjs/hooks.js +203 -0
- package/lib/commonjs/hooks.js.map +1 -1
- package/lib/commonjs/index.js +13 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/specs/CloudXNativeAdViewNativeComponent.js +2 -0
- package/lib/commonjs/specs/CloudXNativeAdViewNativeComponent.js.map +1 -1
- package/lib/commonjs/specs/NativeCloudX.js.map +1 -1
- package/lib/commonjs/types/NativeAd.js +21 -1
- package/lib/commonjs/types/NativeAd.js.map +1 -1
- package/lib/commonjs/types/index.js.map +1 -1
- package/lib/commonjs/version.js +1 -1
- package/lib/module/CloudXNativeAd.js +170 -0
- package/lib/module/CloudXNativeAd.js.map +1 -0
- package/lib/module/CloudXNativeAdView.js +58 -11
- package/lib/module/CloudXNativeAdView.js.map +1 -1
- package/lib/module/hooks.js +202 -0
- package/lib/module/hooks.js.map +1 -1
- package/lib/module/index.js +2 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/specs/CloudXNativeAdViewNativeComponent.js +2 -0
- package/lib/module/specs/CloudXNativeAdViewNativeComponent.js.map +1 -1
- package/lib/module/specs/NativeCloudX.js.map +1 -1
- package/lib/module/types/NativeAd.js +26 -1
- package/lib/module/types/NativeAd.js.map +1 -1
- package/lib/module/types/index.js.map +1 -1
- package/lib/module/version.js +1 -1
- package/lib/typescript/src/CloudXNativeAd.d.ts +58 -0
- package/lib/typescript/src/CloudXNativeAd.d.ts.map +1 -0
- package/lib/typescript/src/CloudXNativeAdView.d.ts +6 -13
- package/lib/typescript/src/CloudXNativeAdView.d.ts.map +1 -1
- package/lib/typescript/src/hooks.d.ts +30 -0
- package/lib/typescript/src/hooks.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +4 -3
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/specs/CloudXNativeAdViewNativeComponent.d.ts +23 -2
- package/lib/typescript/src/specs/CloudXNativeAdViewNativeComponent.d.ts.map +1 -1
- package/lib/typescript/src/specs/NativeCloudX.d.ts +13 -0
- package/lib/typescript/src/specs/NativeCloudX.d.ts.map +1 -1
- package/lib/typescript/src/types/NativeAd.d.ts +76 -13
- package/lib/typescript/src/types/NativeAd.d.ts.map +1 -1
- package/lib/typescript/src/types/index.d.ts +1 -1
- package/lib/typescript/src/types/index.d.ts.map +1 -1
- package/lib/typescript/src/version.d.ts +1 -1
- package/package.json +1 -1
- package/src/CloudXNativeAd.ts +177 -0
- package/src/CloudXNativeAdView.tsx +82 -15
- package/src/hooks.ts +236 -0
- package/src/index.ts +14 -1
- package/src/specs/CloudXNativeAdViewNativeComponent.ts +27 -2
- package/src/specs/NativeCloudX.ts +20 -0
- package/src/types/NativeAd.ts +85 -18
- package/src/types/index.ts +4 -0
- package/src/version.ts +1 -1
package/src/hooks.ts
CHANGED
|
@@ -9,6 +9,10 @@ import { useEffect, useState, useCallback, useRef } from 'react';
|
|
|
9
9
|
import type { EventSubscription } from 'react-native';
|
|
10
10
|
import NativeCloudX from './specs/NativeCloudX';
|
|
11
11
|
import { emitter } from './EventEmitter';
|
|
12
|
+
import { CloudXNativeAd } from './CloudXNativeAd';
|
|
13
|
+
import { useCloudXSdkInitializationGate } from './useCloudXSdkInitialization';
|
|
14
|
+
import type { CloudXAdLoadFailedInfo } from './types/AdInfo';
|
|
15
|
+
import type { CloudXNativeAdLoadOptions } from './types/NativeAd';
|
|
12
16
|
|
|
13
17
|
const {
|
|
14
18
|
ON_INTERSTITIAL_LOADED_EVENT,
|
|
@@ -429,3 +433,235 @@ export function useCloudXBanner(adUnitId: string): CloudXBannerHookResult {
|
|
|
429
433
|
|
|
430
434
|
return { isLoaded, error };
|
|
431
435
|
}
|
|
436
|
+
|
|
437
|
+
// ---------------------------------------------------------------------------
|
|
438
|
+
// useCloudXNativeAd
|
|
439
|
+
// ---------------------------------------------------------------------------
|
|
440
|
+
|
|
441
|
+
export type CloudXNativeAdHookStatus = 'idle' | 'loading' | 'loaded' | 'expired' | 'error';
|
|
442
|
+
|
|
443
|
+
export type CloudXNativeAdHookResult = {
|
|
444
|
+
status: CloudXNativeAdHookStatus;
|
|
445
|
+
nativeAd: CloudXNativeAd | null;
|
|
446
|
+
error: CloudXAdLoadFailedInfo | null;
|
|
447
|
+
load: () => void;
|
|
448
|
+
destroy: () => void;
|
|
449
|
+
};
|
|
450
|
+
|
|
451
|
+
const stableSerialize = (value: unknown): unknown => {
|
|
452
|
+
if (value === null || typeof value !== 'object') {
|
|
453
|
+
return value;
|
|
454
|
+
}
|
|
455
|
+
if (Array.isArray(value)) {
|
|
456
|
+
return value.map(stableSerialize);
|
|
457
|
+
}
|
|
458
|
+
const record = value as Record<string, unknown>;
|
|
459
|
+
const sortedKeys = Object.keys(record).sort();
|
|
460
|
+
const result: Record<string, unknown> = {};
|
|
461
|
+
for (const key of sortedKeys) {
|
|
462
|
+
const val = record[key];
|
|
463
|
+
if (val !== undefined) {
|
|
464
|
+
result[key] = stableSerialize(val);
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
return result;
|
|
468
|
+
};
|
|
469
|
+
|
|
470
|
+
const getOptionsSignature = (options?: CloudXNativeAdLoadOptions): string => {
|
|
471
|
+
if (!options) return '{}';
|
|
472
|
+
return JSON.stringify(stableSerialize(options));
|
|
473
|
+
};
|
|
474
|
+
|
|
475
|
+
/**
|
|
476
|
+
* Hook for managing a preloaded native ad lifecycle.
|
|
477
|
+
*
|
|
478
|
+
* Preloads a native ad ahead of render and holds it until unmount, manual
|
|
479
|
+
* destruction, or identity change. Unlike view-managed ads, a preloaded ad's
|
|
480
|
+
* lifecycle belongs to its handle and this hook: unmounting a view bound to it
|
|
481
|
+
* does not destroy it.
|
|
482
|
+
*
|
|
483
|
+
* With autoLoad (the default) the first load waits until the SDK has
|
|
484
|
+
* initialized, as `CloudXNativeAdView` does. A `load()` call made before
|
|
485
|
+
* initialization fails with `NOT_INITIALIZED`.
|
|
486
|
+
*
|
|
487
|
+
* @param adUnitId - The ad unit identifier, or null to keep idle.
|
|
488
|
+
* @param options - Load options configuring the auction and loader.
|
|
489
|
+
* @param config - Optional configuration (autoLoad defaults to true).
|
|
490
|
+
*/
|
|
491
|
+
export function useCloudXNativeAd(
|
|
492
|
+
adUnitId: string | null,
|
|
493
|
+
options?: CloudXNativeAdLoadOptions,
|
|
494
|
+
config?: { autoLoad?: boolean }
|
|
495
|
+
): CloudXNativeAdHookResult {
|
|
496
|
+
const autoLoad = config?.autoLoad ?? true;
|
|
497
|
+
const optionsSignature = getOptionsSignature(options);
|
|
498
|
+
const isSdkInitialized = useCloudXSdkInitializationGate('useCloudXNativeAd');
|
|
499
|
+
|
|
500
|
+
const [status, setStatus] = useState<CloudXNativeAdHookStatus>(() =>
|
|
501
|
+
autoLoad && adUnitId ? 'loading' : 'idle'
|
|
502
|
+
);
|
|
503
|
+
const [nativeAd, setNativeAd] = useState<CloudXNativeAd | null>(null);
|
|
504
|
+
const [error, setError] = useState<CloudXAdLoadFailedInfo | null>(null);
|
|
505
|
+
|
|
506
|
+
const mountedRef = useRef(true);
|
|
507
|
+
const generationRef = useRef(0);
|
|
508
|
+
const heldAdRef = useRef<CloudXNativeAd | null>(null);
|
|
509
|
+
const optionsRef = useRef(options);
|
|
510
|
+
optionsRef.current = options;
|
|
511
|
+
|
|
512
|
+
const inflightRef = useRef<{
|
|
513
|
+
signature: string;
|
|
514
|
+
generation: number;
|
|
515
|
+
promise: Promise<CloudXNativeAd>;
|
|
516
|
+
} | null>(null);
|
|
517
|
+
|
|
518
|
+
const lastSignatureRef = useRef<string | null>(null);
|
|
519
|
+
|
|
520
|
+
const executeLoad = useCallback(() => {
|
|
521
|
+
if (!adUnitId) {
|
|
522
|
+
setStatus('idle');
|
|
523
|
+
setNativeAd(null);
|
|
524
|
+
setError(null);
|
|
525
|
+
return;
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
const currentSignature = `${adUnitId}::${optionsSignature}`;
|
|
529
|
+
|
|
530
|
+
// Coalesce concurrent loads with the same signature (React StrictMode
|
|
531
|
+
// double effects must not start two loads).
|
|
532
|
+
if (inflightRef.current && inflightRef.current.signature === currentSignature) {
|
|
533
|
+
return;
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
const generation = ++generationRef.current;
|
|
537
|
+
setStatus('loading');
|
|
538
|
+
setError(null);
|
|
539
|
+
|
|
540
|
+
if (heldAdRef.current) {
|
|
541
|
+
heldAdRef.current.destroy();
|
|
542
|
+
heldAdRef.current = null;
|
|
543
|
+
setNativeAd(null);
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
const currentOptions = optionsRef.current;
|
|
547
|
+
const promise = CloudXNativeAd.load(adUnitId, currentOptions);
|
|
548
|
+
inflightRef.current = { signature: currentSignature, generation, promise };
|
|
549
|
+
|
|
550
|
+
promise
|
|
551
|
+
.then((ad) => {
|
|
552
|
+
if (inflightRef.current?.promise === promise) {
|
|
553
|
+
inflightRef.current = null;
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
// A load that resolves after unmount, after destroy(), or after the signature
|
|
557
|
+
// changed is destroyed immediately and never published (generation counter).
|
|
558
|
+
if (!mountedRef.current || generationRef.current !== generation) {
|
|
559
|
+
ad.destroy();
|
|
560
|
+
return;
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
if (heldAdRef.current && heldAdRef.current !== ad) {
|
|
564
|
+
heldAdRef.current.destroy();
|
|
565
|
+
}
|
|
566
|
+
heldAdRef.current = ad;
|
|
567
|
+
|
|
568
|
+
// On the handle's 'expired' event: status 'expired', nativeAd null,
|
|
569
|
+
// and the expired handle destroyed.
|
|
570
|
+
ad.addListener('expired', () => {
|
|
571
|
+
if (generationRef.current === generation && heldAdRef.current === ad) {
|
|
572
|
+
heldAdRef.current = null;
|
|
573
|
+
setStatus('expired');
|
|
574
|
+
setNativeAd(null);
|
|
575
|
+
ad.destroy();
|
|
576
|
+
}
|
|
577
|
+
});
|
|
578
|
+
|
|
579
|
+
setStatus('loaded');
|
|
580
|
+
setNativeAd(ad);
|
|
581
|
+
setError(null);
|
|
582
|
+
})
|
|
583
|
+
.catch((err: CloudXAdLoadFailedInfo) => {
|
|
584
|
+
if (inflightRef.current?.promise === promise) {
|
|
585
|
+
inflightRef.current = null;
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
// Ignores stale rejection after identity change, destroy, or unmount.
|
|
589
|
+
if (!mountedRef.current || generationRef.current !== generation) {
|
|
590
|
+
return;
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
setStatus('error');
|
|
594
|
+
setNativeAd(null);
|
|
595
|
+
setError(err);
|
|
596
|
+
});
|
|
597
|
+
}, [adUnitId, optionsSignature]);
|
|
598
|
+
|
|
599
|
+
// Unmount owns the release. Kept apart from the load effect so a re-run
|
|
600
|
+
// of that effect (autoLoad flipping, say) never destroys an ad this hook
|
|
601
|
+
// has already published. Under StrictMode the simulated unmount only
|
|
602
|
+
// clears mountedRef; the remount sets it again, so a load in flight from
|
|
603
|
+
// the first mount is still published rather than duplicated.
|
|
604
|
+
useEffect(() => {
|
|
605
|
+
mountedRef.current = true;
|
|
606
|
+
return () => {
|
|
607
|
+
mountedRef.current = false;
|
|
608
|
+
if (heldAdRef.current) {
|
|
609
|
+
heldAdRef.current.destroy();
|
|
610
|
+
heldAdRef.current = null;
|
|
611
|
+
}
|
|
612
|
+
};
|
|
613
|
+
}, []);
|
|
614
|
+
|
|
615
|
+
useEffect(() => {
|
|
616
|
+
const currentSignature = adUnitId ? `${adUnitId}::${optionsSignature}` : '';
|
|
617
|
+
const isFirstRun = lastSignatureRef.current === null;
|
|
618
|
+
const signatureChanged = !isFirstRun && lastSignatureRef.current !== currentSignature;
|
|
619
|
+
lastSignatureRef.current = currentSignature;
|
|
620
|
+
|
|
621
|
+
if (signatureChanged) {
|
|
622
|
+
if (heldAdRef.current) {
|
|
623
|
+
heldAdRef.current.destroy();
|
|
624
|
+
heldAdRef.current = null;
|
|
625
|
+
}
|
|
626
|
+
// Never leave the previous identity's (now destroyed) handle
|
|
627
|
+
// published while the replacement loads, nor its status or error:
|
|
628
|
+
// with autoLoad off nothing replaces them, and a `loaded` status
|
|
629
|
+
// with no ad, or a `loading` one that never settles, would stick.
|
|
630
|
+
setNativeAd(null);
|
|
631
|
+
setStatus('idle');
|
|
632
|
+
setError(null);
|
|
633
|
+
generationRef.current++;
|
|
634
|
+
inflightRef.current = null;
|
|
635
|
+
|
|
636
|
+
if (!adUnitId) {
|
|
637
|
+
return;
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
// A held ad survives autoLoad flipping back on; only an identity
|
|
642
|
+
// change (handled above) replaces it.
|
|
643
|
+
if (autoLoad && adUnitId && isSdkInitialized && !heldAdRef.current) {
|
|
644
|
+
executeLoad();
|
|
645
|
+
}
|
|
646
|
+
}, [adUnitId, optionsSignature, autoLoad, isSdkInitialized, executeLoad]);
|
|
647
|
+
|
|
648
|
+
const load = useCallback(() => {
|
|
649
|
+
executeLoad();
|
|
650
|
+
}, [executeLoad]);
|
|
651
|
+
|
|
652
|
+
const destroy = useCallback(() => {
|
|
653
|
+
generationRef.current++;
|
|
654
|
+
inflightRef.current = null;
|
|
655
|
+
|
|
656
|
+
if (heldAdRef.current) {
|
|
657
|
+
heldAdRef.current.destroy();
|
|
658
|
+
heldAdRef.current = null;
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
setStatus('idle');
|
|
662
|
+
setNativeAd(null);
|
|
663
|
+
setError(null);
|
|
664
|
+
}, []);
|
|
665
|
+
|
|
666
|
+
return { status, nativeAd, error, load, destroy };
|
|
667
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -15,6 +15,7 @@ export { CloudXRewardedAd } from './CloudXRewardedAd';
|
|
|
15
15
|
export { CloudXBannerAd } from './CloudXBannerAd';
|
|
16
16
|
export { CloudXMRECAd } from './CloudXMRECAd';
|
|
17
17
|
export { CloudXAdPosition } from './CloudXAdPosition';
|
|
18
|
+
export { CloudXNativeAd } from './CloudXNativeAd';
|
|
18
19
|
|
|
19
20
|
// Ad View Components (in-tree; layer correctly under app overlays)
|
|
20
21
|
export { CloudXBannerView } from './CloudXBannerView';
|
|
@@ -47,12 +48,20 @@ export { CloudXErrorCode } from './CloudXErrorCode';
|
|
|
47
48
|
export { requestTrackingAuthorization, getTrackingAuthorizationStatus, CloudXATTStatus } from './AppTrackingTransparency';
|
|
48
49
|
|
|
49
50
|
// Hooks
|
|
50
|
-
export {
|
|
51
|
+
export {
|
|
52
|
+
useCloudXInterstitial,
|
|
53
|
+
useCloudXAppOpen,
|
|
54
|
+
useCloudXRewarded,
|
|
55
|
+
useCloudXBanner,
|
|
56
|
+
useCloudXNativeAd,
|
|
57
|
+
} from './hooks';
|
|
51
58
|
export type {
|
|
52
59
|
CloudXInterstitialHookResult,
|
|
53
60
|
CloudXAppOpenHookResult,
|
|
54
61
|
CloudXRewardedHookResult,
|
|
55
62
|
CloudXBannerHookResult,
|
|
63
|
+
CloudXNativeAdHookResult,
|
|
64
|
+
CloudXNativeAdHookStatus,
|
|
56
65
|
} from './hooks';
|
|
57
66
|
|
|
58
67
|
// Types
|
|
@@ -92,6 +101,10 @@ export type {
|
|
|
92
101
|
CloudXNativeAdMetadata,
|
|
93
102
|
CloudXNativeAdViewHandle,
|
|
94
103
|
CloudXNativeAdViewProps,
|
|
104
|
+
CloudXNativeAdViewComponentProps,
|
|
105
|
+
CloudXNativeAdViewPreloadedProps,
|
|
106
|
+
CloudXNativeAdLoadOptions,
|
|
107
|
+
CloudXNativeAdEventType,
|
|
95
108
|
CloudXLocalExtraParameters,
|
|
96
109
|
} from './types';
|
|
97
110
|
export { CloudXNativeTemplate } from './types';
|
|
@@ -40,6 +40,11 @@ export type CloudXNativeAdLoadFailedEvent = Readonly<{
|
|
|
40
40
|
message?: string | null;
|
|
41
41
|
}>;
|
|
42
42
|
|
|
43
|
+
/** Internal: names the preloaded ad that just left the view. */
|
|
44
|
+
export type CloudXNativeAdBindingClearedEvent = Readonly<{
|
|
45
|
+
nativeAdId: string;
|
|
46
|
+
}>;
|
|
47
|
+
|
|
43
48
|
export type NativeExtraParameterEntry = Readonly<{
|
|
44
49
|
key: string;
|
|
45
50
|
value: UnsafeMixed;
|
|
@@ -53,8 +58,15 @@ export type NativeExtraParameterEntry = Readonly<{
|
|
|
53
58
|
* normal RN z-ordering.
|
|
54
59
|
*/
|
|
55
60
|
export interface NativeProps extends ViewProps {
|
|
56
|
-
/** Ad unit ID used to load the ad. */
|
|
57
|
-
adUnitId
|
|
61
|
+
/** Ad unit ID used to load the ad. Ignored when `nativeAdId` is set. */
|
|
62
|
+
adUnitId?: string | null;
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Id of an ad already loaded by `loadNativeAd`. When set, the view never
|
|
66
|
+
* loads: it renders the held ad on attach and leaves its lifetime to the
|
|
67
|
+
* holder, so unmounting does not destroy it.
|
|
68
|
+
*/
|
|
69
|
+
nativeAdId?: string | null;
|
|
58
70
|
|
|
59
71
|
/**
|
|
60
72
|
* Publisher-selected template name (e.g. "small_template",
|
|
@@ -103,6 +115,12 @@ export interface NativeProps extends ViewProps {
|
|
|
103
115
|
/** Called when the ad fails to render/display (e.g. manual render before load). */
|
|
104
116
|
onAdDisplayFailedEvent: DirectEventHandler<CloudXNativeAdLoadFailedEvent>;
|
|
105
117
|
|
|
118
|
+
/**
|
|
119
|
+
* Called each time an ad is rendered into this view and registered for
|
|
120
|
+
* click and impression tracking. Fires again after a re-bind.
|
|
121
|
+
*/
|
|
122
|
+
onAdDisplayedEvent: DirectEventHandler<CloudXNativeAdInfoEvent>;
|
|
123
|
+
|
|
106
124
|
/** Called when the ad is clicked. */
|
|
107
125
|
onAdClickedEvent: DirectEventHandler<CloudXNativeAdInfoEvent>;
|
|
108
126
|
|
|
@@ -114,6 +132,13 @@ export interface NativeProps extends ViewProps {
|
|
|
114
132
|
|
|
115
133
|
/** Called when ad revenue is paid. */
|
|
116
134
|
onAdRevenuePaidEvent: DirectEventHandler<CloudXNativeAdInfoEvent>;
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Internal, not a publisher callback: native released the preloaded ad
|
|
138
|
+
* this view showed (destroy, expiry, or a newer view took it), so the JS
|
|
139
|
+
* view clears its asset components.
|
|
140
|
+
*/
|
|
141
|
+
onAdBindingClearedEvent?: DirectEventHandler<CloudXNativeAdBindingClearedEvent>;
|
|
117
142
|
}
|
|
118
143
|
|
|
119
144
|
export interface NativeCommands {
|
|
@@ -61,6 +61,12 @@ export interface Spec extends TurboModule {
|
|
|
61
61
|
ON_APPOPEN_DISPLAY_FAILED_EVENT: string;
|
|
62
62
|
ON_APPOPEN_HIDDEN_EVENT: string;
|
|
63
63
|
ON_APPOPEN_AD_REVENUE_PAID: string;
|
|
64
|
+
|
|
65
|
+
// Preloaded native ad events. Every payload carries `nativeAdId`.
|
|
66
|
+
ON_NATIVE_AD_CLICKED_EVENT: string;
|
|
67
|
+
ON_NATIVE_AD_EXPIRED_EVENT: string;
|
|
68
|
+
ON_NATIVE_AD_CLOSED_EVENT: string;
|
|
69
|
+
ON_NATIVE_AD_REVENUE_PAID: string;
|
|
64
70
|
};
|
|
65
71
|
|
|
66
72
|
// =========================================================================
|
|
@@ -171,6 +177,20 @@ export interface Spec extends TurboModule {
|
|
|
171
177
|
showAppOpen(adUnitId: string, placement?: string | null, customData?: string | null): void;
|
|
172
178
|
destroyAppOpen(adUnitId: string): void;
|
|
173
179
|
|
|
180
|
+
// =========================================================================
|
|
181
|
+
// Native (load first, render later)
|
|
182
|
+
// =========================================================================
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Loads a native ad with no view attached. Resolves with
|
|
186
|
+
* `{ nativeAdId, adInfo }` once an ad is held natively; rejects with the
|
|
187
|
+
* CloudX error code as the promise code. The ad stays held until
|
|
188
|
+
* `destroyNativeAd`, expiry, or module invalidation.
|
|
189
|
+
*/
|
|
190
|
+
loadNativeAd(adUnitId: string, options: UnsafeObject): Promise<UnsafeObject>;
|
|
191
|
+
/** Releases a held native ad. Idempotent; unknown ids are ignored. */
|
|
192
|
+
destroyNativeAd(nativeAdId: string): void;
|
|
193
|
+
|
|
174
194
|
// =========================================================================
|
|
175
195
|
// Event Emitter (required by NativeEventEmitter)
|
|
176
196
|
// =========================================================================
|
package/src/types/NativeAd.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import type { ViewProps } from 'react-native';
|
|
2
2
|
import type { CloudXAdDisplayFailedInfo, CloudXAdInfo } from './AdInfo';
|
|
3
3
|
import type { CloudXAdProps } from './AdProps';
|
|
4
|
-
import type { CloudXExtraParameterValue } from './ExtraParameters';
|
|
4
|
+
import type { CloudXExtraParameters, CloudXExtraParameterValue } from './ExtraParameters';
|
|
5
|
+
import type { CloudXNativeAd } from '../CloudXNativeAd';
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* Built-in native ad template variants rendered by the SDK's view component.
|
|
@@ -85,41 +86,107 @@ export type CloudXLocalExtraParameters = {
|
|
|
85
86
|
};
|
|
86
87
|
|
|
87
88
|
/**
|
|
88
|
-
*
|
|
89
|
+
* Load-time options for {@link CloudXNativeAd.load}. These configure the
|
|
90
|
+
* auction and the loader, so they are fixed once the ad is loaded; the view
|
|
91
|
+
* that later renders the ad only chooses the layout.
|
|
92
|
+
*/
|
|
93
|
+
export type CloudXNativeAdLoadOptions = {
|
|
94
|
+
placement?: string | null;
|
|
95
|
+
customData?: string | null;
|
|
96
|
+
extraParameters?: CloudXExtraParameters | null;
|
|
97
|
+
localExtraParameters?: CloudXLocalExtraParameters | null;
|
|
98
|
+
disableVideoFullScreen?: boolean;
|
|
99
|
+
startVideoUnmuted?: boolean;
|
|
100
|
+
hideVideoMediaControls?: boolean;
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
/** Events a preloaded {@link CloudXNativeAd} reports on its own handle. */
|
|
104
|
+
export type CloudXNativeAdEventType = 'clicked' | 'revenuePaid' | 'expired' | 'closed';
|
|
105
|
+
|
|
106
|
+
/** Props every native-ad view accepts, whichever way the ad was loaded. */
|
|
107
|
+
type CloudXNativeAdViewRenderProps = ViewProps & {
|
|
108
|
+
template?: CloudXNativeTemplate;
|
|
109
|
+
/** Selects between the SDK's bundled template layouts and manual asset binding. */
|
|
110
|
+
renderMode?: 'template' | 'manual';
|
|
111
|
+
/**
|
|
112
|
+
* Called each time the ad is rendered into this view and registered for
|
|
113
|
+
* click and impression tracking. Fires again after a re-bind.
|
|
114
|
+
*/
|
|
115
|
+
onAdDisplayed?: (adInfo: CloudXAdInfo) => void;
|
|
116
|
+
/**
|
|
117
|
+
* Called when an ad fails to display or track in this view.
|
|
118
|
+
*
|
|
119
|
+
* Emitted on both platforms. Android fires it for post-load
|
|
120
|
+
* adapter/render errors and when click/impression registration fails in
|
|
121
|
+
* manual mode. iOS fires it on the manual-mode failure paths: render
|
|
122
|
+
* requested before load, expired ad, and registration refused. With
|
|
123
|
+
* `nativeAd`, it also fires when the handle is destroyed or expired.
|
|
124
|
+
*/
|
|
125
|
+
onAdDisplayFailed?: (errorInfo: CloudXAdDisplayFailedInfo) => void;
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Props for a native-ad view that loads its own ad when it attaches and
|
|
130
|
+
* destroys it on unmount. This is the shape `CloudXNativeAdView` has always
|
|
131
|
+
* taken, so wrappers that extend, `Omit` or `Pick` it keep compiling.
|
|
89
132
|
*
|
|
90
133
|
* Callbacks inherited from {@link CloudXAdProps} (`onAdLoaded`, `onAdLoadFailed`,
|
|
91
134
|
* `onAdClicked`, `onAdRevenuePaid`) receive unwrapped payloads, not synthetic events.
|
|
92
135
|
*/
|
|
93
|
-
export type CloudXNativeAdViewProps =
|
|
94
|
-
|
|
95
|
-
template?: CloudXNativeTemplate;
|
|
136
|
+
export type CloudXNativeAdViewProps = CloudXNativeAdViewRenderProps &
|
|
137
|
+
CloudXAdProps & {
|
|
96
138
|
localExtraParameters?: CloudXLocalExtraParameters;
|
|
97
139
|
disableVideoFullScreen?: boolean;
|
|
98
140
|
startVideoUnmuted?: boolean;
|
|
99
141
|
hideVideoMediaControls?: boolean;
|
|
100
|
-
/** Selects between the SDK's bundled template layouts and manual asset binding. */
|
|
101
|
-
renderMode?: 'template' | 'manual';
|
|
102
|
-
/**
|
|
103
|
-
* Called when a loaded ad subsequently fails to display or track.
|
|
104
|
-
*
|
|
105
|
-
* Emitted on both platforms. Android fires it for post-load
|
|
106
|
-
* adapter/render errors and when click/impression registration fails in
|
|
107
|
-
* manual mode. iOS fires it on the three manual-mode failure paths:
|
|
108
|
-
* render requested before load, expired ad, and registration refused.
|
|
109
|
-
*/
|
|
110
|
-
onAdDisplayFailed?: (errorInfo: CloudXAdDisplayFailedInfo) => void;
|
|
111
142
|
onAdExpired?: (adInfo: CloudXAdInfo) => void;
|
|
112
143
|
onAdClosed?: (adInfo: CloudXAdInfo) => void;
|
|
144
|
+
nativeAd?: never;
|
|
113
145
|
};
|
|
114
146
|
|
|
147
|
+
/**
|
|
148
|
+
* The view renders an ad loaded earlier with {@link CloudXNativeAd.load}. It
|
|
149
|
+
* never loads and never destroys the ad. Clicks, revenue, expiry and close
|
|
150
|
+
* are reported once, on the handle (`nativeAd.addListener`), never on the
|
|
151
|
+
* view, so revenue cannot be counted twice.
|
|
152
|
+
*/
|
|
153
|
+
export type CloudXNativeAdViewPreloadedProps = CloudXNativeAdViewRenderProps & {
|
|
154
|
+
nativeAd: CloudXNativeAd;
|
|
155
|
+
adUnitId?: never;
|
|
156
|
+
placement?: never;
|
|
157
|
+
customData?: never;
|
|
158
|
+
extraParameters?: never;
|
|
159
|
+
localExtraParameters?: never;
|
|
160
|
+
disableVideoFullScreen?: never;
|
|
161
|
+
startVideoUnmuted?: never;
|
|
162
|
+
hideVideoMediaControls?: never;
|
|
163
|
+
onAdLoaded?: never;
|
|
164
|
+
onAdLoadFailed?: never;
|
|
165
|
+
onAdClicked?: never;
|
|
166
|
+
onAdRevenuePaid?: never;
|
|
167
|
+
onAdExpired?: never;
|
|
168
|
+
onAdClosed?: never;
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Everything `CloudXNativeAdView` accepts: either it loads its own ad
|
|
173
|
+
* ({@link CloudXNativeAdViewProps}) or it renders one loaded earlier
|
|
174
|
+
* ({@link CloudXNativeAdViewPreloadedProps}). Mixing the two is a type error.
|
|
175
|
+
*/
|
|
176
|
+
export type CloudXNativeAdViewComponentProps = CloudXNativeAdViewProps | CloudXNativeAdViewPreloadedProps;
|
|
177
|
+
|
|
115
178
|
export type CloudXNativeAdViewHandle = {
|
|
116
179
|
/**
|
|
117
|
-
* Requests a load.
|
|
180
|
+
* Requests a load. No-op when the view renders a preloaded `nativeAd`.
|
|
181
|
+
* This does NOT force a new auction: both native SDKs
|
|
118
182
|
* re-serve the ad they already hold while it is neither expired nor
|
|
119
183
|
* destroyed, including after its impression. Changed targeting is
|
|
120
184
|
* therefore not picked up. Call `destroyAd()` first for a fresh ad.
|
|
121
185
|
*/
|
|
122
186
|
loadAd: () => void;
|
|
123
|
-
/**
|
|
187
|
+
/**
|
|
188
|
+
* Releases the native ad and its resources. No-op when the view renders a
|
|
189
|
+
* preloaded `nativeAd`: the handle owns that ad, so call `nativeAd.destroy()`.
|
|
190
|
+
*/
|
|
124
191
|
destroyAd: () => void;
|
|
125
192
|
};
|
package/src/types/index.ts
CHANGED
|
@@ -29,6 +29,10 @@ export type {
|
|
|
29
29
|
CloudXNativeAdMetadata,
|
|
30
30
|
CloudXNativeAdViewHandle,
|
|
31
31
|
CloudXNativeAdViewProps,
|
|
32
|
+
CloudXNativeAdViewComponentProps,
|
|
33
|
+
CloudXNativeAdViewPreloadedProps,
|
|
34
|
+
CloudXNativeAdLoadOptions,
|
|
35
|
+
CloudXNativeAdEventType,
|
|
32
36
|
CloudXLocalExtraParameters,
|
|
33
37
|
} from './NativeAd';
|
|
34
38
|
export { CloudXNativeTemplate, CloudXNativeAssetType } from './NativeAd';
|
package/src/version.ts
CHANGED
|
@@ -3,4 +3,4 @@
|
|
|
3
3
|
// This value is reported to the native SDK in CloudX.initialize() and is used
|
|
4
4
|
// for wrapper-version telemetry/attribution, so a stale value mis-attributes
|
|
5
5
|
// installs to the wrong release.
|
|
6
|
-
export const PLUGIN_VERSION = '3.
|
|
6
|
+
export const PLUGIN_VERSION = '3.11.1';
|