@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
@@ -0,0 +1,146 @@
1
+ import Foundation
2
+
3
+ /**
4
+ * HTTP client for making network requests
5
+ *
6
+ * Uses URLSession for reliable networking with automatic retries and caching.
7
+ * All methods are async functions using Swift's async/await.
8
+ */
9
+ internal class HTTPClient {
10
+
11
+ private let session: URLSession
12
+
13
+ init(configuration: URLSessionConfiguration? = nil) {
14
+ let config = configuration ?? {
15
+ let defaultConfig = URLSessionConfiguration.default
16
+ defaultConfig.timeoutIntervalForRequest = 10
17
+ defaultConfig.timeoutIntervalForResource = 10
18
+ return defaultConfig
19
+ }()
20
+ self.session = URLSession(configuration: config)
21
+ }
22
+
23
+ /**
24
+ * Perform a GET request
25
+ *
26
+ * - Parameters:
27
+ * - url: The URL to fetch
28
+ * - headers: Optional HTTP headers
29
+ * - Returns: Result containing response body or error
30
+ */
31
+ func get(url: String, headers: [String: String] = [:]) async -> Result<String, Error> {
32
+ guard let url = URL(string: url) else {
33
+ let error = NSError(
34
+ domain: "HTTPClient",
35
+ code: -1,
36
+ userInfo: [NSLocalizedDescriptionKey: "Invalid URL: \(url)"]
37
+ )
38
+ BCLogger.error("GET request failed: Invalid URL")
39
+ return .failure(error)
40
+ }
41
+
42
+ var request = URLRequest(url: url)
43
+ request.httpMethod = "GET"
44
+ headers.forEach { request.addValue($0.value, forHTTPHeaderField: $0.key) }
45
+
46
+ do {
47
+ let (data, response) = try await session.data(for: request)
48
+
49
+ guard let httpResponse = response as? HTTPURLResponse else {
50
+ let error = NSError(
51
+ domain: "HTTPClient",
52
+ code: -1,
53
+ userInfo: [NSLocalizedDescriptionKey: "Invalid response type"]
54
+ )
55
+ return .failure(error)
56
+ }
57
+
58
+ if (200...299).contains(httpResponse.statusCode) {
59
+ let string = String(data: data, encoding: .utf8) ?? ""
60
+ BCLogger.verbose("GET success: \(url.absoluteString) (\(data.count) bytes)")
61
+ return .success(string)
62
+ } else {
63
+ let error = NSError(
64
+ domain: "HTTPClient",
65
+ code: httpResponse.statusCode,
66
+ userInfo: [NSLocalizedDescriptionKey: "HTTP \(httpResponse.statusCode)"]
67
+ )
68
+ BCLogger.warning("GET failed: \(url.absoluteString) - HTTP \(httpResponse.statusCode)")
69
+ return .failure(error)
70
+ }
71
+ } catch {
72
+ BCLogger.error("GET request failed: \(url.absoluteString) - \(error)")
73
+ return .failure(error)
74
+ }
75
+ }
76
+
77
+ /**
78
+ * Perform a POST request
79
+ *
80
+ * - Parameters:
81
+ * - url: The URL to post to
82
+ * - body: Request body (JSON string)
83
+ * - headers: Optional HTTP headers
84
+ * - Returns: Result containing response body or error
85
+ */
86
+ func post(
87
+ url: String,
88
+ body: String,
89
+ headers: [String: String] = [:]
90
+ ) async -> Result<String, Error> {
91
+ guard let url = URL(string: url) else {
92
+ let error = NSError(
93
+ domain: "HTTPClient",
94
+ code: -1,
95
+ userInfo: [NSLocalizedDescriptionKey: "Invalid URL: \(url)"]
96
+ )
97
+ BCLogger.error("POST request failed: Invalid URL")
98
+ return .failure(error)
99
+ }
100
+
101
+ // Log the request body for debugging
102
+ BCLogger.debug("POST to: \(url.absoluteString)")
103
+ BCLogger.debug("Request body: \(body)")
104
+
105
+ var request = URLRequest(url: url)
106
+ request.httpMethod = "POST"
107
+ request.httpBody = body.data(using: .utf8)
108
+ request.addValue("application/json", forHTTPHeaderField: "Content-Type")
109
+ headers.forEach { request.addValue($0.value, forHTTPHeaderField: $0.key) }
110
+
111
+ do {
112
+ let (data, response) = try await session.data(for: request)
113
+
114
+ guard let httpResponse = response as? HTTPURLResponse else {
115
+ let error = NSError(
116
+ domain: "HTTPClient",
117
+ code: -1,
118
+ userInfo: [NSLocalizedDescriptionKey: "Invalid response type"]
119
+ )
120
+ return .failure(error)
121
+ }
122
+
123
+ if (200...299).contains(httpResponse.statusCode) {
124
+ let string = String(data: data, encoding: .utf8) ?? ""
125
+ BCLogger.verbose("POST success: \(url.absoluteString)")
126
+ return .success(string)
127
+ } else {
128
+ // Log response body for 4xx errors to see what the server says
129
+ let errorBody = String(data: data, encoding: .utf8) ?? ""
130
+ let error = NSError(
131
+ domain: "HTTPClient",
132
+ code: httpResponse.statusCode,
133
+ userInfo: [NSLocalizedDescriptionKey: "HTTP \(httpResponse.statusCode)"]
134
+ )
135
+ BCLogger.warning("POST failed: \(url.absoluteString) - HTTP \(httpResponse.statusCode)")
136
+ if !errorBody.isEmpty {
137
+ BCLogger.warning("Error response body: \(errorBody)")
138
+ }
139
+ return .failure(error)
140
+ }
141
+ } catch {
142
+ BCLogger.error("POST request failed: \(url.absoluteString) - \(error)")
143
+ return .failure(error)
144
+ }
145
+ }
146
+ }
@@ -0,0 +1,62 @@
1
+ import Foundation
2
+
3
+ /**
4
+ * Internal logger for BigCrunch Ads SDK
5
+ *
6
+ * All logs are prefixed with "[BCrunch:LEVEL]" for easy filtering.
7
+ * Logging can be disabled in production by setting isEnabled = false.
8
+ * Error logs are always shown regardless of isEnabled flag.
9
+ */
10
+ internal class BCLogger {
11
+
12
+ /**
13
+ * Enable/disable debug logging
14
+ * Defaults to false for production builds
15
+ */
16
+ static var isEnabled = false
17
+
18
+ /**
19
+ * Verbose log - detailed debugging information
20
+ */
21
+ static func verbose(_ message: String) {
22
+ if isEnabled {
23
+ print("[BCrunch:VERBOSE] \(message)")
24
+ }
25
+ }
26
+
27
+ /**
28
+ * Debug log - general debugging information
29
+ */
30
+ static func debug(_ message: String) {
31
+ if isEnabled {
32
+ print("[BCrunch:DEBUG] \(message)")
33
+ }
34
+ }
35
+
36
+ /**
37
+ * Info log - informational messages
38
+ */
39
+ static func info(_ message: String) {
40
+ if isEnabled {
41
+ print("[BCrunch:INFO] \(message)")
42
+ }
43
+ }
44
+
45
+ /**
46
+ * Warning log - potential issues
47
+ */
48
+ static func warning(_ message: String) {
49
+ if isEnabled {
50
+ print("[BCrunch:WARNING] \(message)")
51
+ }
52
+ }
53
+
54
+ /**
55
+ * Error log - critical errors
56
+ * Always logs regardless of isEnabled flag
57
+ */
58
+ static func error(_ message: String) {
59
+ // Always log errors
60
+ print("[BCrunch:ERROR] \(message)")
61
+ }
62
+ }
@@ -0,0 +1,129 @@
1
+ import Foundation
2
+
3
+ /**
4
+ * Centralized privacy signal store
5
+ *
6
+ * Manages GDPR, CCPA, and COPPA privacy signals for the SDK.
7
+ * Reads IAB TCF/USP standard keys from UserDefaults when available,
8
+ * and provides structured objects for bid request construction.
9
+ */
10
+ internal class PrivacyStore {
11
+
12
+ private let lock = NSLock()
13
+
14
+ // SDK-set values (from public API)
15
+ private var _gdprConsentString: String?
16
+ private var _gdprApplies: Bool?
17
+ private var _ccpaString: String?
18
+ private var _coppaApplies: Bool = false
19
+
20
+ // IAB standard UserDefaults keys
21
+ private static let iabTcfConsentKey = "IABTCF_TCString"
22
+ private static let iabTcfGdprAppliesKey = "IABTCF_gdprApplies"
23
+ private static let iabUspStringKey = "IABUSPrivacy_String"
24
+
25
+ // MARK: - Setters (called from public API)
26
+
27
+ func setGdprConsent(_ consent: String) {
28
+ lock.lock()
29
+ defer { lock.unlock() }
30
+ _gdprApplies = true
31
+ _gdprConsentString = consent
32
+ BCLogger.debug("PrivacyStore: GDPR consent set")
33
+ }
34
+
35
+ func setCcpaString(_ ccpa: String) {
36
+ lock.lock()
37
+ defer { lock.unlock() }
38
+ _ccpaString = ccpa
39
+ // Also write to IAB standard key for CMP interop
40
+ UserDefaults.standard.set(ccpa, forKey: Self.iabUspStringKey)
41
+ BCLogger.debug("PrivacyStore: CCPA string set")
42
+ }
43
+
44
+ func setCoppaApplies(_ applies: Bool) {
45
+ lock.lock()
46
+ defer { lock.unlock() }
47
+ _coppaApplies = applies
48
+ BCLogger.debug("PrivacyStore: COPPA set to \(applies)")
49
+ }
50
+
51
+ // MARK: - Getters
52
+
53
+ /// Effective GDPR consent string (SDK-set takes priority, then IAB TCF)
54
+ var gdprConsentString: String? {
55
+ lock.lock()
56
+ defer { lock.unlock() }
57
+ return _gdprConsentString
58
+ ?? UserDefaults.standard.string(forKey: Self.iabTcfConsentKey)
59
+ }
60
+
61
+ /// Whether GDPR applies (SDK-set takes priority, then IAB TCF)
62
+ var gdprApplies: Bool? {
63
+ lock.lock()
64
+ defer { lock.unlock() }
65
+ if let sdkValue = _gdprApplies {
66
+ return sdkValue
67
+ }
68
+ let iabValue = UserDefaults.standard.object(forKey: Self.iabTcfGdprAppliesKey) as? Int
69
+ return iabValue.map { $0 == 1 }
70
+ }
71
+
72
+ /// Effective CCPA/USP string (SDK-set takes priority, then IAB USP)
73
+ var ccpaString: String? {
74
+ lock.lock()
75
+ defer { lock.unlock() }
76
+ return _ccpaString
77
+ ?? UserDefaults.standard.string(forKey: Self.iabUspStringKey)
78
+ }
79
+
80
+ var coppaApplies: Bool {
81
+ lock.lock()
82
+ defer { lock.unlock() }
83
+ return _coppaApplies
84
+ }
85
+
86
+ // MARK: - Bid Request Helpers
87
+
88
+ /// Build the `regs` object for an OpenRTB bid request
89
+ func buildRegsDict() -> [String: Any] {
90
+ var regs: [String: Any] = [:]
91
+ var ext: [String: Any] = [:]
92
+
93
+ if coppaApplies {
94
+ regs["coppa"] = 1
95
+ } else {
96
+ regs["coppa"] = 0
97
+ }
98
+
99
+ if let gdpr = gdprApplies {
100
+ ext["gdpr"] = gdpr ? 1 : 0
101
+ }
102
+
103
+ if let usp = ccpaString {
104
+ ext["us_privacy"] = usp
105
+ }
106
+
107
+ if !ext.isEmpty {
108
+ regs["ext"] = ext
109
+ }
110
+
111
+ return regs
112
+ }
113
+
114
+ /// Build the `user` object for an OpenRTB bid request
115
+ func buildUserDict() -> [String: Any] {
116
+ var user: [String: Any] = [:]
117
+ var ext: [String: Any] = [:]
118
+
119
+ if let consent = gdprConsentString {
120
+ ext["consent"] = consent
121
+ }
122
+
123
+ if !ext.isEmpty {
124
+ user["ext"] = ext
125
+ }
126
+
127
+ return user
128
+ }
129
+ }
@@ -0,0 +1,73 @@
1
+ import Foundation
2
+
3
+ /**
4
+ * Key-value storage protocol for persisting SDK data
5
+ */
6
+ internal protocol KeyValueStore {
7
+ /**
8
+ * Get a string value by key
9
+ *
10
+ * - Parameters:
11
+ * - key: Storage key
12
+ * - default: Default value if key doesn't exist
13
+ * - Returns: Stored value or default
14
+ */
15
+ func getString(key: String, default: String?) -> String?
16
+
17
+ /**
18
+ * Store a string value
19
+ *
20
+ * - Parameters:
21
+ * - key: Storage key
22
+ * - value: Value to store (pass nil to remove the key)
23
+ */
24
+ func putString(key: String, value: String?)
25
+
26
+ /**
27
+ * Clear all stored data
28
+ */
29
+ func clear()
30
+ }
31
+
32
+ /**
33
+ * UserDefaults-based implementation of KeyValueStore
34
+ *
35
+ * Thread-safe implementation using iOS's UserDefaults.
36
+ * All keys are prefixed with "bigcrunch_ads_" for namespace isolation.
37
+ */
38
+ internal class UserDefaultsStore: KeyValueStore {
39
+
40
+ private let userDefaults = UserDefaults.standard
41
+ private let keyPrefix = "bigcrunch_ads_"
42
+
43
+ func getString(key: String, default: String? = nil) -> String? {
44
+ let prefixedKey = keyPrefix + key
45
+ let value = userDefaults.string(forKey: prefixedKey) ?? `default`
46
+ if value != nil {
47
+ BCLogger.verbose("Retrieved value for key: \(key)")
48
+ }
49
+ return value
50
+ }
51
+
52
+ func putString(key: String, value: String?) {
53
+ let prefixedKey = keyPrefix + key
54
+ if let value = value {
55
+ userDefaults.set(value, forKey: prefixedKey)
56
+ BCLogger.verbose("Stored value for key: \(key)")
57
+ } else {
58
+ userDefaults.removeObject(forKey: prefixedKey)
59
+ BCLogger.verbose("Removed value for key: \(key)")
60
+ }
61
+ }
62
+
63
+ func clear() {
64
+ let keys = userDefaults.dictionaryRepresentation().keys
65
+ let prefixedKeys = keys.filter { $0.hasPrefix(keyPrefix) }
66
+
67
+ for key in prefixedKeys {
68
+ userDefaults.removeObject(forKey: key)
69
+ }
70
+
71
+ BCLogger.debug("Cleared all stored data")
72
+ }
73
+ }