cloudx-react-native 3.10.0 → 3.11.0

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.
Files changed (105) hide show
  1. package/README.md +1 -0
  2. package/android/build.gradle +1 -1
  3. package/android/src/main/java/com/cloudxreactnative/CloudXAdEvents.kt +10 -0
  4. package/android/src/main/java/com/cloudxreactnative/CloudXAdInfo.kt +40 -0
  5. package/android/src/main/java/com/cloudxreactnative/CloudXNativeAdView.kt +718 -0
  6. package/android/src/main/java/com/cloudxreactnative/CloudXNativeAdViewManagerImpl.kt +119 -0
  7. package/android/src/main/java/com/cloudxreactnative/CloudXPackage.kt +4 -1
  8. package/android/src/main/res/layout/cloudx_rn_native_media_banner_template.xml +100 -0
  9. package/android/src/main/res/layout/cloudx_rn_native_medium_template.xml +99 -0
  10. package/android/src/main/res/layout/cloudx_rn_native_small_template.xml +72 -0
  11. package/android/src/main/res/layout/cloudx_rn_native_vertical_media_template.xml +117 -0
  12. package/android/src/newarch/com/cloudxreactnative/CloudXModule.kt +1 -0
  13. package/android/src/newarch/com/cloudxreactnative/CloudXNativeAdViewManager.kt +86 -0
  14. package/android/src/oldarch/com/cloudxreactnative/CloudXModule.kt +1 -0
  15. package/android/src/oldarch/com/cloudxreactnative/CloudXNativeAdViewManager.kt +118 -0
  16. package/cloudx-react-native.podspec +1 -1
  17. package/ios/CloudX.h +8 -0
  18. package/ios/CloudX.mm +159 -29
  19. package/ios/CloudXNativeAdView.h +75 -0
  20. package/ios/CloudXNativeAdView.mm +979 -0
  21. package/ios/CloudXNativeAdViewManager.h +12 -0
  22. package/ios/CloudXNativeAdViewManager.mm +119 -0
  23. package/lib/commonjs/CloudXAdViewBase.js +8 -97
  24. package/lib/commonjs/CloudXAdViewBase.js.map +1 -1
  25. package/lib/commonjs/CloudXNativeAdView.js +331 -0
  26. package/lib/commonjs/CloudXNativeAdView.js.map +1 -0
  27. package/lib/commonjs/CloudXNativeAdViewComponents.js +252 -0
  28. package/lib/commonjs/CloudXNativeAdViewComponents.js.map +1 -0
  29. package/lib/commonjs/CloudXNativeAdViewProvider.js +117 -0
  30. package/lib/commonjs/CloudXNativeAdViewProvider.js.map +1 -0
  31. package/lib/commonjs/extraParameters.js +52 -0
  32. package/lib/commonjs/extraParameters.js.map +1 -0
  33. package/lib/commonjs/hooks.js +34 -0
  34. package/lib/commonjs/hooks.js.map +1 -1
  35. package/lib/commonjs/index.js +72 -0
  36. package/lib/commonjs/index.js.map +1 -1
  37. package/lib/commonjs/specs/CloudXNativeAdViewNativeComponent.js +41 -0
  38. package/lib/commonjs/specs/CloudXNativeAdViewNativeComponent.js.map +1 -0
  39. package/lib/commonjs/types/NativeAd.js +70 -0
  40. package/lib/commonjs/types/NativeAd.js.map +1 -0
  41. package/lib/commonjs/types/index.js +13 -0
  42. package/lib/commonjs/types/index.js.map +1 -1
  43. package/lib/commonjs/useCloudXSdkInitialization.js +75 -0
  44. package/lib/commonjs/useCloudXSdkInitialization.js.map +1 -0
  45. package/lib/commonjs/version.js +1 -1
  46. package/lib/module/CloudXAdViewBase.js +7 -96
  47. package/lib/module/CloudXAdViewBase.js.map +1 -1
  48. package/lib/module/CloudXNativeAdView.js +324 -0
  49. package/lib/module/CloudXNativeAdView.js.map +1 -0
  50. package/lib/module/CloudXNativeAdViewComponents.js +240 -0
  51. package/lib/module/CloudXNativeAdViewComponents.js.map +1 -0
  52. package/lib/module/CloudXNativeAdViewProvider.js +110 -0
  53. package/lib/module/CloudXNativeAdViewProvider.js.map +1 -0
  54. package/lib/module/extraParameters.js +45 -0
  55. package/lib/module/extraParameters.js.map +1 -0
  56. package/lib/module/hooks.js +34 -0
  57. package/lib/module/hooks.js.map +1 -1
  58. package/lib/module/index.js +13 -0
  59. package/lib/module/index.js.map +1 -1
  60. package/lib/module/specs/CloudXNativeAdViewNativeComponent.js +35 -0
  61. package/lib/module/specs/CloudXNativeAdViewNativeComponent.js.map +1 -0
  62. package/lib/module/types/NativeAd.js +68 -0
  63. package/lib/module/types/NativeAd.js.map +1 -0
  64. package/lib/module/types/index.js +1 -0
  65. package/lib/module/types/index.js.map +1 -1
  66. package/lib/module/useCloudXSdkInitialization.js +68 -0
  67. package/lib/module/useCloudXSdkInitialization.js.map +1 -0
  68. package/lib/module/version.js +1 -1
  69. package/lib/typescript/src/CloudXAdViewBase.d.ts.map +1 -1
  70. package/lib/typescript/src/CloudXNativeAdView.d.ts +24 -0
  71. package/lib/typescript/src/CloudXNativeAdView.d.ts.map +1 -0
  72. package/lib/typescript/src/CloudXNativeAdViewComponents.d.ts +67 -0
  73. package/lib/typescript/src/CloudXNativeAdViewComponents.d.ts.map +1 -0
  74. package/lib/typescript/src/CloudXNativeAdViewProvider.d.ts +72 -0
  75. package/lib/typescript/src/CloudXNativeAdViewProvider.d.ts.map +1 -0
  76. package/lib/typescript/src/extraParameters.d.ts +4 -0
  77. package/lib/typescript/src/extraParameters.d.ts.map +1 -0
  78. package/lib/typescript/src/hooks.d.ts.map +1 -1
  79. package/lib/typescript/src/index.d.ts +4 -1
  80. package/lib/typescript/src/index.d.ts.map +1 -1
  81. package/lib/typescript/src/specs/CloudXNativeAdViewNativeComponent.d.ts +103 -0
  82. package/lib/typescript/src/specs/CloudXNativeAdViewNativeComponent.d.ts.map +1 -0
  83. package/lib/typescript/src/types/AdInfo.d.ts +4 -1
  84. package/lib/typescript/src/types/AdInfo.d.ts.map +1 -1
  85. package/lib/typescript/src/types/NativeAd.d.ts +114 -0
  86. package/lib/typescript/src/types/NativeAd.d.ts.map +1 -0
  87. package/lib/typescript/src/types/index.d.ts +2 -0
  88. package/lib/typescript/src/types/index.d.ts.map +1 -1
  89. package/lib/typescript/src/useCloudXSdkInitialization.d.ts +16 -0
  90. package/lib/typescript/src/useCloudXSdkInitialization.d.ts.map +1 -0
  91. package/lib/typescript/src/version.d.ts +1 -1
  92. package/package.json +1 -1
  93. package/src/CloudXAdViewBase.tsx +8 -125
  94. package/src/CloudXNativeAdView.tsx +419 -0
  95. package/src/CloudXNativeAdViewComponents.tsx +203 -0
  96. package/src/CloudXNativeAdViewProvider.tsx +149 -0
  97. package/src/extraParameters.ts +65 -0
  98. package/src/hooks.ts +38 -0
  99. package/src/index.ts +24 -0
  100. package/src/specs/CloudXNativeAdViewNativeComponent.ts +137 -0
  101. package/src/types/AdInfo.ts +5 -1
  102. package/src/types/NativeAd.ts +125 -0
  103. package/src/types/index.ts +7 -0
  104. package/src/useCloudXSdkInitialization.ts +73 -0
  105. 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>;
@@ -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
+ };
@@ -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';