@bigcrunch/react-native-ads 0.4.0 → 0.6.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 (58) 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 +300 -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 +87 -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 +8 -2
  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 +305 -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 +97 -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 +37 -9
  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/package.json +7 -1
  56. package/react-native-bigcrunch-ads.podspec +0 -1
  57. package/scripts/inject-version.js +55 -0
  58. package/src/index.ts +3 -2
package/README.md CHANGED
@@ -1,12 +1,12 @@
1
1
  # BigCrunch Mobile Ads SDK for React Native
2
2
 
3
- Simplified in-app advertising for React Native apps with Prebid and Google Ad Manager integration.
3
+ Simplified in-app advertising for React Native apps with S2S demand and Google Ad Manager integration.
4
4
 
5
5
  ## Features
6
6
 
7
- - **Simple Integration**: One SDK to handle Prebid, Google Ad Manager, and Amazon demand
7
+ - **Simple Integration**: One SDK to handle S2S demand, Google Ad Manager, and Amazon integration
8
8
  - **Built-in Analytics**: Automatic tracking of screen views, impressions, clicks, and revenue
9
- - **Revenue Optimization**: Server-side header bidding via Prebid Server
9
+ - **Revenue Optimization**: Server-side header bidding via BigCrunch S2S
10
10
  - **Configuration-Driven**: Manage placements and ad sizes from the BigCrunch dashboard
11
11
  - **Cross-Platform**: Supports both iOS and Android
12
12
  - **Ad Formats**: Banner, Interstitial, and Rewarded ads
@@ -137,7 +137,7 @@ function ArticleScreen() {
137
137
  | Prop | Type | Default | Description |
138
138
  |------|------|---------|-------------|
139
139
  | `placementId` | `string` | *required* | Placement ID from the BigCrunch dashboard |
140
- | `size` | `BannerSize \| { width, height }` | *from config* | Optional size override. If omitted, uses the size from placement config. |
140
+ | `size` | `BannerSize \| { width, height }` | `'BANNER'` | Banner size. Defaults to standard 320x50. |
141
141
  | `autoLoad` | `boolean` | `true` | Automatically load ad on mount |
142
142
  | `refreshInterval` | `number` | `0` | Auto-refresh interval in seconds (0 = disabled) |
143
143
  | `customTargeting` | `Record<string, string>` | — | Custom key-value targeting |
@@ -316,7 +316,7 @@ console.log('SDK initialized:', isReady);
316
316
  // Get session information
317
317
  const session = await BigCrunchAds.getSessionInfo();
318
318
  console.log('Session ID:', session.sessionId);
319
- console.log('Screen views:', session.screenViewCount);
319
+ console.log('Session depth:', session.sessionDepth);
320
320
 
321
321
  // Enable debug logging during development
322
322
  await BigCrunchAds.setDebugMode(true);
@@ -0,0 +1,434 @@
1
+ package com.bigcrunch.ads
2
+
3
+ import android.content.Context
4
+ import com.bigcrunch.ads.core.AnalyticsClient
5
+ import com.bigcrunch.ads.core.BidRequestClient
6
+ import com.bigcrunch.ads.core.ConfigManager
7
+ import com.bigcrunch.ads.core.SessionManager
8
+ import com.bigcrunch.ads.internal.BCLogger
9
+ import com.bigcrunch.ads.internal.DeviceHelper
10
+ import com.bigcrunch.ads.internal.HttpClient
11
+ import com.bigcrunch.ads.internal.PrivacyStore
12
+ import com.bigcrunch.ads.internal.SharedPreferencesStore
13
+ import com.bigcrunch.ads.models.AppConfig
14
+ import com.bigcrunch.ads.models.DeviceData
15
+ import com.bigcrunch.ads.models.SessionInfo
16
+ import com.google.android.gms.ads.MobileAds
17
+ import com.google.android.gms.ads.RequestConfiguration
18
+ import com.squareup.moshi.Moshi
19
+ import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory
20
+ import kotlinx.coroutines.CoroutineScope
21
+ import kotlinx.coroutines.Dispatchers
22
+ import kotlinx.coroutines.SupervisorJob
23
+ import kotlinx.coroutines.launch
24
+ import kotlinx.coroutines.CompletableDeferred
25
+
26
+ /**
27
+ * BigCrunch Mobile Ads SDK - Main entry point
28
+ *
29
+ * Initialize the SDK before using any ad components:
30
+ * ```
31
+ * BigCrunchAds.initialize(
32
+ * context = applicationContext,
33
+ * propertyId = "your-property-id"
34
+ * )
35
+ * ```
36
+ */
37
+ object BigCrunchAds {
38
+
39
+ private const val TAG = "BigCrunchAds"
40
+
41
+ enum class Environment {
42
+ Prod, Staging
43
+ }
44
+
45
+ /**
46
+ * Safely execute a block of code, catching any exceptions to prevent SDK errors
47
+ * from crashing the host app. Used for public API methods.
48
+ */
49
+ private inline fun <T> runSafely(default: T, block: () -> T): T {
50
+ return try {
51
+ block()
52
+ } catch (e: Exception) {
53
+ BCLogger.e(TAG, "SDK exception caught - will not propagate to prevent app crash", e)
54
+ default
55
+ }
56
+ }
57
+
58
+ /**
59
+ * Safely execute a Unit-returning block, catching any exceptions.
60
+ */
61
+ private inline fun runSafely(block: () -> Unit) {
62
+ try {
63
+ block()
64
+ } catch (e: Exception) {
65
+ BCLogger.e(TAG, "SDK exception caught - will not propagate to prevent app crash", e)
66
+ }
67
+ }
68
+
69
+ private var initialized = false
70
+ private var configReady = false
71
+ private val configDeferred = CompletableDeferred<Boolean>()
72
+ private lateinit var appContext: Context
73
+ private lateinit var configManager: ConfigManager
74
+ private lateinit var analyticsClient: AnalyticsClient
75
+ private val initScope = CoroutineScope(Dispatchers.Main + SupervisorJob())
76
+ private var debugMode = false
77
+ private val testDeviceIds = mutableSetOf<String>()
78
+ internal lateinit var privacyStore: PrivacyStore
79
+ private set
80
+ internal var bidRequestClient: BidRequestClient? = null
81
+ private set
82
+
83
+ internal var propertyId: String = ""
84
+ private set
85
+ internal var environment: Environment = Environment.Prod
86
+ private set
87
+
88
+ /**
89
+ * Callback interface for SDK initialization completion
90
+ */
91
+ interface InitializationCallback {
92
+ /**
93
+ * Called when SDK initialization is complete and config is ready
94
+ */
95
+ fun onInitialized()
96
+
97
+ /**
98
+ * Called if SDK initialization fails
99
+ * @param error Error message describing the failure
100
+ */
101
+ fun onInitializationFailed(error: String)
102
+ }
103
+
104
+ /**
105
+ * Initialize the BigCrunch Ads SDK
106
+ *
107
+ * @param context Application context
108
+ * @param propertyId Your BigCrunch property ID
109
+ * @param env Environment (Prod or Staging)
110
+ * @param useMockConfig If true, uses hardcoded mock config for testing (default: false)
111
+ * @param callback Optional callback to be notified when initialization is complete
112
+ */
113
+ fun initialize(
114
+ context: Context,
115
+ propertyId: String,
116
+ env: Environment = Environment.Prod,
117
+ useMockConfig: Boolean = false,
118
+ callback: InitializationCallback? = null
119
+ ) {
120
+ if (initialized) {
121
+ BCLogger.w("BigCrunchAds", "SDK already initialized, ignoring duplicate call")
122
+ return
123
+ }
124
+
125
+ BCLogger.i("BigCrunchAds", "BigCrunch Ads SDK v${com.bigcrunch.ads.core.DeviceContext.SDK_VERSION} initializing...")
126
+ BCLogger.d("BigCrunchAds", "Property ID: $propertyId, Environment: $env")
127
+
128
+ // Store initialization parameters
129
+ this.appContext = context.applicationContext
130
+ this.propertyId = propertyId
131
+ this.environment = env
132
+
133
+ // Initialize Google Mobile Ads SDK
134
+ BCLogger.d("BigCrunchAds", "Initializing Google Mobile Ads SDK...")
135
+ MobileAds.initialize(appContext) { initStatus ->
136
+ BCLogger.d("BigCrunchAds", "Google Mobile Ads initialized: ${initStatus.adapterStatusMap}")
137
+ }
138
+
139
+ // Initialize device context FIRST - must be done synchronously before anything else
140
+ BCLogger.d("BigCrunchAds", "Initializing device context...")
141
+ com.bigcrunch.ads.core.DeviceContext.initialize(appContext)
142
+
143
+ // Enable verbose logging in staging
144
+ if (env == Environment.Staging) {
145
+ BCLogger.isEnabled = true
146
+ }
147
+
148
+ // Create internal components
149
+ val httpClient = HttpClient()
150
+ val storage = SharedPreferencesStore(appContext)
151
+ val moshi = Moshi.Builder()
152
+ .add(KotlinJsonAdapterFactory())
153
+ .build()
154
+
155
+ // Initialize session manager
156
+ BCLogger.d("BigCrunchAds", "Initializing session manager...")
157
+ SessionManager.initialize(storage)
158
+
159
+ // Analytics always uses pipeline.bigcrunch.com for both prod and staging
160
+ val baseUrl = "https://pipeline.bigcrunch.com"
161
+
162
+ configManager = ConfigManager(httpClient, storage, moshi)
163
+ analyticsClient = AnalyticsClient(appContext, httpClient, moshi, baseUrl)
164
+ privacyStore = PrivacyStore(appContext)
165
+
166
+ // Mark as initialized (but not config ready yet)
167
+ initialized = true
168
+
169
+ // Kick off async config fetch
170
+ BCLogger.d("BigCrunchAds", "Fetching app configuration...")
171
+ initScope.launch {
172
+ val result = configManager.loadConfig(
173
+ propertyId = propertyId,
174
+ isProd = env == Environment.Prod,
175
+ useMockConfig = useMockConfig
176
+ )
177
+
178
+ when {
179
+ result.isSuccess -> {
180
+ val config = result.getOrNull()
181
+ if (config == null) {
182
+ BCLogger.e(TAG, "Config was null despite success result")
183
+ configDeferred.complete(false)
184
+ callback?.onInitializationFailed("Internal error: config was null")
185
+ return@launch
186
+ }
187
+ BCLogger.d(TAG, "Configuration loaded successfully")
188
+ BCLogger.v(TAG, "Placements: ${config.placements.size}")
189
+
190
+ // Create shared BidRequestClient for S2S demand
191
+ if (config.s2s.enabled) {
192
+ bidRequestClient = BidRequestClient(
193
+ httpClient = httpClient,
194
+ configManager = configManager,
195
+ privacyStore = privacyStore,
196
+ s2sConfig = config.s2s
197
+ )
198
+ BCLogger.d(TAG, "BidRequestClient created: ${config.s2s.serverUrl}")
199
+ } else {
200
+ BCLogger.d(TAG, "S2S is disabled in config")
201
+ }
202
+
203
+ // Mark config as ready and complete the deferred
204
+ configReady = true
205
+ configDeferred.complete(true)
206
+
207
+ // Notify callback of successful initialization
208
+ callback?.onInitialized()
209
+ }
210
+ result.isFailure -> {
211
+ val error = result.exceptionOrNull()?.message ?: "Unknown error"
212
+ BCLogger.e(TAG, "Failed to load configuration", result.exceptionOrNull())
213
+ // Complete the deferred even on failure so waiters don't hang
214
+ configDeferred.complete(false)
215
+
216
+ // Notify callback of initialization failure
217
+ callback?.onInitializationFailed(error)
218
+ }
219
+ }
220
+ }
221
+
222
+ BCLogger.d("BigCrunchAds", "BigCrunch Ads SDK initialization complete")
223
+ }
224
+
225
+ /**
226
+ * Track screen view for analytics
227
+ *
228
+ * @param screenName Name of the screen being viewed
229
+ */
230
+ fun trackScreen(screenName: String) = runSafely {
231
+ if (!initialized) {
232
+ BCLogger.w(TAG, "trackScreen called before initialization, ignoring")
233
+ return@runSafely
234
+ }
235
+ analyticsClient.trackScreenView(screenName)
236
+ SessionManager.incrementScreenViewCount()
237
+ }
238
+
239
+ /**
240
+ * Track screen view for analytics (alias for React Native compatibility)
241
+ *
242
+ * @param screenName Name of the screen being viewed
243
+ */
244
+ fun trackScreenView(screenName: String) = runSafely {
245
+ trackScreen(screenName)
246
+ }
247
+
248
+ /**
249
+ * Check if the SDK has been initialized
250
+ *
251
+ * @return true if initialized, false otherwise
252
+ */
253
+ fun isInitialized(): Boolean = initialized
254
+
255
+ /**
256
+ * Check if configuration has been loaded
257
+ *
258
+ * @return true if configuration has been successfully loaded
259
+ */
260
+ fun isConfigReady(): Boolean = configReady
261
+
262
+ /**
263
+ * Wait for configuration to be loaded
264
+ *
265
+ * This suspends until the configuration is loaded or fails to load.
266
+ * Returns true if config loaded successfully, false otherwise.
267
+ *
268
+ * @return true if configuration loaded successfully
269
+ */
270
+ suspend fun waitForConfig(): Boolean {
271
+ return configDeferred.await()
272
+ }
273
+
274
+ /**
275
+ * Get the current app configuration
276
+ *
277
+ * @return The app configuration, or null if not yet loaded
278
+ */
279
+ fun getAppConfig(): AppConfig? {
280
+ return if (initialized) {
281
+ configManager.getCachedConfig()
282
+ } else {
283
+ null
284
+ }
285
+ }
286
+
287
+ /**
288
+ * Refresh the app configuration from the server
289
+ */
290
+ suspend fun refreshConfig() {
291
+ if (!initialized) {
292
+ BCLogger.w("BigCrunchAds", "refreshConfig called before initialization")
293
+ return
294
+ }
295
+ configManager.loadConfig(
296
+ propertyId = propertyId,
297
+ isProd = environment == Environment.Prod,
298
+ useMockConfig = false
299
+ )
300
+ }
301
+
302
+ /**
303
+ * Get current session information
304
+ *
305
+ * @return Session info with tracking counts
306
+ */
307
+ fun getSessionInfo(): SessionInfo {
308
+ return SessionInfo(
309
+ sessionId = SessionManager.getSessionId(),
310
+ startTime = SessionManager.getSessionStartTime(),
311
+ screenViewCount = SessionManager.getScreenViewCount(),
312
+ adRequestCount = SessionManager.getAdRequestCount(),
313
+ adImpressionCount = SessionManager.getAdImpressionCount(),
314
+ totalRevenueMicros = SessionManager.getTotalRevenueMicros()
315
+ )
316
+ }
317
+
318
+ /**
319
+ * Start a new session (resets all counters)
320
+ */
321
+ fun startNewSession() {
322
+ SessionManager.startNewSession()
323
+ }
324
+
325
+ /**
326
+ * Get device data
327
+ *
328
+ * @return Device data with device information
329
+ */
330
+ fun getDeviceData(): DeviceData? = runSafely(null) {
331
+ requireInitialized()
332
+ DeviceHelper.getDeviceData(appContext)
333
+ }
334
+
335
+ /**
336
+ * Set GDPR consent string for privacy compliance
337
+ *
338
+ * @param consent GDPR consent string
339
+ */
340
+ fun setGdprConsent(consent: String) = runSafely {
341
+ privacyStore.setGdprConsent(consent)
342
+ BCLogger.d(TAG, "GDPR consent set")
343
+ }
344
+
345
+ /**
346
+ * Set CCPA string for privacy compliance
347
+ *
348
+ * @param ccpaString CCPA consent string
349
+ */
350
+ fun setCcpaString(ccpaString: String) = runSafely {
351
+ privacyStore.setCcpaString(ccpaString)
352
+ BCLogger.d(TAG, "CCPA string set: $ccpaString")
353
+ }
354
+
355
+ /**
356
+ * Set COPPA compliance flag
357
+ *
358
+ * @param isCompliant true if the app should comply with COPPA
359
+ */
360
+ fun setCoppaCompliant(isCompliant: Boolean) = runSafely {
361
+ privacyStore.setCoppaApplies(isCompliant)
362
+ val config = RequestConfiguration.Builder()
363
+ .setTagForChildDirectedTreatment(
364
+ if (isCompliant) RequestConfiguration.TAG_FOR_CHILD_DIRECTED_TREATMENT_TRUE
365
+ else RequestConfiguration.TAG_FOR_CHILD_DIRECTED_TREATMENT_FALSE
366
+ )
367
+ .build()
368
+ MobileAds.setRequestConfiguration(config)
369
+ BCLogger.d(TAG, "COPPA compliance set to: $isCompliant")
370
+ }
371
+
372
+ /**
373
+ * Enable or disable debug mode
374
+ *
375
+ * @param enabled true to enable debug logging
376
+ */
377
+ fun setDebugMode(enabled: Boolean) = runSafely {
378
+ debugMode = enabled
379
+ BCLogger.isEnabled = enabled
380
+ BCLogger.d(TAG, "Debug mode set to: $enabled")
381
+ }
382
+
383
+ /**
384
+ * Add a test device ID for Google Ads testing
385
+ *
386
+ * @param deviceId Test device ID from Google Ads logs
387
+ */
388
+ fun addTestDevice(deviceId: String) = runSafely {
389
+ testDeviceIds.add(deviceId)
390
+ updateTestDeviceConfiguration()
391
+ BCLogger.d(TAG, "Added test device: $deviceId")
392
+ }
393
+
394
+ /**
395
+ * Remove a test device ID
396
+ *
397
+ * @param deviceId Test device ID to remove
398
+ */
399
+ fun removeTestDevice(deviceId: String) = runSafely {
400
+ testDeviceIds.remove(deviceId)
401
+ updateTestDeviceConfiguration()
402
+ BCLogger.d(TAG, "Removed test device: $deviceId")
403
+ }
404
+
405
+ /**
406
+ * Get list of test device IDs
407
+ *
408
+ * @return List of currently configured test device IDs
409
+ */
410
+ fun getTestDevices(): List<String> = testDeviceIds.toList()
411
+
412
+ private fun updateTestDeviceConfiguration() {
413
+ val config = RequestConfiguration.Builder()
414
+ .setTestDeviceIds(testDeviceIds.toList())
415
+ .build()
416
+ MobileAds.setRequestConfiguration(config)
417
+ }
418
+
419
+ internal fun requireInitialized() {
420
+ check(initialized) {
421
+ "BigCrunchAds SDK not initialized. Call BigCrunchAds.initialize() first."
422
+ }
423
+ }
424
+
425
+ internal fun getConfigManager(): ConfigManager {
426
+ requireInitialized()
427
+ return configManager
428
+ }
429
+
430
+ internal fun getAnalyticsClient(): AnalyticsClient {
431
+ requireInitialized()
432
+ return analyticsClient
433
+ }
434
+ }