@bigcrunch/react-native-ads 0.14.0 → 0.15.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/android/bigcrunch-ads/com/bigcrunch/ads/adapters/GoogleAdsAdapter.kt +6 -3
- package/android/bigcrunch-ads/com/bigcrunch/ads/core/AnalyticsClient.kt +13 -9
- package/android/bigcrunch-ads/com/bigcrunch/ads/core/BidRequestClient.kt +11 -7
- package/android/bigcrunch-ads/com/bigcrunch/ads/core/ConfigManager.kt +25 -4
- package/android/bigcrunch-ads/com/bigcrunch/ads/core/DeviceContext.kt +1 -1
- package/android/bigcrunch-ads/com/bigcrunch/ads/models/AdEvent.kt +2 -0
- package/android/bigcrunch-ads/com/bigcrunch/ads/models/PlacementConfig.kt +3 -0
- package/android/src/main/java/com/bigcrunch/ads/react/BigCrunchAdsModule.kt +1 -1
- package/ios/BigCrunchAds/Sources/Adapters/GoogleAdsAdapter.swift +4 -0
- package/ios/BigCrunchAds/Sources/BigCrunchRewarded.swift +2 -0
- package/ios/BigCrunchAds/Sources/Core/AnalyticsClient.swift +13 -9
- package/ios/BigCrunchAds/Sources/Core/BidRequestClient.swift +11 -7
- package/ios/BigCrunchAds/Sources/Core/ConfigManager.swift +60 -3
- package/ios/BigCrunchAds/Sources/Core/DeviceContext.swift +1 -1
- package/ios/BigCrunchAds/Sources/Models/AdEvent.swift +4 -0
- package/ios/BigCrunchAds/Sources/Models/PlacementConfig.swift +3 -0
- package/lib/types/config.d.ts +3 -1
- package/lib/types/config.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/types/config.ts +3 -1
|
@@ -238,6 +238,7 @@ internal class GoogleAdsAdapter(
|
|
|
238
238
|
|
|
239
239
|
analyticsClient.trackAdImpression(
|
|
240
240
|
placementId = placementConfig.placementId,
|
|
241
|
+
slotId = placementConfig.id,
|
|
241
242
|
format = placementConfig.format,
|
|
242
243
|
gamAdUnit = placementConfig.gamAdUnit,
|
|
243
244
|
adSize = adSizeString,
|
|
@@ -257,7 +258,7 @@ internal class GoogleAdsAdapter(
|
|
|
257
258
|
|
|
258
259
|
override fun onAdClicked() {
|
|
259
260
|
BCLogger.d(TAG, "Banner ad clicked: ${placementConfig.placementId}")
|
|
260
|
-
analyticsClient.trackAdClick(placementConfig.placementId, placementConfig.format)
|
|
261
|
+
analyticsClient.trackAdClick(placementConfig.placementId, placementConfig.id, placementConfig.format)
|
|
261
262
|
safeCallback { callback.onAdClicked() }
|
|
262
263
|
}
|
|
263
264
|
|
|
@@ -398,6 +399,7 @@ internal class GoogleAdsAdapter(
|
|
|
398
399
|
|
|
399
400
|
analyticsClient.trackAdImpression(
|
|
400
401
|
placementId = placementConfig.placementId,
|
|
402
|
+
slotId = placementConfig.id,
|
|
401
403
|
format = placementConfig.format,
|
|
402
404
|
gamAdUnit = placementConfig.gamAdUnit,
|
|
403
405
|
advertiserId = adMetadata["advertiser_id"] as? String,
|
|
@@ -420,7 +422,7 @@ internal class GoogleAdsAdapter(
|
|
|
420
422
|
|
|
421
423
|
override fun onAdClicked() {
|
|
422
424
|
BCLogger.d(TAG, "Interstitial ad clicked: ${placementConfig.placementId}")
|
|
423
|
-
analyticsClient.trackAdClick(placementConfig.placementId, placementConfig.format)
|
|
425
|
+
analyticsClient.trackAdClick(placementConfig.placementId, placementConfig.id, placementConfig.format)
|
|
424
426
|
safeCallback { callback.onAdClicked() }
|
|
425
427
|
}
|
|
426
428
|
|
|
@@ -506,6 +508,7 @@ internal class GoogleAdsAdapter(
|
|
|
506
508
|
|
|
507
509
|
analyticsClient.trackAdImpression(
|
|
508
510
|
placementId = placementConfig.placementId,
|
|
511
|
+
slotId = placementConfig.id,
|
|
509
512
|
format = placementConfig.format,
|
|
510
513
|
gamAdUnit = placementConfig.gamAdUnit,
|
|
511
514
|
advertiserId = adMetadata["advertiser_id"] as? String,
|
|
@@ -528,7 +531,7 @@ internal class GoogleAdsAdapter(
|
|
|
528
531
|
|
|
529
532
|
override fun onAdClicked() {
|
|
530
533
|
BCLogger.d(TAG, "Rewarded ad clicked: ${placementConfig.placementId}")
|
|
531
|
-
analyticsClient.trackAdClick(placementConfig.placementId, placementConfig.format)
|
|
534
|
+
analyticsClient.trackAdClick(placementConfig.placementId, placementConfig.id, placementConfig.format)
|
|
532
535
|
safeCallback { callback.onAdClicked() }
|
|
533
536
|
}
|
|
534
537
|
|
|
@@ -293,6 +293,7 @@ internal class AnalyticsClient(
|
|
|
293
293
|
*/
|
|
294
294
|
fun createImpressionContext(
|
|
295
295
|
placementId: String,
|
|
296
|
+
slotId: String,
|
|
296
297
|
gamAdUnit: String,
|
|
297
298
|
format: String,
|
|
298
299
|
width: Int? = null,
|
|
@@ -300,6 +301,7 @@ internal class AnalyticsClient(
|
|
|
300
301
|
): ImpressionContext {
|
|
301
302
|
val context = ImpressionContext(
|
|
302
303
|
placementId = placementId,
|
|
304
|
+
slotId = slotId,
|
|
303
305
|
gamAdUnit = gamAdUnit,
|
|
304
306
|
format = format,
|
|
305
307
|
width = width,
|
|
@@ -396,7 +398,7 @@ internal class AnalyticsClient(
|
|
|
396
398
|
|
|
397
399
|
// Create impression record with auction data fields populated
|
|
398
400
|
val impressionRecord = ImpressionRecord(
|
|
399
|
-
slotId = context.
|
|
401
|
+
slotId = context.slotId,
|
|
400
402
|
gamUnit = context.gamAdUnit,
|
|
401
403
|
gamPriceBucket = effectiveAuctionData.gamPriceBucket ?: "",
|
|
402
404
|
impressionId = context.impressionId,
|
|
@@ -458,6 +460,7 @@ internal class AnalyticsClient(
|
|
|
458
460
|
*/
|
|
459
461
|
fun trackAdImpression(
|
|
460
462
|
placementId: String,
|
|
463
|
+
slotId: String,
|
|
461
464
|
format: String,
|
|
462
465
|
gamAdUnit: String = "",
|
|
463
466
|
adSize: String = "",
|
|
@@ -482,7 +485,7 @@ internal class AnalyticsClient(
|
|
|
482
485
|
|
|
483
486
|
// Create impression record with auction data fields populated
|
|
484
487
|
val impressionRecord = ImpressionRecord(
|
|
485
|
-
slotId =
|
|
488
|
+
slotId = slotId,
|
|
486
489
|
gamUnit = gamAdUnit,
|
|
487
490
|
gamPriceBucket = auctionData?.gamPriceBucket ?: "",
|
|
488
491
|
impressionId = UUID.randomUUID().toString(),
|
|
@@ -552,7 +555,7 @@ internal class AnalyticsClient(
|
|
|
552
555
|
* @param placementId Placement ID
|
|
553
556
|
* @param format Ad format
|
|
554
557
|
*/
|
|
555
|
-
fun trackAdClick(impressionId: String, placementId: String, format: String) {
|
|
558
|
+
fun trackAdClick(impressionId: String, placementId: String, slotId: String, format: String) {
|
|
556
559
|
// Get common event fields
|
|
557
560
|
val common = getCommonEventFields()
|
|
558
561
|
|
|
@@ -562,7 +565,7 @@ internal class AnalyticsClient(
|
|
|
562
565
|
// Create nested click data - impressionId must be valid UUID
|
|
563
566
|
val clickData = ClickData(
|
|
564
567
|
clickId = UUID.randomUUID().toString(),
|
|
565
|
-
slotId =
|
|
568
|
+
slotId = slotId,
|
|
566
569
|
impressionId = impressionId.takeIf { it.isNotEmpty() } ?: UUID.randomUUID().toString()
|
|
567
570
|
)
|
|
568
571
|
|
|
@@ -607,8 +610,8 @@ internal class AnalyticsClient(
|
|
|
607
610
|
/**
|
|
608
611
|
* Track an ad click (simple version without impression ID)
|
|
609
612
|
*/
|
|
610
|
-
fun trackAdClick(placementId: String, format: String) {
|
|
611
|
-
trackAdClick("", placementId, format)
|
|
613
|
+
fun trackAdClick(placementId: String, slotId: String, format: String) {
|
|
614
|
+
trackAdClick("", placementId, slotId, format)
|
|
612
615
|
}
|
|
613
616
|
|
|
614
617
|
// MARK: - Viewability Tracking
|
|
@@ -625,6 +628,7 @@ internal class AnalyticsClient(
|
|
|
625
628
|
fun trackAdViewable(
|
|
626
629
|
impressionId: String,
|
|
627
630
|
placementId: String,
|
|
631
|
+
slotId: String,
|
|
628
632
|
format: String,
|
|
629
633
|
viewableTimeMs: Long,
|
|
630
634
|
percentVisible: Int
|
|
@@ -637,7 +641,7 @@ internal class AnalyticsClient(
|
|
|
637
641
|
|
|
638
642
|
// Create nested viewability data - impressionId must be valid UUID
|
|
639
643
|
val viewabilityData = ViewabilityData(
|
|
640
|
-
slotId =
|
|
644
|
+
slotId = slotId,
|
|
641
645
|
impressionId = impressionId.takeIf { it.isNotEmpty() } ?: UUID.randomUUID().toString()
|
|
642
646
|
)
|
|
643
647
|
|
|
@@ -682,8 +686,8 @@ internal class AnalyticsClient(
|
|
|
682
686
|
/**
|
|
683
687
|
* Track ad viewability (simple version without metrics)
|
|
684
688
|
*/
|
|
685
|
-
fun trackAdViewable(placementId: String, format: String) {
|
|
686
|
-
trackAdViewable("", placementId, format, 0, 0)
|
|
689
|
+
fun trackAdViewable(placementId: String, slotId: String, format: String) {
|
|
690
|
+
trackAdViewable("", placementId, slotId, format, 0, 0)
|
|
687
691
|
}
|
|
688
692
|
|
|
689
693
|
// MARK: - Engagement Tracking
|
|
@@ -188,7 +188,7 @@ internal class BidRequestClient(
|
|
|
188
188
|
|
|
189
189
|
private fun buildImp(placement: PlacementConfig): JSONObject {
|
|
190
190
|
val imp = JSONObject()
|
|
191
|
-
imp.put("id", placement.
|
|
191
|
+
imp.put("id", placement.id)
|
|
192
192
|
|
|
193
193
|
val deviceContext = DeviceContext.getInstance()
|
|
194
194
|
|
|
@@ -268,7 +268,8 @@ internal class BidRequestClient(
|
|
|
268
268
|
*/
|
|
269
269
|
private fun buildBiddersExt(placements: List<PlacementConfig>): JSONObject {
|
|
270
270
|
val bidders = configManager.getCachedConfig()?.bidders ?: return JSONObject()
|
|
271
|
-
val
|
|
271
|
+
val placementIdToUuid = placements.associate { it.placementId to it.id }
|
|
272
|
+
val placementIds = placementIdToUuid.keys
|
|
272
273
|
val biddersExt = JSONObject()
|
|
273
274
|
|
|
274
275
|
for ((bidderName, bidderEntry) in bidders) {
|
|
@@ -285,7 +286,7 @@ internal class BidRequestClient(
|
|
|
285
286
|
for (placementId in placementIds) {
|
|
286
287
|
bidderPlacements[placementId]?.let { impParams ->
|
|
287
288
|
impArray.put(JSONObject().apply {
|
|
288
|
-
put("impid", placementId)
|
|
289
|
+
put("impid", placementIdToUuid[placementId])
|
|
289
290
|
put("params", mapToJson(impParams))
|
|
290
291
|
})
|
|
291
292
|
}
|
|
@@ -316,8 +317,9 @@ internal class BidRequestClient(
|
|
|
316
317
|
|
|
317
318
|
val auctionId = json.optString("id", "")
|
|
318
319
|
|
|
319
|
-
// Build floor price lookup
|
|
320
|
-
val floorPrices = placements.associate { it.
|
|
320
|
+
// Build floor price lookup and UUID-to-placementId mapping
|
|
321
|
+
val floorPrices = placements.associate { it.id to it.floorPrice }
|
|
322
|
+
val uuidToPlacementId = placements.associate { it.id to it.placementId }
|
|
321
323
|
|
|
322
324
|
// Collect all bids grouped by impid
|
|
323
325
|
data class BidInfo(
|
|
@@ -376,8 +378,10 @@ internal class BidRequestClient(
|
|
|
376
378
|
demandChannel = "S2S"
|
|
377
379
|
)
|
|
378
380
|
|
|
379
|
-
|
|
380
|
-
|
|
381
|
+
// Re-key from UUID to placementId for internal use
|
|
382
|
+
val placementId = uuidToPlacementId[impid] ?: impid
|
|
383
|
+
results[placementId] = BidResponse(winner.targeting, auctionData)
|
|
384
|
+
BCLogger.d(TAG, "Winner for $placementId: $${winner.price}")
|
|
381
385
|
}
|
|
382
386
|
|
|
383
387
|
BCLogger.i(TAG, "Parsed ${results.size} winning bids")
|
|
@@ -5,10 +5,14 @@ import com.bigcrunch.ads.internal.HttpClient
|
|
|
5
5
|
import com.bigcrunch.ads.internal.KeyValueStore
|
|
6
6
|
import com.bigcrunch.ads.models.AppConfig
|
|
7
7
|
import com.bigcrunch.ads.models.PlacementConfig
|
|
8
|
+
import com.squareup.moshi.JsonDataException
|
|
9
|
+
import com.squareup.moshi.JsonEncodingException
|
|
8
10
|
import com.squareup.moshi.Moshi
|
|
9
11
|
import kotlinx.coroutines.sync.Mutex
|
|
10
12
|
import kotlinx.coroutines.sync.withLock
|
|
11
13
|
|
|
14
|
+
class ConfigParseException(message: String, cause: Throwable? = null) : Exception(message, cause)
|
|
15
|
+
|
|
12
16
|
/**
|
|
13
17
|
* Manages application configuration fetching, caching, and access
|
|
14
18
|
*
|
|
@@ -61,12 +65,14 @@ internal class ConfigManager(
|
|
|
61
65
|
refresh = com.bigcrunch.ads.models.RefreshConfig(enabled = true, intervalMs = 30000, maxRefreshes = 20),
|
|
62
66
|
placements = listOf(
|
|
63
67
|
PlacementConfig(
|
|
68
|
+
id = "00000000-0000-0000-0000-000000000001",
|
|
64
69
|
placementId = "test_banner_320x50",
|
|
65
70
|
format = "banner",
|
|
66
71
|
gamAdUnit = "ca-app-pub-3940256099942544/6300978111",
|
|
67
72
|
sizes = listOf(com.bigcrunch.ads.models.AdSize(width = 320, height = 50))
|
|
68
73
|
),
|
|
69
74
|
PlacementConfig(
|
|
75
|
+
id = "00000000-0000-0000-0000-000000000002",
|
|
70
76
|
placementId = "test_mrec",
|
|
71
77
|
format = "banner",
|
|
72
78
|
gamAdUnit = "ca-app-pub-3940256099942544/6300978111",
|
|
@@ -74,18 +80,21 @@ internal class ConfigManager(
|
|
|
74
80
|
refresh = com.bigcrunch.ads.models.RefreshConfig(enabled = true, intervalMs = 15000, maxRefreshes = 40)
|
|
75
81
|
),
|
|
76
82
|
PlacementConfig(
|
|
83
|
+
id = "00000000-0000-0000-0000-000000000003",
|
|
77
84
|
placementId = "test_adaptive_banner",
|
|
78
85
|
format = "banner",
|
|
79
86
|
gamAdUnit = "ca-app-pub-3940256099942544/6300978111",
|
|
80
87
|
sizes = listOf(com.bigcrunch.ads.models.AdSize.adaptive())
|
|
81
88
|
),
|
|
82
89
|
PlacementConfig(
|
|
90
|
+
id = "00000000-0000-0000-0000-000000000004",
|
|
83
91
|
placementId = "test_interstitial",
|
|
84
92
|
format = "interstitial",
|
|
85
93
|
gamAdUnit = "ca-app-pub-3940256099942544/1033173712",
|
|
86
94
|
sizes = null
|
|
87
95
|
),
|
|
88
96
|
PlacementConfig(
|
|
97
|
+
id = "00000000-0000-0000-0000-000000000005",
|
|
89
98
|
placementId = "test_rewarded",
|
|
90
99
|
format = "rewarded",
|
|
91
100
|
gamAdUnit = "ca-app-pub-3940256099942544/5224354917",
|
|
@@ -150,8 +159,9 @@ internal class ConfigManager(
|
|
|
150
159
|
val config = try {
|
|
151
160
|
adapter.fromJson(json)
|
|
152
161
|
} catch (e: Exception) {
|
|
153
|
-
|
|
154
|
-
|
|
162
|
+
val message = describeJsonError(e)
|
|
163
|
+
BCLogger.e("ConfigManager", "Failed to parse config JSON from $url: $message", e)
|
|
164
|
+
return Result.failure(ConfigParseException(message, e))
|
|
155
165
|
}
|
|
156
166
|
|
|
157
167
|
if (config != null) {
|
|
@@ -163,7 +173,7 @@ internal class ConfigManager(
|
|
|
163
173
|
Result.success(config)
|
|
164
174
|
} else {
|
|
165
175
|
BCLogger.e("ConfigManager", "Invalid config JSON")
|
|
166
|
-
Result.failure(
|
|
176
|
+
Result.failure(ConfigParseException("Config JSON parsed to null"))
|
|
167
177
|
}
|
|
168
178
|
}
|
|
169
179
|
storedConfig != null -> {
|
|
@@ -288,11 +298,22 @@ internal class ConfigManager(
|
|
|
288
298
|
val json = storage.getString(CONFIG_STORAGE_KEY) ?: return null
|
|
289
299
|
adapter.fromJson(json)
|
|
290
300
|
} catch (e: Exception) {
|
|
291
|
-
BCLogger.e("ConfigManager", "Failed to load config from storage", e)
|
|
301
|
+
BCLogger.e("ConfigManager", "Failed to load config from storage: ${describeJsonError(e)}", e)
|
|
292
302
|
null
|
|
293
303
|
}
|
|
294
304
|
}
|
|
295
305
|
|
|
306
|
+
/**
|
|
307
|
+
* Produce a human-readable description from a Moshi parse error
|
|
308
|
+
*/
|
|
309
|
+
private fun describeJsonError(e: Exception): String {
|
|
310
|
+
return when (e) {
|
|
311
|
+
is JsonDataException -> e.message ?: "Invalid JSON data"
|
|
312
|
+
is JsonEncodingException -> e.message ?: "Malformed JSON"
|
|
313
|
+
else -> e.message ?: e.toString()
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
|
|
296
317
|
/**
|
|
297
318
|
* Save config to persistent storage
|
|
298
319
|
*/
|
|
@@ -28,7 +28,7 @@ internal class DeviceContext private constructor(context: Context) {
|
|
|
28
28
|
|
|
29
29
|
companion object {
|
|
30
30
|
private const val TAG = "DeviceContext"
|
|
31
|
-
internal const val SDK_VERSION = "0.
|
|
31
|
+
internal const val SDK_VERSION = "0.15.0"
|
|
32
32
|
|
|
33
33
|
@Volatile
|
|
34
34
|
private var instance: DeviceContext? = null
|
|
@@ -46,7 +46,7 @@ class BigCrunchAdsModule(reactContext: ReactApplicationContext) :
|
|
|
46
46
|
BigCrunchAds.initialize(
|
|
47
47
|
context = context,
|
|
48
48
|
propertyId = propertyId,
|
|
49
|
-
env = if (environment == "staging")
|
|
49
|
+
env = if (environment == "sandbox" || environment == "staging")
|
|
50
50
|
BigCrunchAds.Environment.Staging
|
|
51
51
|
else
|
|
52
52
|
BigCrunchAds.Environment.Prod,
|
|
@@ -367,6 +367,7 @@ private class BannerDelegateWrapper: NSObject, GoogleMobileAds.BannerViewDelegat
|
|
|
367
367
|
|
|
368
368
|
analyticsClient.trackAdImpression(
|
|
369
369
|
placementId: placementConfig.placementId,
|
|
370
|
+
slotId: placementConfig.id,
|
|
370
371
|
format: placementConfig.format,
|
|
371
372
|
gamAdUnit: placementConfig.gamAdUnit,
|
|
372
373
|
adSize: adSizeString,
|
|
@@ -388,6 +389,7 @@ private class BannerDelegateWrapper: NSObject, GoogleMobileAds.BannerViewDelegat
|
|
|
388
389
|
BCLogger.debug("GoogleAdsAdapter: Banner ad clicked: \(placementConfig.placementId)")
|
|
389
390
|
analyticsClient.trackAdClick(
|
|
390
391
|
placementId: placementConfig.placementId,
|
|
392
|
+
slotId: placementConfig.id,
|
|
391
393
|
format: placementConfig.format
|
|
392
394
|
)
|
|
393
395
|
delegate?.bannerAdDidRecordClick(bannerView)
|
|
@@ -431,6 +433,7 @@ private class InterstitialDelegateWrapper: NSObject, GoogleMobileAds.FullScreenC
|
|
|
431
433
|
|
|
432
434
|
analyticsClient.trackAdImpression(
|
|
433
435
|
placementId: placementConfig.placementId,
|
|
436
|
+
slotId: placementConfig.id,
|
|
434
437
|
format: placementConfig.format,
|
|
435
438
|
gamAdUnit: placementConfig.gamAdUnit,
|
|
436
439
|
advertiserId: adMetadata["advertiser_id"] as? String,
|
|
@@ -457,6 +460,7 @@ private class InterstitialDelegateWrapper: NSObject, GoogleMobileAds.FullScreenC
|
|
|
457
460
|
BCLogger.debug("GoogleAdsAdapter: Interstitial ad clicked: \(placementConfig.placementId)")
|
|
458
461
|
analyticsClient.trackAdClick(
|
|
459
462
|
placementId: placementConfig.placementId,
|
|
463
|
+
slotId: placementConfig.id,
|
|
460
464
|
format: placementConfig.format
|
|
461
465
|
)
|
|
462
466
|
delegate?.interstitialAdDidRecordClick(interstitialAd)
|
|
@@ -465,6 +465,7 @@ private class RewardedDelegateWrapper: NSObject, FullScreenContentDelegate {
|
|
|
465
465
|
|
|
466
466
|
analyticsClient.trackAdImpression(
|
|
467
467
|
placementId: placementConfig.placementId,
|
|
468
|
+
slotId: placementConfig.id,
|
|
468
469
|
format: placementConfig.format,
|
|
469
470
|
advertiserId: adMetadata["advertiser_id"] as? String,
|
|
470
471
|
campaignId: adMetadata["campaign_id"] as? String,
|
|
@@ -492,6 +493,7 @@ private class RewardedDelegateWrapper: NSObject, FullScreenContentDelegate {
|
|
|
492
493
|
BCLogger.debug("BigCrunchRewarded: Rewarded ad clicked: \(placementId)")
|
|
493
494
|
analyticsClient.trackAdClick(
|
|
494
495
|
placementId: placementConfig.placementId,
|
|
496
|
+
slotId: placementConfig.id,
|
|
495
497
|
format: placementConfig.format
|
|
496
498
|
)
|
|
497
499
|
delegate?.rewardedDidClick(placementId: placementId)
|
|
@@ -239,6 +239,7 @@ internal class AnalyticsClient {
|
|
|
239
239
|
*/
|
|
240
240
|
func createImpressionContext(
|
|
241
241
|
placementId: String,
|
|
242
|
+
slotId: String,
|
|
242
243
|
gamAdUnit: String,
|
|
243
244
|
format: String,
|
|
244
245
|
width: Int? = nil,
|
|
@@ -246,6 +247,7 @@ internal class AnalyticsClient {
|
|
|
246
247
|
) -> ImpressionContext {
|
|
247
248
|
let context = ImpressionContext(
|
|
248
249
|
placementId: placementId,
|
|
250
|
+
slotId: slotId,
|
|
249
251
|
gamAdUnit: gamAdUnit,
|
|
250
252
|
format: format,
|
|
251
253
|
width: width,
|
|
@@ -351,7 +353,7 @@ internal class AnalyticsClient {
|
|
|
351
353
|
|
|
352
354
|
// Create the impression record
|
|
353
355
|
let impressionRecord = ImpressionRecord(
|
|
354
|
-
slotId: context.
|
|
356
|
+
slotId: context.slotId,
|
|
355
357
|
gamUnit: context.gamAdUnit,
|
|
356
358
|
gamPriceBucket: effectiveAuctionData.gamPriceBucket ?? "",
|
|
357
359
|
impressionId: context.impressionId,
|
|
@@ -417,6 +419,7 @@ internal class AnalyticsClient {
|
|
|
417
419
|
*/
|
|
418
420
|
func trackAdImpression(
|
|
419
421
|
placementId: String,
|
|
422
|
+
slotId: String,
|
|
420
423
|
format: String,
|
|
421
424
|
gamAdUnit: String = "",
|
|
422
425
|
adSize: String = "",
|
|
@@ -445,7 +448,7 @@ internal class AnalyticsClient {
|
|
|
445
448
|
|
|
446
449
|
// Create the impression record with auction data fields populated
|
|
447
450
|
let impressionRecord = ImpressionRecord(
|
|
448
|
-
slotId:
|
|
451
|
+
slotId: slotId,
|
|
449
452
|
gamUnit: gamAdUnit,
|
|
450
453
|
gamPriceBucket: auctionData?.gamPriceBucket ?? "",
|
|
451
454
|
impressionId: UUID().uuidString,
|
|
@@ -516,7 +519,7 @@ internal class AnalyticsClient {
|
|
|
516
519
|
* - placementId: Placement ID
|
|
517
520
|
* - format: Ad format
|
|
518
521
|
*/
|
|
519
|
-
func trackAdClick(impressionId: String, placementId: String, format: String) {
|
|
522
|
+
func trackAdClick(impressionId: String, placementId: String, slotId: String, format: String) {
|
|
520
523
|
// Get common event fields
|
|
521
524
|
let common = getCommonEventFields()
|
|
522
525
|
|
|
@@ -530,7 +533,7 @@ internal class AnalyticsClient {
|
|
|
530
533
|
// Note: customDimensions values must be string arrays per backend validation
|
|
531
534
|
let clickData = ClickData(
|
|
532
535
|
clickId: UUID().uuidString,
|
|
533
|
-
slotId:
|
|
536
|
+
slotId: slotId,
|
|
534
537
|
impressionId: impressionId.isEmpty ? UUID().uuidString : impressionId, // Must be valid UUID
|
|
535
538
|
refreshCount: 0,
|
|
536
539
|
adAmznp: "",
|
|
@@ -586,8 +589,8 @@ internal class AnalyticsClient {
|
|
|
586
589
|
/**
|
|
587
590
|
* Track an ad click (simple version without impression ID)
|
|
588
591
|
*/
|
|
589
|
-
func trackAdClick(placementId: String, format: String) {
|
|
590
|
-
trackAdClick(impressionId: "", placementId: placementId, format: format)
|
|
592
|
+
func trackAdClick(placementId: String, slotId: String, format: String) {
|
|
593
|
+
trackAdClick(impressionId: "", placementId: placementId, slotId: slotId, format: format)
|
|
591
594
|
}
|
|
592
595
|
|
|
593
596
|
// MARK: - Viewability Tracking
|
|
@@ -605,6 +608,7 @@ internal class AnalyticsClient {
|
|
|
605
608
|
func trackAdViewable(
|
|
606
609
|
impressionId: String,
|
|
607
610
|
placementId: String,
|
|
611
|
+
slotId: String,
|
|
608
612
|
format: String,
|
|
609
613
|
viewableTimeMs: Int64,
|
|
610
614
|
percentVisible: Int
|
|
@@ -620,7 +624,7 @@ internal class AnalyticsClient {
|
|
|
620
624
|
|
|
621
625
|
// Create viewability data with nested structure per backend schema
|
|
622
626
|
let viewabilityData = ViewabilityData(
|
|
623
|
-
slotId:
|
|
627
|
+
slotId: slotId,
|
|
624
628
|
impressionId: impressionId.isEmpty ? UUID().uuidString : impressionId, // Must be valid UUID
|
|
625
629
|
refreshCount: 0,
|
|
626
630
|
adAmznp: "",
|
|
@@ -675,7 +679,7 @@ internal class AnalyticsClient {
|
|
|
675
679
|
/**
|
|
676
680
|
* Track ad viewability (simple version without metrics)
|
|
677
681
|
*/
|
|
678
|
-
func trackAdViewable(placementId: String, format: String) {
|
|
682
|
+
func trackAdViewable(placementId: String, slotId: String, format: String) {
|
|
679
683
|
// Get common event fields
|
|
680
684
|
let common = getCommonEventFields()
|
|
681
685
|
|
|
@@ -687,7 +691,7 @@ internal class AnalyticsClient {
|
|
|
687
691
|
|
|
688
692
|
// Create viewability data with nested structure per backend schema
|
|
689
693
|
let viewabilityData = ViewabilityData(
|
|
690
|
-
slotId:
|
|
694
|
+
slotId: slotId,
|
|
691
695
|
impressionId: UUID().uuidString, // Generate UUID since none provided
|
|
692
696
|
refreshCount: 0,
|
|
693
697
|
adAmznp: "",
|
|
@@ -189,7 +189,7 @@ internal class BidRequestClient {
|
|
|
189
189
|
|
|
190
190
|
private func buildImp(_ placement: PlacementConfig) -> [String: Any] {
|
|
191
191
|
var imp: [String: Any] = [
|
|
192
|
-
"id": placement.
|
|
192
|
+
"id": placement.id
|
|
193
193
|
]
|
|
194
194
|
|
|
195
195
|
switch placement.format {
|
|
@@ -262,7 +262,8 @@ internal class BidRequestClient {
|
|
|
262
262
|
return [:]
|
|
263
263
|
}
|
|
264
264
|
|
|
265
|
-
let
|
|
265
|
+
let placementIdToUuid = Dictionary(uniqueKeysWithValues: placements.map { ($0.placementId, $0.id) })
|
|
266
|
+
let placementIds = Set(placementIdToUuid.keys)
|
|
266
267
|
var biddersExt: [String: Any] = [:]
|
|
267
268
|
|
|
268
269
|
for (bidderName, bidderEntry) in bidders {
|
|
@@ -279,7 +280,7 @@ internal class BidRequestClient {
|
|
|
279
280
|
for placementId in placementIds {
|
|
280
281
|
if let impParams = bidderPlacements[placementId] {
|
|
281
282
|
impEntries.append([
|
|
282
|
-
"impid": placementId,
|
|
283
|
+
"impid": placementIdToUuid[placementId] ?? placementId,
|
|
283
284
|
"params": impParams.mapValues { $0.value }
|
|
284
285
|
])
|
|
285
286
|
}
|
|
@@ -326,8 +327,9 @@ internal class BidRequestClient {
|
|
|
326
327
|
|
|
327
328
|
let auctionId = json["id"] as? String
|
|
328
329
|
|
|
329
|
-
// Build floor price lookup
|
|
330
|
-
let floorPrices = Dictionary(uniqueKeysWithValues: placements.map { ($0.
|
|
330
|
+
// Build floor price lookup (keyed by UUID) and UUID-to-placementId mapping
|
|
331
|
+
let floorPrices = Dictionary(uniqueKeysWithValues: placements.map { ($0.id, $0.floorPrice) })
|
|
332
|
+
let uuidToPlacementId = Dictionary(uniqueKeysWithValues: placements.map { ($0.id, $0.placementId) })
|
|
331
333
|
|
|
332
334
|
// Collect all bids grouped by impid
|
|
333
335
|
struct BidInfo {
|
|
@@ -376,8 +378,10 @@ internal class BidRequestClient {
|
|
|
376
378
|
demandChannel: "S2S"
|
|
377
379
|
)
|
|
378
380
|
|
|
379
|
-
|
|
380
|
-
|
|
381
|
+
// Re-key from UUID to placementId for internal use
|
|
382
|
+
let placementId = uuidToPlacementId[impid] ?? impid
|
|
383
|
+
results[placementId] = BidResponse(targeting: winner.targeting, auctionData: auctionData)
|
|
384
|
+
BCLogger.debug("BidRequestClient: Winner for \(placementId): $\(winner.price)")
|
|
381
385
|
}
|
|
382
386
|
|
|
383
387
|
BCLogger.info("BidRequestClient: Parsed \(results.count) winning bids")
|
|
@@ -12,6 +12,17 @@ import Foundation
|
|
|
12
12
|
*
|
|
13
13
|
* The config is fetched once at SDK initialization and cached for the app session.
|
|
14
14
|
*/
|
|
15
|
+
enum ConfigError: LocalizedError {
|
|
16
|
+
case parseError(String)
|
|
17
|
+
|
|
18
|
+
var errorDescription: String? {
|
|
19
|
+
switch self {
|
|
20
|
+
case .parseError(let message):
|
|
21
|
+
return message
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
15
26
|
internal class ConfigManager {
|
|
16
27
|
|
|
17
28
|
private let httpClient: HTTPClient
|
|
@@ -55,12 +66,14 @@ internal class ConfigManager {
|
|
|
55
66
|
refresh: RefreshConfig(enabled: true, intervalMs: 30000, maxRefreshes: 20),
|
|
56
67
|
placements: [
|
|
57
68
|
PlacementConfig(
|
|
69
|
+
id: "00000000-0000-0000-0000-000000000001",
|
|
58
70
|
placementId: "test_banner_320x50",
|
|
59
71
|
format: "banner",
|
|
60
72
|
gamAdUnit: "ca-app-pub-3940256099942544/2435281174",
|
|
61
73
|
sizes: [AdSize(width: 320, height: 50)]
|
|
62
74
|
),
|
|
63
75
|
PlacementConfig(
|
|
76
|
+
id: "00000000-0000-0000-0000-000000000002",
|
|
64
77
|
placementId: "test_mrec",
|
|
65
78
|
format: "banner",
|
|
66
79
|
gamAdUnit: "ca-app-pub-3940256099942544/2435281174",
|
|
@@ -68,18 +81,21 @@ internal class ConfigManager {
|
|
|
68
81
|
refresh: RefreshConfig(enabled: true, intervalMs: 15000, maxRefreshes: 40)
|
|
69
82
|
),
|
|
70
83
|
PlacementConfig(
|
|
84
|
+
id: "00000000-0000-0000-0000-000000000003",
|
|
71
85
|
placementId: "test_adaptive_banner",
|
|
72
86
|
format: "banner",
|
|
73
87
|
gamAdUnit: "ca-app-pub-3940256099942544/2435281174",
|
|
74
88
|
sizes: [AdSize.adaptive()]
|
|
75
89
|
),
|
|
76
90
|
PlacementConfig(
|
|
91
|
+
id: "00000000-0000-0000-0000-000000000004",
|
|
77
92
|
placementId: "test_interstitial",
|
|
78
93
|
format: "interstitial",
|
|
79
94
|
gamAdUnit: "ca-app-pub-3940256099942544/4411468910",
|
|
80
95
|
sizes: nil
|
|
81
96
|
),
|
|
82
97
|
PlacementConfig(
|
|
98
|
+
id: "00000000-0000-0000-0000-000000000005",
|
|
83
99
|
placementId: "test_rewarded",
|
|
84
100
|
format: "rewarded",
|
|
85
101
|
gamAdUnit: "ca-app-pub-3940256099942544/1712485313",
|
|
@@ -152,8 +168,9 @@ internal class ConfigManager {
|
|
|
152
168
|
BCLogger.verbose("Config JSON: \(json)")
|
|
153
169
|
return .success(config)
|
|
154
170
|
} catch {
|
|
155
|
-
|
|
156
|
-
|
|
171
|
+
let message = Self.describeDecodingError(error)
|
|
172
|
+
BCLogger.error("Failed to parse config JSON from \(url): \(message)")
|
|
173
|
+
return .failure(ConfigError.parseError(message))
|
|
157
174
|
}
|
|
158
175
|
|
|
159
176
|
case .failure(let error):
|
|
@@ -295,11 +312,51 @@ internal class ConfigManager {
|
|
|
295
312
|
do {
|
|
296
313
|
return try JSONDecoder().decode(AppConfig.self, from: data)
|
|
297
314
|
} catch {
|
|
298
|
-
BCLogger.error("Failed to load config from storage: \(error)")
|
|
315
|
+
BCLogger.error("Failed to load config from storage: \(Self.describeDecodingError(error))")
|
|
299
316
|
return nil
|
|
300
317
|
}
|
|
301
318
|
}
|
|
302
319
|
|
|
320
|
+
/**
|
|
321
|
+
* Produce a human-readable description from a DecodingError
|
|
322
|
+
*/
|
|
323
|
+
private static func describeDecodingError(_ error: Error) -> String {
|
|
324
|
+
guard let decodingError = error as? DecodingError else {
|
|
325
|
+
return error.localizedDescription
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
let path: String
|
|
329
|
+
let detail: String
|
|
330
|
+
|
|
331
|
+
switch decodingError {
|
|
332
|
+
case .keyNotFound(let key, let context):
|
|
333
|
+
path = Self.formatCodingPath(context.codingPath)
|
|
334
|
+
detail = "missing required field '\(key.stringValue)'"
|
|
335
|
+
case .typeMismatch(let type, let context):
|
|
336
|
+
path = Self.formatCodingPath(context.codingPath)
|
|
337
|
+
detail = "expected \(type)"
|
|
338
|
+
case .valueNotFound(let type, let context):
|
|
339
|
+
path = Self.formatCodingPath(context.codingPath)
|
|
340
|
+
detail = "null value for \(type)"
|
|
341
|
+
case .dataCorrupted(let context):
|
|
342
|
+
path = Self.formatCodingPath(context.codingPath)
|
|
343
|
+
detail = context.debugDescription
|
|
344
|
+
@unknown default:
|
|
345
|
+
return error.localizedDescription
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
return path.isEmpty ? detail : "\(path): \(detail)"
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
private static func formatCodingPath(_ codingPath: [CodingKey]) -> String {
|
|
352
|
+
return codingPath.map { key in
|
|
353
|
+
if let index = key.intValue {
|
|
354
|
+
return "[\(index)]"
|
|
355
|
+
}
|
|
356
|
+
return key.stringValue
|
|
357
|
+
}.joined(separator: ".")
|
|
358
|
+
}
|
|
359
|
+
|
|
303
360
|
/**
|
|
304
361
|
* Save config to persistent storage
|
|
305
362
|
*/
|
|
@@ -860,6 +860,8 @@ internal struct ImpressionContext {
|
|
|
860
860
|
|
|
861
861
|
/// Placement configuration
|
|
862
862
|
let placementId: String
|
|
863
|
+
/// UUID for backend reporting (slot_id)
|
|
864
|
+
let slotId: String
|
|
863
865
|
let gamAdUnit: String
|
|
864
866
|
let format: String
|
|
865
867
|
|
|
@@ -875,6 +877,7 @@ internal struct ImpressionContext {
|
|
|
875
877
|
|
|
876
878
|
init(
|
|
877
879
|
placementId: String,
|
|
880
|
+
slotId: String,
|
|
878
881
|
gamAdUnit: String,
|
|
879
882
|
format: String,
|
|
880
883
|
width: Int? = nil,
|
|
@@ -882,6 +885,7 @@ internal struct ImpressionContext {
|
|
|
882
885
|
) {
|
|
883
886
|
self.impressionId = UUID().uuidString
|
|
884
887
|
self.placementId = placementId
|
|
888
|
+
self.slotId = slotId
|
|
885
889
|
self.gamAdUnit = gamAdUnit
|
|
886
890
|
self.format = format
|
|
887
891
|
self.width = width
|
|
@@ -8,6 +8,7 @@ import Foundation
|
|
|
8
8
|
* in the top-level `AppConfig.bidders` dictionary.
|
|
9
9
|
*/
|
|
10
10
|
public struct PlacementConfig: Codable {
|
|
11
|
+
public let id: String
|
|
11
12
|
public let placementId: String
|
|
12
13
|
public let format: String // "banner", "interstitial", "rewarded"
|
|
13
14
|
public let gamAdUnit: String
|
|
@@ -16,6 +17,7 @@ public struct PlacementConfig: Codable {
|
|
|
16
17
|
public let floorPrice: Double?
|
|
17
18
|
|
|
18
19
|
public init(
|
|
20
|
+
id: String,
|
|
19
21
|
placementId: String,
|
|
20
22
|
format: String,
|
|
21
23
|
gamAdUnit: String,
|
|
@@ -23,6 +25,7 @@ public struct PlacementConfig: Codable {
|
|
|
23
25
|
refresh: RefreshConfig? = nil,
|
|
24
26
|
floorPrice: Double? = nil
|
|
25
27
|
) {
|
|
28
|
+
self.id = id
|
|
26
29
|
self.placementId = placementId
|
|
27
30
|
self.format = format
|
|
28
31
|
self.gamAdUnit = gamAdUnit
|
package/lib/types/config.d.ts
CHANGED
|
@@ -27,7 +27,9 @@ export interface AppConfig {
|
|
|
27
27
|
* Individual placement configuration
|
|
28
28
|
*/
|
|
29
29
|
export interface PlacementConfig {
|
|
30
|
-
/** Unique placement
|
|
30
|
+
/** Unique placement UUID for backend reporting */
|
|
31
|
+
id: string;
|
|
32
|
+
/** Developer-facing placement identifier */
|
|
31
33
|
placementId: string;
|
|
32
34
|
/** Placement name for reporting */
|
|
33
35
|
placementName?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/types/config.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,kBAAkB;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,oBAAoB;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,gCAAgC;IAChC,GAAG,CAAC,EAAE,SAAS,CAAC;IAChB,iEAAiE;IACjE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACtC,oCAAoC;IACpC,UAAU,EAAE,eAAe,EAAE,CAAC;IAC9B,sBAAsB;IACtB,QAAQ,CAAC,EAAE,cAAc,CAAC;IAC1B,6BAA6B;IAC7B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,qBAAqB;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/types/config.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bigcrunch/react-native-ads",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.15.0",
|
|
4
4
|
"description": "BigCrunch Mobile Ads SDK for React Native - Simplified in-app advertising with S2S demand and Google Ad Manager",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"types": "lib/index.d.ts",
|
package/src/types/config.ts
CHANGED
|
@@ -30,7 +30,9 @@ export interface AppConfig {
|
|
|
30
30
|
* Individual placement configuration
|
|
31
31
|
*/
|
|
32
32
|
export interface PlacementConfig {
|
|
33
|
-
/** Unique placement
|
|
33
|
+
/** Unique placement UUID for backend reporting */
|
|
34
|
+
id: string;
|
|
35
|
+
/** Developer-facing placement identifier */
|
|
34
36
|
placementId: string;
|
|
35
37
|
/** Placement name for reporting */
|
|
36
38
|
placementName?: string;
|