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.
- package/README.md +1 -0
- package/android/build.gradle +1 -1
- 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/cloudx-react-native.podspec +1 -1
- 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,118 @@
|
|
|
1
|
+
package com.cloudxreactnative
|
|
2
|
+
|
|
3
|
+
import android.view.View
|
|
4
|
+
import com.facebook.react.bridge.ReadableArray
|
|
5
|
+
import com.facebook.react.uimanager.ThemedReactContext
|
|
6
|
+
import com.facebook.react.uimanager.ViewGroupManager
|
|
7
|
+
import com.facebook.react.uimanager.annotations.ReactProp
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Old-Architecture (Paper) view manager for CloudXNativeAdView. Props are
|
|
11
|
+
* wired via [ReactProp] and commands via manual [receiveCommand] overloads
|
|
12
|
+
* (Paper has no codegen delegate); all logic delegates to the shared
|
|
13
|
+
* CloudXNativeAdViewManagerImpl.
|
|
14
|
+
*/
|
|
15
|
+
class CloudXNativeAdViewManager : ViewGroupManager<CloudXNativeAdView>() {
|
|
16
|
+
|
|
17
|
+
private companion object {
|
|
18
|
+
const val COMMAND_LOAD_AD = 1
|
|
19
|
+
const val COMMAND_DESTROY_AD = 2
|
|
20
|
+
const val COMMAND_UPDATE_ASSET_VIEW = 3
|
|
21
|
+
const val COMMAND_RENDER_NATIVE_AD = 4
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
override fun getName(): String = CloudXNativeAdViewManagerImpl.NAME
|
|
25
|
+
|
|
26
|
+
override fun createViewInstance(reactContext: ThemedReactContext): CloudXNativeAdView =
|
|
27
|
+
CloudXNativeAdViewManagerImpl.createViewInstance(reactContext)
|
|
28
|
+
|
|
29
|
+
override fun getExportedCustomDirectEventTypeConstants(): MutableMap<String, Any> =
|
|
30
|
+
CloudXNativeAdViewManagerImpl.getExportedCustomDirectEventTypeConstants()
|
|
31
|
+
|
|
32
|
+
@ReactProp(name = "adUnitId")
|
|
33
|
+
fun setAdUnitId(view: CloudXNativeAdView, value: String?) = CloudXNativeAdViewManagerImpl.setAdUnitId(view, value)
|
|
34
|
+
|
|
35
|
+
@ReactProp(name = "templateName")
|
|
36
|
+
fun setTemplateName(view: CloudXNativeAdView, value: String?) = CloudXNativeAdViewManagerImpl.setTemplateName(view, value)
|
|
37
|
+
|
|
38
|
+
// Legacy alias matching the archived package's public prop name; the Old
|
|
39
|
+
// Architecture is not governed by the codegen props struct, so it can keep
|
|
40
|
+
// accepting `template` for publisher compatibility (parity with iOS).
|
|
41
|
+
@ReactProp(name = "template")
|
|
42
|
+
fun setTemplate(view: CloudXNativeAdView, value: String?) = CloudXNativeAdViewManagerImpl.setTemplateName(view, value)
|
|
43
|
+
|
|
44
|
+
@ReactProp(name = "placement")
|
|
45
|
+
fun setPlacement(view: CloudXNativeAdView, value: String?) = CloudXNativeAdViewManagerImpl.setPlacement(view, value)
|
|
46
|
+
|
|
47
|
+
@ReactProp(name = "customData")
|
|
48
|
+
fun setCustomData(view: CloudXNativeAdView, value: String?) = CloudXNativeAdViewManagerImpl.setCustomData(view, value)
|
|
49
|
+
|
|
50
|
+
@ReactProp(name = "extraParameters")
|
|
51
|
+
fun setExtraParameters(view: CloudXNativeAdView, value: ReadableArray?) = CloudXNativeAdViewManagerImpl.setExtraParameters(view, value)
|
|
52
|
+
|
|
53
|
+
@ReactProp(name = "localExtraParameters")
|
|
54
|
+
fun setLocalExtraParameters(view: CloudXNativeAdView, value: ReadableArray?) = CloudXNativeAdViewManagerImpl.setLocalExtraParameters(view, value)
|
|
55
|
+
|
|
56
|
+
@ReactProp(name = "disableVideoFullScreen", defaultBoolean = false)
|
|
57
|
+
fun setDisableVideoFullScreen(view: CloudXNativeAdView, value: Boolean) = CloudXNativeAdViewManagerImpl.setDisableVideoFullScreen(view, value)
|
|
58
|
+
|
|
59
|
+
@ReactProp(name = "startVideoUnmuted", defaultBoolean = false)
|
|
60
|
+
fun setStartVideoUnmuted(view: CloudXNativeAdView, value: Boolean) = CloudXNativeAdViewManagerImpl.setStartVideoUnmuted(view, value)
|
|
61
|
+
|
|
62
|
+
@ReactProp(name = "hideVideoMediaControls", defaultBoolean = false)
|
|
63
|
+
fun setHideVideoMediaControls(view: CloudXNativeAdView, value: Boolean) = CloudXNativeAdViewManagerImpl.setHideVideoMediaControls(view, value)
|
|
64
|
+
|
|
65
|
+
@ReactProp(name = "manualRender", defaultBoolean = false)
|
|
66
|
+
fun setManualRender(view: CloudXNativeAdView, value: Boolean) = CloudXNativeAdViewManagerImpl.setManualRender(view, value)
|
|
67
|
+
|
|
68
|
+
// React-children shadow accessors: see CloudXNativeAdViewManagerImpl for why
|
|
69
|
+
// the SDK-owned ad view must stay invisible to React's manageChildren.
|
|
70
|
+
|
|
71
|
+
override fun getChildCount(parent: CloudXNativeAdView): Int = CloudXNativeAdViewManagerImpl.getChildCount(parent)
|
|
72
|
+
|
|
73
|
+
override fun getChildAt(parent: CloudXNativeAdView, index: Int): View? = CloudXNativeAdViewManagerImpl.getChildAt(parent, index)
|
|
74
|
+
|
|
75
|
+
override fun addView(parent: CloudXNativeAdView, child: View, index: Int) = CloudXNativeAdViewManagerImpl.addView(parent, child, index)
|
|
76
|
+
|
|
77
|
+
override fun removeViewAt(parent: CloudXNativeAdView, index: Int) = CloudXNativeAdViewManagerImpl.removeViewAt(parent, index)
|
|
78
|
+
|
|
79
|
+
override fun removeAllViews(parent: CloudXNativeAdView) = CloudXNativeAdViewManagerImpl.removeAllViews(parent)
|
|
80
|
+
|
|
81
|
+
override fun getCommandsMap(): MutableMap<String, Int> =
|
|
82
|
+
mutableMapOf(
|
|
83
|
+
"loadAd" to COMMAND_LOAD_AD,
|
|
84
|
+
"destroyAd" to COMMAND_DESTROY_AD,
|
|
85
|
+
"updateAssetView" to COMMAND_UPDATE_ASSET_VIEW,
|
|
86
|
+
"renderNativeAd" to COMMAND_RENDER_NATIVE_AD,
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
override fun receiveCommand(view: CloudXNativeAdView, commandId: String?, args: ReadableArray?) {
|
|
90
|
+
when (commandId) {
|
|
91
|
+
"loadAd" -> CloudXNativeAdViewManagerImpl.loadAd(view)
|
|
92
|
+
"destroyAd" -> CloudXNativeAdViewManagerImpl.destroyAd(view)
|
|
93
|
+
"updateAssetView" -> {
|
|
94
|
+
if (args == null || args.size() < 2) return
|
|
95
|
+
CloudXNativeAdViewManagerImpl.updateAssetView(view, args.getInt(0), args.getString(1) ?: return)
|
|
96
|
+
}
|
|
97
|
+
"renderNativeAd" -> CloudXNativeAdViewManagerImpl.renderNativeAd(view)
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
@Deprecated("Use the String-based receiveCommand overload.")
|
|
102
|
+
override fun receiveCommand(view: CloudXNativeAdView, commandId: Int, args: ReadableArray?) {
|
|
103
|
+
when (commandId) {
|
|
104
|
+
COMMAND_LOAD_AD -> CloudXNativeAdViewManagerImpl.loadAd(view)
|
|
105
|
+
COMMAND_DESTROY_AD -> CloudXNativeAdViewManagerImpl.destroyAd(view)
|
|
106
|
+
COMMAND_UPDATE_ASSET_VIEW -> {
|
|
107
|
+
if (args == null || args.size() < 2) return
|
|
108
|
+
CloudXNativeAdViewManagerImpl.updateAssetView(view, args.getInt(0), args.getString(1) ?: return)
|
|
109
|
+
}
|
|
110
|
+
COMMAND_RENDER_NATIVE_AD -> CloudXNativeAdViewManagerImpl.renderNativeAd(view)
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
override fun onDropViewInstance(view: CloudXNativeAdView) {
|
|
115
|
+
CloudXNativeAdViewManagerImpl.onDropViewInstance(view)
|
|
116
|
+
super.onDropViewInstance(view)
|
|
117
|
+
}
|
|
118
|
+
}
|
|
@@ -14,7 +14,7 @@ Pod::Spec.new do |s|
|
|
|
14
14
|
|
|
15
15
|
s.requires_arc = true
|
|
16
16
|
|
|
17
|
-
s.dependency "CloudXCore", "~> 3.
|
|
17
|
+
s.dependency "CloudXCore", "~> 3.11.0"
|
|
18
18
|
|
|
19
19
|
s.source_files = "ios/**/*.{h,mm}"
|
|
20
20
|
s.resource_bundles = { 'CloudXReactNativePrivacy' => ['ios/PrivacyInfo.xcprivacy'] }
|
package/ios/CloudX.h
CHANGED
|
@@ -42,6 +42,14 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
42
42
|
*/
|
|
43
43
|
- (NSDictionary<NSString *, id> *)adDisplayFailedInfoForAd:(CLXAd *)ad withError:(CLXError *)error;
|
|
44
44
|
|
|
45
|
+
/**
|
|
46
|
+
* Builds the native ad's own metadata dictionary (title, media, icon, etc.) from a
|
|
47
|
+
* @c CLXAd . Exposed so the in-tree @c CloudXNativeAdView host and this class's
|
|
48
|
+
* generic ad-info builder share one source of truth for the shape of native ad
|
|
49
|
+
* metadata instead of duplicating the icon/media/options extraction logic.
|
|
50
|
+
*/
|
|
51
|
+
- (NSDictionary<NSString *, id> *)nativeAdMetadataForAd:(CLXAd *)ad;
|
|
52
|
+
|
|
45
53
|
@end
|
|
46
54
|
|
|
47
55
|
NS_ASSUME_NONNULL_END
|
package/ios/CloudX.mm
CHANGED
|
@@ -177,7 +177,7 @@ RCT_EXPORT_MODULE(CloudX)
|
|
|
177
177
|
self.appOpenAds = [NSMutableDictionary dictionaryWithCapacity: 2];
|
|
178
178
|
self.rewardedAds = [NSMutableDictionary dictionaryWithCapacity: 2];
|
|
179
179
|
|
|
180
|
-
self.adViews
|
|
180
|
+
self.adViews = [NSMutableDictionary dictionaryWithCapacity: 2];
|
|
181
181
|
self.adViewAdFormats = [NSMutableDictionary dictionaryWithCapacity: 2];
|
|
182
182
|
self.adViewPositions = [NSMutableDictionary dictionaryWithCapacity: 2];
|
|
183
183
|
self.adViewOffsets = [NSMutableDictionary dictionaryWithCapacity: 2];
|
|
@@ -190,6 +190,42 @@ RCT_EXPORT_MODULE(CloudX)
|
|
|
190
190
|
return self;
|
|
191
191
|
}
|
|
192
192
|
|
|
193
|
+
- (void)invalidate
|
|
194
|
+
{
|
|
195
|
+
[super invalidate];
|
|
196
|
+
|
|
197
|
+
dispatch_async( dispatch_get_main_queue(), ^{
|
|
198
|
+
for ( CLXAppOpen *appOpen in self.appOpenAds.allValues )
|
|
199
|
+
{
|
|
200
|
+
appOpen.delegate = nil;
|
|
201
|
+
[appOpen destroy];
|
|
202
|
+
}
|
|
203
|
+
[self.appOpenAds removeAllObjects];
|
|
204
|
+
|
|
205
|
+
for ( CLXInterstitial *interstitial in self.interstitials.allValues )
|
|
206
|
+
{
|
|
207
|
+
interstitial.delegate = nil;
|
|
208
|
+
[interstitial destroy];
|
|
209
|
+
}
|
|
210
|
+
[self.interstitials removeAllObjects];
|
|
211
|
+
|
|
212
|
+
for ( CLXRewarded *rewarded in self.rewardedAds.allValues )
|
|
213
|
+
{
|
|
214
|
+
rewarded.delegate = nil;
|
|
215
|
+
[rewarded destroy];
|
|
216
|
+
}
|
|
217
|
+
[self.rewardedAds removeAllObjects];
|
|
218
|
+
|
|
219
|
+
// Banner/MREC overlays: each ad unit owns a window-level CLXBannerAdView
|
|
220
|
+
// plus a safe-area background and per-unit maps. Without tearing these
|
|
221
|
+
// down here, bridge invalidation orphans the attached overlay views.
|
|
222
|
+
for ( NSString *adUnitIdentifier in self.adViews.allKeys )
|
|
223
|
+
{
|
|
224
|
+
[self teardownAdViewForAdUnitIdentifier: adUnitIdentifier];
|
|
225
|
+
}
|
|
226
|
+
} );
|
|
227
|
+
}
|
|
228
|
+
|
|
193
229
|
#pragma mark - Initialization
|
|
194
230
|
|
|
195
231
|
RCT_EXPORT_METHOD(isInitialized:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject)
|
|
@@ -1188,32 +1224,41 @@ RCT_EXPORT_METHOD(destroyRewarded:(NSString *)adUnitIdentifier)
|
|
|
1188
1224
|
{
|
|
1189
1225
|
[self executeOnMainQueue:^{
|
|
1190
1226
|
[self log: @"Destroying %ld with ad unit identifier \"%@\"", (long)adFormat, adUnitIdentifier];
|
|
1227
|
+
[self teardownAdViewForAdUnitIdentifier: adUnitIdentifier];
|
|
1228
|
+
}];
|
|
1229
|
+
}
|
|
1191
1230
|
|
|
1192
|
-
|
|
1231
|
+
// Per-view overlay teardown shared by destroyAdViewWithAdUnitIdentifier: and
|
|
1232
|
+
// invalidate so bridge invalidation can't orphan banner/MREC overlays. Must be
|
|
1233
|
+
// called on the main queue. On the main queue retrieveAdViewForAdUnitIdentifier:
|
|
1234
|
+
// with a nil position returns exactly self.adViews[adUnitIdentifier], so reading
|
|
1235
|
+
// the map directly keeps the public method byte-identical.
|
|
1236
|
+
- (void)teardownAdViewForAdUnitIdentifier:(NSString *)adUnitIdentifier
|
|
1237
|
+
{
|
|
1238
|
+
[self.adUnitIdentifiersToShowAfterCreate removeObject: adUnitIdentifier];
|
|
1193
1239
|
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1240
|
+
CLXBannerAdView *view = self.adViews[adUnitIdentifier];
|
|
1241
|
+
view.delegate = nil;
|
|
1242
|
+
view.revenueDelegate = nil;
|
|
1197
1243
|
|
|
1198
|
-
|
|
1199
|
-
|
|
1244
|
+
NSArray<NSLayoutConstraint *> *activeConstraints = self.adViewConstraints[adUnitIdentifier];
|
|
1245
|
+
[NSLayoutConstraint deactivateConstraints: activeConstraints];
|
|
1200
1246
|
|
|
1201
|
-
|
|
1202
|
-
|
|
1247
|
+
[view destroy];
|
|
1248
|
+
[view removeFromSuperview];
|
|
1203
1249
|
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1250
|
+
UIView *safeAreaBg = self.safeAreaBackgrounds[adUnitIdentifier];
|
|
1251
|
+
[NSLayoutConstraint deactivateConstraints: safeAreaBg.constraints];
|
|
1252
|
+
[safeAreaBg removeFromSuperview];
|
|
1207
1253
|
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
}];
|
|
1254
|
+
[self.adViews removeObjectForKey: adUnitIdentifier];
|
|
1255
|
+
[self.adViewPositions removeObjectForKey: adUnitIdentifier];
|
|
1256
|
+
[self.adViewOffsets removeObjectForKey: adUnitIdentifier];
|
|
1257
|
+
[self.adViewAdFormats removeObjectForKey: adUnitIdentifier];
|
|
1258
|
+
[self.adViewConstraints removeObjectForKey: adUnitIdentifier];
|
|
1259
|
+
[self.adViewExtraParameters removeObjectForKey: adUnitIdentifier];
|
|
1260
|
+
[self.safeAreaBackgrounds removeObjectForKey: adUnitIdentifier];
|
|
1261
|
+
[self.publisherBannerBackgroundColors removeObjectForKey: adUnitIdentifier];
|
|
1217
1262
|
}
|
|
1218
1263
|
|
|
1219
1264
|
- (CLXInterstitial *)retrieveInterstitialForAdUnitIdentifier:(NSString *)adUnitIdentifier
|
|
@@ -1732,14 +1777,98 @@ RCT_EXPORT_METHOD(destroyRewarded:(NSString *)adUnitIdentifier)
|
|
|
1732
1777
|
|
|
1733
1778
|
- (NSDictionary<NSString *, id> *)adInfoForAd:(CLXAd *)ad
|
|
1734
1779
|
{
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1780
|
+
NSMutableDictionary<NSString *, id> *info = [@{@"adUnitId": ad.adUnitId ?: @"",
|
|
1781
|
+
@"adFormat": [self adFormatStringForAd: ad],
|
|
1782
|
+
@"networkName": ad.networkName ?: @"",
|
|
1783
|
+
@"networkPlacement": ad.networkPlacement ?: @"",
|
|
1784
|
+
@"placement": ad.placement ?: @"",
|
|
1785
|
+
@"creativeId": ad.creativeIdentifier ?: @"",
|
|
1786
|
+
@"revenue": ad.revenue ?: @(0),
|
|
1787
|
+
@"adValues": ad.adValues ?: @{}} mutableCopy];
|
|
1788
|
+
|
|
1789
|
+
if ( ad.nativeAd )
|
|
1790
|
+
{
|
|
1791
|
+
info[@"nativeAd"] = [self nativeAdMetadataForAd: ad];
|
|
1792
|
+
}
|
|
1793
|
+
|
|
1794
|
+
return info;
|
|
1795
|
+
}
|
|
1796
|
+
|
|
1797
|
+
// An icon crosses the RN bridge as a base64 PNG string, and this metadata is
|
|
1798
|
+
// rebuilt on every native-ad callback. Full-resolution artwork therefore costs a
|
|
1799
|
+
// multi-megabyte copy per event. 96pt matches the Android bridge's cap.
|
|
1800
|
+
static const CGFloat kCloudXNativeIconMaxDimension = 96.0;
|
|
1801
|
+
|
|
1802
|
+
- (nullable NSString *)base64PNGForIconImage:(UIImage *)image
|
|
1803
|
+
{
|
|
1804
|
+
CGFloat longestSide = MAX(image.size.width, image.size.height);
|
|
1805
|
+
UIImage *source = image;
|
|
1806
|
+
|
|
1807
|
+
if ( longestSide > kCloudXNativeIconMaxDimension && longestSide > 0 )
|
|
1808
|
+
{
|
|
1809
|
+
CGFloat scale = kCloudXNativeIconMaxDimension / longestSide;
|
|
1810
|
+
CGSize targetSize = CGSizeMake(round(image.size.width * scale), round(image.size.height * scale));
|
|
1811
|
+
|
|
1812
|
+
if ( targetSize.width >= 1 && targetSize.height >= 1 )
|
|
1813
|
+
{
|
|
1814
|
+
UIGraphicsImageRenderer *renderer = [[UIGraphicsImageRenderer alloc] initWithSize: targetSize];
|
|
1815
|
+
source = [renderer imageWithActions: ^(UIGraphicsImageRendererContext *context) {
|
|
1816
|
+
[image drawInRect: CGRectMake(0, 0, targetSize.width, targetSize.height)];
|
|
1817
|
+
}];
|
|
1818
|
+
}
|
|
1819
|
+
}
|
|
1820
|
+
|
|
1821
|
+
NSData *imageData = UIImagePNGRepresentation(source);
|
|
1822
|
+
if ( !imageData )
|
|
1823
|
+
{
|
|
1824
|
+
NSLog(@"[%@] [%@] could not PNG-encode native ad icon of size %@", SDK_TAG, TAG, NSStringFromCGSize(source.size));
|
|
1825
|
+
return nil;
|
|
1826
|
+
}
|
|
1827
|
+
|
|
1828
|
+
return [imageData base64EncodedStringWithOptions: 0];
|
|
1829
|
+
}
|
|
1830
|
+
|
|
1831
|
+
- (NSDictionary<NSString *, id> *)nativeAdMetadataForAd:(CLXAd *)ad
|
|
1832
|
+
{
|
|
1833
|
+
CLXNativeAd *nativeAd = ad.nativeAd;
|
|
1834
|
+
NSMutableDictionary<NSString *, id> *info = [NSMutableDictionary dictionaryWithCapacity: 16];
|
|
1835
|
+
|
|
1836
|
+
// CloudXNativeAdMetadata declares these as `string | null`, and the Android
|
|
1837
|
+
// bridge sends null. Substituting @"" here made `title ?? fallback` resolve
|
|
1838
|
+
// differently per platform for an asset the creative simply does not carry.
|
|
1839
|
+
info[@"title"] = nativeAd.title ?: [NSNull null];
|
|
1840
|
+
info[@"advertiser"] = nativeAd.advertiser ?: [NSNull null];
|
|
1841
|
+
info[@"body"] = nativeAd.body ?: [NSNull null];
|
|
1842
|
+
info[@"callToAction"] = nativeAd.callToAction ?: [NSNull null];
|
|
1843
|
+
if ( nativeAd.starRating ) info[@"starRating"] = nativeAd.starRating;
|
|
1844
|
+
|
|
1845
|
+
if ( nativeAd.mediaContentAspectRatio > 0 )
|
|
1846
|
+
{
|
|
1847
|
+
info[@"mediaContentAspectRatio"] = @(nativeAd.mediaContentAspectRatio);
|
|
1848
|
+
}
|
|
1849
|
+
|
|
1850
|
+
BOOL iconAvailable = (nativeAd.icon != nil || nativeAd.iconView != nil);
|
|
1851
|
+
info[@"isIconImageAvailable"] = @(iconAvailable);
|
|
1852
|
+
info[@"isOptionsViewAvailable"] = @(nativeAd.optionsView != nil);
|
|
1853
|
+
info[@"isMediaViewAvailable"] = @(nativeAd.mediaView != nil);
|
|
1854
|
+
|
|
1855
|
+
if ( nativeAd.icon )
|
|
1856
|
+
{
|
|
1857
|
+
if ( nativeAd.icon.URL )
|
|
1858
|
+
{
|
|
1859
|
+
info[@"url"] = nativeAd.icon.URL.absoluteString;
|
|
1860
|
+
}
|
|
1861
|
+
else if ( nativeAd.icon.image )
|
|
1862
|
+
{
|
|
1863
|
+
info[@"imageSource"] = [self base64PNGForIconImage: nativeAd.icon.image] ?: [NSNull null];
|
|
1864
|
+
}
|
|
1865
|
+
}
|
|
1866
|
+
|
|
1867
|
+
info[@"isVideoContent"] = @(nativeAd.isVideoContent);
|
|
1868
|
+
info[@"videoDuration"] = @(nativeAd.videoDuration);
|
|
1869
|
+
info[@"isExpired"] = @(nativeAd.isExpired);
|
|
1870
|
+
|
|
1871
|
+
return info;
|
|
1743
1872
|
}
|
|
1744
1873
|
|
|
1745
1874
|
- (NSDictionary<NSString *, id> *)adLoadFailedInfoForAd:(NSString *)adUnitIdentifier withError:(nullable CLXError *)error
|
|
@@ -2038,6 +2167,7 @@ RCT_EXPORT_METHOD(destroyRewarded:(NSString *)adUnitIdentifier)
|
|
|
2038
2167
|
case CLXAdFormatMREC: return @"MREC";
|
|
2039
2168
|
case CLXAdFormatInterstitial: return @"INTERSTITIAL";
|
|
2040
2169
|
case CLXAdFormatAppOpen: return @"APP_OPEN";
|
|
2170
|
+
case CLXAdFormatNative: return @"NATIVE";
|
|
2041
2171
|
case CLXAdFormatRewarded: return @"REWARDED";
|
|
2042
2172
|
default: return @"";
|
|
2043
2173
|
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
//
|
|
2
|
+
// CloudXNativeAdView.h
|
|
3
|
+
// cloudx-react-native
|
|
4
|
+
//
|
|
5
|
+
// In-tree native ad view component. Unlike CloudXAdView (banner/MREC), which
|
|
6
|
+
// hosts a single SDK-owned ad view, this host owns a dedicated
|
|
7
|
+
// CLXNativeAdLoader and renders either the SDK's bundled template views or a
|
|
8
|
+
// publisher-driven manual layout bound via the loadAd/updateAssetView/
|
|
9
|
+
// renderNativeAd commands.
|
|
10
|
+
//
|
|
11
|
+
|
|
12
|
+
#import <React/RCTUIManager.h>
|
|
13
|
+
#import <CloudXCore/CloudXCore.h>
|
|
14
|
+
|
|
15
|
+
#ifdef RCT_NEW_ARCH_ENABLED
|
|
16
|
+
#import <React/RCTViewComponentView.h>
|
|
17
|
+
@interface CloudXNativeAdView : RCTViewComponentView <CLXNativeAdDelegate, CLXAdRevenueDelegate>
|
|
18
|
+
#else
|
|
19
|
+
@interface CloudXNativeAdView : UIView <CLXNativeAdDelegate, CLXAdRevenueDelegate>
|
|
20
|
+
#endif
|
|
21
|
+
|
|
22
|
+
NS_ASSUME_NONNULL_BEGIN
|
|
23
|
+
|
|
24
|
+
@property (nonatomic, copy, nullable) NSString *adUnitId;
|
|
25
|
+
@property (nonatomic, copy, nullable) NSString *templateName;
|
|
26
|
+
@property (nonatomic, copy, nullable) NSString *placement;
|
|
27
|
+
@property (nonatomic, copy, nullable) NSString *customData;
|
|
28
|
+
@property (nonatomic, assign) BOOL disableVideoFullScreen;
|
|
29
|
+
@property (nonatomic, assign) BOOL startVideoUnmuted;
|
|
30
|
+
@property (nonatomic, assign) BOOL hideVideoMediaControls;
|
|
31
|
+
|
|
32
|
+
/// Controls how a loaded ad is rendered: when @c YES , the host skips
|
|
33
|
+
/// template view creation and lets the JS layer drive layout through the
|
|
34
|
+
/// @c updateAssetView + @c renderNativeAd commands. Auto-load on window
|
|
35
|
+
/// attachment runs in both modes.
|
|
36
|
+
@property (nonatomic, assign) BOOL manualRender;
|
|
37
|
+
|
|
38
|
+
// Nil by default on the Old Architecture (only set when the publisher passes
|
|
39
|
+
// the corresponding callback); delegate call sites guard with `if (self.onX)`.
|
|
40
|
+
@property (nonatomic, copy, nullable) RCTDirectEventBlock onAdLoadedEvent;
|
|
41
|
+
@property (nonatomic, copy, nullable) RCTDirectEventBlock onAdLoadFailedEvent;
|
|
42
|
+
@property (nonatomic, copy, nullable) RCTDirectEventBlock onAdDisplayFailedEvent;
|
|
43
|
+
@property (nonatomic, copy, nullable) RCTDirectEventBlock onAdClickedEvent;
|
|
44
|
+
@property (nonatomic, copy, nullable) RCTDirectEventBlock onAdExpiredEvent;
|
|
45
|
+
@property (nonatomic, copy, nullable) RCTDirectEventBlock onAdClosedEvent;
|
|
46
|
+
@property (nonatomic, copy, nullable) RCTDirectEventBlock onAdRevenuePaidEvent;
|
|
47
|
+
|
|
48
|
+
- (void)setExtraParametersFromEntryArray:(nullable NSArray<NSDictionary<NSString *, id> *> *)extraParameters;
|
|
49
|
+
- (void)setLocalExtraParametersFromEntryArray:(nullable NSArray<NSDictionary<NSString *, id> *> *)localExtraParameters;
|
|
50
|
+
|
|
51
|
+
#pragma mark - Commands
|
|
52
|
+
//
|
|
53
|
+
// These selectors are named to match RCTCloudXNativeAdViewViewProtocol
|
|
54
|
+
// (react/renderer/components/CloudXSpec/RCTComponentViewHelpers.h) exactly, so
|
|
55
|
+
// the same implementations serve both the Fabric command-dispatch protocol
|
|
56
|
+
// and the Old Architecture manager's UIManager-block command handlers.
|
|
57
|
+
|
|
58
|
+
/// Forces a (re)load, bypassing the "already requested" auto-load guard.
|
|
59
|
+
- (void)loadAd;
|
|
60
|
+
|
|
61
|
+
/// Destroys the current loaded ad(s) and loader state. Safe to call multiple
|
|
62
|
+
/// times; a no-op when nothing is loaded.
|
|
63
|
+
- (void)destroyAd;
|
|
64
|
+
|
|
65
|
+
/// Binds a publisher-supplied asset subview (resolved by descendant tag
|
|
66
|
+
/// lookup within this host) to a named asset role for manual rendering.
|
|
67
|
+
- (void)updateAssetView:(NSInteger)assetViewTag assetName:(NSString *)assetName;
|
|
68
|
+
|
|
69
|
+
/// Registers click/impression tracking against the publisher's manually
|
|
70
|
+
/// bound asset views and fires onAdLoaded/onAdDisplayFailed accordingly.
|
|
71
|
+
- (void)renderNativeAd;
|
|
72
|
+
|
|
73
|
+
@end
|
|
74
|
+
|
|
75
|
+
NS_ASSUME_NONNULL_END
|