1 | #import <EXAdsFacebook/EXNativeAdManager.h>
|
2 | #import <EXAdsFacebook/EXNativeAdView.h>
|
3 |
|
4 | #import <FBAudienceNetwork/FBAudienceNetwork.h>
|
5 | #import <UMCore/UMUtilities.h>
|
6 | #import <UMCore/UMUIManager.h>
|
7 | #import <UMCore/UMEventEmitterService.h>
|
8 |
|
9 | @class EXAdManagerDelegate;
|
10 |
|
11 | @interface EXNativeAdManager ()
|
12 |
|
13 | @property (nonatomic, weak) UMModuleRegistry *moduleRegistry;
|
14 | @property (nonatomic, strong) NSMutableDictionary<NSString*, FBNativeAdsManager*> *adsManagers;
|
15 | @property (nonatomic, strong) NSMutableDictionary<NSString*, EXAdManagerDelegate*> *adsManagersDelegates;
|
16 |
|
17 | - (void)nativeAdsLoaded;
|
18 | - (void)nativeAdForPlacementId:(NSString *)placementId failedToLoadWithError:(NSError *)error;
|
19 |
|
20 | @end
|
21 |
|
22 | // A light delegate object responsible for delivering information
|
23 | // about errors to EXNativeAdManager, but with a specific placement ID
|
24 | // for which the error has happened. FBNativeAdsManagerDelegate protocol
|
25 | // does not provide such information, we only get the error. Proxying
|
26 | // the event through this middleman lets us assign specific placement ID
|
27 | // to each error.
|
28 |
|
29 | @interface EXAdManagerDelegate : NSObject <FBNativeAdsManagerDelegate>
|
30 |
|
31 | @property (nonatomic, weak) EXNativeAdManager *manager;
|
32 | @property (nonatomic, strong) NSString *placementId;
|
33 |
|
34 | @end
|
35 |
|
36 | @implementation EXAdManagerDelegate
|
37 |
|
38 | - (instancetype)initWithPlacementId:(NSString *)placementId andManager:(EXNativeAdManager *)manager
|
39 | {
|
40 | if (self = [super init]) {
|
41 | _manager = manager;
|
42 | _placementId = placementId;
|
43 | }
|
44 | return self;
|
45 | }
|
46 |
|
47 | - (void)nativeAdsLoaded
|
48 | {
|
49 | [_manager nativeAdsLoaded];
|
50 | }
|
51 |
|
52 | - (void)nativeAdsFailedToLoadWithError:(NSError *)errors
|
53 | {
|
54 | [_manager nativeAdForPlacementId:_placementId failedToLoadWithError:errors];
|
55 | }
|
56 |
|
57 | @end
|
58 |
|
59 | @implementation EXNativeAdManager
|
60 |
|
61 | UM_EXPORT_MODULE(CTKNativeAdManager)
|
62 |
|
63 | - (instancetype)init
|
64 | {
|
65 | self = [super init];
|
66 | if (self) {
|
67 | _adsManagers = [NSMutableDictionary new];
|
68 | _adsManagersDelegates = [NSMutableDictionary new];
|
69 | }
|
70 | return self;
|
71 | }
|
72 |
|
73 | - (NSString *)viewName
|
74 | {
|
75 | return @"CTKNativeAd";
|
76 | }
|
77 |
|
78 | - (void)setModuleRegistry:(UMModuleRegistry *)moduleRegistry
|
79 | {
|
80 | _moduleRegistry = moduleRegistry;
|
81 | }
|
82 |
|
83 | - (NSArray<NSString *> *)supportedEvents
|
84 | {
|
85 | return @[@"CTKNativeAdsManagersChanged", @"CTKNativeAdManagerErrored", @"onAdLoaded"];
|
86 | }
|
87 |
|
88 | UM_EXPORT_METHOD_AS(registerViewsForInteraction,
|
89 | registerViewsForInteraction:(NSNumber *)nativeAdViewTag
|
90 | mediaViewTag:(NSNumber *)mediaViewTag
|
91 | adIconViewTag:(NSNumber *)adIconViewTag
|
92 | clickableViewsTags:(NSArray *)tags
|
93 | resolve:(UMPromiseResolveBlock)resolve
|
94 | reject:(UMPromiseRejectBlock)reject)
|
95 | {
|
96 | id<UMUIManager> uiManager = [_moduleRegistry getModuleImplementingProtocol:@protocol(UMUIManager)];
|
97 | [uiManager executeUIBlock:^(NSDictionary<id,UIView *> * viewRegistry) {
|
98 | UIView *mediaView = nil;
|
99 | UIView *adIconView = nil;
|
100 | UIView *nativeAdView = nil;
|
101 | NSMutableArray<UIView *> *clickableViews = [NSMutableArray new];
|
102 |
|
103 | mediaView = viewRegistry[mediaViewTag];
|
104 | adIconView = viewRegistry[adIconViewTag];
|
105 | nativeAdView = viewRegistry[nativeAdViewTag];
|
106 | for (id tag in tags) {
|
107 | if (viewRegistry[tag]) {
|
108 | [clickableViews addObject:viewRegistry[tag]];
|
109 | }
|
110 | }
|
111 |
|
112 | if (!clickableViews) {
|
113 | reject(@"E_INVALID_VIEW_TAG", @"Could not find view for one of the clickable views tags", nil);
|
114 | return;
|
115 | }
|
116 |
|
117 | if (mediaView == nil) {
|
118 | reject(@"E_NO_VIEW_FOR_TAG", @"Could not find mediaView", nil);
|
119 | return;
|
120 | }
|
121 |
|
122 | if (nativeAdView == nil) {
|
123 | reject(@"E_NO_NATIVEAD_VIEW", @"Could not find nativeAdView", nil);
|
124 | return;
|
125 | }
|
126 |
|
127 | if (![mediaView isKindOfClass:[FBMediaView class]]) {
|
128 | reject(@"E_INVALID_VIEW_CLASS", @"View returned for passed media view tag is not an instance of FBMediaView", nil);
|
129 | return;
|
130 | }
|
131 |
|
132 | if (![nativeAdView isKindOfClass:[EXNativeAdView class]]) {
|
133 | reject(@"E_INVALID_VIEW_CLASS", @"View returned for passed native ad view tag is not an instance of EXNativeAdView", nil);
|
134 | return;
|
135 | }
|
136 |
|
137 | if (adIconView) {
|
138 | if (![adIconView isKindOfClass:[FBMediaView class]]) {
|
139 | reject(@"E_INVALID_VIEW_CLASS", @"View returned for passed ad icon view tag is not an instance of FBMediaView", nil);
|
140 | return;
|
141 | }
|
142 | }
|
143 |
|
144 | [clickableViews addObject:mediaView];
|
145 | [clickableViews addObject:adIconView];
|
146 |
|
147 | [(EXNativeAdView *)nativeAdView registerViewsForInteraction:(FBMediaView *)mediaView adIcon:(FBAdIconView *)adIconView clickableViews:clickableViews];
|
148 | resolve(@[]);
|
149 | }];
|
150 | }
|
151 |
|
152 | UM_EXPORT_METHOD_AS(init,
|
153 | init:(NSString *)placementId
|
154 | withAdsToRequest:(NSNumber *)adsToRequest
|
155 | resolve:(UMPromiseResolveBlock)resolve
|
156 | reject:(UMPromiseRejectBlock)reject)
|
157 | {
|
158 | FBNativeAdsManager *adsManager = [[FBNativeAdsManager alloc] initWithPlacementID:placementId
|
159 | forNumAdsRequested:[adsToRequest intValue]];
|
160 |
|
161 | EXAdManagerDelegate *delegate = [[EXAdManagerDelegate alloc] initWithPlacementId:placementId andManager:self];
|
162 | _adsManagersDelegates[placementId] = delegate;
|
163 | [adsManager setDelegate:delegate];
|
164 |
|
165 | [UMUtilities performSynchronouslyOnMainThread:^{
|
166 | [adsManager loadAds];
|
167 | }];
|
168 |
|
169 | [_adsManagers setValue:adsManager forKey:placementId];
|
170 | resolve(nil);
|
171 | }
|
172 |
|
173 | UM_EXPORT_METHOD_AS(setMediaCachePolicy,
|
174 | setMediaCachePolicy:(NSString *)placementId
|
175 | cachePolicy:(NSString *)cachePolicy
|
176 | resolve:(UMPromiseResolveBlock)resolve
|
177 | reject:(UMPromiseRejectBlock)reject)
|
178 | {
|
179 | FBNativeAdsCachePolicy policy = [@{
|
180 | @"none": @(FBNativeAdsCachePolicyNone),
|
181 | @"all": @(FBNativeAdsCachePolicyAll),
|
182 | }[cachePolicy] integerValue] ?: FBNativeAdsCachePolicyNone;
|
183 | [_adsManagers[placementId] setMediaCachePolicy:policy];
|
184 | resolve(nil);
|
185 | }
|
186 |
|
187 | UM_EXPORT_METHOD_AS(disableAutoRefresh,
|
188 | disableAutoRefresh:(NSString*)placementId
|
189 | resolve:(UMPromiseResolveBlock)resolve
|
190 | reject:(UMPromiseRejectBlock)reject)
|
191 | {
|
192 | [_adsManagers[placementId] disableAutoRefresh];
|
193 | resolve(nil);
|
194 | }
|
195 |
|
196 | - (void)nativeAdsLoaded
|
197 | {
|
198 | NSMutableDictionary<NSString*, NSNumber*> *adsManagersState = [NSMutableDictionary new];
|
199 |
|
200 | [_adsManagers enumerateKeysAndObjectsUsingBlock:^(NSString* key, FBNativeAdsManager* adManager, __unused BOOL* stop) {
|
201 | [adsManagersState setValue:@([adManager isValid]) forKey:key];
|
202 | }];
|
203 |
|
204 | [[_moduleRegistry getModuleImplementingProtocol:@protocol(UMEventEmitterService)] sendEventWithName:@"CTKNativeAdsManagersChanged" body:adsManagersState];
|
205 | }
|
206 |
|
207 | - (void)nativeAdForPlacementId:(NSString *)placementId failedToLoadWithError:(NSError *)error
|
208 | {
|
209 | [[_moduleRegistry getModuleImplementingProtocol:@protocol(UMEventEmitterService)] sendEventWithName:@"CTKNativeAdManagerErrored" body:@{
|
210 | @"placementId": placementId,
|
211 | @"error": @{
|
212 | @"message": error.localizedDescription ?: error.description,
|
213 | @"code": @(error.code)
|
214 | },
|
215 | }];
|
216 | }
|
217 |
|
218 | - (UIView *)view
|
219 | {
|
220 | return [[EXNativeAdView alloc] initWithModuleRegistry:_moduleRegistry];
|
221 | }
|
222 |
|
223 | UM_VIEW_PROPERTY(adsManager, NSString *, EXNativeAdView)
|
224 | {
|
225 | [view setNativeAd:[_adsManagers[value] nextNativeAd]];
|
226 | }
|
227 |
|
228 | - (void)startObserving {
|
229 | }
|
230 |
|
231 | - (void)stopObserving {
|
232 | }
|
233 |
|
234 | @end
|