@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.
Files changed (52) hide show
  1. package/README.md +417 -0
  2. package/android/build.gradle +70 -0
  3. package/android/settings.gradle +6 -0
  4. package/android/src/main/AndroidManifest.xml +3 -0
  5. package/android/src/main/java/com/bigcrunch/ads/react/BigCrunchAdsModule.kt +653 -0
  6. package/android/src/main/java/com/bigcrunch/ads/react/BigCrunchAdsPackage.kt +20 -0
  7. package/android/src/main/java/com/bigcrunch/ads/react/BigCrunchBannerViewManager.kt +296 -0
  8. package/ios/BigCrunchAdsModule.swift +588 -0
  9. package/ios/BigCrunchBannerViewManager.swift +270 -0
  10. package/ios/react-native-bigcrunch-ads-Bridging-Header.h +8 -0
  11. package/lib/BigCrunchAds.d.ts +168 -0
  12. package/lib/BigCrunchAds.d.ts.map +1 -0
  13. package/lib/BigCrunchAds.js +241 -0
  14. package/lib/BigCrunchBannerView.d.ts +21 -0
  15. package/lib/BigCrunchBannerView.d.ts.map +1 -0
  16. package/lib/BigCrunchBannerView.js +176 -0
  17. package/lib/BigCrunchInterstitial.d.ts +66 -0
  18. package/lib/BigCrunchInterstitial.d.ts.map +1 -0
  19. package/lib/BigCrunchInterstitial.js +222 -0
  20. package/lib/BigCrunchRewarded.d.ts +85 -0
  21. package/lib/BigCrunchRewarded.d.ts.map +1 -0
  22. package/lib/BigCrunchRewarded.js +257 -0
  23. package/lib/NativeBigCrunchAds.d.ts +71 -0
  24. package/lib/NativeBigCrunchAds.d.ts.map +1 -0
  25. package/lib/NativeBigCrunchAds.js +54 -0
  26. package/lib/index.d.ts +28 -0
  27. package/lib/index.d.ts.map +1 -0
  28. package/lib/index.js +32 -0
  29. package/lib/types/ads.d.ts +101 -0
  30. package/lib/types/ads.d.ts.map +1 -0
  31. package/lib/types/ads.js +4 -0
  32. package/lib/types/config.d.ts +137 -0
  33. package/lib/types/config.d.ts.map +1 -0
  34. package/lib/types/config.js +4 -0
  35. package/lib/types/events.d.ts +306 -0
  36. package/lib/types/events.d.ts.map +1 -0
  37. package/lib/types/events.js +4 -0
  38. package/lib/types/index.d.ts +175 -0
  39. package/lib/types/index.d.ts.map +1 -0
  40. package/lib/types/index.js +23 -0
  41. package/package.json +88 -0
  42. package/react-native-bigcrunch-ads.podspec +27 -0
  43. package/src/BigCrunchAds.ts +298 -0
  44. package/src/BigCrunchBannerView.tsx +262 -0
  45. package/src/BigCrunchInterstitial.ts +266 -0
  46. package/src/BigCrunchRewarded.ts +307 -0
  47. package/src/NativeBigCrunchAds.ts +120 -0
  48. package/src/index.ts +71 -0
  49. package/src/types/ads.ts +112 -0
  50. package/src/types/config.ts +145 -0
  51. package/src/types/events.ts +337 -0
  52. package/src/types/index.ts +193 -0
package/package.json ADDED
@@ -0,0 +1,88 @@
1
+ {
2
+ "name": "@bigcrunch/react-native-ads",
3
+ "version": "0.1.0",
4
+ "description": "BigCrunch Mobile Ads SDK for React Native - Simplified in-app advertising with Prebid and Google Ad Manager",
5
+ "main": "lib/index.js",
6
+ "types": "lib/index.d.ts",
7
+ "react-native": "src/index.ts",
8
+ "source": "src/index.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./lib/index.d.ts",
12
+ "import": "./lib/index.js",
13
+ "require": "./lib/index.js",
14
+ "react-native": "./src/index.ts",
15
+ "default": "./lib/index.js"
16
+ }
17
+ },
18
+ "files": [
19
+ "src",
20
+ "lib",
21
+ "android/src",
22
+ "android/build.gradle",
23
+ "android/settings.gradle",
24
+ "ios/*.swift",
25
+ "ios/*.m",
26
+ "ios/*.h",
27
+ "react-native-bigcrunch-ads.podspec",
28
+ "!**/__tests__",
29
+ "!**/__fixtures__",
30
+ "!**/__mocks__"
31
+ ],
32
+ "scripts": {
33
+ "typescript": "tsc --noEmit",
34
+ "build": "tsc",
35
+ "prepare": "npm run build || echo 'Build skipped during install'",
36
+ "release": "release-it",
37
+ "example": "yarn --cwd example",
38
+ "clean": "del-cli lib"
39
+ },
40
+ "keywords": [
41
+ "react-native",
42
+ "ios",
43
+ "android",
44
+ "ads",
45
+ "advertising",
46
+ "monetization",
47
+ "prebid",
48
+ "google-ad-manager",
49
+ "gam",
50
+ "banner",
51
+ "interstitial",
52
+ "rewarded",
53
+ "bigcrunch"
54
+ ],
55
+ "repository": {
56
+ "type": "git",
57
+ "url": "git+https://github.com/bigcrunch/mobile-ads-sdk.git"
58
+ },
59
+ "author": "BigCrunch <support@bigcrunch.com> (https://www.bigcrunch.com)",
60
+ "license": "MIT",
61
+ "bugs": {
62
+ "url": "https://github.com/bigcrunch/mobile-ads-sdk/issues"
63
+ },
64
+ "homepage": "https://github.com/bigcrunch/mobile-ads-sdk#readme",
65
+ "publishConfig": {
66
+ "registry": "https://registry.npmjs.org/",
67
+ "access": "public"
68
+ },
69
+ "devDependencies": {
70
+ "@types/react": "^18.2.0",
71
+ "@types/react-native": "^0.72.0",
72
+ "del-cli": "^5.0.0",
73
+ "release-it": "^15.0.0",
74
+ "typescript": "^5.0.0"
75
+ },
76
+ "peerDependencies": {
77
+ "react": "*",
78
+ "react-native": "*"
79
+ },
80
+ "peerDependenciesMeta": {
81
+ "react": {
82
+ "optional": false
83
+ },
84
+ "react-native": {
85
+ "optional": false
86
+ }
87
+ }
88
+ }
@@ -0,0 +1,27 @@
1
+ require "json"
2
+
3
+ package = JSON.parse(File.read(File.join(__dir__, "package.json")))
4
+
5
+ Pod::Spec.new do |s|
6
+ s.name = "react-native-bigcrunch-ads"
7
+ s.version = package["version"]
8
+ s.summary = package["description"]
9
+ s.description = <<-DESC
10
+ BigCrunch Mobile Ads SDK for React Native - Simplified in-app advertising with Prebid and Google Ad Manager
11
+ DESC
12
+ s.homepage = "https://github.com/bigcrunch/mobile-ads-sdk"
13
+ s.license = "MIT"
14
+ s.authors = { "BigCrunch" => "support@bigcrunch.com" }
15
+ s.platforms = { :ios => "13.0" }
16
+ s.source = { :git => "https://github.com/bigcrunch/mobile-ads-sdk.git", :tag => "#{s.version}" }
17
+
18
+ s.source_files = "ios/**/*.{h,c,cc,cpp,m,mm,swift}"
19
+ s.requires_arc = true
20
+
21
+ s.dependency "React"
22
+ s.dependency "BigCrunchAds", "~> 0.1.0" # Reference to main iOS SDK
23
+ s.dependency "Google-Mobile-Ads-SDK", ">= 10.14.0"
24
+ s.dependency "PrebidMobile", "~> 2.1.6"
25
+
26
+ s.swift_version = "5.9"
27
+ end
@@ -0,0 +1,298 @@
1
+ /**
2
+ * BigCrunch Mobile Ads SDK for React Native
3
+ * Main API class
4
+ */
5
+
6
+ import {
7
+ NativeBigCrunchAds,
8
+ BigCrunchAdsEventEmitter,
9
+ NativeEventNames,
10
+ } from './NativeBigCrunchAds';
11
+ import type {
12
+ InitializationOptions,
13
+ Environment,
14
+ SessionInfo,
15
+ DeviceContext,
16
+ AppConfig,
17
+ EventSubscription,
18
+ } from './types';
19
+
20
+ /**
21
+ * Main entry point for BigCrunch Mobile Ads SDK
22
+ */
23
+ export class BigCrunchAds {
24
+ private static isInitializedFlag = false;
25
+ private static initializationPromise: Promise<void> | null = null;
26
+
27
+ /**
28
+ * Initialize the BigCrunch Ads SDK
29
+ * Must be called before using any other SDK features
30
+ *
31
+ * @param propertyId - Your BigCrunch property ID
32
+ * @param apiKey - Your API key for authentication
33
+ * @param environment - Environment to use (default: 'production')
34
+ * @param options - Additional initialization options
35
+ *
36
+ * @example
37
+ * ```typescript
38
+ * await BigCrunchAds.initialize(
39
+ * 'your-property-id',
40
+ * 'your-api-key',
41
+ * 'production'
42
+ * );
43
+ * ```
44
+ */
45
+ static async initialize(
46
+ propertyId: string,
47
+ apiKey: string,
48
+ environment: Environment = 'production',
49
+ options?: Partial<InitializationOptions>
50
+ ): Promise<void> {
51
+ if (this.isInitializedFlag) {
52
+ console.warn('BigCrunchAds: SDK is already initialized');
53
+ return this.initializationPromise!;
54
+ }
55
+
56
+ const initOptions: InitializationOptions = {
57
+ propertyId,
58
+ apiKey,
59
+ environment,
60
+ ...options,
61
+ };
62
+
63
+ this.initializationPromise = NativeBigCrunchAds.initialize(initOptions)
64
+ .then(() => {
65
+ this.isInitializedFlag = true;
66
+ console.log('BigCrunchAds: SDK initialized successfully');
67
+ })
68
+ .catch((error) => {
69
+ this.isInitializedFlag = false;
70
+ this.initializationPromise = null;
71
+ throw error;
72
+ });
73
+
74
+ return this.initializationPromise;
75
+ }
76
+
77
+ /**
78
+ * Check if the SDK is initialized
79
+ */
80
+ static async isInitialized(): Promise<boolean> {
81
+ if (this.isInitializedFlag) {
82
+ return true;
83
+ }
84
+ return NativeBigCrunchAds.isInitialized();
85
+ }
86
+
87
+ /**
88
+ * Track a screen view for analytics
89
+ *
90
+ * @param screenName - Name of the screen being viewed
91
+ *
92
+ * @example
93
+ * ```typescript
94
+ * BigCrunchAds.trackScreenView('HomeScreen');
95
+ * ```
96
+ */
97
+ static async trackScreenView(screenName: string): Promise<void> {
98
+ this.ensureInitialized();
99
+ return NativeBigCrunchAds.trackScreenView(screenName);
100
+ }
101
+
102
+ /**
103
+ * Get the current app configuration
104
+ * Returns null if config hasn't been loaded yet
105
+ */
106
+ static async getAppConfig(): Promise<AppConfig | null> {
107
+ this.ensureInitialized();
108
+ return NativeBigCrunchAds.getAppConfig();
109
+ }
110
+
111
+ /**
112
+ * Force refresh the app configuration from backend
113
+ */
114
+ static async refreshConfig(): Promise<void> {
115
+ this.ensureInitialized();
116
+ return NativeBigCrunchAds.refreshConfig();
117
+ }
118
+
119
+ /**
120
+ * Get current session information
121
+ */
122
+ static async getSessionInfo(): Promise<SessionInfo> {
123
+ this.ensureInitialized();
124
+ return NativeBigCrunchAds.getSessionInfo();
125
+ }
126
+
127
+ /**
128
+ * Start a new session (usually handled automatically)
129
+ */
130
+ static async startNewSession(): Promise<void> {
131
+ this.ensureInitialized();
132
+ return NativeBigCrunchAds.startNewSession();
133
+ }
134
+
135
+ /**
136
+ * Get device context information
137
+ */
138
+ static async getDeviceContext(): Promise<DeviceContext> {
139
+ return NativeBigCrunchAds.getDeviceContext();
140
+ }
141
+
142
+ /**
143
+ * Set GDPR consent string
144
+ *
145
+ * @param consent - GDPR consent string
146
+ */
147
+ static async setGdprConsent(consent: string): Promise<void> {
148
+ return NativeBigCrunchAds.setGdprConsent(consent);
149
+ }
150
+
151
+ /**
152
+ * Set CCPA compliance string
153
+ *
154
+ * @param ccpaString - CCPA string (e.g., "1YNN")
155
+ */
156
+ static async setCcpaString(ccpaString: string): Promise<void> {
157
+ return NativeBigCrunchAds.setCcpaString(ccpaString);
158
+ }
159
+
160
+ /**
161
+ * Set COPPA compliance
162
+ *
163
+ * @param isCompliant - Whether the app is COPPA compliant
164
+ */
165
+ static async setCoppaCompliant(isCompliant: boolean): Promise<void> {
166
+ return NativeBigCrunchAds.setCoppaCompliant(isCompliant);
167
+ }
168
+
169
+ /**
170
+ * Enable or disable debug mode
171
+ *
172
+ * @param enabled - Whether to enable debug mode
173
+ */
174
+ static async setDebugMode(enabled: boolean): Promise<void> {
175
+ return NativeBigCrunchAds.setDebugMode(enabled);
176
+ }
177
+
178
+ /**
179
+ * Add a test device ID for testing ads
180
+ *
181
+ * @param deviceId - Device ID to add as test device
182
+ */
183
+ static async addTestDevice(deviceId: string): Promise<void> {
184
+ return NativeBigCrunchAds.addTestDevice(deviceId);
185
+ }
186
+
187
+ /**
188
+ * Remove a test device ID
189
+ *
190
+ * @param deviceId - Device ID to remove from test devices
191
+ */
192
+ static async removeTestDevice(deviceId: string): Promise<void> {
193
+ return NativeBigCrunchAds.removeTestDevice(deviceId);
194
+ }
195
+
196
+ /**
197
+ * Get list of test device IDs
198
+ */
199
+ static async getTestDevices(): Promise<string[]> {
200
+ return NativeBigCrunchAds.getTestDevices();
201
+ }
202
+
203
+ /**
204
+ * Set UTM parameters for attribution tracking
205
+ *
206
+ * These parameters are persisted and used for all analytics events.
207
+ * Typically set from deep link parameters.
208
+ *
209
+ * @param params - UTM parameters object
210
+ *
211
+ * @example
212
+ * ```typescript
213
+ * BigCrunchAds.setUTMParameters({
214
+ * source: 'google',
215
+ * medium: 'cpc',
216
+ * campaign: 'summer_sale',
217
+ * term: 'running shoes',
218
+ * content: 'variant_a'
219
+ * });
220
+ * ```
221
+ */
222
+ static async setUTMParameters(params: {
223
+ source?: string;
224
+ medium?: string;
225
+ campaign?: string;
226
+ term?: string;
227
+ content?: string;
228
+ }): Promise<void> {
229
+ return NativeBigCrunchAds.setUTMParameters(params);
230
+ }
231
+
232
+ /**
233
+ * Clear UTM parameters
234
+ */
235
+ static async clearUTMParameters(): Promise<void> {
236
+ return NativeBigCrunchAds.clearUTMParameters();
237
+ }
238
+
239
+ /**
240
+ * Add a global event listener
241
+ *
242
+ * @param eventName - Native event name to listen to
243
+ * @param listener - Callback function
244
+ * @returns Subscription object with remove() method
245
+ */
246
+ static addEventListener(
247
+ eventName: string,
248
+ listener: (event: any) => void
249
+ ): EventSubscription {
250
+ const subscription = BigCrunchAdsEventEmitter.addListener(eventName, listener);
251
+ return {
252
+ remove: () => subscription.remove(),
253
+ };
254
+ }
255
+
256
+ /**
257
+ * Listen for configuration updates
258
+ */
259
+ static onConfigUpdated(listener: (config: AppConfig) => void): EventSubscription {
260
+ return this.addEventListener(NativeEventNames.CONFIG_UPDATED, listener);
261
+ }
262
+
263
+ /**
264
+ * Listen for configuration failures
265
+ */
266
+ static onConfigFailed(listener: (error: Error) => void): EventSubscription {
267
+ return this.addEventListener(NativeEventNames.CONFIG_FAILED, listener);
268
+ }
269
+
270
+ /**
271
+ * Listen for session start events
272
+ */
273
+ static onSessionStarted(listener: (session: SessionInfo) => void): EventSubscription {
274
+ return this.addEventListener(NativeEventNames.SESSION_STARTED, listener);
275
+ }
276
+
277
+ /**
278
+ * Listen for session end events
279
+ */
280
+ static onSessionEnded(listener: (session: SessionInfo) => void): EventSubscription {
281
+ return this.addEventListener(NativeEventNames.SESSION_ENDED, listener);
282
+ }
283
+
284
+ /**
285
+ * Ensure SDK is initialized before calling methods
286
+ * @private
287
+ */
288
+ private static ensureInitialized(): void {
289
+ if (!this.isInitializedFlag && !this.initializationPromise) {
290
+ throw new Error(
291
+ 'BigCrunchAds: SDK is not initialized. Call BigCrunchAds.initialize() first.'
292
+ );
293
+ }
294
+ }
295
+ }
296
+
297
+ // Export as default for convenience
298
+ export default BigCrunchAds;
@@ -0,0 +1,262 @@
1
+ /**
2
+ * BigCrunchBannerView - React Native component for displaying banner ads
3
+ */
4
+
5
+ import React, { useEffect, useRef, useCallback, useMemo } from 'react';
6
+ import {
7
+ requireNativeComponent,
8
+ ViewStyle,
9
+ StyleSheet,
10
+ findNodeHandle,
11
+ UIManager,
12
+ } from 'react-native';
13
+ import { BigCrunchAdsEventEmitter, NativeEventNames } from './NativeBigCrunchAds';
14
+ import type {
15
+ BigCrunchBannerViewProps,
16
+ BannerSize,
17
+ AdError,
18
+ AdRevenue,
19
+ EventSubscription,
20
+ } from './types';
21
+
22
+ // Native component name
23
+ const NATIVE_COMPONENT_NAME = 'BigCrunchBannerView';
24
+
25
+ // Banner size dimensions
26
+ const BANNER_SIZES = {
27
+ BANNER: { width: 320, height: 50 },
28
+ LARGE_BANNER: { width: 320, height: 100 },
29
+ MEDIUM_RECTANGLE: { width: 300, height: 250 },
30
+ FULL_BANNER: { width: 468, height: 60 },
31
+ LEADERBOARD: { width: 728, height: 90 },
32
+ ADAPTIVE: { width: -1, height: -1 }, // Calculated dynamically
33
+ SMART: { width: -1, height: -1 }, // Deprecated, use ADAPTIVE
34
+ };
35
+
36
+ // Native view component
37
+ const NativeBannerView = requireNativeComponent<any>(NATIVE_COMPONENT_NAME);
38
+
39
+ /**
40
+ * React component for displaying BigCrunch banner ads
41
+ *
42
+ * @example
43
+ * ```tsx
44
+ * <BigCrunchBannerView
45
+ * placementId="banner-home"
46
+ * size="BANNER"
47
+ * onAdLoaded={() => console.log('Ad loaded')}
48
+ * onAdFailedToLoad={(error) => console.error('Ad failed to load', error)}
49
+ * />
50
+ * ```
51
+ */
52
+ export const BigCrunchBannerView: React.FC<BigCrunchBannerViewProps> = ({
53
+ placementId,
54
+ size = 'BANNER',
55
+ autoLoad = true,
56
+ refreshInterval = 0,
57
+ customTargeting,
58
+ style,
59
+ onAdLoaded,
60
+ onAdFailedToLoad,
61
+ onAdImpression,
62
+ onAdClicked,
63
+ onAdOpened,
64
+ onAdClosed,
65
+ onAdRevenue,
66
+ }) => {
67
+ const viewRef = useRef<any>(null);
68
+ const subscriptionsRef = useRef<EventSubscription[]>([]);
69
+ const viewIdRef = useRef<string>(`banner_${placementId}_${Date.now()}`);
70
+
71
+ // Calculate banner size
72
+ const bannerSize = useMemo(() => {
73
+ if (typeof size === 'object' && 'width' in size && 'height' in size) {
74
+ // Custom size
75
+ return size;
76
+ } else if (typeof size === 'string' && size in BANNER_SIZES) {
77
+ // Predefined size
78
+ const dimensions = BANNER_SIZES[size as BannerSize];
79
+ if (dimensions.width === -1 || dimensions.height === -1) {
80
+ // Adaptive/Smart banner - will be calculated natively
81
+ return { width: 0, height: 0, adaptive: true };
82
+ }
83
+ return dimensions;
84
+ }
85
+ // Default to BANNER size
86
+ return BANNER_SIZES.BANNER;
87
+ }, [size]);
88
+
89
+ // Handle native events
90
+ const handleNativeEvent = useCallback((_eventName: string, handler?: Function) => {
91
+ return (event: any) => {
92
+ // Check if event is for this specific banner view
93
+ if (event.viewId === viewIdRef.current || event.placementId === placementId) {
94
+ handler?.(event);
95
+ }
96
+ };
97
+ }, [placementId]);
98
+
99
+ // Setup event listeners
100
+ useEffect(() => {
101
+ const subscriptions: EventSubscription[] = [];
102
+
103
+ if (onAdLoaded) {
104
+ subscriptions.push(
105
+ BigCrunchAdsEventEmitter.addListener(
106
+ NativeEventNames.BANNER_AD_LOADED,
107
+ handleNativeEvent(NativeEventNames.BANNER_AD_LOADED, onAdLoaded)
108
+ )
109
+ );
110
+ }
111
+
112
+ if (onAdFailedToLoad) {
113
+ subscriptions.push(
114
+ BigCrunchAdsEventEmitter.addListener(
115
+ NativeEventNames.BANNER_AD_FAILED_TO_LOAD,
116
+ handleNativeEvent(NativeEventNames.BANNER_AD_FAILED_TO_LOAD, (event: any) => {
117
+ const error: AdError = {
118
+ code: event.errorCode || 'UNKNOWN',
119
+ message: event.errorMessage || 'Ad failed to load',
120
+ underlyingError: event.underlyingError,
121
+ };
122
+ onAdFailedToLoad(error);
123
+ })
124
+ )
125
+ );
126
+ }
127
+
128
+ if (onAdImpression) {
129
+ subscriptions.push(
130
+ BigCrunchAdsEventEmitter.addListener(
131
+ NativeEventNames.BANNER_AD_IMPRESSION,
132
+ handleNativeEvent(NativeEventNames.BANNER_AD_IMPRESSION, onAdImpression)
133
+ )
134
+ );
135
+ }
136
+
137
+ if (onAdClicked) {
138
+ subscriptions.push(
139
+ BigCrunchAdsEventEmitter.addListener(
140
+ NativeEventNames.BANNER_AD_CLICKED,
141
+ handleNativeEvent(NativeEventNames.BANNER_AD_CLICKED, onAdClicked)
142
+ )
143
+ );
144
+ }
145
+
146
+ if (onAdOpened) {
147
+ subscriptions.push(
148
+ BigCrunchAdsEventEmitter.addListener(
149
+ NativeEventNames.BANNER_AD_OPENED,
150
+ handleNativeEvent(NativeEventNames.BANNER_AD_OPENED, onAdOpened)
151
+ )
152
+ );
153
+ }
154
+
155
+ if (onAdClosed) {
156
+ subscriptions.push(
157
+ BigCrunchAdsEventEmitter.addListener(
158
+ NativeEventNames.BANNER_AD_CLOSED,
159
+ handleNativeEvent(NativeEventNames.BANNER_AD_CLOSED, onAdClosed)
160
+ )
161
+ );
162
+ }
163
+
164
+ if (onAdRevenue) {
165
+ subscriptions.push(
166
+ BigCrunchAdsEventEmitter.addListener(
167
+ NativeEventNames.BANNER_AD_REVENUE,
168
+ handleNativeEvent(NativeEventNames.BANNER_AD_REVENUE, (event: any) => {
169
+ const revenue: AdRevenue = {
170
+ valueMicros: event.valueMicros,
171
+ currencyCode: event.currencyCode,
172
+ adUnitId: event.adUnitId,
173
+ precision: event.precision,
174
+ };
175
+ onAdRevenue(revenue);
176
+ })
177
+ )
178
+ );
179
+ }
180
+
181
+ subscriptionsRef.current = subscriptions;
182
+
183
+ // Cleanup on unmount
184
+ return () => {
185
+ subscriptions.forEach(sub => sub.remove());
186
+ subscriptionsRef.current = [];
187
+ };
188
+ }, [
189
+ placementId,
190
+ handleNativeEvent,
191
+ onAdLoaded,
192
+ onAdFailedToLoad,
193
+ onAdImpression,
194
+ onAdClicked,
195
+ onAdOpened,
196
+ onAdClosed,
197
+ onAdRevenue,
198
+ ]);
199
+
200
+ // Load ad programmatically
201
+ const loadAd = useCallback(() => {
202
+ if (viewRef.current) {
203
+ const handle = findNodeHandle(viewRef.current);
204
+ if (handle) {
205
+ const viewManagerConfig = UIManager.getViewManagerConfig(NATIVE_COMPONENT_NAME);
206
+ const command = viewManagerConfig?.Commands?.loadAd;
207
+ if (command !== undefined) {
208
+ UIManager.dispatchViewManagerCommand(handle, command, []);
209
+ }
210
+ }
211
+ }
212
+ }, []);
213
+
214
+ // Auto-load ad on mount if enabled
215
+ useEffect(() => {
216
+ if (autoLoad) {
217
+ // Delay to ensure native view is ready
218
+ const timer = setTimeout(loadAd, 100);
219
+ return () => clearTimeout(timer);
220
+ }
221
+ return undefined;
222
+ }, [autoLoad, loadAd]);
223
+
224
+ // Container styles
225
+ const containerStyle: ViewStyle = useMemo(() => {
226
+ const baseStyle: ViewStyle = {
227
+ width: bannerSize.width > 0 ? bannerSize.width : 320,
228
+ height: bannerSize.height > 0 ? bannerSize.height : 50,
229
+ // Remove overflow: 'hidden' to avoid clipping the ad content
230
+ };
231
+
232
+ if ((bannerSize as any).adaptive) {
233
+ // Adaptive banner - let it size itself
234
+ baseStyle.alignSelf = 'stretch';
235
+ baseStyle.width = '100%';
236
+ }
237
+
238
+ return StyleSheet.flatten([baseStyle, style]);
239
+ }, [bannerSize, style]);
240
+
241
+ // Native view props
242
+ // Always pass explicit dimensions to the native view
243
+ const nativeProps = {
244
+ ref: viewRef,
245
+ style: containerStyle,
246
+ placementId,
247
+ size: typeof size === 'string' ? size : 'CUSTOM',
248
+ // Always pass width and height, even for standard sizes
249
+ customWidth: bannerSize.width > 0 ? bannerSize.width : undefined,
250
+ customHeight: bannerSize.height > 0 ? bannerSize.height : undefined,
251
+ autoLoad,
252
+ refreshInterval,
253
+ customTargeting,
254
+ viewId: viewIdRef.current,
255
+ };
256
+
257
+ // Return the native view directly with the container style
258
+ return <NativeBannerView {...nativeProps} />;
259
+ };
260
+
261
+ // Export as default
262
+ export default BigCrunchBannerView;