cloudx-react-native 3.10.0 → 3.10.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/README.md +1 -0
- package/android/src/main/java/com/cloudxreactnative/CloudXAdEvents.kt +10 -0
- package/android/src/main/java/com/cloudxreactnative/CloudXAdInfo.kt +40 -0
- package/android/src/main/java/com/cloudxreactnative/CloudXNativeAdView.kt +718 -0
- package/android/src/main/java/com/cloudxreactnative/CloudXNativeAdViewManagerImpl.kt +119 -0
- package/android/src/main/java/com/cloudxreactnative/CloudXPackage.kt +4 -1
- package/android/src/main/res/layout/cloudx_rn_native_media_banner_template.xml +100 -0
- package/android/src/main/res/layout/cloudx_rn_native_medium_template.xml +99 -0
- package/android/src/main/res/layout/cloudx_rn_native_small_template.xml +72 -0
- package/android/src/main/res/layout/cloudx_rn_native_vertical_media_template.xml +117 -0
- package/android/src/newarch/com/cloudxreactnative/CloudXModule.kt +1 -0
- package/android/src/newarch/com/cloudxreactnative/CloudXNativeAdViewManager.kt +86 -0
- package/android/src/oldarch/com/cloudxreactnative/CloudXModule.kt +1 -0
- package/android/src/oldarch/com/cloudxreactnative/CloudXNativeAdViewManager.kt +118 -0
- package/ios/CloudX.h +8 -0
- package/ios/CloudX.mm +159 -29
- package/ios/CloudXNativeAdView.h +75 -0
- package/ios/CloudXNativeAdView.mm +979 -0
- package/ios/CloudXNativeAdViewManager.h +12 -0
- package/ios/CloudXNativeAdViewManager.mm +119 -0
- package/lib/commonjs/CloudXAdViewBase.js +8 -97
- package/lib/commonjs/CloudXAdViewBase.js.map +1 -1
- package/lib/commonjs/CloudXNativeAdView.js +331 -0
- package/lib/commonjs/CloudXNativeAdView.js.map +1 -0
- package/lib/commonjs/CloudXNativeAdViewComponents.js +252 -0
- package/lib/commonjs/CloudXNativeAdViewComponents.js.map +1 -0
- package/lib/commonjs/CloudXNativeAdViewProvider.js +117 -0
- package/lib/commonjs/CloudXNativeAdViewProvider.js.map +1 -0
- package/lib/commonjs/extraParameters.js +52 -0
- package/lib/commonjs/extraParameters.js.map +1 -0
- package/lib/commonjs/hooks.js +34 -0
- package/lib/commonjs/hooks.js.map +1 -1
- package/lib/commonjs/index.js +72 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/specs/CloudXNativeAdViewNativeComponent.js +41 -0
- package/lib/commonjs/specs/CloudXNativeAdViewNativeComponent.js.map +1 -0
- package/lib/commonjs/types/NativeAd.js +70 -0
- package/lib/commonjs/types/NativeAd.js.map +1 -0
- package/lib/commonjs/types/index.js +13 -0
- package/lib/commonjs/types/index.js.map +1 -1
- package/lib/commonjs/useCloudXSdkInitialization.js +75 -0
- package/lib/commonjs/useCloudXSdkInitialization.js.map +1 -0
- package/lib/commonjs/version.js +1 -1
- package/lib/module/CloudXAdViewBase.js +7 -96
- package/lib/module/CloudXAdViewBase.js.map +1 -1
- package/lib/module/CloudXNativeAdView.js +324 -0
- package/lib/module/CloudXNativeAdView.js.map +1 -0
- package/lib/module/CloudXNativeAdViewComponents.js +240 -0
- package/lib/module/CloudXNativeAdViewComponents.js.map +1 -0
- package/lib/module/CloudXNativeAdViewProvider.js +110 -0
- package/lib/module/CloudXNativeAdViewProvider.js.map +1 -0
- package/lib/module/extraParameters.js +45 -0
- package/lib/module/extraParameters.js.map +1 -0
- package/lib/module/hooks.js +34 -0
- package/lib/module/hooks.js.map +1 -1
- package/lib/module/index.js +13 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/specs/CloudXNativeAdViewNativeComponent.js +35 -0
- package/lib/module/specs/CloudXNativeAdViewNativeComponent.js.map +1 -0
- package/lib/module/types/NativeAd.js +68 -0
- package/lib/module/types/NativeAd.js.map +1 -0
- package/lib/module/types/index.js +1 -0
- package/lib/module/types/index.js.map +1 -1
- package/lib/module/useCloudXSdkInitialization.js +68 -0
- package/lib/module/useCloudXSdkInitialization.js.map +1 -0
- package/lib/module/version.js +1 -1
- package/lib/typescript/src/CloudXAdViewBase.d.ts.map +1 -1
- package/lib/typescript/src/CloudXNativeAdView.d.ts +24 -0
- package/lib/typescript/src/CloudXNativeAdView.d.ts.map +1 -0
- package/lib/typescript/src/CloudXNativeAdViewComponents.d.ts +67 -0
- package/lib/typescript/src/CloudXNativeAdViewComponents.d.ts.map +1 -0
- package/lib/typescript/src/CloudXNativeAdViewProvider.d.ts +72 -0
- package/lib/typescript/src/CloudXNativeAdViewProvider.d.ts.map +1 -0
- package/lib/typescript/src/extraParameters.d.ts +4 -0
- package/lib/typescript/src/extraParameters.d.ts.map +1 -0
- package/lib/typescript/src/hooks.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +4 -1
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/specs/CloudXNativeAdViewNativeComponent.d.ts +103 -0
- package/lib/typescript/src/specs/CloudXNativeAdViewNativeComponent.d.ts.map +1 -0
- package/lib/typescript/src/types/AdInfo.d.ts +4 -1
- package/lib/typescript/src/types/AdInfo.d.ts.map +1 -1
- package/lib/typescript/src/types/NativeAd.d.ts +114 -0
- package/lib/typescript/src/types/NativeAd.d.ts.map +1 -0
- package/lib/typescript/src/types/index.d.ts +2 -0
- package/lib/typescript/src/types/index.d.ts.map +1 -1
- package/lib/typescript/src/useCloudXSdkInitialization.d.ts +16 -0
- package/lib/typescript/src/useCloudXSdkInitialization.d.ts.map +1 -0
- package/lib/typescript/src/version.d.ts +1 -1
- package/package.json +1 -1
- package/src/CloudXAdViewBase.tsx +8 -125
- package/src/CloudXNativeAdView.tsx +419 -0
- package/src/CloudXNativeAdViewComponents.tsx +203 -0
- package/src/CloudXNativeAdViewProvider.tsx +149 -0
- package/src/extraParameters.ts +65 -0
- package/src/hooks.ts +38 -0
- package/src/index.ts +24 -0
- package/src/specs/CloudXNativeAdViewNativeComponent.ts +137 -0
- package/src/types/AdInfo.ts +5 -1
- package/src/types/NativeAd.ts +125 -0
- package/src/types/index.ts +7 -0
- package/src/useCloudXSdkInitialization.ts +73 -0
- package/src/version.ts +1 -1
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Context provider for the manual-render `<CloudXNativeAdView/>` flow.
|
|
3
|
+
*
|
|
4
|
+
* The pre-built asset components (title, advertiser, body, CTA, icon,
|
|
5
|
+
* options, media, star rating) read metadata and refs from this context.
|
|
6
|
+
* The host `<CloudXNativeAdView/>` owns the `setNativeAd` state setter and
|
|
7
|
+
* publishes the latest `CloudXNativeAdMetadata` when `onAdLoaded` fires so
|
|
8
|
+
* pre-built components re-render with the new content.
|
|
9
|
+
*
|
|
10
|
+
* Design notes:
|
|
11
|
+
* - A `starRatingRef` lets the star component participate in the binder
|
|
12
|
+
* pipeline (even though the native side treats it as decorative).
|
|
13
|
+
* - Refs are typed explicitly rather than relying on `any`, so misuse
|
|
14
|
+
* surfaces at compile time.
|
|
15
|
+
* - Adds `registerAssetRole`, called by every pre-built asset component on
|
|
16
|
+
* mount. The host `<CloudXNativeAdView/>` passes `onAssetRoleRegistered`
|
|
17
|
+
* to detect an asset component mounted while `renderMode` is `'template'`
|
|
18
|
+
* — a likely publisher mistake — and warn once.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
import * as React from 'react';
|
|
22
|
+
import { useCallback, useMemo, useRef, useState, createContext } from 'react';
|
|
23
|
+
import type { ReactNode } from 'react';
|
|
24
|
+
import type { Image, Text, View } from 'react-native';
|
|
25
|
+
import type { CloudXNativeAdMetadata } from './types/NativeAd';
|
|
26
|
+
|
|
27
|
+
type TextRef = React.ElementRef<typeof Text>;
|
|
28
|
+
type ImageRef = React.ElementRef<typeof Image>;
|
|
29
|
+
type ViewRef = React.ElementRef<typeof View>;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Shape exposed to pre-built asset components. Consumers typically destructure
|
|
33
|
+
* a single ref + the `nativeAd` field; the setter is only used by the host.
|
|
34
|
+
*/
|
|
35
|
+
export type CloudXNativeAdViewContextValue = {
|
|
36
|
+
titleRef: React.RefObject<TextRef | null>;
|
|
37
|
+
advertiserRef: React.RefObject<TextRef | null>;
|
|
38
|
+
bodyRef: React.RefObject<TextRef | null>;
|
|
39
|
+
callToActionRef: React.RefObject<TextRef | null>;
|
|
40
|
+
iconRef: React.RefObject<ImageRef | null>;
|
|
41
|
+
optionsRef: React.RefObject<ViewRef | null>;
|
|
42
|
+
mediaRef: React.RefObject<ViewRef | null>;
|
|
43
|
+
starRatingRef: React.RefObject<ViewRef | null>;
|
|
44
|
+
nativeAd: CloudXNativeAdMetadata | null;
|
|
45
|
+
setNativeAd: React.Dispatch<React.SetStateAction<CloudXNativeAdMetadata | null>>;
|
|
46
|
+
/**
|
|
47
|
+
* Called by each pre-built asset component on mount, naming its asset
|
|
48
|
+
* role. Returns an unregister function, so an effect can simply
|
|
49
|
+
* `return registerAssetRole('CloudXTitleView')` and have the role drop
|
|
50
|
+
* out again when the component unmounts.
|
|
51
|
+
*/
|
|
52
|
+
registerAssetRole: (role: string) => () => void;
|
|
53
|
+
/**
|
|
54
|
+
* Roles whose component is currently mounted. The host intersects this
|
|
55
|
+
* with the loaded ad's own asset set, so it only waits on a binding the
|
|
56
|
+
* publisher's layout can actually satisfy.
|
|
57
|
+
*/
|
|
58
|
+
mountedAssetRoles: React.MutableRefObject<Set<string>>;
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Default / no-op type mirror. Consumers that mount a pre-built asset view
|
|
63
|
+
* outside a `<CloudXNativeAdView/>` fall through this and render empty —
|
|
64
|
+
* which is preferable to throwing because a publisher might legitimately
|
|
65
|
+
* mount the UI before an ad is ever loaded.
|
|
66
|
+
*/
|
|
67
|
+
const noopRef = { current: null } as React.RefObject<unknown> as React.RefObject<never>;
|
|
68
|
+
|
|
69
|
+
export const CloudXNativeAdViewContext = createContext<CloudXNativeAdViewContextValue>({
|
|
70
|
+
titleRef: noopRef,
|
|
71
|
+
advertiserRef: noopRef,
|
|
72
|
+
bodyRef: noopRef,
|
|
73
|
+
callToActionRef: noopRef,
|
|
74
|
+
iconRef: noopRef,
|
|
75
|
+
optionsRef: noopRef,
|
|
76
|
+
mediaRef: noopRef,
|
|
77
|
+
starRatingRef: noopRef,
|
|
78
|
+
nativeAd: null,
|
|
79
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-function -- default/no-op context value; see comment above.
|
|
80
|
+
setNativeAd: () => {},
|
|
81
|
+
registerAssetRole: () => () => {
|
|
82
|
+
/* default/no-op context value; see comment above */
|
|
83
|
+
},
|
|
84
|
+
mountedAssetRoles: { current: new Set<string>() },
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
type ProviderProps = {
|
|
88
|
+
children: ReactNode;
|
|
89
|
+
/**
|
|
90
|
+
* Invoked when a descendant asset component registers its role. The host
|
|
91
|
+
* `<CloudXNativeAdView/>` uses this to warn when an asset component is
|
|
92
|
+
* mounted while `renderMode` is `'template'`.
|
|
93
|
+
*/
|
|
94
|
+
onAssetRoleRegistered?: (role: string) => void;
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Wrap this around the root of a `<CloudXNativeAdView/>` tree so descendant
|
|
99
|
+
* asset components share refs and ad state.
|
|
100
|
+
*/
|
|
101
|
+
export const CloudXNativeAdViewProvider: React.FC<ProviderProps> = ({ children, onAssetRoleRegistered }) => {
|
|
102
|
+
const titleRef = useRef<TextRef | null>(null);
|
|
103
|
+
const advertiserRef = useRef<TextRef | null>(null);
|
|
104
|
+
const bodyRef = useRef<TextRef | null>(null);
|
|
105
|
+
const callToActionRef = useRef<TextRef | null>(null);
|
|
106
|
+
const iconRef = useRef<ImageRef | null>(null);
|
|
107
|
+
const optionsRef = useRef<ViewRef | null>(null);
|
|
108
|
+
const mediaRef = useRef<ViewRef | null>(null);
|
|
109
|
+
const starRatingRef = useRef<ViewRef | null>(null);
|
|
110
|
+
const [nativeAd, setNativeAd] = useState<CloudXNativeAdMetadata | null>(null);
|
|
111
|
+
|
|
112
|
+
// Ref so `registerAssetRole` stays referentially stable across renders
|
|
113
|
+
// without forcing callers to memoize `onAssetRoleRegistered`.
|
|
114
|
+
const onAssetRoleRegisteredRef = useRef(onAssetRoleRegistered);
|
|
115
|
+
onAssetRoleRegisteredRef.current = onAssetRoleRegistered;
|
|
116
|
+
|
|
117
|
+
// Mounted roles live in a ref, not state: the host reads them inside its
|
|
118
|
+
// bind effect and must not re-run that effect (which dispatches native
|
|
119
|
+
// commands) just because a sibling asset component mounted.
|
|
120
|
+
const mountedAssetRoles = useRef<Set<string>>(new Set());
|
|
121
|
+
|
|
122
|
+
const registerAssetRole = useCallback((role: string) => {
|
|
123
|
+
mountedAssetRoles.current.add(role);
|
|
124
|
+
onAssetRoleRegisteredRef.current?.(role);
|
|
125
|
+
return () => {
|
|
126
|
+
mountedAssetRoles.current.delete(role);
|
|
127
|
+
};
|
|
128
|
+
}, []);
|
|
129
|
+
|
|
130
|
+
const value = useMemo<CloudXNativeAdViewContextValue>(
|
|
131
|
+
() => ({
|
|
132
|
+
titleRef,
|
|
133
|
+
advertiserRef,
|
|
134
|
+
bodyRef,
|
|
135
|
+
callToActionRef,
|
|
136
|
+
iconRef,
|
|
137
|
+
optionsRef,
|
|
138
|
+
mediaRef,
|
|
139
|
+
starRatingRef,
|
|
140
|
+
nativeAd,
|
|
141
|
+
setNativeAd,
|
|
142
|
+
registerAssetRole,
|
|
143
|
+
mountedAssetRoles,
|
|
144
|
+
}),
|
|
145
|
+
[nativeAd, registerAssetRole]
|
|
146
|
+
);
|
|
147
|
+
|
|
148
|
+
return <CloudXNativeAdViewContext.Provider value={value}>{children}</CloudXNativeAdViewContext.Provider>;
|
|
149
|
+
};
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import type { NativeExtraParameterEntry } from './specs/CloudXAdViewNativeComponent';
|
|
2
|
+
import type { CloudXAdProps } from './types/AdProps';
|
|
3
|
+
|
|
4
|
+
const warnIgnoredUndefinedExtraParameter = (keyPath: string): void => {
|
|
5
|
+
console.warn(
|
|
6
|
+
`CloudX ad view ignored extra parameter "${keyPath}" because ` +
|
|
7
|
+
'undefined values are not supported. Use null when a value is intentional.'
|
|
8
|
+
);
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
const normalizeExtraParameterValue = (
|
|
12
|
+
keyPath: string,
|
|
13
|
+
value: unknown
|
|
14
|
+
): NativeExtraParameterEntry['value'] | undefined => {
|
|
15
|
+
if (value === undefined) {
|
|
16
|
+
warnIgnoredUndefinedExtraParameter(keyPath);
|
|
17
|
+
return undefined;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (Array.isArray(value)) {
|
|
21
|
+
return value.reduce<unknown[]>((items, item, index) => {
|
|
22
|
+
const normalized = normalizeExtraParameterValue(`${keyPath}[${index}]`, item);
|
|
23
|
+
if (normalized !== undefined) {
|
|
24
|
+
items.push(normalized);
|
|
25
|
+
}
|
|
26
|
+
return items;
|
|
27
|
+
}, []);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (value !== null && typeof value === 'object') {
|
|
31
|
+
return Object.entries(value as Record<string, unknown>).reduce<Record<string, unknown>>(
|
|
32
|
+
(object, [childKey, childValue]) => {
|
|
33
|
+
const normalized = normalizeExtraParameterValue(`${keyPath}.${childKey}`, childValue);
|
|
34
|
+
if (normalized !== undefined) {
|
|
35
|
+
object[childKey] = normalized;
|
|
36
|
+
}
|
|
37
|
+
return object;
|
|
38
|
+
},
|
|
39
|
+
{}
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return value;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
export const toNativeExtraParameterEntries = (
|
|
47
|
+
extraParameters?: CloudXAdProps['extraParameters']
|
|
48
|
+
): ReadonlyArray<NativeExtraParameterEntry> => {
|
|
49
|
+
if (!extraParameters) {
|
|
50
|
+
return [];
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return Object.entries(extraParameters as Record<string, unknown>).reduce<NativeExtraParameterEntry[]>(
|
|
54
|
+
(entries, [key, value]) => {
|
|
55
|
+
const normalizedValue = normalizeExtraParameterValue(key, value);
|
|
56
|
+
if (normalizedValue === undefined) {
|
|
57
|
+
return entries;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
entries.push({ key, value: normalizedValue });
|
|
61
|
+
return entries;
|
|
62
|
+
},
|
|
63
|
+
[]
|
|
64
|
+
);
|
|
65
|
+
};
|
package/src/hooks.ts
CHANGED
|
@@ -54,6 +54,16 @@ export function useCloudXInterstitial(adUnitId: string): CloudXInterstitialHookR
|
|
|
54
54
|
|
|
55
55
|
useEffect(() => {
|
|
56
56
|
mountedRef.current = true;
|
|
57
|
+
|
|
58
|
+
// A changed adUnitId must not keep reporting the previous unit's
|
|
59
|
+
// result: without this, isLoaded stays true for an ad unit that
|
|
60
|
+
// has not loaded until the new unit happens to emit. isLoading is
|
|
61
|
+
// reset too, because the cleanup below destroys the in-flight
|
|
62
|
+
// request and no load/fail event for it will ever arrive.
|
|
63
|
+
setIsLoaded(false);
|
|
64
|
+
setIsLoading(false);
|
|
65
|
+
setError(null);
|
|
66
|
+
|
|
57
67
|
const subs: EventSubscription[] = [];
|
|
58
68
|
|
|
59
69
|
subs.push(
|
|
@@ -153,6 +163,16 @@ export function useCloudXAppOpen(adUnitId: string): CloudXAppOpenHookResult {
|
|
|
153
163
|
|
|
154
164
|
useEffect(() => {
|
|
155
165
|
mountedRef.current = true;
|
|
166
|
+
|
|
167
|
+
// A changed adUnitId must not keep reporting the previous unit's
|
|
168
|
+
// result: without this, isLoaded stays true for an ad unit that
|
|
169
|
+
// has not loaded until the new unit happens to emit. isLoading is
|
|
170
|
+
// reset too, because the cleanup below destroys the in-flight
|
|
171
|
+
// request and no load/fail event for it will ever arrive.
|
|
172
|
+
setIsLoaded(false);
|
|
173
|
+
setIsLoading(false);
|
|
174
|
+
setError(null);
|
|
175
|
+
|
|
156
176
|
const subs: EventSubscription[] = [];
|
|
157
177
|
|
|
158
178
|
subs.push(
|
|
@@ -254,6 +274,17 @@ export function useCloudXRewarded(adUnitId: string): CloudXRewardedHookResult {
|
|
|
254
274
|
|
|
255
275
|
useEffect(() => {
|
|
256
276
|
mountedRef.current = true;
|
|
277
|
+
|
|
278
|
+
// A changed adUnitId must not keep reporting the previous unit's
|
|
279
|
+
// result: without this, isLoaded stays true for an ad unit that
|
|
280
|
+
// has not loaded until the new unit happens to emit. isLoading is
|
|
281
|
+
// reset too, because the cleanup below destroys the in-flight
|
|
282
|
+
// request and no load/fail event for it will ever arrive.
|
|
283
|
+
setIsLoaded(false);
|
|
284
|
+
setIsLoading(false);
|
|
285
|
+
setError(null);
|
|
286
|
+
setRewardEarned(false);
|
|
287
|
+
|
|
257
288
|
const subs: EventSubscription[] = [];
|
|
258
289
|
|
|
259
290
|
subs.push(
|
|
@@ -362,6 +393,13 @@ export function useCloudXBanner(adUnitId: string): CloudXBannerHookResult {
|
|
|
362
393
|
|
|
363
394
|
useEffect(() => {
|
|
364
395
|
mountedRef.current = true;
|
|
396
|
+
|
|
397
|
+
// A changed adUnitId must not keep reporting the previous unit's
|
|
398
|
+
// result: without this, isLoaded stays true for an ad unit that
|
|
399
|
+
// has not loaded until the new unit happens to emit.
|
|
400
|
+
setIsLoaded(false);
|
|
401
|
+
setError(null);
|
|
402
|
+
|
|
365
403
|
const subs: EventSubscription[] = [];
|
|
366
404
|
|
|
367
405
|
subs.push(
|
package/src/index.ts
CHANGED
|
@@ -19,6 +19,25 @@ export { CloudXAdPosition } from './CloudXAdPosition';
|
|
|
19
19
|
// Ad View Components (in-tree; layer correctly under app overlays)
|
|
20
20
|
export { CloudXBannerView } from './CloudXBannerView';
|
|
21
21
|
export { CloudXMRECView } from './CloudXMRECView';
|
|
22
|
+
export { CloudXNativeAdView } from './CloudXNativeAdView';
|
|
23
|
+
export {
|
|
24
|
+
CloudXTitleView,
|
|
25
|
+
CloudXAdvertiserView,
|
|
26
|
+
CloudXBodyView,
|
|
27
|
+
CloudXCallToActionView,
|
|
28
|
+
CloudXIconView,
|
|
29
|
+
CloudXOptionsView,
|
|
30
|
+
CloudXMediaView,
|
|
31
|
+
CloudXStarRatingView,
|
|
32
|
+
} from './CloudXNativeAdViewComponents';
|
|
33
|
+
// Exposed so publishers can build fully custom manual layouts that consume
|
|
34
|
+
// the loaded-ad context outside the bundled asset components.
|
|
35
|
+
// The provider, its context and the context value type are deliberately NOT
|
|
36
|
+
// public. The host `<CloudXNativeAdView/>` always mounts its own provider: one
|
|
37
|
+
// mounted outside it is ignored, and one mounted inside it breaks binding for
|
|
38
|
+
// the asset components beneath. Exporting the value type would also freeze
|
|
39
|
+
// `setNativeAd` and every asset ref as public API. Widening this surface later
|
|
40
|
+
// is additive; removing it after release would be a breaking change.
|
|
22
41
|
export type { CloudXAdViewProps, CloudXAdViewFormat } from './CloudXAdViewBase';
|
|
23
42
|
|
|
24
43
|
// Error Codes
|
|
@@ -70,7 +89,12 @@ export type {
|
|
|
70
89
|
CloudXAdEventListener,
|
|
71
90
|
CloudXExtraParameterValue,
|
|
72
91
|
CloudXExtraParameters,
|
|
92
|
+
CloudXNativeAdMetadata,
|
|
93
|
+
CloudXNativeAdViewHandle,
|
|
94
|
+
CloudXNativeAdViewProps,
|
|
95
|
+
CloudXLocalExtraParameters,
|
|
73
96
|
} from './types';
|
|
97
|
+
export { CloudXNativeTemplate } from './types';
|
|
74
98
|
|
|
75
99
|
// Log level constants
|
|
76
100
|
export const CloudXLogLevel = {
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import type * as React from 'react';
|
|
2
|
+
import type { HostComponent, ViewProps } from 'react-native';
|
|
3
|
+
import type {
|
|
4
|
+
Double,
|
|
5
|
+
Int32,
|
|
6
|
+
DirectEventHandler,
|
|
7
|
+
UnsafeMixed,
|
|
8
|
+
} from 'react-native/Libraries/Types/CodegenTypes';
|
|
9
|
+
import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent';
|
|
10
|
+
import codegenNativeCommands from 'react-native/Libraries/Utilities/codegenNativeCommands';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Payload for native-ad lifecycle events (load, click, revenue).
|
|
14
|
+
*
|
|
15
|
+
* Codegen cannot express `Record<string, string>`, so the SDK-owned ad values
|
|
16
|
+
* are delivered as a JSON-encoded string in `adValuesJson` (mirroring
|
|
17
|
+
* CloudXAdViewNativeComponent) and re-parsed into a map by the JS wrapper.
|
|
18
|
+
* The loaded native ad's own metadata (title, media, icon, etc.) is likewise
|
|
19
|
+
* delivered as a JSON-encoded string in `nativeAdJson`, since codegen cannot
|
|
20
|
+
* express the native ad's heterogeneous field set as typed props.
|
|
21
|
+
*/
|
|
22
|
+
export type CloudXNativeAdInfoEvent = Readonly<{
|
|
23
|
+
adUnitId: string;
|
|
24
|
+
adFormat: string;
|
|
25
|
+
networkName: string;
|
|
26
|
+
networkPlacement?: string | null;
|
|
27
|
+
placement?: string | null;
|
|
28
|
+
creativeId?: string | null;
|
|
29
|
+
revenue: Double;
|
|
30
|
+
adValuesJson?: string | null;
|
|
31
|
+
nativeAdJson?: string | null;
|
|
32
|
+
}>;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Payload for native-ad load/display-failure events.
|
|
36
|
+
*/
|
|
37
|
+
export type CloudXNativeAdLoadFailedEvent = Readonly<{
|
|
38
|
+
adUnitId: string;
|
|
39
|
+
code: Double;
|
|
40
|
+
message?: string | null;
|
|
41
|
+
}>;
|
|
42
|
+
|
|
43
|
+
export type NativeExtraParameterEntry = Readonly<{
|
|
44
|
+
key: string;
|
|
45
|
+
value: UnsafeMixed;
|
|
46
|
+
}>;
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Props for the native CloudXNativeAdView component.
|
|
50
|
+
*
|
|
51
|
+
* Mirrors the in-tree CloudXAdView (banner/MREC) component: the ad renders as
|
|
52
|
+
* an ordinary React Native view so publisher overlays layer above it via
|
|
53
|
+
* normal RN z-ordering.
|
|
54
|
+
*/
|
|
55
|
+
export interface NativeProps extends ViewProps {
|
|
56
|
+
/** Ad unit ID used to load the ad. */
|
|
57
|
+
adUnitId: string;
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Publisher-selected template name (e.g. "small_template",
|
|
61
|
+
* "medium_template"). Named `templateName`, not `template` — codegen
|
|
62
|
+
* emits the prop as a literal `std::string template` struct member on
|
|
63
|
+
* the generated Props class, and `template` is a reserved word in C++,
|
|
64
|
+
* so that spelling fails to compile. The Old Architecture manager also
|
|
65
|
+
* accepts the legacy `template` prop name and aliases it internally for
|
|
66
|
+
* publisher compatibility.
|
|
67
|
+
*/
|
|
68
|
+
templateName?: string | null;
|
|
69
|
+
|
|
70
|
+
/** Optional placement name for reporting. */
|
|
71
|
+
placement?: string | null;
|
|
72
|
+
|
|
73
|
+
/** Optional custom data string. */
|
|
74
|
+
customData?: string | null;
|
|
75
|
+
|
|
76
|
+
/** Extra parameters applied to the underlying native ad loader. */
|
|
77
|
+
extraParameters?: ReadonlyArray<NativeExtraParameterEntry>;
|
|
78
|
+
|
|
79
|
+
/** Local-only extra parameters applied to the underlying native ad loader. */
|
|
80
|
+
localExtraParameters?: ReadonlyArray<NativeExtraParameterEntry>;
|
|
81
|
+
|
|
82
|
+
/** Disables the video full-screen affordance when true. */
|
|
83
|
+
disableVideoFullScreen?: boolean;
|
|
84
|
+
|
|
85
|
+
/** Starts video creatives unmuted when true. */
|
|
86
|
+
startVideoUnmuted?: boolean;
|
|
87
|
+
|
|
88
|
+
/** Hides video media controls when true. */
|
|
89
|
+
hideVideoMediaControls?: boolean;
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* When true, the host skips template rendering and lets the JS layer
|
|
93
|
+
* drive layout through the `updateAssetView` + `renderNativeAd` commands.
|
|
94
|
+
*/
|
|
95
|
+
manualRender?: boolean;
|
|
96
|
+
|
|
97
|
+
/** Called when an ad is successfully loaded. */
|
|
98
|
+
onAdLoadedEvent: DirectEventHandler<CloudXNativeAdInfoEvent>;
|
|
99
|
+
|
|
100
|
+
/** Called when the SDK fails to load an ad. */
|
|
101
|
+
onAdLoadFailedEvent: DirectEventHandler<CloudXNativeAdLoadFailedEvent>;
|
|
102
|
+
|
|
103
|
+
/** Called when the ad fails to render/display (e.g. manual render before load). */
|
|
104
|
+
onAdDisplayFailedEvent: DirectEventHandler<CloudXNativeAdLoadFailedEvent>;
|
|
105
|
+
|
|
106
|
+
/** Called when the ad is clicked. */
|
|
107
|
+
onAdClickedEvent: DirectEventHandler<CloudXNativeAdInfoEvent>;
|
|
108
|
+
|
|
109
|
+
/** Called when the loaded ad expires. */
|
|
110
|
+
onAdExpiredEvent: DirectEventHandler<CloudXNativeAdInfoEvent>;
|
|
111
|
+
|
|
112
|
+
/** Called when the ad is closed. */
|
|
113
|
+
onAdClosedEvent: DirectEventHandler<CloudXNativeAdInfoEvent>;
|
|
114
|
+
|
|
115
|
+
/** Called when ad revenue is paid. */
|
|
116
|
+
onAdRevenuePaidEvent: DirectEventHandler<CloudXNativeAdInfoEvent>;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export interface NativeCommands {
|
|
120
|
+
loadAd: (viewRef: React.ElementRef<HostComponent<NativeProps>>) => void;
|
|
121
|
+
destroyAd: (viewRef: React.ElementRef<HostComponent<NativeProps>>) => void;
|
|
122
|
+
updateAssetView: (
|
|
123
|
+
viewRef: React.ElementRef<HostComponent<NativeProps>>,
|
|
124
|
+
assetViewTag: Int32,
|
|
125
|
+
assetName: string
|
|
126
|
+
) => void;
|
|
127
|
+
renderNativeAd: (viewRef: React.ElementRef<HostComponent<NativeProps>>) => void;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export const Commands: NativeCommands = codegenNativeCommands<NativeCommands>({
|
|
131
|
+
supportedCommands: ['loadAd', 'destroyAd', 'updateAssetView', 'renderNativeAd'],
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Native in-tree view component backing the publisher-facing native ad view.
|
|
136
|
+
*/
|
|
137
|
+
export default codegenNativeComponent<NativeProps>('CloudXNativeAdView') as HostComponent<NativeProps>;
|
package/src/types/AdInfo.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { CloudXErrorCode } from '../CloudXErrorCode';
|
|
2
|
+
import type { CloudXNativeAdMetadata } from './NativeAd';
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* Represents a successfully loaded ad served by CloudX.
|
|
@@ -7,7 +8,7 @@ export type CloudXAdInfo = {
|
|
|
7
8
|
/** The ad unit ID for this ad. */
|
|
8
9
|
adUnitId: string;
|
|
9
10
|
|
|
10
|
-
/** The format of the ad (e.g., "BANNER", "MREC", "INTERSTITIAL", "REWARDED"). */
|
|
11
|
+
/** The format of the ad (e.g., "BANNER", "MREC", "INTERSTITIAL", "REWARDED", "NATIVE"). */
|
|
11
12
|
adFormat: string;
|
|
12
13
|
|
|
13
14
|
/** The name of the ad network that served the ad. */
|
|
@@ -27,6 +28,9 @@ export type CloudXAdInfo = {
|
|
|
27
28
|
|
|
28
29
|
/** SDK-owned metadata values associated with this loaded ad. */
|
|
29
30
|
adValues: Record<string, string>;
|
|
31
|
+
|
|
32
|
+
/** Structured native-ad metadata when the loaded creative is a native ad. */
|
|
33
|
+
nativeAd?: CloudXNativeAdMetadata | null;
|
|
30
34
|
};
|
|
31
35
|
|
|
32
36
|
/**
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import type { ViewProps } from 'react-native';
|
|
2
|
+
import type { CloudXAdDisplayFailedInfo, CloudXAdInfo } from './AdInfo';
|
|
3
|
+
import type { CloudXAdProps } from './AdProps';
|
|
4
|
+
import type { CloudXExtraParameterValue } from './ExtraParameters';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Built-in native ad template variants rendered by the SDK's view component.
|
|
8
|
+
*
|
|
9
|
+
* All four variants have a distinct bundled layout on both iOS and Android,
|
|
10
|
+
* and unknown values fall back to `MEDIUM` on both.
|
|
11
|
+
*
|
|
12
|
+
* On both platforms this prop selects the **local layout only**. Neither
|
|
13
|
+
* bid request carries the selection, so the server sizes the creative's
|
|
14
|
+
* assets for `medium` whatever is chosen here:
|
|
15
|
+
*
|
|
16
|
+
* - iOS: `CLXNativeAdLoader` builds its publisher with
|
|
17
|
+
* `CLXNativeTemplateDefault`, which is `CLXNativeTemplateMedium`.
|
|
18
|
+
* `CLXBidSignals` would thread a non-default template, but the loader
|
|
19
|
+
* never supplies one.
|
|
20
|
+
* - Android: `BidSignalsProvider` writes `nativeRequirements.template`
|
|
21
|
+
* as a fixed `"medium"`, pending a public template-selection API.
|
|
22
|
+
*
|
|
23
|
+
* A creative rendered in a non-`MEDIUM` layout therefore carries assets cut
|
|
24
|
+
* for `MEDIUM` — most visible with `VERTICAL_MEDIA`, the full-screen shape.
|
|
25
|
+
* Tracked as CXD-5385.
|
|
26
|
+
*/
|
|
27
|
+
export enum CloudXNativeTemplate {
|
|
28
|
+
/** 320x90 compact template: icon, title, advertiser, CTA. */
|
|
29
|
+
SMALL = 'small_template',
|
|
30
|
+
|
|
31
|
+
/** 320x250 template. */
|
|
32
|
+
MEDIUM = 'medium_template',
|
|
33
|
+
|
|
34
|
+
/** 320x300 media-forward template. */
|
|
35
|
+
MEDIA_BANNER = 'media_banner_template',
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Full-screen vertical template sized to the available bounds.
|
|
39
|
+
* Intended for feed-style vertical experiences. Bundled layout on both
|
|
40
|
+
* iOS and Android.
|
|
41
|
+
*/
|
|
42
|
+
VERTICAL_MEDIA = 'vertical_media_template',
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Type-safe asset identifiers for custom native-ad binding.
|
|
47
|
+
*/
|
|
48
|
+
export enum CloudXNativeAssetType {
|
|
49
|
+
TITLE = 'TitleView',
|
|
50
|
+
ADVERTISER = 'AdvertiserView',
|
|
51
|
+
BODY = 'BodyView',
|
|
52
|
+
CALL_TO_ACTION = 'CallToActionView',
|
|
53
|
+
ICON = 'IconView',
|
|
54
|
+
OPTIONS = 'OptionsView',
|
|
55
|
+
MEDIA = 'MediaView',
|
|
56
|
+
STAR_RATING = 'StarRatingView',
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Structured metadata for a single loaded native ad.
|
|
61
|
+
*
|
|
62
|
+
* Surfaced on the `onAdLoaded` callback as `CloudXAdInfo.nativeAd`.
|
|
63
|
+
*/
|
|
64
|
+
export type CloudXNativeAdMetadata = {
|
|
65
|
+
title?: string | null;
|
|
66
|
+
advertiser?: string | null;
|
|
67
|
+
body?: string | null;
|
|
68
|
+
callToAction?: string | null;
|
|
69
|
+
starRating?: number | null;
|
|
70
|
+
mediaContentAspectRatio?: number;
|
|
71
|
+
isIconImageAvailable: boolean;
|
|
72
|
+
isOptionsViewAvailable: boolean;
|
|
73
|
+
isMediaViewAvailable: boolean;
|
|
74
|
+
url?: string | null;
|
|
75
|
+
imageSource?: string | null;
|
|
76
|
+
isVideoContent: boolean;
|
|
77
|
+
videoDuration: number;
|
|
78
|
+
isExpired: boolean;
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
// Shares one value type with `extraParameters`: both native setters accept any
|
|
82
|
+
// value, so narrowing one of the two sibling props was an accidental restriction.
|
|
83
|
+
export type CloudXLocalExtraParameters = {
|
|
84
|
+
[key: string]: CloudXExtraParameterValue;
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Props for the native-ad view component.
|
|
89
|
+
*
|
|
90
|
+
* Callbacks inherited from {@link CloudXAdProps} (`onAdLoaded`, `onAdLoadFailed`,
|
|
91
|
+
* `onAdClicked`, `onAdRevenuePaid`) receive unwrapped payloads, not synthetic events.
|
|
92
|
+
*/
|
|
93
|
+
export type CloudXNativeAdViewProps = CloudXAdProps &
|
|
94
|
+
ViewProps & {
|
|
95
|
+
template?: CloudXNativeTemplate;
|
|
96
|
+
localExtraParameters?: CloudXLocalExtraParameters;
|
|
97
|
+
disableVideoFullScreen?: boolean;
|
|
98
|
+
startVideoUnmuted?: boolean;
|
|
99
|
+
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
|
+
onAdExpired?: (adInfo: CloudXAdInfo) => void;
|
|
112
|
+
onAdClosed?: (adInfo: CloudXAdInfo) => void;
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
export type CloudXNativeAdViewHandle = {
|
|
116
|
+
/**
|
|
117
|
+
* Requests a load. This does NOT force a new auction: both native SDKs
|
|
118
|
+
* re-serve the ad they already hold while it is neither expired nor
|
|
119
|
+
* destroyed, including after its impression. Changed targeting is
|
|
120
|
+
* therefore not picked up. Call `destroyAd()` first for a fresh ad.
|
|
121
|
+
*/
|
|
122
|
+
loadAd: () => void;
|
|
123
|
+
/** Releases the native ad and its resources. */
|
|
124
|
+
destroyAd: () => void;
|
|
125
|
+
};
|
package/src/types/index.ts
CHANGED
|
@@ -25,3 +25,10 @@ export type { CloudXMRECAdType } from './MRECAd';
|
|
|
25
25
|
export type { CloudXAdProps } from './AdProps';
|
|
26
26
|
export type { CloudXAdEventObject, CloudXAdEventListener } from './AdEvent';
|
|
27
27
|
export type { CloudXExtraParameterValue, CloudXExtraParameters } from './ExtraParameters';
|
|
28
|
+
export type {
|
|
29
|
+
CloudXNativeAdMetadata,
|
|
30
|
+
CloudXNativeAdViewHandle,
|
|
31
|
+
CloudXNativeAdViewProps,
|
|
32
|
+
CloudXLocalExtraParameters,
|
|
33
|
+
} from './NativeAd';
|
|
34
|
+
export { CloudXNativeTemplate, CloudXNativeAssetType } from './NativeAd';
|