@bigcrunch/react-native-ads 0.1.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 +417 -0
- package/android/build.gradle +70 -0
- package/android/settings.gradle +6 -0
- package/android/src/main/AndroidManifest.xml +3 -0
- package/android/src/main/java/com/bigcrunch/ads/react/BigCrunchAdsModule.kt +653 -0
- package/android/src/main/java/com/bigcrunch/ads/react/BigCrunchAdsPackage.kt +20 -0
- package/android/src/main/java/com/bigcrunch/ads/react/BigCrunchBannerViewManager.kt +296 -0
- package/ios/BigCrunchAdsModule.swift +588 -0
- package/ios/BigCrunchBannerViewManager.swift +270 -0
- package/ios/react-native-bigcrunch-ads-Bridging-Header.h +8 -0
- package/lib/BigCrunchAds.d.ts +168 -0
- package/lib/BigCrunchAds.d.ts.map +1 -0
- package/lib/BigCrunchAds.js +241 -0
- package/lib/BigCrunchBannerView.d.ts +21 -0
- package/lib/BigCrunchBannerView.d.ts.map +1 -0
- package/lib/BigCrunchBannerView.js +176 -0
- package/lib/BigCrunchInterstitial.d.ts +66 -0
- package/lib/BigCrunchInterstitial.d.ts.map +1 -0
- package/lib/BigCrunchInterstitial.js +222 -0
- package/lib/BigCrunchRewarded.d.ts +85 -0
- package/lib/BigCrunchRewarded.d.ts.map +1 -0
- package/lib/BigCrunchRewarded.js +257 -0
- package/lib/NativeBigCrunchAds.d.ts +71 -0
- package/lib/NativeBigCrunchAds.d.ts.map +1 -0
- package/lib/NativeBigCrunchAds.js +54 -0
- package/lib/index.d.ts +28 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +32 -0
- package/lib/types/ads.d.ts +101 -0
- package/lib/types/ads.d.ts.map +1 -0
- package/lib/types/ads.js +4 -0
- package/lib/types/config.d.ts +137 -0
- package/lib/types/config.d.ts.map +1 -0
- package/lib/types/config.js +4 -0
- package/lib/types/events.d.ts +306 -0
- package/lib/types/events.d.ts.map +1 -0
- package/lib/types/events.js +4 -0
- package/lib/types/index.d.ts +175 -0
- package/lib/types/index.d.ts.map +1 -0
- package/lib/types/index.js +23 -0
- package/package.json +88 -0
- package/react-native-bigcrunch-ads.podspec +27 -0
- package/src/BigCrunchAds.ts +298 -0
- package/src/BigCrunchBannerView.tsx +262 -0
- package/src/BigCrunchInterstitial.ts +266 -0
- package/src/BigCrunchRewarded.ts +307 -0
- package/src/NativeBigCrunchAds.ts +120 -0
- package/src/index.ts +71 -0
- package/src/types/ads.ts +112 -0
- package/src/types/config.ts +145 -0
- package/src/types/events.ts +337 -0
- package/src/types/index.ts +193 -0
|
@@ -0,0 +1,588 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
import BigCrunchAds
|
|
3
|
+
#if canImport(React)
|
|
4
|
+
import React
|
|
5
|
+
#endif
|
|
6
|
+
|
|
7
|
+
// MARK: - Interstitial Delegate
|
|
8
|
+
|
|
9
|
+
class InterstitialDelegate: NSObject, BigCrunchInterstitialDelegate {
|
|
10
|
+
weak var module: BigCrunchAdsModule?
|
|
11
|
+
let placementId: String
|
|
12
|
+
|
|
13
|
+
init(module: BigCrunchAdsModule, placementId: String) {
|
|
14
|
+
self.module = module
|
|
15
|
+
self.placementId = placementId
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
func interstitialDidShow(placementId: String) {
|
|
19
|
+
if module?.hasListeners == true {
|
|
20
|
+
module?.sendEvent(withName: "BigCrunchInterstitialAdOpened", body: [
|
|
21
|
+
"placementId": placementId
|
|
22
|
+
])
|
|
23
|
+
// Also emit impression event
|
|
24
|
+
module?.sendEvent(withName: "BigCrunchInterstitialAdImpression", body: [
|
|
25
|
+
"placementId": placementId
|
|
26
|
+
])
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
func interstitialDidDismiss(placementId: String) {
|
|
31
|
+
if module?.hasListeners == true {
|
|
32
|
+
module?.sendEvent(withName: "BigCrunchInterstitialAdClosed", body: [
|
|
33
|
+
"placementId": placementId
|
|
34
|
+
])
|
|
35
|
+
}
|
|
36
|
+
// Clear from cache
|
|
37
|
+
module?.interstitialCache.removeValue(forKey: placementId)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
func interstitialDidClick(placementId: String) {
|
|
41
|
+
if module?.hasListeners == true {
|
|
42
|
+
module?.sendEvent(withName: "BigCrunchInterstitialAdClicked", body: [
|
|
43
|
+
"placementId": placementId
|
|
44
|
+
])
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
func interstitialDidFail(placementId: String, error: String) {
|
|
49
|
+
if module?.hasListeners == true {
|
|
50
|
+
module?.sendEvent(withName: "BigCrunchInterstitialAdFailedToShow", body: [
|
|
51
|
+
"placementId": placementId,
|
|
52
|
+
"errorCode": "SHOW_FAILED",
|
|
53
|
+
"errorMessage": error
|
|
54
|
+
])
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// MARK: - Rewarded Delegate
|
|
60
|
+
|
|
61
|
+
class RewardedDelegate: NSObject, BigCrunchRewardedDelegate {
|
|
62
|
+
weak var module: BigCrunchAdsModule?
|
|
63
|
+
let placementId: String
|
|
64
|
+
|
|
65
|
+
init(module: BigCrunchAdsModule, placementId: String) {
|
|
66
|
+
self.module = module
|
|
67
|
+
self.placementId = placementId
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
func rewardedDidShow(placementId: String) {
|
|
71
|
+
if module?.hasListeners == true {
|
|
72
|
+
module?.sendEvent(withName: "BigCrunchRewardedAdOpened", body: [
|
|
73
|
+
"placementId": placementId
|
|
74
|
+
])
|
|
75
|
+
// Also emit impression event
|
|
76
|
+
module?.sendEvent(withName: "BigCrunchRewardedAdImpression", body: [
|
|
77
|
+
"placementId": placementId
|
|
78
|
+
])
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
func rewardedDidDismiss(placementId: String) {
|
|
83
|
+
if module?.hasListeners == true {
|
|
84
|
+
module?.sendEvent(withName: "BigCrunchRewardedAdClosed", body: [
|
|
85
|
+
"placementId": placementId
|
|
86
|
+
])
|
|
87
|
+
}
|
|
88
|
+
// Clear from cache and delegate
|
|
89
|
+
module?.rewardedCache.removeValue(forKey: placementId)
|
|
90
|
+
module?.rewardedDelegates.removeValue(forKey: placementId)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
func rewardedDidClick(placementId: String) {
|
|
94
|
+
if module?.hasListeners == true {
|
|
95
|
+
module?.sendEvent(withName: "BigCrunchRewardedAdClicked", body: [
|
|
96
|
+
"placementId": placementId
|
|
97
|
+
])
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
func rewardedDidEarnReward(placementId: String, type: String, amount: Int) {
|
|
102
|
+
if module?.hasListeners == true {
|
|
103
|
+
module?.sendEvent(withName: "BigCrunchRewardedAdEarned", body: [
|
|
104
|
+
"placementId": placementId,
|
|
105
|
+
"type": type,
|
|
106
|
+
"amount": amount
|
|
107
|
+
])
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
func rewardedDidFail(placementId: String, error: String) {
|
|
112
|
+
if module?.hasListeners == true {
|
|
113
|
+
module?.sendEvent(withName: "BigCrunchRewardedAdFailedToShow", body: [
|
|
114
|
+
"placementId": placementId,
|
|
115
|
+
"errorCode": "SHOW_FAILED",
|
|
116
|
+
"errorMessage": error
|
|
117
|
+
])
|
|
118
|
+
}
|
|
119
|
+
// Clean up delegate on failure
|
|
120
|
+
module?.rewardedDelegates.removeValue(forKey: placementId)
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
@objc(BigCrunchAdsModule)
|
|
125
|
+
class BigCrunchAdsModule: RCTEventEmitter {
|
|
126
|
+
|
|
127
|
+
// Made internal for delegate access
|
|
128
|
+
var hasListeners = false
|
|
129
|
+
var interstitialCache: [String: Any] = [:]
|
|
130
|
+
var rewardedCache: [String: Any] = [:]
|
|
131
|
+
private var interstitialDelegates: [String: InterstitialDelegate] = [:]
|
|
132
|
+
var rewardedDelegates: [String: RewardedDelegate] = [:]
|
|
133
|
+
|
|
134
|
+
override static func moduleName() -> String! {
|
|
135
|
+
return "BigCrunchAdsModule"
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
override static func requiresMainQueueSetup() -> Bool {
|
|
139
|
+
return true
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
override func supportedEvents() -> [String]! {
|
|
143
|
+
return [
|
|
144
|
+
// Banner events - matching TypeScript NativeEventNames
|
|
145
|
+
"BigCrunchBannerAdLoaded",
|
|
146
|
+
"BigCrunchBannerAdFailedToLoad",
|
|
147
|
+
"BigCrunchBannerAdImpression",
|
|
148
|
+
"BigCrunchBannerAdClicked",
|
|
149
|
+
"BigCrunchBannerAdOpened",
|
|
150
|
+
"BigCrunchBannerAdClosed",
|
|
151
|
+
"BigCrunchBannerAdRevenue",
|
|
152
|
+
"BigCrunchBannerAdViewable",
|
|
153
|
+
|
|
154
|
+
// Interstitial events - matching TypeScript NativeEventNames
|
|
155
|
+
"BigCrunchInterstitialAdLoaded",
|
|
156
|
+
"BigCrunchInterstitialAdFailedToLoad",
|
|
157
|
+
"BigCrunchInterstitialAdOpened",
|
|
158
|
+
"BigCrunchInterstitialAdImpression",
|
|
159
|
+
"BigCrunchInterstitialAdClicked",
|
|
160
|
+
"BigCrunchInterstitialAdClosed",
|
|
161
|
+
"BigCrunchInterstitialAdFailedToShow",
|
|
162
|
+
"BigCrunchInterstitialAdRevenue",
|
|
163
|
+
|
|
164
|
+
// Rewarded events - matching TypeScript NativeEventNames
|
|
165
|
+
"BigCrunchRewardedAdLoaded",
|
|
166
|
+
"BigCrunchRewardedAdFailedToLoad",
|
|
167
|
+
"BigCrunchRewardedAdOpened",
|
|
168
|
+
"BigCrunchRewardedAdImpression",
|
|
169
|
+
"BigCrunchRewardedAdClicked",
|
|
170
|
+
"BigCrunchRewardedAdClosed",
|
|
171
|
+
"BigCrunchRewardedAdEarned",
|
|
172
|
+
"BigCrunchRewardedAdFailedToShow",
|
|
173
|
+
"BigCrunchRewardedAdRevenue",
|
|
174
|
+
|
|
175
|
+
// Configuration events
|
|
176
|
+
"BigCrunchConfigUpdated",
|
|
177
|
+
"BigCrunchConfigFailed",
|
|
178
|
+
|
|
179
|
+
// Session events
|
|
180
|
+
"BigCrunchSessionStarted",
|
|
181
|
+
"BigCrunchSessionEnded"
|
|
182
|
+
]
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
override func startObserving() {
|
|
186
|
+
hasListeners = true
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
override func stopObserving() {
|
|
190
|
+
hasListeners = false
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// MARK: - Initialization
|
|
194
|
+
|
|
195
|
+
@objc(initialize:resolver:rejecter:)
|
|
196
|
+
func initialize(options: NSDictionary,
|
|
197
|
+
resolver: @escaping RCTPromiseResolveBlock,
|
|
198
|
+
rejecter: @escaping RCTPromiseRejectBlock) {
|
|
199
|
+
guard let propertyId = options["propertyId"] as? String,
|
|
200
|
+
let apiKey = options["apiKey"] as? String else {
|
|
201
|
+
rejecter("INIT_ERROR", "propertyId and apiKey are required", nil)
|
|
202
|
+
return
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
let environment = options["environment"] as? String ?? "production"
|
|
206
|
+
let debug = options["debug"] as? Bool ?? false
|
|
207
|
+
let useMockConfig = options["useMockConfig"] as? Bool ?? false
|
|
208
|
+
|
|
209
|
+
DispatchQueue.main.async {
|
|
210
|
+
// Map environment strings to SDK enum - "sandbox" maps to .staging
|
|
211
|
+
let env: BigCrunchEnv = environment == "sandbox" ? .staging : .prod
|
|
212
|
+
|
|
213
|
+
BigCrunchAds.initialize(
|
|
214
|
+
propertyId: propertyId,
|
|
215
|
+
apiKey: apiKey,
|
|
216
|
+
env: env,
|
|
217
|
+
useMockConfig: useMockConfig
|
|
218
|
+
)
|
|
219
|
+
|
|
220
|
+
// Track that we've initialized
|
|
221
|
+
BigCrunchAdsModule.isSDKInitialized = true
|
|
222
|
+
|
|
223
|
+
// Note: debug mode is handled by SDK based on env (.staging enables verbose logging)
|
|
224
|
+
resolver(nil)
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
private static var isSDKInitialized = false
|
|
229
|
+
|
|
230
|
+
@objc(isInitialized:rejecter:)
|
|
231
|
+
func isInitialized(resolver: RCTPromiseResolveBlock,
|
|
232
|
+
rejecter: RCTPromiseRejectBlock) {
|
|
233
|
+
// iOS SDK doesn't expose isInitialized() publicly yet
|
|
234
|
+
// Return true if we've called initialize (tracked locally)
|
|
235
|
+
resolver(BigCrunchAdsModule.isSDKInitialized)
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// MARK: - Screen Tracking
|
|
239
|
+
|
|
240
|
+
@objc(trackScreenView:resolver:rejecter:)
|
|
241
|
+
func trackScreenView(screenName: String,
|
|
242
|
+
resolver: @escaping RCTPromiseResolveBlock,
|
|
243
|
+
rejecter: @escaping RCTPromiseRejectBlock) {
|
|
244
|
+
DispatchQueue.main.async {
|
|
245
|
+
BigCrunchAds.trackScreen(screenName)
|
|
246
|
+
resolver(nil)
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// MARK: - Configuration
|
|
251
|
+
|
|
252
|
+
@objc(getAppConfig:rejecter:)
|
|
253
|
+
func getAppConfig(resolver: @escaping RCTPromiseResolveBlock,
|
|
254
|
+
rejecter: @escaping RCTPromiseRejectBlock) {
|
|
255
|
+
if let config = BigCrunchAds.getAppConfig() {
|
|
256
|
+
// Convert AppConfig to dictionary
|
|
257
|
+
let configDict: [String: Any] = [
|
|
258
|
+
"propertyId": config.propertyId,
|
|
259
|
+
"appName": config.appName,
|
|
260
|
+
"environment": config.environment,
|
|
261
|
+
"gamNetworkCode": config.gamNetworkCode,
|
|
262
|
+
"prebid": [
|
|
263
|
+
"serverUrl": config.prebid.serverUrl,
|
|
264
|
+
"timeoutMs": config.prebid.timeoutMs
|
|
265
|
+
],
|
|
266
|
+
"placements": config.placements.map { placement in
|
|
267
|
+
var placementDict: [String: Any] = [
|
|
268
|
+
"placementId": placement.placementId,
|
|
269
|
+
"format": placement.format,
|
|
270
|
+
"gamAdUnit": placement.gamAdUnit
|
|
271
|
+
]
|
|
272
|
+
if let sizes = placement.sizes {
|
|
273
|
+
placementDict["sizes"] = sizes.map { ["width": $0.width, "height": $0.height] }
|
|
274
|
+
}
|
|
275
|
+
if let prebidConfigId = placement.prebidConfigId {
|
|
276
|
+
placementDict["prebidConfigId"] = prebidConfigId
|
|
277
|
+
}
|
|
278
|
+
return placementDict
|
|
279
|
+
}
|
|
280
|
+
]
|
|
281
|
+
resolver(configDict)
|
|
282
|
+
} else {
|
|
283
|
+
resolver(nil)
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
@objc(refreshConfig:rejecter:)
|
|
288
|
+
func refreshConfig(resolver: @escaping RCTPromiseResolveBlock,
|
|
289
|
+
rejecter: @escaping RCTPromiseRejectBlock) {
|
|
290
|
+
Task {
|
|
291
|
+
await BigCrunchAds.refreshConfig()
|
|
292
|
+
DispatchQueue.main.async {
|
|
293
|
+
resolver(nil)
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
// MARK: - Interstitial Ads
|
|
299
|
+
|
|
300
|
+
@objc(loadInterstitial:resolver:rejecter:)
|
|
301
|
+
func loadInterstitial(options: NSDictionary,
|
|
302
|
+
resolver: @escaping RCTPromiseResolveBlock,
|
|
303
|
+
rejecter: @escaping RCTPromiseRejectBlock) {
|
|
304
|
+
guard let placementId = options["placementId"] as? String else {
|
|
305
|
+
rejecter("LOAD_ERROR", "placementId is required", nil)
|
|
306
|
+
return
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
let customTargeting = options["customTargeting"] as? [String: String]
|
|
310
|
+
|
|
311
|
+
// Use preload with completion handler to emit events
|
|
312
|
+
BigCrunchInterstitial.preload(placementId: placementId) { [weak self] result in
|
|
313
|
+
switch result {
|
|
314
|
+
case .success:
|
|
315
|
+
// Store in cache and emit loaded event
|
|
316
|
+
self?.interstitialCache[placementId] = true
|
|
317
|
+
|
|
318
|
+
if self?.hasListeners == true {
|
|
319
|
+
self?.sendEvent(withName: "BigCrunchInterstitialAdLoaded", body: [
|
|
320
|
+
"placementId": placementId
|
|
321
|
+
])
|
|
322
|
+
}
|
|
323
|
+
resolver(nil)
|
|
324
|
+
|
|
325
|
+
case .failure(let error):
|
|
326
|
+
// Emit failed event
|
|
327
|
+
if self?.hasListeners == true {
|
|
328
|
+
self?.sendEvent(withName: "BigCrunchInterstitialAdFailedToLoad", body: [
|
|
329
|
+
"placementId": placementId,
|
|
330
|
+
"errorCode": "LOAD_FAILED",
|
|
331
|
+
"errorMessage": error.localizedDescription
|
|
332
|
+
])
|
|
333
|
+
}
|
|
334
|
+
rejecter("LOAD_ERROR", "Failed to load interstitial: \(error.localizedDescription)", error)
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
@objc(showInterstitial:resolver:rejecter:)
|
|
340
|
+
func showInterstitial(placementId: String,
|
|
341
|
+
resolver: @escaping RCTPromiseResolveBlock,
|
|
342
|
+
rejecter: @escaping RCTPromiseRejectBlock) {
|
|
343
|
+
DispatchQueue.main.async { [weak self] in
|
|
344
|
+
guard let self = self else { return }
|
|
345
|
+
guard let rootViewController = UIApplication.shared.keyWindow?.rootViewController else {
|
|
346
|
+
rejecter("NO_VIEWCONTROLLER", "No root view controller available", nil)
|
|
347
|
+
return
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
// Create and store delegate
|
|
351
|
+
let delegate = InterstitialDelegate(module: self, placementId: placementId)
|
|
352
|
+
self.interstitialDelegates[placementId] = delegate
|
|
353
|
+
|
|
354
|
+
// Show with delegate
|
|
355
|
+
let success = BigCrunchInterstitial.show(
|
|
356
|
+
from: rootViewController,
|
|
357
|
+
placementId: placementId,
|
|
358
|
+
delegate: delegate
|
|
359
|
+
)
|
|
360
|
+
|
|
361
|
+
if success {
|
|
362
|
+
resolver(nil)
|
|
363
|
+
} else {
|
|
364
|
+
// Clean up delegate if show failed immediately
|
|
365
|
+
self.interstitialDelegates.removeValue(forKey: placementId)
|
|
366
|
+
rejecter("SHOW_ERROR", "Failed to show interstitial: Ad not loaded", nil)
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
@objc(isInterstitialLoaded:resolver:rejecter:)
|
|
372
|
+
func isInterstitialLoaded(placementId: String,
|
|
373
|
+
resolver: RCTPromiseResolveBlock,
|
|
374
|
+
rejecter: RCTPromiseRejectBlock) {
|
|
375
|
+
resolver(BigCrunchInterstitial.isReady(placementId: placementId))
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
@objc(destroyInterstitial:resolver:rejecter:)
|
|
379
|
+
func destroyInterstitial(placementId: String,
|
|
380
|
+
resolver: RCTPromiseResolveBlock,
|
|
381
|
+
rejecter: RCTPromiseRejectBlock) {
|
|
382
|
+
// iOS SDK uses clearCache() instead of per-placement destroy
|
|
383
|
+
// Just clear our local cache for now
|
|
384
|
+
interstitialCache.removeValue(forKey: placementId)
|
|
385
|
+
resolver(nil)
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
// MARK: - Rewarded Ads
|
|
389
|
+
|
|
390
|
+
@objc(loadRewarded:resolver:rejecter:)
|
|
391
|
+
func loadRewarded(options: NSDictionary,
|
|
392
|
+
resolver: @escaping RCTPromiseResolveBlock,
|
|
393
|
+
rejecter: @escaping RCTPromiseRejectBlock) {
|
|
394
|
+
guard let placementId = options["placementId"] as? String else {
|
|
395
|
+
rejecter("LOAD_ERROR", "placementId is required", nil)
|
|
396
|
+
return
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
// customTargeting can be used in future for custom Prebid targeting
|
|
400
|
+
// let customTargeting = options["customTargeting"] as? [String: String]
|
|
401
|
+
|
|
402
|
+
BigCrunchRewarded.preload(placementId: placementId) { [weak self] result in
|
|
403
|
+
switch result {
|
|
404
|
+
case .success:
|
|
405
|
+
// Mark as loaded in our cache
|
|
406
|
+
self?.rewardedCache[placementId] = true
|
|
407
|
+
if self?.hasListeners == true {
|
|
408
|
+
self?.sendEvent(withName: "BigCrunchRewardedAdLoaded", body: [
|
|
409
|
+
"placementId": placementId
|
|
410
|
+
])
|
|
411
|
+
}
|
|
412
|
+
resolver(nil)
|
|
413
|
+
case .failure(let error):
|
|
414
|
+
if self?.hasListeners == true {
|
|
415
|
+
self?.sendEvent(withName: "BigCrunchRewardedAdFailedToLoad", body: [
|
|
416
|
+
"placementId": placementId,
|
|
417
|
+
"errorCode": "LOAD_FAILED",
|
|
418
|
+
"errorMessage": error.localizedDescription
|
|
419
|
+
])
|
|
420
|
+
}
|
|
421
|
+
rejecter("LOAD_ERROR", error.localizedDescription, error)
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
@objc(showRewarded:resolver:rejecter:)
|
|
427
|
+
func showRewarded(placementId: String,
|
|
428
|
+
resolver: @escaping RCTPromiseResolveBlock,
|
|
429
|
+
rejecter: @escaping RCTPromiseRejectBlock) {
|
|
430
|
+
DispatchQueue.main.async { [weak self] in
|
|
431
|
+
guard let self = self else {
|
|
432
|
+
rejecter("SHOW_ERROR", "Module deallocated", nil)
|
|
433
|
+
return
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
guard let rootViewController = UIApplication.shared.keyWindow?.rootViewController else {
|
|
437
|
+
rejecter("SHOW_ERROR", "No root view controller available", nil)
|
|
438
|
+
return
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
// Create and store delegate
|
|
442
|
+
let delegate = RewardedDelegate(module: self, placementId: placementId)
|
|
443
|
+
self.rewardedDelegates[placementId] = delegate
|
|
444
|
+
|
|
445
|
+
// Show with delegate
|
|
446
|
+
let success = BigCrunchRewarded.show(
|
|
447
|
+
from: rootViewController,
|
|
448
|
+
placementId: placementId,
|
|
449
|
+
delegate: delegate
|
|
450
|
+
)
|
|
451
|
+
|
|
452
|
+
if success {
|
|
453
|
+
resolver(nil)
|
|
454
|
+
} else {
|
|
455
|
+
// Clean up delegate if show failed immediately
|
|
456
|
+
self.rewardedDelegates.removeValue(forKey: placementId)
|
|
457
|
+
rejecter("SHOW_ERROR", "Failed to show rewarded: Ad not loaded", nil)
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
@objc(isRewardedLoaded:resolver:rejecter:)
|
|
463
|
+
func isRewardedLoaded(placementId: String,
|
|
464
|
+
resolver: RCTPromiseResolveBlock,
|
|
465
|
+
rejecter: RCTPromiseRejectBlock) {
|
|
466
|
+
resolver(BigCrunchRewarded.isReady(placementId: placementId))
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
@objc(destroyRewarded:resolver:rejecter:)
|
|
470
|
+
func destroyRewarded(placementId: String,
|
|
471
|
+
resolver: RCTPromiseResolveBlock,
|
|
472
|
+
rejecter: RCTPromiseRejectBlock) {
|
|
473
|
+
// iOS SDK doesn't have per-placement destroy for rewarded
|
|
474
|
+
// Just clear our local cache for now
|
|
475
|
+
rewardedCache.removeValue(forKey: placementId)
|
|
476
|
+
resolver(nil)
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
// MARK: - Session Management
|
|
480
|
+
|
|
481
|
+
@objc(getSessionInfo:rejecter:)
|
|
482
|
+
func getSessionInfo(resolver: @escaping RCTPromiseResolveBlock,
|
|
483
|
+
rejecter: @escaping RCTPromiseRejectBlock) {
|
|
484
|
+
let info = BigCrunchAds.getSessionInfo()
|
|
485
|
+
let sessionInfo: [String: Any] = [
|
|
486
|
+
"sessionId": info.sessionId,
|
|
487
|
+
"userId": info.userId,
|
|
488
|
+
"startTime": info.startTime,
|
|
489
|
+
"screenViewCount": info.screenViewCount,
|
|
490
|
+
"adRequestCount": info.adRequestCount,
|
|
491
|
+
"adImpressionCount": info.adImpressionCount,
|
|
492
|
+
"totalRevenueMicros": info.totalRevenueMicros
|
|
493
|
+
]
|
|
494
|
+
resolver(sessionInfo)
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
@objc(startNewSession:rejecter:)
|
|
498
|
+
func startNewSession(resolver: @escaping RCTPromiseResolveBlock,
|
|
499
|
+
rejecter: @escaping RCTPromiseRejectBlock) {
|
|
500
|
+
BigCrunchAds.startNewSession()
|
|
501
|
+
resolver(nil)
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
// MARK: - Device Context
|
|
505
|
+
|
|
506
|
+
@objc(getDeviceContext:rejecter:)
|
|
507
|
+
func getDeviceContext(resolver: @escaping RCTPromiseResolveBlock,
|
|
508
|
+
rejecter: @escaping RCTPromiseRejectBlock) {
|
|
509
|
+
let data = BigCrunchAds.getDeviceData()
|
|
510
|
+
let deviceContext: [String: Any] = [
|
|
511
|
+
"os": "iOS",
|
|
512
|
+
"osVersion": data.osVersion,
|
|
513
|
+
"deviceModel": data.deviceModel,
|
|
514
|
+
"screenWidth": data.screenWidth,
|
|
515
|
+
"screenHeight": data.screenHeight,
|
|
516
|
+
"screenDensity": UIScreen.main.scale,
|
|
517
|
+
"appVersion": data.appVersion,
|
|
518
|
+
"sdkVersion": "0.1.0",
|
|
519
|
+
"locale": "\(data.language)_\(data.country)",
|
|
520
|
+
"timezone": TimeZone.current.identifier,
|
|
521
|
+
"isTablet": data.isTablet,
|
|
522
|
+
"deviceId": data.deviceId
|
|
523
|
+
]
|
|
524
|
+
resolver(deviceContext)
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
// MARK: - Privacy
|
|
528
|
+
|
|
529
|
+
@objc(setGdprConsent:resolver:rejecter:)
|
|
530
|
+
func setGdprConsent(consent: String,
|
|
531
|
+
resolver: RCTPromiseResolveBlock,
|
|
532
|
+
rejecter: RCTPromiseRejectBlock) {
|
|
533
|
+
BigCrunchAds.setGdprConsent(consent)
|
|
534
|
+
resolver(nil)
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
@objc(setCcpaString:resolver:rejecter:)
|
|
538
|
+
func setCcpaString(ccpaString: String,
|
|
539
|
+
resolver: RCTPromiseResolveBlock,
|
|
540
|
+
rejecter: RCTPromiseRejectBlock) {
|
|
541
|
+
BigCrunchAds.setCcpaString(ccpaString)
|
|
542
|
+
resolver(nil)
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
@objc(setCoppaCompliant:resolver:rejecter:)
|
|
546
|
+
func setCoppaCompliant(isCompliant: Bool,
|
|
547
|
+
resolver: RCTPromiseResolveBlock,
|
|
548
|
+
rejecter: RCTPromiseRejectBlock) {
|
|
549
|
+
BigCrunchAds.setCoppaCompliant(isCompliant)
|
|
550
|
+
resolver(nil)
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
// MARK: - Debug & Testing
|
|
554
|
+
|
|
555
|
+
@objc(setDebugMode:resolver:rejecter:)
|
|
556
|
+
func setDebugMode(enabled: Bool,
|
|
557
|
+
resolver: RCTPromiseResolveBlock,
|
|
558
|
+
rejecter: RCTPromiseRejectBlock) {
|
|
559
|
+
BigCrunchAds.setDebugMode(enabled)
|
|
560
|
+
resolver(nil)
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
@objc(addTestDevice:resolver:rejecter:)
|
|
564
|
+
func addTestDevice(deviceId: String,
|
|
565
|
+
resolver: RCTPromiseResolveBlock,
|
|
566
|
+
rejecter: RCTPromiseRejectBlock) {
|
|
567
|
+
BigCrunchAds.addTestDevice(deviceId)
|
|
568
|
+
resolver(nil)
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
@objc(removeTestDevice:resolver:rejecter:)
|
|
572
|
+
func removeTestDevice(deviceId: String,
|
|
573
|
+
resolver: RCTPromiseResolveBlock,
|
|
574
|
+
rejecter: RCTPromiseRejectBlock) {
|
|
575
|
+
BigCrunchAds.removeTestDevice(deviceId)
|
|
576
|
+
resolver(nil)
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
@objc(getTestDevices:rejecter:)
|
|
580
|
+
func getTestDevices(resolver: RCTPromiseResolveBlock,
|
|
581
|
+
rejecter: RCTPromiseRejectBlock) {
|
|
582
|
+
resolver(BigCrunchAds.getTestDevices())
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
// MARK: - Helper Methods
|
|
586
|
+
// Note: convertAppConfigToDictionary and convertPlacementConfigToDictionary
|
|
587
|
+
// are kept for future use when iOS SDK exposes getAppConfig
|
|
588
|
+
}
|