cloudx-react-native 3.4.6 → 3.4.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/android/build.gradle +1 -1
- package/android/src/main/java/com/cloudxreactnative/CloudXAdEvents.kt +10 -0
- package/android/src/main/java/com/cloudxreactnative/CloudXAdView.kt +244 -0
- package/android/src/main/java/com/cloudxreactnative/CloudXAdViewEvent.kt +28 -0
- package/android/src/main/java/com/cloudxreactnative/CloudXAdViewManagerImpl.kt +54 -0
- package/android/src/main/java/com/cloudxreactnative/CloudXExtraParameters.kt +101 -0
- package/android/src/main/java/com/cloudxreactnative/CloudXModuleImpl.kt +5 -57
- package/android/src/main/java/com/cloudxreactnative/CloudXPackage.kt +1 -1
- package/android/src/newarch/com/cloudxreactnative/CloudXAdViewManager.kt +52 -0
- package/android/src/oldarch/com/cloudxreactnative/CloudXAdViewManager.kt +46 -0
- package/ios/CloudX.mm +13 -57
- package/ios/CloudXAdView.h +35 -0
- package/ios/CloudXAdView.mm +505 -0
- package/ios/CloudXAdViewManager.h +12 -0
- package/ios/CloudXAdViewManager.mm +38 -0
- package/ios/CloudXExtraParameters.h +27 -0
- package/ios/CloudXExtraParameters.mm +117 -0
- package/lib/commonjs/CloudXAdViewBase.js +248 -0
- package/lib/commonjs/CloudXAdViewBase.js.map +1 -0
- package/lib/commonjs/CloudXBannerView.js +27 -0
- package/lib/commonjs/CloudXBannerView.js.map +1 -0
- package/lib/commonjs/CloudXMRECView.js +27 -0
- package/lib/commonjs/CloudXMRECView.js.map +1 -0
- package/lib/commonjs/index.js +16 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/specs/CloudXAdViewNativeComponent.js +30 -0
- package/lib/commonjs/specs/CloudXAdViewNativeComponent.js.map +1 -0
- package/lib/commonjs/version.js +1 -1
- package/lib/module/CloudXAdViewBase.js +240 -0
- package/lib/module/CloudXAdViewBase.js.map +1 -0
- package/lib/module/CloudXBannerView.js +19 -0
- package/lib/module/CloudXBannerView.js.map +1 -0
- package/lib/module/CloudXMRECView.js +19 -0
- package/lib/module/CloudXMRECView.js.map +1 -0
- package/lib/module/index.js +3 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/specs/CloudXAdViewNativeComponent.js +27 -0
- package/lib/module/specs/CloudXAdViewNativeComponent.js.map +1 -0
- package/lib/module/version.js +1 -1
- package/lib/typescript/src/CloudXAdViewBase.d.ts +28 -0
- package/lib/typescript/src/CloudXAdViewBase.d.ts.map +1 -0
- package/lib/typescript/src/CloudXBannerView.d.ts +16 -0
- package/lib/typescript/src/CloudXBannerView.d.ts.map +1 -0
- package/lib/typescript/src/CloudXMRECView.d.ts +16 -0
- package/lib/typescript/src/CloudXMRECView.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +3 -0
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/specs/CloudXAdViewNativeComponent.d.ts +62 -0
- package/lib/typescript/src/specs/CloudXAdViewNativeComponent.d.ts.map +1 -0
- package/lib/typescript/src/types/AdProps.d.ts +3 -0
- package/lib/typescript/src/types/AdProps.d.ts.map +1 -1
- package/lib/typescript/src/version.d.ts +1 -1
- package/package.json +1 -1
- package/src/CloudXAdViewBase.tsx +293 -0
- package/src/CloudXBannerView.tsx +20 -0
- package/src/CloudXMRECView.tsx +20 -0
- package/src/index.ts +5 -0
- package/src/specs/CloudXAdViewNativeComponent.ts +84 -0
- package/src/types/AdProps.ts +4 -0
- package/src/version.ts +1 -1
package/ios/CloudX.mm
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
//
|
|
5
5
|
|
|
6
6
|
#import "CloudX.h"
|
|
7
|
+
#import "CloudXExtraParameters.h"
|
|
7
8
|
#import <React/RCTUtils.h>
|
|
8
9
|
|
|
9
10
|
|
|
@@ -431,7 +432,9 @@ RCT_EXPORT_METHOD(loadInterstitial:(NSString *)adUnitIdentifier)
|
|
|
431
432
|
RCT_EXPORT_METHOD(setInterstitialExtraParameters:(NSString *)adUnitIdentifier extraParameters:(NSDictionary<NSString *, id> *)extraParameters)
|
|
432
433
|
{
|
|
433
434
|
CLXInterstitial *interstitial = [self retrieveInterstitialForAdUnitIdentifier: adUnitIdentifier];
|
|
434
|
-
[
|
|
435
|
+
[CloudXExtraParameters applyExtraParameters: extraParameters toFullscreenAd: interstitial logBlock:^(NSString *message) {
|
|
436
|
+
[self log: @"%@", message];
|
|
437
|
+
}];
|
|
435
438
|
}
|
|
436
439
|
|
|
437
440
|
RCT_EXPORT_METHOD(isInterstitialReady:(NSString *)adUnitIdentifier resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject)
|
|
@@ -483,7 +486,9 @@ RCT_EXPORT_METHOD(loadRewarded:(NSString *)adUnitIdentifier)
|
|
|
483
486
|
RCT_EXPORT_METHOD(setRewardedExtraParameters:(NSString *)adUnitIdentifier extraParameters:(NSDictionary<NSString *, id> *)extraParameters)
|
|
484
487
|
{
|
|
485
488
|
CLXRewarded *rewardedAd = [self retrieveRewardedAdForAdUnitIdentifier: adUnitIdentifier];
|
|
486
|
-
[
|
|
489
|
+
[CloudXExtraParameters applyExtraParameters: extraParameters toFullscreenAd: rewardedAd logBlock:^(NSString *message) {
|
|
490
|
+
[self log: @"%@", message];
|
|
491
|
+
}];
|
|
487
492
|
}
|
|
488
493
|
|
|
489
494
|
RCT_EXPORT_METHOD(isRewardedReady:(NSString *)adUnitIdentifier resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject)
|
|
@@ -876,7 +881,9 @@ RCT_EXPORT_METHOD(destroyRewarded:(NSString *)adUnitIdentifier)
|
|
|
876
881
|
CLXBannerAdView *adView = [self retrieveAdViewForAdUnitIdentifier: adUnitIdentifier adFormat: adFormat];
|
|
877
882
|
if ( adView )
|
|
878
883
|
{
|
|
879
|
-
[
|
|
884
|
+
[CloudXExtraParameters applyExtraParameters: extraParameters toAdView: adView logBlock:^(NSString *message) {
|
|
885
|
+
[self log: @"%@", message];
|
|
886
|
+
}];
|
|
880
887
|
return;
|
|
881
888
|
}
|
|
882
889
|
|
|
@@ -887,17 +894,7 @@ RCT_EXPORT_METHOD(destroyRewarded:(NSString *)adUnitIdentifier)
|
|
|
887
894
|
self.adViewExtraParameters[adUnitIdentifier] = pending;
|
|
888
895
|
}
|
|
889
896
|
|
|
890
|
-
[
|
|
891
|
-
if ( !key || key.length == 0 ) return;
|
|
892
|
-
if ( !value || [value isKindOfClass: [NSNull class]] )
|
|
893
|
-
{
|
|
894
|
-
[pending removeObjectForKey: key];
|
|
895
|
-
}
|
|
896
|
-
else
|
|
897
|
-
{
|
|
898
|
-
pending[key] = value;
|
|
899
|
-
}
|
|
900
|
-
}];
|
|
897
|
+
[CloudXExtraParameters mergeExtraParameters: extraParameters intoPendingDictionary: pending];
|
|
901
898
|
}];
|
|
902
899
|
}
|
|
903
900
|
|
|
@@ -905,49 +902,8 @@ RCT_EXPORT_METHOD(destroyRewarded:(NSString *)adUnitIdentifier)
|
|
|
905
902
|
{
|
|
906
903
|
NSDictionary<NSString *, id> *pending = [self.adViewExtraParameters[adUnitIdentifier] copy];
|
|
907
904
|
if ( pending.count == 0 ) return;
|
|
908
|
-
[
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
- (void)applyExtraParameterValue:(id)value forKey:(NSString *)key toTarget:(id)target
|
|
912
|
-
{
|
|
913
|
-
if ( !target || !key || key.length == 0 ) return;
|
|
914
|
-
|
|
915
|
-
SEL selector = NSSelectorFromString(@"setExtraParameter:value:");
|
|
916
|
-
if ( ![target respondsToSelector: selector] )
|
|
917
|
-
{
|
|
918
|
-
selector = NSSelectorFromString(@"setExtraParameterForKey:value:");
|
|
919
|
-
}
|
|
920
|
-
|
|
921
|
-
if ( ![target respondsToSelector: selector] )
|
|
922
|
-
{
|
|
923
|
-
[self log: @"Skipping extra parameter \"%@\" because %@ does not respond to setExtraParameter:value: or setExtraParameterForKey:value:", key, NSStringFromClass([target class])];
|
|
924
|
-
return;
|
|
925
|
-
}
|
|
926
|
-
|
|
927
|
-
using SetExtraParameterMethod = void (*)(id, SEL, NSString *, id);
|
|
928
|
-
SetExtraParameterMethod method = (SetExtraParameterMethod)[target methodForSelector: selector];
|
|
929
|
-
method(target, selector, key, value);
|
|
930
|
-
|
|
931
|
-
[self log: @"Applied extra parameter \"%@\" with value \"%@\" to %@", key, value ?: @"(cleared)", NSStringFromClass([target class])];
|
|
932
|
-
}
|
|
933
|
-
|
|
934
|
-
- (void)applyExtraParameters:(NSDictionary<NSString *, id> *)extraParameters toAdView:(CLXBannerAdView *)adView
|
|
935
|
-
{
|
|
936
|
-
[extraParameters enumerateKeysAndObjectsUsingBlock:^(NSString *key, id value, BOOL *stop) {
|
|
937
|
-
if ( !key || key.length == 0 ) return;
|
|
938
|
-
id normalizedValue = [value isKindOfClass: [NSNull class]] ? nil : value;
|
|
939
|
-
SEL selector = NSSelectorFromString(@"setExtraParameter:value:");
|
|
940
|
-
id target = [adView respondsToSelector: selector] ? adView : adView.ad;
|
|
941
|
-
[self applyExtraParameterValue: normalizedValue forKey: key toTarget: target];
|
|
942
|
-
}];
|
|
943
|
-
}
|
|
944
|
-
|
|
945
|
-
- (void)applyExtraParameters:(NSDictionary<NSString *, id> *)extraParameters toFullscreenAd:(id<CLXFullscreenAd>)ad
|
|
946
|
-
{
|
|
947
|
-
[extraParameters enumerateKeysAndObjectsUsingBlock:^(NSString *key, id value, BOOL *stop) {
|
|
948
|
-
if ( !key || key.length == 0 ) return;
|
|
949
|
-
id normalizedValue = [value isKindOfClass: [NSNull class]] ? nil : value;
|
|
950
|
-
[self applyExtraParameterValue: normalizedValue forKey: key toTarget: ad];
|
|
905
|
+
[CloudXExtraParameters applyExtraParameters: pending toAdView: adView logBlock:^(NSString *message) {
|
|
906
|
+
[self log: @"%@", message];
|
|
951
907
|
}];
|
|
952
908
|
}
|
|
953
909
|
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* CloudXAdView.h
|
|
3
|
+
* cloudx-react-native
|
|
4
|
+
*
|
|
5
|
+
* In-tree banner/MREC view component. Unlike the imperative overlay banner in
|
|
6
|
+
* CloudX.mm (attached above the whole RN view tree), this hosts a
|
|
7
|
+
* CLXBannerAdView as an ordinary RN view so app overlays layer above it.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
#import <React/RCTUIManager.h>
|
|
11
|
+
#import <CloudXCore/CloudXCore.h>
|
|
12
|
+
|
|
13
|
+
#ifdef RCT_NEW_ARCH_ENABLED
|
|
14
|
+
#import <React/RCTViewComponentView.h>
|
|
15
|
+
@interface CloudXAdView : RCTViewComponentView <CLXBannerDelegate, CLXAdRevenueDelegate>
|
|
16
|
+
#else
|
|
17
|
+
@interface CloudXAdView : UIView <CLXBannerDelegate, CLXAdRevenueDelegate>
|
|
18
|
+
#endif
|
|
19
|
+
|
|
20
|
+
NS_ASSUME_NONNULL_BEGIN
|
|
21
|
+
|
|
22
|
+
/*
|
|
23
|
+
* Nil by default on the Old Architecture (only set when the publisher passes
|
|
24
|
+
* the corresponding callback); delegate call sites guard with `if (self.onX)`.
|
|
25
|
+
*/
|
|
26
|
+
@property (nonatomic, copy, nullable) RCTDirectEventBlock onAdLoadedEvent;
|
|
27
|
+
@property (nonatomic, copy, nullable) RCTDirectEventBlock onAdLoadFailedEvent;
|
|
28
|
+
@property (nonatomic, copy, nullable) RCTDirectEventBlock onAdClickedEvent;
|
|
29
|
+
@property (nonatomic, copy, nullable) RCTDirectEventBlock onAdRevenuePaidEvent;
|
|
30
|
+
|
|
31
|
+
- (void)setExtraParametersFromEntryArray:(nullable NSArray<NSDictionary<NSString *, id> *> *)extraParameters;
|
|
32
|
+
|
|
33
|
+
@end
|
|
34
|
+
|
|
35
|
+
NS_ASSUME_NONNULL_END
|
|
@@ -0,0 +1,505 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* CloudXAdView.mm
|
|
3
|
+
* cloudx-react-native
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
#import "CloudXAdView.h"
|
|
7
|
+
#import "CloudXExtraParameters.h"
|
|
8
|
+
#import <React/RCTLog.h>
|
|
9
|
+
|
|
10
|
+
#ifdef RCT_NEW_ARCH_ENABLED
|
|
11
|
+
#import <react/renderer/components/CloudXSpec/ComponentDescriptors.h>
|
|
12
|
+
#import <react/renderer/components/CloudXSpec/EventEmitters.h>
|
|
13
|
+
#import <react/renderer/components/CloudXSpec/Props.h>
|
|
14
|
+
#import <react/renderer/components/CloudXSpec/RCTComponentViewHelpers.h>
|
|
15
|
+
#import <React/RCTConversions.h>
|
|
16
|
+
#import "RCTFabricComponentsPlugins.h"
|
|
17
|
+
|
|
18
|
+
using namespace facebook::react;
|
|
19
|
+
|
|
20
|
+
/*
|
|
21
|
+
* Fills a generated AdInfo-style event struct from the NSDictionary the ad
|
|
22
|
+
* delegate builds. All three ad-info events share the same field set, so this
|
|
23
|
+
* macro keeps the three emitter blocks in sync.
|
|
24
|
+
*/
|
|
25
|
+
#define CLX_FILL_ADINFO(result, event) \
|
|
26
|
+
result.adUnitId = std::string([(event[@"adUnitId"] ?: @"") UTF8String]); \
|
|
27
|
+
result.adFormat = std::string([(event[@"adFormat"] ?: @"") UTF8String]); \
|
|
28
|
+
result.networkName = std::string([(event[@"networkName"] ?: @"") UTF8String]); \
|
|
29
|
+
result.networkPlacement = std::string([(event[@"networkPlacement"] ?: @"") UTF8String]); \
|
|
30
|
+
result.placement = std::string([(event[@"placement"] ?: @"") UTF8String]); \
|
|
31
|
+
result.revenue = [event[@"revenue"] doubleValue]; \
|
|
32
|
+
result.adValuesJson = std::string([(event[@"adValuesJson"] ?: @"") UTF8String]);
|
|
33
|
+
|
|
34
|
+
static id CLXIdFromFollyDynamic(const folly::dynamic &dynamicValue)
|
|
35
|
+
{
|
|
36
|
+
switch ( dynamicValue.type() )
|
|
37
|
+
{
|
|
38
|
+
case folly::dynamic::NULLT:
|
|
39
|
+
return [NSNull null];
|
|
40
|
+
case folly::dynamic::BOOL:
|
|
41
|
+
return @(dynamicValue.getBool());
|
|
42
|
+
case folly::dynamic::INT64:
|
|
43
|
+
return @(dynamicValue.getInt());
|
|
44
|
+
case folly::dynamic::DOUBLE:
|
|
45
|
+
return @(dynamicValue.getDouble());
|
|
46
|
+
case folly::dynamic::STRING:
|
|
47
|
+
return [[NSString alloc] initWithBytes: dynamicValue.c_str() length: dynamicValue.size() encoding: NSUTF8StringEncoding] ?: @"";
|
|
48
|
+
case folly::dynamic::ARRAY: {
|
|
49
|
+
NSMutableArray *array = [NSMutableArray arrayWithCapacity: dynamicValue.size()];
|
|
50
|
+
for ( const auto &item : dynamicValue )
|
|
51
|
+
{
|
|
52
|
+
[array addObject: CLXIdFromFollyDynamic(item) ?: [NSNull null]];
|
|
53
|
+
}
|
|
54
|
+
return [array copy];
|
|
55
|
+
}
|
|
56
|
+
case folly::dynamic::OBJECT: {
|
|
57
|
+
NSMutableDictionary<NSString *, id> *dictionary = [NSMutableDictionary dictionaryWithCapacity: dynamicValue.size()];
|
|
58
|
+
for ( const auto &item : dynamicValue.items() )
|
|
59
|
+
{
|
|
60
|
+
id key = CLXIdFromFollyDynamic(item.first);
|
|
61
|
+
if ( ![key isKindOfClass: [NSString class]] ) continue;
|
|
62
|
+
dictionary[key] = CLXIdFromFollyDynamic(item.second) ?: [NSNull null];
|
|
63
|
+
}
|
|
64
|
+
return [dictionary copy];
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return [NSNull null];
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
@interface CloudXAdView () <RCTCloudXAdViewViewProtocol>
|
|
72
|
+
#else
|
|
73
|
+
@interface CloudXAdView ()
|
|
74
|
+
#endif
|
|
75
|
+
|
|
76
|
+
@property (nonatomic, strong, nullable) CLXBannerAdView *adView;
|
|
77
|
+
@property (nonatomic, copy, nullable) NSString *adUnitId;
|
|
78
|
+
@property (nonatomic, copy, nullable) NSString *adFormat;
|
|
79
|
+
@property (nonatomic, copy, nullable) NSString *placement;
|
|
80
|
+
@property (nonatomic, copy, nullable) NSString *customData;
|
|
81
|
+
@property (nonatomic, copy) NSDictionary<NSString *, id> *extraParameters;
|
|
82
|
+
@property (nonatomic, copy) NSSet<NSString *> *appliedExtraParameterKeys;
|
|
83
|
+
|
|
84
|
+
@end
|
|
85
|
+
|
|
86
|
+
@implementation CloudXAdView
|
|
87
|
+
|
|
88
|
+
- (void)commonInit
|
|
89
|
+
{
|
|
90
|
+
_extraParameters = @{};
|
|
91
|
+
_appliedExtraParameterKeys = [NSSet set];
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
#ifdef RCT_NEW_ARCH_ENABLED
|
|
95
|
+
|
|
96
|
+
+ (ComponentDescriptorProvider)componentDescriptorProvider
|
|
97
|
+
{
|
|
98
|
+
return concreteComponentDescriptorProvider<CloudXAdViewComponentDescriptor>();
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
- (instancetype)initWithFrame:(CGRect)frame
|
|
102
|
+
{
|
|
103
|
+
self = [super initWithFrame: frame];
|
|
104
|
+
if ( self )
|
|
105
|
+
{
|
|
106
|
+
[self commonInit];
|
|
107
|
+
static const auto defaultProps = std::make_shared<const CloudXAdViewProps>();
|
|
108
|
+
_props = defaultProps;
|
|
109
|
+
[self setupEventHandlers];
|
|
110
|
+
}
|
|
111
|
+
return self;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/*
|
|
115
|
+
* On Fabric the RCTDirectEventBlock properties are not wired by a view manager,
|
|
116
|
+
* so point each block at the generated C++ EventEmitter. The delegate callbacks
|
|
117
|
+
* below always call self.onXxxEvent(dict) regardless of architecture.
|
|
118
|
+
*/
|
|
119
|
+
- (void)setupEventHandlers
|
|
120
|
+
{
|
|
121
|
+
__weak CloudXAdView *weakSelf = self;
|
|
122
|
+
|
|
123
|
+
self.onAdLoadedEvent = ^(NSDictionary *event) {
|
|
124
|
+
CloudXAdView *strongSelf = weakSelf;
|
|
125
|
+
if ( !strongSelf || !strongSelf->_eventEmitter ) return;
|
|
126
|
+
auto emitter = std::static_pointer_cast<CloudXAdViewEventEmitter const>(strongSelf->_eventEmitter);
|
|
127
|
+
CloudXAdViewEventEmitter::OnAdLoadedEvent result;
|
|
128
|
+
CLX_FILL_ADINFO(result, event);
|
|
129
|
+
emitter->onAdLoadedEvent(result);
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
self.onAdClickedEvent = ^(NSDictionary *event) {
|
|
133
|
+
CloudXAdView *strongSelf = weakSelf;
|
|
134
|
+
if ( !strongSelf || !strongSelf->_eventEmitter ) return;
|
|
135
|
+
auto emitter = std::static_pointer_cast<CloudXAdViewEventEmitter const>(strongSelf->_eventEmitter);
|
|
136
|
+
CloudXAdViewEventEmitter::OnAdClickedEvent result;
|
|
137
|
+
CLX_FILL_ADINFO(result, event);
|
|
138
|
+
emitter->onAdClickedEvent(result);
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
self.onAdRevenuePaidEvent = ^(NSDictionary *event) {
|
|
142
|
+
CloudXAdView *strongSelf = weakSelf;
|
|
143
|
+
if ( !strongSelf || !strongSelf->_eventEmitter ) return;
|
|
144
|
+
auto emitter = std::static_pointer_cast<CloudXAdViewEventEmitter const>(strongSelf->_eventEmitter);
|
|
145
|
+
CloudXAdViewEventEmitter::OnAdRevenuePaidEvent result;
|
|
146
|
+
CLX_FILL_ADINFO(result, event);
|
|
147
|
+
emitter->onAdRevenuePaidEvent(result);
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
self.onAdLoadFailedEvent = ^(NSDictionary *event) {
|
|
151
|
+
CloudXAdView *strongSelf = weakSelf;
|
|
152
|
+
if ( !strongSelf || !strongSelf->_eventEmitter ) return;
|
|
153
|
+
auto emitter = std::static_pointer_cast<CloudXAdViewEventEmitter const>(strongSelf->_eventEmitter);
|
|
154
|
+
CloudXAdViewEventEmitter::OnAdLoadFailedEvent result;
|
|
155
|
+
result.adUnitId = std::string([(event[@"adUnitId"] ?: @"") UTF8String]);
|
|
156
|
+
result.code = [event[@"code"] doubleValue];
|
|
157
|
+
result.message = std::string([(event[@"message"] ?: @"") UTF8String]);
|
|
158
|
+
emitter->onAdLoadFailedEvent(result);
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
- (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps
|
|
163
|
+
{
|
|
164
|
+
const auto &oldViewProps = *std::static_pointer_cast<CloudXAdViewProps const>(_props);
|
|
165
|
+
const auto &newViewProps = *std::static_pointer_cast<CloudXAdViewProps const>(props);
|
|
166
|
+
|
|
167
|
+
BOOL shouldAttach = NO;
|
|
168
|
+
|
|
169
|
+
if ( oldViewProps.adUnitId != newViewProps.adUnitId )
|
|
170
|
+
{
|
|
171
|
+
[self setAdUnitId: RCTNSStringFromString(newViewProps.adUnitId)];
|
|
172
|
+
shouldAttach = YES;
|
|
173
|
+
}
|
|
174
|
+
if ( oldViewProps.adFormat != newViewProps.adFormat )
|
|
175
|
+
{
|
|
176
|
+
[self setAdFormat: RCTNSStringFromString(newViewProps.adFormat)];
|
|
177
|
+
shouldAttach = YES;
|
|
178
|
+
}
|
|
179
|
+
if ( oldViewProps.placement != newViewProps.placement )
|
|
180
|
+
{
|
|
181
|
+
[self setPlacement: RCTNSStringFromStringNilIfEmpty(newViewProps.placement)];
|
|
182
|
+
}
|
|
183
|
+
if ( oldViewProps.customData != newViewProps.customData )
|
|
184
|
+
{
|
|
185
|
+
[self setCustomData: RCTNSStringFromStringNilIfEmpty(newViewProps.customData)];
|
|
186
|
+
}
|
|
187
|
+
/*
|
|
188
|
+
* CloudXAdViewExtraParametersStruct contains folly::dynamic, so the
|
|
189
|
+
* generated props do not support a simple old/new equality guard like the
|
|
190
|
+
* scalar props above. Applying is idempotent, with removed keys cleared by
|
|
191
|
+
* applyExtraParametersIfReady.
|
|
192
|
+
*/
|
|
193
|
+
[self setExtraParametersFromEntryArray: [self entryArrayFromFabricExtraParameters: newViewProps.extraParameters]];
|
|
194
|
+
|
|
195
|
+
if ( shouldAttach )
|
|
196
|
+
{
|
|
197
|
+
[self attachAdViewIfNeeded];
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
[super updateProps: props oldProps: oldProps];
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
- (void)prepareForRecycle
|
|
204
|
+
{
|
|
205
|
+
[super prepareForRecycle];
|
|
206
|
+
|
|
207
|
+
static const auto defaultProps = std::make_shared<const CloudXAdViewProps>();
|
|
208
|
+
_props = defaultProps;
|
|
209
|
+
|
|
210
|
+
[self destroyAdIfNeeded];
|
|
211
|
+
self.adUnitId = nil;
|
|
212
|
+
self.adFormat = nil;
|
|
213
|
+
self.placement = nil;
|
|
214
|
+
self.customData = nil;
|
|
215
|
+
self.extraParameters = @{};
|
|
216
|
+
self.appliedExtraParameterKeys = [NSSet set];
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
- (NSArray<NSDictionary<NSString *, id> *> *)entryArrayFromFabricExtraParameters:(const std::vector<CloudXAdViewExtraParametersStruct> &)entries
|
|
220
|
+
{
|
|
221
|
+
NSMutableArray<NSDictionary<NSString *, id> *> *result = [NSMutableArray arrayWithCapacity: entries.size()];
|
|
222
|
+
for ( const auto &entry : entries )
|
|
223
|
+
{
|
|
224
|
+
NSString *key = [NSString stringWithUTF8String: entry.key.c_str()] ?: @"";
|
|
225
|
+
id value = CLXIdFromFollyDynamic(entry.value) ?: [NSNull null];
|
|
226
|
+
[result addObject: @{@"key": key, @"value": value}];
|
|
227
|
+
}
|
|
228
|
+
return [result copy];
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
#else
|
|
232
|
+
|
|
233
|
+
- (instancetype)init
|
|
234
|
+
{
|
|
235
|
+
self = [super init];
|
|
236
|
+
if ( self )
|
|
237
|
+
{
|
|
238
|
+
[self commonInit];
|
|
239
|
+
}
|
|
240
|
+
return self;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
#endif // RCT_NEW_ARCH_ENABLED
|
|
244
|
+
|
|
245
|
+
#pragma mark - Property setters (shared; Paper view manager sets these via KVC)
|
|
246
|
+
|
|
247
|
+
- (void)setAdUnitId:(NSString *)adUnitId
|
|
248
|
+
{
|
|
249
|
+
if ( self.adView )
|
|
250
|
+
{
|
|
251
|
+
/*
|
|
252
|
+
* Ad unit ID is immutable once the ad view is created. Warn only on an
|
|
253
|
+
* actual change; unchanged re-sets on re-render stay quiet.
|
|
254
|
+
*/
|
|
255
|
+
if ( ![adUnitId isEqualToString: _adUnitId] )
|
|
256
|
+
{
|
|
257
|
+
RCTLogWarn(@"CloudXAdView: adUnitId cannot change after the ad view is created; remount the component (e.g. via a React key).");
|
|
258
|
+
}
|
|
259
|
+
return;
|
|
260
|
+
}
|
|
261
|
+
_adUnitId = adUnitId;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
- (void)setAdFormat:(NSString *)adFormat
|
|
265
|
+
{
|
|
266
|
+
if ( self.adView )
|
|
267
|
+
{
|
|
268
|
+
if ( ![adFormat isEqualToString: _adFormat] )
|
|
269
|
+
{
|
|
270
|
+
RCTLogWarn(@"CloudXAdView: adFormat cannot change after the ad view is created; remount the component (e.g. via a React key).");
|
|
271
|
+
}
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
_adFormat = adFormat;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
- (void)setPlacement:(NSString *)placement
|
|
278
|
+
{
|
|
279
|
+
_placement = placement;
|
|
280
|
+
self.adView.placement = placement;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
- (void)setCustomData:(NSString *)customData
|
|
284
|
+
{
|
|
285
|
+
_customData = customData;
|
|
286
|
+
self.adView.customData = customData;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
- (void)setExtraParametersFromEntryArray:(nullable NSArray<NSDictionary<NSString *, id> *> *)extraParameters
|
|
290
|
+
{
|
|
291
|
+
self.extraParameters = [CloudXExtraParameters dictionaryFromEntryArray: extraParameters];
|
|
292
|
+
[self applyExtraParametersIfReady];
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
#pragma mark - Paper attach hook
|
|
296
|
+
|
|
297
|
+
// Invoked after all JS props are set when mounting on the Old Architecture.
|
|
298
|
+
- (void)didSetProps:(NSArray<NSString *> *)changedProps
|
|
299
|
+
{
|
|
300
|
+
[self attachAdViewIfNeeded];
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
#pragma mark - Ad view lifecycle
|
|
304
|
+
|
|
305
|
+
- (void)attachAdViewIfNeeded
|
|
306
|
+
{
|
|
307
|
+
NSString *adUnitId = self.adUnitId;
|
|
308
|
+
NSString *adFormat = self.adFormat;
|
|
309
|
+
|
|
310
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
311
|
+
if ( self.adView ) return;
|
|
312
|
+
if ( adUnitId.length == 0 || adFormat.length == 0 ) return;
|
|
313
|
+
|
|
314
|
+
CLXBannerAdView *adView;
|
|
315
|
+
if ( [adFormat caseInsensitiveCompare: @"MREC"] == NSOrderedSame )
|
|
316
|
+
{
|
|
317
|
+
adView = [[CloudXCore shared] createMRECWithAdUnitId: adUnitId];
|
|
318
|
+
}
|
|
319
|
+
else
|
|
320
|
+
{
|
|
321
|
+
adView = [[CloudXCore shared] createBannerWithAdUnitId: adUnitId];
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
if ( !adView )
|
|
325
|
+
{
|
|
326
|
+
/*
|
|
327
|
+
* createBanner/createMRECWithAdUnitId: returned nil. The JS layer
|
|
328
|
+
* gates mounting on SDK initialization, so a nil here post-init is
|
|
329
|
+
* an invalid/expired ad unit - surface it as a load failure instead
|
|
330
|
+
* of leaving a permanently-dead, silent view (self.adView stays nil
|
|
331
|
+
* and props don't re-land, so there is no retry).
|
|
332
|
+
*/
|
|
333
|
+
if ( self.onAdLoadFailedEvent )
|
|
334
|
+
{
|
|
335
|
+
self.onAdLoadFailedEvent(@{@"adUnitId": adUnitId ?: @"",
|
|
336
|
+
@"code": @(CLXErrorCodeInvalidAdUnit),
|
|
337
|
+
@"message": @"Ad view creation returned nil (invalid ad unit or SDK not initialized)"});
|
|
338
|
+
}
|
|
339
|
+
return;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
adView.delegate = self;
|
|
343
|
+
adView.revenueDelegate = self;
|
|
344
|
+
adView.placement = self.placement;
|
|
345
|
+
adView.customData = self.customData;
|
|
346
|
+
adView.userInteractionEnabled = YES;
|
|
347
|
+
adView.translatesAutoresizingMaskIntoConstraints = NO;
|
|
348
|
+
|
|
349
|
+
self.adView = adView;
|
|
350
|
+
[self applyExtraParametersIfReady];
|
|
351
|
+
[self addSubview: adView];
|
|
352
|
+
[NSLayoutConstraint activateConstraints: @[
|
|
353
|
+
[adView.topAnchor constraintEqualToAnchor: self.topAnchor],
|
|
354
|
+
[adView.bottomAnchor constraintEqualToAnchor: self.bottomAnchor],
|
|
355
|
+
[adView.leadingAnchor constraintEqualToAnchor: self.leadingAnchor],
|
|
356
|
+
[adView.trailingAnchor constraintEqualToAnchor: self.trailingAnchor],
|
|
357
|
+
]];
|
|
358
|
+
|
|
359
|
+
[adView load];
|
|
360
|
+
[self updateAutoRefreshForWindowVisibility];
|
|
361
|
+
});
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
- (void)updateAutoRefreshForWindowVisibility
|
|
365
|
+
{
|
|
366
|
+
if ( !self.adView ) return;
|
|
367
|
+
if ( self.window )
|
|
368
|
+
{
|
|
369
|
+
[self.adView startAutoRefresh];
|
|
370
|
+
}
|
|
371
|
+
else
|
|
372
|
+
{
|
|
373
|
+
[self.adView stopAutoRefresh];
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
- (void)didMoveToWindow
|
|
378
|
+
{
|
|
379
|
+
[super didMoveToWindow];
|
|
380
|
+
[self updateAutoRefreshForWindowVisibility];
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
- (void)didMoveToSuperview
|
|
384
|
+
{
|
|
385
|
+
[super didMoveToSuperview];
|
|
386
|
+
|
|
387
|
+
if ( self.superview != nil )
|
|
388
|
+
{
|
|
389
|
+
[self updateAutoRefreshForWindowVisibility];
|
|
390
|
+
return;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
/*
|
|
394
|
+
* Superview nil could be a real unmount or brief reparenting (react-native-screens).
|
|
395
|
+
* Defer one main-queue turn; destroy only if it is still detached. Strong ref so the
|
|
396
|
+
* ad is always torn down on a genuine unmount.
|
|
397
|
+
*/
|
|
398
|
+
CloudXAdView *viewRef = self;
|
|
399
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
400
|
+
if ( viewRef.superview != nil )
|
|
401
|
+
{
|
|
402
|
+
[viewRef updateAutoRefreshForWindowVisibility];
|
|
403
|
+
return;
|
|
404
|
+
}
|
|
405
|
+
[viewRef destroyAdIfNeeded];
|
|
406
|
+
});
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
- (void)dealloc
|
|
410
|
+
{
|
|
411
|
+
[self destroyAdIfNeeded];
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
- (void)destroyAdIfNeeded
|
|
415
|
+
{
|
|
416
|
+
if ( !self.adView ) return;
|
|
417
|
+
|
|
418
|
+
[self.adView stopAutoRefresh];
|
|
419
|
+
self.adView.delegate = nil;
|
|
420
|
+
self.adView.revenueDelegate = nil;
|
|
421
|
+
[self.adView destroy];
|
|
422
|
+
[self.adView removeFromSuperview];
|
|
423
|
+
self.adView = nil;
|
|
424
|
+
self.appliedExtraParameterKeys = [NSSet set];
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
- (void)applyExtraParametersIfReady
|
|
428
|
+
{
|
|
429
|
+
if ( !self.adView ) return;
|
|
430
|
+
|
|
431
|
+
NSDictionary<NSString *, id> *extraParameters = self.extraParameters ?: @{};
|
|
432
|
+
[CloudXExtraParameters applyExtraParameters: extraParameters toAdView: self.adView logBlock: nil];
|
|
433
|
+
|
|
434
|
+
NSMutableDictionary<NSString *, id> *removed = [NSMutableDictionary dictionary];
|
|
435
|
+
for ( NSString *key in self.appliedExtraParameterKeys )
|
|
436
|
+
{
|
|
437
|
+
if ( !extraParameters[key] )
|
|
438
|
+
{
|
|
439
|
+
removed[key] = [NSNull null];
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
[CloudXExtraParameters applyExtraParameters: removed toAdView: self.adView logBlock: nil];
|
|
443
|
+
self.appliedExtraParameterKeys = [NSSet setWithArray: extraParameters.allKeys];
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
#pragma mark - Event payloads
|
|
447
|
+
|
|
448
|
+
- (NSDictionary<NSString *, id> *)adInfoDictForAd:(CLXAd *)ad
|
|
449
|
+
{
|
|
450
|
+
NSString *adValuesJson = @"";
|
|
451
|
+
if ( ad.adValues )
|
|
452
|
+
{
|
|
453
|
+
NSData *data = [NSJSONSerialization dataWithJSONObject: ad.adValues options: 0 error: nil];
|
|
454
|
+
if ( data )
|
|
455
|
+
{
|
|
456
|
+
adValuesJson = [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding] ?: @"";
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
return @{@"adUnitId": ad.adUnitId ?: @"",
|
|
461
|
+
@"adFormat": self.adFormat ?: @"",
|
|
462
|
+
@"networkName": ad.networkName ?: @"",
|
|
463
|
+
@"networkPlacement": ad.networkPlacement ?: @"",
|
|
464
|
+
@"placement": ad.placement ?: @"",
|
|
465
|
+
@"revenue": ad.revenue ?: @(0),
|
|
466
|
+
@"adValuesJson": adValuesJson};
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
- (NSDictionary<NSString *, id> *)loadFailedDictForAdUnit:(NSString *)adUnitId error:(CLXError *)error
|
|
470
|
+
{
|
|
471
|
+
return @{@"adUnitId": adUnitId ?: (self.adUnitId ?: @""),
|
|
472
|
+
@"code": error ? @(error.code) : @(CLXErrorCodeInternalError),
|
|
473
|
+
@"message": error.localizedDescription ?: @""};
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
#pragma mark - CLXBannerDelegate / CLXAdRevenueDelegate
|
|
477
|
+
|
|
478
|
+
- (void)didLoadAd:(CLXAd *)ad
|
|
479
|
+
{
|
|
480
|
+
if ( self.onAdLoadedEvent ) self.onAdLoadedEvent([self adInfoDictForAd: ad]);
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
- (void)didFailToLoadAd:(NSString *)adUnitId error:(CLXError *)error
|
|
484
|
+
{
|
|
485
|
+
if ( self.onAdLoadFailedEvent ) self.onAdLoadFailedEvent([self loadFailedDictForAdUnit: adUnitId error: error]);
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
- (void)didClickAd:(CLXAd *)ad
|
|
489
|
+
{
|
|
490
|
+
if ( self.onAdClickedEvent ) self.onAdClickedEvent([self adInfoDictForAd: ad]);
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
- (void)didPayRevenueForAd:(CLXAd *)ad
|
|
494
|
+
{
|
|
495
|
+
if ( self.onAdRevenuePaidEvent ) self.onAdRevenuePaidEvent([self adInfoDictForAd: ad]);
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
@end
|
|
499
|
+
|
|
500
|
+
#ifdef RCT_NEW_ARCH_ENABLED
|
|
501
|
+
Class<RCTComponentViewProtocol> CloudXAdViewCls(void)
|
|
502
|
+
{
|
|
503
|
+
return [CloudXAdView class];
|
|
504
|
+
}
|
|
505
|
+
#endif
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* CloudXAdViewManager.mm
|
|
3
|
+
* cloudx-react-native
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
#import "CloudXAdViewManager.h"
|
|
7
|
+
#import "CloudXAdView.h"
|
|
8
|
+
|
|
9
|
+
@implementation CloudXAdViewManager
|
|
10
|
+
|
|
11
|
+
RCT_EXPORT_MODULE(CloudXAdView)
|
|
12
|
+
|
|
13
|
+
RCT_EXPORT_VIEW_PROPERTY(adUnitId, NSString)
|
|
14
|
+
RCT_EXPORT_VIEW_PROPERTY(adFormat, NSString)
|
|
15
|
+
RCT_EXPORT_VIEW_PROPERTY(placement, NSString)
|
|
16
|
+
RCT_EXPORT_VIEW_PROPERTY(customData, NSString)
|
|
17
|
+
RCT_CUSTOM_VIEW_PROPERTY(extraParameters, NSArray, CloudXAdView)
|
|
18
|
+
{
|
|
19
|
+
NSArray<NSDictionary<NSString *, id> *> *entries = [json isKindOfClass: [NSArray class]] ? json : nil;
|
|
20
|
+
[view setExtraParametersFromEntryArray: entries];
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
RCT_EXPORT_VIEW_PROPERTY(onAdLoadedEvent, RCTDirectEventBlock)
|
|
24
|
+
RCT_EXPORT_VIEW_PROPERTY(onAdLoadFailedEvent, RCTDirectEventBlock)
|
|
25
|
+
RCT_EXPORT_VIEW_PROPERTY(onAdClickedEvent, RCTDirectEventBlock)
|
|
26
|
+
RCT_EXPORT_VIEW_PROPERTY(onAdRevenuePaidEvent, RCTDirectEventBlock)
|
|
27
|
+
|
|
28
|
+
+ (BOOL)requiresMainQueueSetup
|
|
29
|
+
{
|
|
30
|
+
return YES;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
- (UIView *)view
|
|
34
|
+
{
|
|
35
|
+
return [[CloudXAdView alloc] init];
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
@end
|