@bigcrunch/react-native-ads 0.3.1 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/README.md +5 -5
  2. package/android/bigcrunch-ads/com/bigcrunch/ads/BigCrunchAds.kt +434 -0
  3. package/android/bigcrunch-ads/com/bigcrunch/ads/BigCrunchBannerView.kt +484 -0
  4. package/android/bigcrunch-ads/com/bigcrunch/ads/BigCrunchInterstitial.kt +403 -0
  5. package/android/bigcrunch-ads/com/bigcrunch/ads/BigCrunchRewarded.kt +409 -0
  6. package/android/bigcrunch-ads/com/bigcrunch/ads/adapters/GoogleAdsAdapter.kt +592 -0
  7. package/android/bigcrunch-ads/com/bigcrunch/ads/core/AdOrchestrator.kt +623 -0
  8. package/android/bigcrunch-ads/com/bigcrunch/ads/core/AnalyticsClient.kt +719 -0
  9. package/android/bigcrunch-ads/com/bigcrunch/ads/core/BidRequestClient.kt +364 -0
  10. package/android/bigcrunch-ads/com/bigcrunch/ads/core/ConfigManager.kt +301 -0
  11. package/android/bigcrunch-ads/com/bigcrunch/ads/core/DeviceContext.kt +385 -0
  12. package/android/bigcrunch-ads/com/bigcrunch/ads/core/RewardedCallback.kt +42 -0
  13. package/android/bigcrunch-ads/com/bigcrunch/ads/core/SessionManager.kt +330 -0
  14. package/android/bigcrunch-ads/com/bigcrunch/ads/internal/DeviceHelper.kt +60 -0
  15. package/android/bigcrunch-ads/com/bigcrunch/ads/internal/HttpClient.kt +114 -0
  16. package/android/bigcrunch-ads/com/bigcrunch/ads/internal/Logger.kt +71 -0
  17. package/android/bigcrunch-ads/com/bigcrunch/ads/internal/PrivacyStore.kt +125 -0
  18. package/android/bigcrunch-ads/com/bigcrunch/ads/internal/Storage.kt +88 -0
  19. package/android/bigcrunch-ads/com/bigcrunch/ads/listeners/BannerAdListener.kt +55 -0
  20. package/android/bigcrunch-ads/com/bigcrunch/ads/listeners/InterstitialAdListener.kt +55 -0
  21. package/android/bigcrunch-ads/com/bigcrunch/ads/listeners/RewardedAdListener.kt +58 -0
  22. package/android/bigcrunch-ads/com/bigcrunch/ads/models/AdEvent.kt +880 -0
  23. package/android/bigcrunch-ads/com/bigcrunch/ads/models/AppConfig.kt +90 -0
  24. package/android/bigcrunch-ads/com/bigcrunch/ads/models/DeviceData.kt +18 -0
  25. package/android/bigcrunch-ads/com/bigcrunch/ads/models/PlacementConfig.kt +70 -0
  26. package/android/bigcrunch-ads/com/bigcrunch/ads/models/SessionInfo.kt +21 -0
  27. package/android/build.gradle +22 -10
  28. package/android/settings.gradle +2 -6
  29. package/android/src/main/java/com/bigcrunch/ads/react/BigCrunchAdsModule.kt +0 -23
  30. package/ios/BigCrunchAds/Sources/Adapters/GoogleAdsAdapter.swift +512 -0
  31. package/ios/BigCrunchAds/Sources/BigCrunchAds.swift +387 -0
  32. package/ios/BigCrunchAds/Sources/BigCrunchBannerView.swift +448 -0
  33. package/ios/BigCrunchAds/Sources/BigCrunchInterstitial.swift +412 -0
  34. package/ios/BigCrunchAds/Sources/BigCrunchRewarded.swift +523 -0
  35. package/ios/BigCrunchAds/Sources/Core/AdOrchestrator.swift +514 -0
  36. package/ios/BigCrunchAds/Sources/Core/AnalyticsClient.swift +874 -0
  37. package/ios/BigCrunchAds/Sources/Core/BidRequestClient.swift +344 -0
  38. package/ios/BigCrunchAds/Sources/Core/ConfigManager.swift +306 -0
  39. package/ios/BigCrunchAds/Sources/Core/DeviceContext.swift +284 -0
  40. package/ios/BigCrunchAds/Sources/Core/SessionManager.swift +392 -0
  41. package/ios/BigCrunchAds/Sources/Internal/HTTPClient.swift +146 -0
  42. package/ios/BigCrunchAds/Sources/Internal/Logger.swift +62 -0
  43. package/ios/BigCrunchAds/Sources/Internal/PrivacyStore.swift +129 -0
  44. package/ios/BigCrunchAds/Sources/Internal/Storage.swift +73 -0
  45. package/ios/BigCrunchAds/Sources/Models/AdEvent.swift +784 -0
  46. package/ios/BigCrunchAds/Sources/Models/AppConfig.swift +100 -0
  47. package/ios/BigCrunchAds/Sources/Models/DeviceData.swift +68 -0
  48. package/ios/BigCrunchAds/Sources/Models/PlacementConfig.swift +137 -0
  49. package/ios/BigCrunchAds/Sources/Models/SessionInfo.swift +48 -0
  50. package/ios/BigCrunchAdsModule.swift +5 -14
  51. package/ios/BigCrunchBannerViewManager.swift +0 -1
  52. package/lib/index.d.ts +1 -1
  53. package/lib/index.d.ts.map +1 -1
  54. package/lib/index.js +3 -2
  55. package/lib/types/config.d.ts +22 -9
  56. package/lib/types/config.d.ts.map +1 -1
  57. package/lib/types/events.d.ts +4 -4
  58. package/lib/types/events.d.ts.map +1 -1
  59. package/package.json +11 -4
  60. package/react-native-bigcrunch-ads.podspec +1 -3
  61. package/scripts/inject-version.js +55 -0
  62. package/src/index.ts +3 -2
  63. package/src/types/config.ts +23 -9
  64. package/src/types/events.ts +4 -4
@@ -0,0 +1,412 @@
1
+ import UIKit
2
+
3
+ /**
4
+ * BigCrunch Interstitial Ads - Static API for full-screen interstitial ads
5
+ *
6
+ * Interstitial ads are full-screen ads that cover the interface of an app until
7
+ * closed by the user. They're best used at natural transition points in the app.
8
+ *
9
+ * Usage:
10
+ * ```swift
11
+ * // 1. Preload the ad (do this early, e.g., when entering a screen)
12
+ * BigCrunchInterstitial.preload(placementId: "article_interstitial") { result in
13
+ * switch result {
14
+ * case .success:
15
+ * print("Ad ready to show")
16
+ * case .failure(let error):
17
+ * print("Failed to load: \(error)")
18
+ * }
19
+ * }
20
+ *
21
+ * // 2. Check if ready (optional)
22
+ * if BigCrunchInterstitial.isReady(placementId: "article_interstitial") {
23
+ * // Ad is ready to show
24
+ * }
25
+ *
26
+ * // 3. Show when appropriate (e.g., after completing an action)
27
+ * BigCrunchInterstitial.show(
28
+ * from: self,
29
+ * placementId: "article_interstitial",
30
+ * delegate: self
31
+ * )
32
+ * ```
33
+ *
34
+ * Implement BigCrunchInterstitialDelegate for events:
35
+ * ```swift
36
+ * extension ViewController: BigCrunchInterstitialDelegate {
37
+ * func interstitialDidShow(placementId: String) { }
38
+ * func interstitialDidDismiss(placementId: String) { }
39
+ * func interstitialDidClick(placementId: String) { }
40
+ * func interstitialDidFail(placementId: String, error: String) { }
41
+ * }
42
+ * ```
43
+ */
44
+ public final class BigCrunchInterstitial {
45
+
46
+ private static let TAG = "BigCrunchInterstitial"
47
+ private static var adOrchestrator: AdOrchestrator?
48
+ private static let orchestratorLock = NSLock()
49
+
50
+ // Store delegates to prevent deallocation during show
51
+ private static var activeDelegates: [String: InterstitialDelegateWrapper] = [:]
52
+ private static let delegateLock = NSLock()
53
+
54
+ // Private initializer to prevent instantiation
55
+ private init() {}
56
+
57
+ // MARK: - Callback Protocol (Legacy)
58
+
59
+ /**
60
+ * Legacy callback protocol for interstitial ad events
61
+ */
62
+ public protocol Callback {
63
+ func onAdShown()
64
+ func onAdDismissed()
65
+ func onAdFailed(error: String)
66
+ }
67
+
68
+ // MARK: - Preload Methods
69
+
70
+ /**
71
+ * Preload an interstitial ad for the given placement
72
+ *
73
+ * Call this early (e.g., when entering a screen) to give the ad time to load.
74
+ *
75
+ * - Parameters:
76
+ * - placementId: The placement ID from BigCrunch dashboard
77
+ * - completion: Optional completion handler called when preload finishes
78
+ */
79
+ public static func preload(
80
+ placementId: String,
81
+ completion: ((Result<Void, Error>) -> Void)? = nil
82
+ ) {
83
+ BCLogger.debug("\(TAG): Preloading interstitial: \(placementId)")
84
+
85
+ guard BigCrunchAds.isInitialized() else {
86
+ BCLogger.error("\(TAG): SDK not initialized")
87
+ completion?(.failure(BigCrunchError.notInitialized))
88
+ return
89
+ }
90
+
91
+ guard !placementId.isEmpty else {
92
+ BCLogger.error("\(TAG): Invalid placementId: cannot be empty")
93
+ completion?(.failure(BigCrunchError.invalidPlacement("placementId cannot be empty")))
94
+ return
95
+ }
96
+
97
+ let orchestrator = getOrCreateOrchestrator()
98
+
99
+ let callback = PreloadCallbackImpl(placementId: placementId, completion: completion)
100
+ orchestrator.preloadInterstitialAd(placementId: placementId, callback: callback)
101
+ }
102
+
103
+ /**
104
+ * Preload an interstitial ad (simplified version without completion)
105
+ *
106
+ * - Parameter placementId: The placement ID from BigCrunch dashboard
107
+ */
108
+ public static func preload(placementId: String) {
109
+ preload(placementId: placementId, completion: nil)
110
+ }
111
+
112
+ // MARK: - Show Methods
113
+
114
+ /**
115
+ * Show a preloaded interstitial ad
116
+ *
117
+ * The ad must be preloaded first using `preload(placementId:)`. Check `isReady(placementId:)`
118
+ * before calling this to ensure an ad is available.
119
+ *
120
+ * - Parameters:
121
+ * - viewController: The view controller to present the ad from
122
+ * - placementId: The placement ID
123
+ * - delegate: Optional delegate for ad events
124
+ * - Returns: true if an ad was available and will be shown, false otherwise
125
+ */
126
+ @discardableResult
127
+ public static func show(
128
+ from viewController: UIViewController,
129
+ placementId: String,
130
+ delegate: BigCrunchInterstitialDelegate? = nil
131
+ ) -> Bool {
132
+ BCLogger.debug("\(TAG): Showing interstitial: \(placementId)")
133
+
134
+ guard BigCrunchAds.isInitialized() else {
135
+ BCLogger.error("\(TAG): SDK not initialized")
136
+ delegate?.interstitialDidFail(placementId: placementId, error: "SDK not initialized. Call BigCrunchAds.initialize() first.")
137
+ return false
138
+ }
139
+
140
+ guard !placementId.isEmpty else {
141
+ BCLogger.error("\(TAG): Invalid placementId: cannot be empty")
142
+ delegate?.interstitialDidFail(placementId: placementId, error: "Invalid placementId")
143
+ return false
144
+ }
145
+
146
+ let orchestrator = getOrCreateOrchestrator()
147
+
148
+ // Create and store delegate wrapper
149
+ let wrapper = InterstitialDelegateWrapper(placementId: placementId, delegate: delegate)
150
+
151
+ delegateLock.lock()
152
+ activeDelegates[placementId] = wrapper
153
+ delegateLock.unlock()
154
+
155
+ let callback = ShowCallbackImpl(placementId: placementId, delegate: delegate) { pid in
156
+ // Cleanup delegate wrapper after ad is dismissed or fails
157
+ delegateLock.lock()
158
+ activeDelegates.removeValue(forKey: pid)
159
+ delegateLock.unlock()
160
+ }
161
+
162
+ return orchestrator.showInterstitialAd(
163
+ from: viewController,
164
+ placementId: placementId,
165
+ callback: callback
166
+ )
167
+ }
168
+
169
+ /**
170
+ * Show a preloaded interstitial ad (legacy API)
171
+ *
172
+ * - Parameters:
173
+ * - viewController: The view controller to present the ad from
174
+ * - placementId: The placement ID
175
+ * - callback: Legacy callback for ad events
176
+ */
177
+ public static func show(
178
+ viewController: UIViewController,
179
+ placementId: String,
180
+ callback: Callback? = nil
181
+ ) {
182
+ let delegate: BigCrunchInterstitialDelegate? = callback.map { cb in
183
+ LegacyCallbackAdapter(callback: cb)
184
+ }
185
+ show(from: viewController, placementId: placementId, delegate: delegate)
186
+ }
187
+
188
+ // MARK: - Query Methods
189
+
190
+ /**
191
+ * Check if an interstitial ad is ready to show
192
+ *
193
+ * - Parameter placementId: The placement ID
194
+ * - Returns: true if an ad is preloaded and ready to show
195
+ */
196
+ public static func isReady(placementId: String) -> Bool {
197
+ // Check if orchestrator exists (which means SDK was initialized and preload was called)
198
+ guard let orchestrator = adOrchestrator else {
199
+ return false
200
+ }
201
+ return orchestrator.isInterstitialReady(placementId: placementId)
202
+ }
203
+
204
+ /**
205
+ * Clear all cached interstitial ads
206
+ *
207
+ * Call this to free up memory when ads are no longer needed.
208
+ */
209
+ public static func clearCache() {
210
+ BCLogger.debug("\(TAG): Clearing interstitial cache")
211
+ orchestratorLock.lock()
212
+ adOrchestrator?.clearCache()
213
+ orchestratorLock.unlock()
214
+ }
215
+
216
+ // MARK: - Private Methods
217
+
218
+ private static func getOrCreateOrchestrator() -> AdOrchestrator {
219
+ orchestratorLock.lock()
220
+ defer { orchestratorLock.unlock() }
221
+
222
+ if adOrchestrator == nil {
223
+ let configManager = BigCrunchAds.getConfigManager()
224
+ let analyticsClient = BigCrunchAds.getAnalyticsClient()
225
+ let googleAdsAdapter = GoogleAdsAdapter(analyticsClient: analyticsClient)
226
+
227
+ let bidRequestClient = BigCrunchAds.getBidRequestClient() ?? BidRequestClient(
228
+ httpClient: HTTPClient(),
229
+ configManager: configManager,
230
+ privacyStore: BigCrunchAds.privacyStore,
231
+ s2sConfig: S2SConfig(enabled: false, serverUrl: "", timeoutMs: 0)
232
+ )
233
+
234
+ adOrchestrator = AdOrchestrator(
235
+ configManager: configManager,
236
+ analyticsClient: analyticsClient,
237
+ bidRequestClient: bidRequestClient,
238
+ googleAdsAdapter: googleAdsAdapter
239
+ )
240
+ }
241
+ return adOrchestrator!
242
+ }
243
+
244
+ // MARK: - Testing Support
245
+
246
+ internal static func resetForTesting() {
247
+ orchestratorLock.lock()
248
+ adOrchestrator?.clearCache()
249
+ adOrchestrator = nil
250
+ orchestratorLock.unlock()
251
+
252
+ delegateLock.lock()
253
+ activeDelegates.removeAll()
254
+ delegateLock.unlock()
255
+ }
256
+ }
257
+
258
+ // MARK: - Delegate Protocol
259
+
260
+ /**
261
+ * Delegate protocol for BigCrunchInterstitial events
262
+ */
263
+ public protocol BigCrunchInterstitialDelegate: AnyObject {
264
+ /**
265
+ * Called when the interstitial ad is displayed on screen
266
+ */
267
+ func interstitialDidShow(placementId: String)
268
+
269
+ /**
270
+ * Called when the interstitial ad is dismissed by the user
271
+ */
272
+ func interstitialDidDismiss(placementId: String)
273
+
274
+ /**
275
+ * Called when the user clicks on the interstitial ad
276
+ */
277
+ func interstitialDidClick(placementId: String)
278
+
279
+ /**
280
+ * Called when the interstitial ad fails to show
281
+ */
282
+ func interstitialDidFail(placementId: String, error: String)
283
+ }
284
+
285
+ // MARK: - Default Implementations
286
+
287
+ public extension BigCrunchInterstitialDelegate {
288
+ func interstitialDidShow(placementId: String) {}
289
+ func interstitialDidDismiss(placementId: String) {}
290
+ func interstitialDidClick(placementId: String) {}
291
+ func interstitialDidFail(placementId: String, error: String) {}
292
+ }
293
+
294
+ // MARK: - Error Types
295
+
296
+ public enum BigCrunchError: Error, LocalizedError {
297
+ case notInitialized
298
+ case invalidPlacement(String)
299
+ case noAdAvailable
300
+ case loadFailed(String)
301
+
302
+ public var errorDescription: String? {
303
+ switch self {
304
+ case .notInitialized:
305
+ return "BigCrunchAds SDK not initialized. Call BigCrunchAds.initialize() first."
306
+ case .invalidPlacement(let message):
307
+ return "Invalid placement: \(message)"
308
+ case .noAdAvailable:
309
+ return "No ad available for this placement"
310
+ case .loadFailed(let message):
311
+ return "Failed to load ad: \(message)"
312
+ }
313
+ }
314
+ }
315
+
316
+ // MARK: - Private Helper Classes
317
+
318
+ private class InterstitialDelegateWrapper {
319
+ let placementId: String
320
+ weak var delegate: BigCrunchInterstitialDelegate?
321
+
322
+ init(placementId: String, delegate: BigCrunchInterstitialDelegate?) {
323
+ self.placementId = placementId
324
+ self.delegate = delegate
325
+ }
326
+ }
327
+
328
+ private class PreloadCallbackImpl: InterstitialCallback {
329
+ let placementId: String
330
+ let completion: ((Result<Void, Error>) -> Void)?
331
+
332
+ init(placementId: String, completion: ((Result<Void, Error>) -> Void)?) {
333
+ self.placementId = placementId
334
+ self.completion = completion
335
+ }
336
+
337
+ func onAdLoaded() {
338
+ BCLogger.debug("BigCrunchInterstitial: Interstitial preloaded: \(placementId)")
339
+ completion?(.success(()))
340
+ }
341
+
342
+ func onAdFailedToLoad(error: String) {
343
+ BCLogger.warning("BigCrunchInterstitial: Interstitial failed to preload: \(placementId) - \(error)")
344
+ completion?(.failure(BigCrunchError.loadFailed(error)))
345
+ }
346
+
347
+ func onAdShowed() {}
348
+ func onAdDismissed() {}
349
+ func onAdClicked() {}
350
+ }
351
+
352
+ private class ShowCallbackImpl: InterstitialCallback {
353
+ let placementId: String
354
+ weak var delegate: BigCrunchInterstitialDelegate?
355
+ let cleanup: (String) -> Void
356
+
357
+ init(placementId: String, delegate: BigCrunchInterstitialDelegate?, cleanup: @escaping (String) -> Void) {
358
+ self.placementId = placementId
359
+ self.delegate = delegate
360
+ self.cleanup = cleanup
361
+ }
362
+
363
+ func onAdLoaded() {
364
+ // Not used during show
365
+ }
366
+
367
+ func onAdFailedToLoad(error: String) {
368
+ BCLogger.warning("BigCrunchInterstitial: Interstitial failed to show: \(placementId) - \(error)")
369
+ delegate?.interstitialDidFail(placementId: placementId, error: error)
370
+ cleanup(placementId)
371
+ }
372
+
373
+ func onAdShowed() {
374
+ BCLogger.debug("BigCrunchInterstitial: Interstitial showed: \(placementId)")
375
+ delegate?.interstitialDidShow(placementId: placementId)
376
+ }
377
+
378
+ func onAdDismissed() {
379
+ BCLogger.debug("BigCrunchInterstitial: Interstitial dismissed: \(placementId)")
380
+ delegate?.interstitialDidDismiss(placementId: placementId)
381
+ cleanup(placementId)
382
+ }
383
+
384
+ func onAdClicked() {
385
+ BCLogger.debug("BigCrunchInterstitial: Interstitial clicked: \(placementId)")
386
+ delegate?.interstitialDidClick(placementId: placementId)
387
+ }
388
+ }
389
+
390
+ private class LegacyCallbackAdapter: BigCrunchInterstitialDelegate {
391
+ let callback: BigCrunchInterstitial.Callback
392
+
393
+ init(callback: BigCrunchInterstitial.Callback) {
394
+ self.callback = callback
395
+ }
396
+
397
+ func interstitialDidShow(placementId: String) {
398
+ callback.onAdShown()
399
+ }
400
+
401
+ func interstitialDidDismiss(placementId: String) {
402
+ callback.onAdDismissed()
403
+ }
404
+
405
+ func interstitialDidClick(placementId: String) {
406
+ // Not in legacy callback
407
+ }
408
+
409
+ func interstitialDidFail(placementId: String, error: String) {
410
+ callback.onAdFailed(error: error)
411
+ }
412
+ }