@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.
- package/README.md +417 -0
- package/android/build.gradle +70 -0
- package/android/settings.gradle +6 -0
- package/android/src/main/AndroidManifest.xml +3 -0
- package/android/src/main/java/com/bigcrunch/ads/react/BigCrunchAdsModule.kt +653 -0
- package/android/src/main/java/com/bigcrunch/ads/react/BigCrunchAdsPackage.kt +20 -0
- package/android/src/main/java/com/bigcrunch/ads/react/BigCrunchBannerViewManager.kt +296 -0
- package/ios/BigCrunchAdsModule.swift +588 -0
- package/ios/BigCrunchBannerViewManager.swift +270 -0
- package/ios/react-native-bigcrunch-ads-Bridging-Header.h +8 -0
- package/lib/BigCrunchAds.d.ts +168 -0
- package/lib/BigCrunchAds.d.ts.map +1 -0
- package/lib/BigCrunchAds.js +241 -0
- package/lib/BigCrunchBannerView.d.ts +21 -0
- package/lib/BigCrunchBannerView.d.ts.map +1 -0
- package/lib/BigCrunchBannerView.js +176 -0
- package/lib/BigCrunchInterstitial.d.ts +66 -0
- package/lib/BigCrunchInterstitial.d.ts.map +1 -0
- package/lib/BigCrunchInterstitial.js +222 -0
- package/lib/BigCrunchRewarded.d.ts +85 -0
- package/lib/BigCrunchRewarded.d.ts.map +1 -0
- package/lib/BigCrunchRewarded.js +257 -0
- package/lib/NativeBigCrunchAds.d.ts +71 -0
- package/lib/NativeBigCrunchAds.d.ts.map +1 -0
- package/lib/NativeBigCrunchAds.js +54 -0
- package/lib/index.d.ts +28 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +32 -0
- package/lib/types/ads.d.ts +101 -0
- package/lib/types/ads.d.ts.map +1 -0
- package/lib/types/ads.js +4 -0
- package/lib/types/config.d.ts +137 -0
- package/lib/types/config.d.ts.map +1 -0
- package/lib/types/config.js +4 -0
- package/lib/types/events.d.ts +306 -0
- package/lib/types/events.d.ts.map +1 -0
- package/lib/types/events.js +4 -0
- package/lib/types/index.d.ts +175 -0
- package/lib/types/index.d.ts.map +1 -0
- package/lib/types/index.js +23 -0
- package/package.json +88 -0
- package/react-native-bigcrunch-ads.podspec +27 -0
- package/src/BigCrunchAds.ts +298 -0
- package/src/BigCrunchBannerView.tsx +262 -0
- package/src/BigCrunchInterstitial.ts +266 -0
- package/src/BigCrunchRewarded.ts +307 -0
- package/src/NativeBigCrunchAds.ts +120 -0
- package/src/index.ts +71 -0
- package/src/types/ads.ts +112 -0
- package/src/types/config.ts +145 -0
- package/src/types/events.ts +337 -0
- package/src/types/index.ts +193 -0
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BigCrunchInterstitial - API for interstitial ads
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { NativeBigCrunchAds, BigCrunchAdsEventEmitter, NativeEventNames } from './NativeBigCrunchAds';
|
|
6
|
+
import type {
|
|
7
|
+
InterstitialAd,
|
|
8
|
+
AdRequestOptions,
|
|
9
|
+
AdEvent,
|
|
10
|
+
AdEventListener,
|
|
11
|
+
EventSubscription,
|
|
12
|
+
AdError,
|
|
13
|
+
AdRevenue,
|
|
14
|
+
} from './types';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Static API for BigCrunch interstitial ads
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```typescript
|
|
21
|
+
* // Load an interstitial
|
|
22
|
+
* await BigCrunchInterstitial.load({ placementId: 'interstitial-level-complete' });
|
|
23
|
+
*
|
|
24
|
+
* // Show when ready
|
|
25
|
+
* if (await BigCrunchInterstitial.isLoaded('interstitial-level-complete')) {
|
|
26
|
+
* await BigCrunchInterstitial.show('interstitial-level-complete');
|
|
27
|
+
* }
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
export class BigCrunchInterstitial {
|
|
31
|
+
private static instances = new Map<string, InterstitialAdInstance>();
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Load an interstitial ad
|
|
35
|
+
*
|
|
36
|
+
* @param options - Ad request options including placementId
|
|
37
|
+
*/
|
|
38
|
+
static async load(options: AdRequestOptions): Promise<void> {
|
|
39
|
+
const { placementId } = options;
|
|
40
|
+
|
|
41
|
+
// Create or get existing instance
|
|
42
|
+
let instance = this.instances.get(placementId);
|
|
43
|
+
if (!instance) {
|
|
44
|
+
instance = new InterstitialAdInstance(placementId);
|
|
45
|
+
this.instances.set(placementId, instance);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return instance.load(options);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Show a loaded interstitial ad
|
|
53
|
+
*
|
|
54
|
+
* @param placementId - The placement ID of the ad to show
|
|
55
|
+
*/
|
|
56
|
+
static async show(placementId: string): Promise<void> {
|
|
57
|
+
const instance = this.instances.get(placementId);
|
|
58
|
+
if (!instance) {
|
|
59
|
+
throw new Error(`No interstitial loaded for placement: ${placementId}`);
|
|
60
|
+
}
|
|
61
|
+
return instance.show();
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Check if an interstitial is loaded and ready to show
|
|
66
|
+
*
|
|
67
|
+
* @param placementId - The placement ID to check
|
|
68
|
+
*/
|
|
69
|
+
static async isLoaded(placementId: string): Promise<boolean> {
|
|
70
|
+
const instance = this.instances.get(placementId);
|
|
71
|
+
if (!instance) {
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
return instance.isLoaded();
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Destroy an interstitial instance
|
|
79
|
+
*
|
|
80
|
+
* @param placementId - The placement ID of the ad to destroy
|
|
81
|
+
*/
|
|
82
|
+
static destroy(placementId: string): void {
|
|
83
|
+
const instance = this.instances.get(placementId);
|
|
84
|
+
if (instance) {
|
|
85
|
+
instance.destroy();
|
|
86
|
+
this.instances.delete(placementId);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Destroy all interstitial instances
|
|
92
|
+
*/
|
|
93
|
+
static destroyAll(): void {
|
|
94
|
+
this.instances.forEach(instance => instance.destroy());
|
|
95
|
+
this.instances.clear();
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Create an interstitial ad instance
|
|
100
|
+
* Alternative to static methods for more control
|
|
101
|
+
*
|
|
102
|
+
* @param placementId - The placement ID for this ad
|
|
103
|
+
*/
|
|
104
|
+
static createAd(placementId: string): InterstitialAd {
|
|
105
|
+
let instance = this.instances.get(placementId);
|
|
106
|
+
if (!instance) {
|
|
107
|
+
instance = new InterstitialAdInstance(placementId);
|
|
108
|
+
this.instances.set(placementId, instance);
|
|
109
|
+
}
|
|
110
|
+
return instance;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Add event listener for a specific placement
|
|
115
|
+
*
|
|
116
|
+
* @param placementId - The placement ID to listen to
|
|
117
|
+
* @param eventType - The event type to listen for
|
|
118
|
+
* @param listener - The callback function
|
|
119
|
+
*/
|
|
120
|
+
static addEventListener<T extends AdEvent>(
|
|
121
|
+
placementId: string,
|
|
122
|
+
eventType: T['type'],
|
|
123
|
+
listener: AdEventListener<T>
|
|
124
|
+
): EventSubscription {
|
|
125
|
+
const instance = this.instances.get(placementId);
|
|
126
|
+
if (!instance) {
|
|
127
|
+
const newInstance = new InterstitialAdInstance(placementId);
|
|
128
|
+
this.instances.set(placementId, newInstance);
|
|
129
|
+
return newInstance.addEventListener(eventType, listener);
|
|
130
|
+
}
|
|
131
|
+
return instance.addEventListener(eventType, listener);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Internal interstitial ad instance
|
|
137
|
+
*/
|
|
138
|
+
class InterstitialAdInstance implements InterstitialAd {
|
|
139
|
+
private placementId: string;
|
|
140
|
+
private subscriptions: EventSubscription[] = [];
|
|
141
|
+
private listeners = new Map<string, Set<AdEventListener<AdEvent>>>();
|
|
142
|
+
|
|
143
|
+
constructor(placementId: string) {
|
|
144
|
+
this.placementId = placementId;
|
|
145
|
+
this.setupEventListeners();
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
async load(options: AdRequestOptions): Promise<void> {
|
|
149
|
+
return NativeBigCrunchAds.loadInterstitial(options);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
async show(): Promise<void> {
|
|
153
|
+
return NativeBigCrunchAds.showInterstitial(this.placementId);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
async isLoaded(): Promise<boolean> {
|
|
157
|
+
return NativeBigCrunchAds.isInterstitialLoaded(this.placementId);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
destroy(): void {
|
|
161
|
+
this.removeAllListeners();
|
|
162
|
+
NativeBigCrunchAds.destroyInterstitial(this.placementId).catch(console.error);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
addEventListener<T extends AdEvent>(
|
|
166
|
+
eventType: T['type'],
|
|
167
|
+
listener: AdEventListener<T>
|
|
168
|
+
): EventSubscription {
|
|
169
|
+
// Add to local listeners
|
|
170
|
+
if (!this.listeners.has(eventType)) {
|
|
171
|
+
this.listeners.set(eventType, new Set());
|
|
172
|
+
}
|
|
173
|
+
// Cast listener to base type for storage - runtime behavior is the same
|
|
174
|
+
const typedListener = listener as AdEventListener<AdEvent>;
|
|
175
|
+
this.listeners.get(eventType)!.add(typedListener);
|
|
176
|
+
|
|
177
|
+
// Return subscription
|
|
178
|
+
return {
|
|
179
|
+
remove: () => {
|
|
180
|
+
const listeners = this.listeners.get(eventType);
|
|
181
|
+
if (listeners) {
|
|
182
|
+
listeners.delete(typedListener);
|
|
183
|
+
}
|
|
184
|
+
},
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
removeAllListeners(): void {
|
|
189
|
+
this.subscriptions.forEach(sub => sub.remove());
|
|
190
|
+
this.subscriptions = [];
|
|
191
|
+
this.listeners.clear();
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
private setupEventListeners(): void {
|
|
195
|
+
const eventMap = {
|
|
196
|
+
adLoaded: NativeEventNames.INTERSTITIAL_AD_LOADED,
|
|
197
|
+
adFailedToLoad: NativeEventNames.INTERSTITIAL_AD_FAILED_TO_LOAD,
|
|
198
|
+
adImpression: NativeEventNames.INTERSTITIAL_AD_IMPRESSION,
|
|
199
|
+
adClicked: NativeEventNames.INTERSTITIAL_AD_CLICKED,
|
|
200
|
+
adOpened: NativeEventNames.INTERSTITIAL_AD_OPENED,
|
|
201
|
+
adClosed: NativeEventNames.INTERSTITIAL_AD_CLOSED,
|
|
202
|
+
adRevenue: NativeEventNames.INTERSTITIAL_AD_REVENUE,
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
Object.entries(eventMap).forEach(([eventType, nativeEvent]) => {
|
|
206
|
+
const subscription = BigCrunchAdsEventEmitter.addListener(nativeEvent, (event: any) => {
|
|
207
|
+
// Check if event is for this placement
|
|
208
|
+
if (event.placementId === this.placementId) {
|
|
209
|
+
// Transform event data if needed
|
|
210
|
+
let transformedEvent: AdEvent;
|
|
211
|
+
|
|
212
|
+
switch (eventType) {
|
|
213
|
+
case 'adFailedToLoad':
|
|
214
|
+
transformedEvent = {
|
|
215
|
+
type: eventType as any,
|
|
216
|
+
placementId: this.placementId,
|
|
217
|
+
format: 'interstitial',
|
|
218
|
+
timestamp: Date.now(),
|
|
219
|
+
error: {
|
|
220
|
+
code: event.errorCode || 'UNKNOWN',
|
|
221
|
+
message: event.errorMessage || 'Ad failed to load',
|
|
222
|
+
underlyingError: event.underlyingError,
|
|
223
|
+
} as AdError,
|
|
224
|
+
};
|
|
225
|
+
break;
|
|
226
|
+
|
|
227
|
+
case 'adRevenue':
|
|
228
|
+
transformedEvent = {
|
|
229
|
+
type: eventType as any,
|
|
230
|
+
placementId: this.placementId,
|
|
231
|
+
format: 'interstitial',
|
|
232
|
+
timestamp: Date.now(),
|
|
233
|
+
revenue: {
|
|
234
|
+
valueMicros: event.valueMicros,
|
|
235
|
+
currencyCode: event.currencyCode,
|
|
236
|
+
adUnitId: event.adUnitId,
|
|
237
|
+
precision: event.precision,
|
|
238
|
+
} as AdRevenue,
|
|
239
|
+
};
|
|
240
|
+
break;
|
|
241
|
+
|
|
242
|
+
default:
|
|
243
|
+
transformedEvent = {
|
|
244
|
+
type: eventType as any,
|
|
245
|
+
placementId: this.placementId,
|
|
246
|
+
format: 'interstitial',
|
|
247
|
+
timestamp: Date.now(),
|
|
248
|
+
...event,
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// Notify local listeners
|
|
253
|
+
const listeners = this.listeners.get(eventType);
|
|
254
|
+
if (listeners) {
|
|
255
|
+
listeners.forEach(listener => listener(transformedEvent));
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
this.subscriptions.push(subscription);
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// Export as default
|
|
266
|
+
export default BigCrunchInterstitial;
|
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BigCrunchRewarded - API for rewarded ads
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { NativeBigCrunchAds, BigCrunchAdsEventEmitter, NativeEventNames } from './NativeBigCrunchAds';
|
|
6
|
+
import type {
|
|
7
|
+
RewardedAd,
|
|
8
|
+
AdRequestOptions,
|
|
9
|
+
AdEvent,
|
|
10
|
+
AdEventListener,
|
|
11
|
+
EventSubscription,
|
|
12
|
+
AdError,
|
|
13
|
+
AdRevenue,
|
|
14
|
+
RewardedAdEarnedEvent,
|
|
15
|
+
} from './types';
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Static API for BigCrunch rewarded ads
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```typescript
|
|
22
|
+
* // Load a rewarded ad
|
|
23
|
+
* await BigCrunchRewarded.load({ placementId: 'rewarded-extra-life' });
|
|
24
|
+
*
|
|
25
|
+
* // Set up reward listener
|
|
26
|
+
* BigCrunchRewarded.addEventListener(
|
|
27
|
+
* 'rewarded-extra-life',
|
|
28
|
+
* 'rewardEarned',
|
|
29
|
+
* (event) => {
|
|
30
|
+
* console.log(`User earned ${event.rewardAmount} ${event.rewardType}`);
|
|
31
|
+
* }
|
|
32
|
+
* );
|
|
33
|
+
*
|
|
34
|
+
* // Show when ready
|
|
35
|
+
* if (await BigCrunchRewarded.isLoaded('rewarded-extra-life')) {
|
|
36
|
+
* await BigCrunchRewarded.show('rewarded-extra-life');
|
|
37
|
+
* }
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
export class BigCrunchRewarded {
|
|
41
|
+
private static instances = new Map<string, RewardedAdInstance>();
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Load a rewarded ad
|
|
45
|
+
*
|
|
46
|
+
* @param options - Ad request options including placementId
|
|
47
|
+
*/
|
|
48
|
+
static async load(options: AdRequestOptions): Promise<void> {
|
|
49
|
+
const { placementId } = options;
|
|
50
|
+
|
|
51
|
+
// Create or get existing instance
|
|
52
|
+
let instance = this.instances.get(placementId);
|
|
53
|
+
if (!instance) {
|
|
54
|
+
instance = new RewardedAdInstance(placementId);
|
|
55
|
+
this.instances.set(placementId, instance);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return instance.load(options);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Show a loaded rewarded ad
|
|
63
|
+
*
|
|
64
|
+
* @param placementId - The placement ID of the ad to show
|
|
65
|
+
*/
|
|
66
|
+
static async show(placementId: string): Promise<void> {
|
|
67
|
+
const instance = this.instances.get(placementId);
|
|
68
|
+
if (!instance) {
|
|
69
|
+
throw new Error(`No rewarded ad loaded for placement: ${placementId}`);
|
|
70
|
+
}
|
|
71
|
+
return instance.show();
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Check if a rewarded ad is loaded and ready to show
|
|
76
|
+
*
|
|
77
|
+
* @param placementId - The placement ID to check
|
|
78
|
+
*/
|
|
79
|
+
static async isLoaded(placementId: string): Promise<boolean> {
|
|
80
|
+
const instance = this.instances.get(placementId);
|
|
81
|
+
if (!instance) {
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
return instance.isLoaded();
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Destroy a rewarded ad instance
|
|
89
|
+
*
|
|
90
|
+
* @param placementId - The placement ID of the ad to destroy
|
|
91
|
+
*/
|
|
92
|
+
static destroy(placementId: string): void {
|
|
93
|
+
const instance = this.instances.get(placementId);
|
|
94
|
+
if (instance) {
|
|
95
|
+
instance.destroy();
|
|
96
|
+
this.instances.delete(placementId);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Destroy all rewarded ad instances
|
|
102
|
+
*/
|
|
103
|
+
static destroyAll(): void {
|
|
104
|
+
this.instances.forEach(instance => instance.destroy());
|
|
105
|
+
this.instances.clear();
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Create a rewarded ad instance
|
|
110
|
+
* Alternative to static methods for more control
|
|
111
|
+
*
|
|
112
|
+
* @param placementId - The placement ID for this ad
|
|
113
|
+
*/
|
|
114
|
+
static createAd(placementId: string): RewardedAd {
|
|
115
|
+
let instance = this.instances.get(placementId);
|
|
116
|
+
if (!instance) {
|
|
117
|
+
instance = new RewardedAdInstance(placementId);
|
|
118
|
+
this.instances.set(placementId, instance);
|
|
119
|
+
}
|
|
120
|
+
return instance;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Add event listener for a specific placement
|
|
125
|
+
*
|
|
126
|
+
* @param placementId - The placement ID to listen to
|
|
127
|
+
* @param eventType - The event type to listen for
|
|
128
|
+
* @param listener - The callback function
|
|
129
|
+
*/
|
|
130
|
+
static addEventListener<T extends AdEvent>(
|
|
131
|
+
placementId: string,
|
|
132
|
+
eventType: T['type'],
|
|
133
|
+
listener: AdEventListener<T>
|
|
134
|
+
): EventSubscription {
|
|
135
|
+
const instance = this.instances.get(placementId);
|
|
136
|
+
if (!instance) {
|
|
137
|
+
const newInstance = new RewardedAdInstance(placementId);
|
|
138
|
+
this.instances.set(placementId, newInstance);
|
|
139
|
+
return newInstance.addEventListener(eventType, listener);
|
|
140
|
+
}
|
|
141
|
+
return instance.addEventListener(eventType, listener);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Convenience method to listen for reward earned events
|
|
146
|
+
*
|
|
147
|
+
* @param placementId - The placement ID to listen to
|
|
148
|
+
* @param listener - Callback when user earns reward
|
|
149
|
+
*/
|
|
150
|
+
static onRewardEarned(
|
|
151
|
+
placementId: string,
|
|
152
|
+
listener: (reward: { rewardType: string; rewardAmount: number }) => void
|
|
153
|
+
): EventSubscription {
|
|
154
|
+
return this.addEventListener(placementId, 'rewardEarned' as any, (event: any) => {
|
|
155
|
+
const rewardEvent = event as RewardedAdEarnedEvent;
|
|
156
|
+
listener({
|
|
157
|
+
rewardType: rewardEvent.rewardType,
|
|
158
|
+
rewardAmount: rewardEvent.rewardAmount,
|
|
159
|
+
});
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Internal rewarded ad instance
|
|
166
|
+
*/
|
|
167
|
+
class RewardedAdInstance implements RewardedAd {
|
|
168
|
+
private placementId: string;
|
|
169
|
+
private subscriptions: EventSubscription[] = [];
|
|
170
|
+
private listeners = new Map<string, Set<AdEventListener<AdEvent>>>();
|
|
171
|
+
|
|
172
|
+
constructor(placementId: string) {
|
|
173
|
+
this.placementId = placementId;
|
|
174
|
+
this.setupEventListeners();
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
async load(options: AdRequestOptions): Promise<void> {
|
|
178
|
+
return NativeBigCrunchAds.loadRewarded(options);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
async show(): Promise<void> {
|
|
182
|
+
return NativeBigCrunchAds.showRewarded(this.placementId);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
async isLoaded(): Promise<boolean> {
|
|
186
|
+
return NativeBigCrunchAds.isRewardedLoaded(this.placementId);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
destroy(): void {
|
|
190
|
+
this.removeAllListeners();
|
|
191
|
+
NativeBigCrunchAds.destroyRewarded(this.placementId).catch(console.error);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
addEventListener<T extends AdEvent>(
|
|
195
|
+
eventType: T['type'],
|
|
196
|
+
listener: AdEventListener<T>
|
|
197
|
+
): EventSubscription {
|
|
198
|
+
// Add to local listeners
|
|
199
|
+
if (!this.listeners.has(eventType)) {
|
|
200
|
+
this.listeners.set(eventType, new Set());
|
|
201
|
+
}
|
|
202
|
+
// Cast listener to base type for storage - runtime behavior is the same
|
|
203
|
+
const typedListener = listener as AdEventListener<AdEvent>;
|
|
204
|
+
this.listeners.get(eventType)!.add(typedListener);
|
|
205
|
+
|
|
206
|
+
// Return subscription
|
|
207
|
+
return {
|
|
208
|
+
remove: () => {
|
|
209
|
+
const listeners = this.listeners.get(eventType);
|
|
210
|
+
if (listeners) {
|
|
211
|
+
listeners.delete(typedListener);
|
|
212
|
+
}
|
|
213
|
+
},
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
removeAllListeners(): void {
|
|
218
|
+
this.subscriptions.forEach(sub => sub.remove());
|
|
219
|
+
this.subscriptions = [];
|
|
220
|
+
this.listeners.clear();
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
private setupEventListeners(): void {
|
|
224
|
+
const eventMap = {
|
|
225
|
+
adLoaded: NativeEventNames.REWARDED_AD_LOADED,
|
|
226
|
+
adFailedToLoad: NativeEventNames.REWARDED_AD_FAILED_TO_LOAD,
|
|
227
|
+
adImpression: NativeEventNames.REWARDED_AD_IMPRESSION,
|
|
228
|
+
adClicked: NativeEventNames.REWARDED_AD_CLICKED,
|
|
229
|
+
adOpened: NativeEventNames.REWARDED_AD_OPENED,
|
|
230
|
+
adClosed: NativeEventNames.REWARDED_AD_CLOSED,
|
|
231
|
+
adRevenue: NativeEventNames.REWARDED_AD_REVENUE,
|
|
232
|
+
rewardEarned: NativeEventNames.REWARDED_AD_EARNED,
|
|
233
|
+
};
|
|
234
|
+
|
|
235
|
+
Object.entries(eventMap).forEach(([eventType, nativeEvent]) => {
|
|
236
|
+
const subscription = BigCrunchAdsEventEmitter.addListener(nativeEvent, (event: any) => {
|
|
237
|
+
// Check if event is for this placement
|
|
238
|
+
if (event.placementId === this.placementId) {
|
|
239
|
+
// Transform event data if needed
|
|
240
|
+
let transformedEvent: AdEvent;
|
|
241
|
+
|
|
242
|
+
switch (eventType) {
|
|
243
|
+
case 'adFailedToLoad':
|
|
244
|
+
transformedEvent = {
|
|
245
|
+
type: eventType as any,
|
|
246
|
+
placementId: this.placementId,
|
|
247
|
+
format: 'rewarded',
|
|
248
|
+
timestamp: Date.now(),
|
|
249
|
+
error: {
|
|
250
|
+
code: event.errorCode || 'UNKNOWN',
|
|
251
|
+
message: event.errorMessage || 'Ad failed to load',
|
|
252
|
+
underlyingError: event.underlyingError,
|
|
253
|
+
} as AdError,
|
|
254
|
+
};
|
|
255
|
+
break;
|
|
256
|
+
|
|
257
|
+
case 'adRevenue':
|
|
258
|
+
transformedEvent = {
|
|
259
|
+
type: eventType as any,
|
|
260
|
+
placementId: this.placementId,
|
|
261
|
+
format: 'rewarded',
|
|
262
|
+
timestamp: Date.now(),
|
|
263
|
+
revenue: {
|
|
264
|
+
valueMicros: event.valueMicros,
|
|
265
|
+
currencyCode: event.currencyCode,
|
|
266
|
+
adUnitId: event.adUnitId,
|
|
267
|
+
precision: event.precision,
|
|
268
|
+
} as AdRevenue,
|
|
269
|
+
};
|
|
270
|
+
break;
|
|
271
|
+
|
|
272
|
+
case 'rewardEarned':
|
|
273
|
+
transformedEvent = {
|
|
274
|
+
type: eventType as any,
|
|
275
|
+
placementId: this.placementId,
|
|
276
|
+
format: 'rewarded',
|
|
277
|
+
timestamp: Date.now(),
|
|
278
|
+
rewardType: event.rewardType || 'default',
|
|
279
|
+
rewardAmount: event.rewardAmount || 1,
|
|
280
|
+
} as RewardedAdEarnedEvent;
|
|
281
|
+
break;
|
|
282
|
+
|
|
283
|
+
default:
|
|
284
|
+
transformedEvent = {
|
|
285
|
+
type: eventType as any,
|
|
286
|
+
placementId: this.placementId,
|
|
287
|
+
format: 'rewarded',
|
|
288
|
+
timestamp: Date.now(),
|
|
289
|
+
...event,
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// Notify local listeners
|
|
294
|
+
const listeners = this.listeners.get(eventType);
|
|
295
|
+
if (listeners) {
|
|
296
|
+
listeners.forEach(listener => listener(transformedEvent));
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
this.subscriptions.push(subscription);
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
// Export as default
|
|
307
|
+
export default BigCrunchRewarded;
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Native module interface for BigCrunch Ads
|
|
3
|
+
* This is the bridge to the native Android/iOS implementation
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { NativeModules, NativeEventEmitter, Platform } from 'react-native';
|
|
7
|
+
import type { InitializationOptions, AdRequestOptions, SessionInfo, DeviceContext, AppConfig } from './types';
|
|
8
|
+
|
|
9
|
+
// Type definition for the native module
|
|
10
|
+
export interface NativeBigCrunchAdsModule {
|
|
11
|
+
// Initialization
|
|
12
|
+
initialize(options: InitializationOptions): Promise<void>;
|
|
13
|
+
isInitialized(): Promise<boolean>;
|
|
14
|
+
|
|
15
|
+
// Configuration
|
|
16
|
+
getAppConfig(): Promise<AppConfig | null>;
|
|
17
|
+
refreshConfig(): Promise<void>;
|
|
18
|
+
|
|
19
|
+
// Screen tracking
|
|
20
|
+
trackScreenView(screenName: string): Promise<void>;
|
|
21
|
+
|
|
22
|
+
// Interstitial ads
|
|
23
|
+
loadInterstitial(options: AdRequestOptions): Promise<void>;
|
|
24
|
+
showInterstitial(placementId: string): Promise<void>;
|
|
25
|
+
isInterstitialLoaded(placementId: string): Promise<boolean>;
|
|
26
|
+
destroyInterstitial(placementId: string): Promise<void>;
|
|
27
|
+
|
|
28
|
+
// Rewarded ads
|
|
29
|
+
loadRewarded(options: AdRequestOptions): Promise<void>;
|
|
30
|
+
showRewarded(placementId: string): Promise<void>;
|
|
31
|
+
isRewardedLoaded(placementId: string): Promise<boolean>;
|
|
32
|
+
destroyRewarded(placementId: string): Promise<void>;
|
|
33
|
+
|
|
34
|
+
// Session management
|
|
35
|
+
getSessionInfo(): Promise<SessionInfo>;
|
|
36
|
+
startNewSession(): Promise<void>;
|
|
37
|
+
|
|
38
|
+
// Device context
|
|
39
|
+
getDeviceContext(): Promise<DeviceContext>;
|
|
40
|
+
|
|
41
|
+
// Privacy
|
|
42
|
+
setGdprConsent(consent: string): Promise<void>;
|
|
43
|
+
setCcpaString(ccpaString: string): Promise<void>;
|
|
44
|
+
setCoppaCompliant(isCompliant: boolean): Promise<void>;
|
|
45
|
+
|
|
46
|
+
// Debug
|
|
47
|
+
setDebugMode(enabled: boolean): Promise<void>;
|
|
48
|
+
addTestDevice(deviceId: string): Promise<void>;
|
|
49
|
+
removeTestDevice(deviceId: string): Promise<void>;
|
|
50
|
+
getTestDevices(): Promise<string[]>;
|
|
51
|
+
|
|
52
|
+
// UTM Attribution
|
|
53
|
+
setUTMParameters(params: {
|
|
54
|
+
source?: string;
|
|
55
|
+
medium?: string;
|
|
56
|
+
campaign?: string;
|
|
57
|
+
term?: string;
|
|
58
|
+
content?: string;
|
|
59
|
+
}): Promise<void>;
|
|
60
|
+
clearUTMParameters(): Promise<void>;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Get the native module
|
|
64
|
+
const { BigCrunchAdsModule } = NativeModules;
|
|
65
|
+
|
|
66
|
+
if (!BigCrunchAdsModule) {
|
|
67
|
+
const errorMessage = Platform.select({
|
|
68
|
+
ios: 'BigCrunchAdsModule native module is not available on iOS. Make sure you have run `pod install` and rebuilt the app.',
|
|
69
|
+
android: 'BigCrunchAdsModule native module is not available on Android. Make sure you have rebuilt the app.',
|
|
70
|
+
default: 'BigCrunchAdsModule native module is not available. Make sure the library is properly linked.',
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
throw new Error(errorMessage);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Export the native module with proper typing
|
|
77
|
+
export const NativeBigCrunchAds = BigCrunchAdsModule as NativeBigCrunchAdsModule;
|
|
78
|
+
|
|
79
|
+
// Export the event emitter for the native module
|
|
80
|
+
export const BigCrunchAdsEventEmitter = new NativeEventEmitter(BigCrunchAdsModule);
|
|
81
|
+
|
|
82
|
+
// Event names used by the native module
|
|
83
|
+
export const NativeEventNames = {
|
|
84
|
+
// Banner events
|
|
85
|
+
BANNER_AD_LOADED: 'BigCrunchBannerAdLoaded',
|
|
86
|
+
BANNER_AD_FAILED_TO_LOAD: 'BigCrunchBannerAdFailedToLoad',
|
|
87
|
+
BANNER_AD_IMPRESSION: 'BigCrunchBannerAdImpression',
|
|
88
|
+
BANNER_AD_CLICKED: 'BigCrunchBannerAdClicked',
|
|
89
|
+
BANNER_AD_OPENED: 'BigCrunchBannerAdOpened',
|
|
90
|
+
BANNER_AD_CLOSED: 'BigCrunchBannerAdClosed',
|
|
91
|
+
BANNER_AD_REVENUE: 'BigCrunchBannerAdRevenue',
|
|
92
|
+
BANNER_AD_VIEWABLE: 'BigCrunchBannerAdViewable',
|
|
93
|
+
|
|
94
|
+
// Interstitial events
|
|
95
|
+
INTERSTITIAL_AD_LOADED: 'BigCrunchInterstitialAdLoaded',
|
|
96
|
+
INTERSTITIAL_AD_FAILED_TO_LOAD: 'BigCrunchInterstitialAdFailedToLoad',
|
|
97
|
+
INTERSTITIAL_AD_IMPRESSION: 'BigCrunchInterstitialAdImpression',
|
|
98
|
+
INTERSTITIAL_AD_CLICKED: 'BigCrunchInterstitialAdClicked',
|
|
99
|
+
INTERSTITIAL_AD_OPENED: 'BigCrunchInterstitialAdOpened',
|
|
100
|
+
INTERSTITIAL_AD_CLOSED: 'BigCrunchInterstitialAdClosed',
|
|
101
|
+
INTERSTITIAL_AD_REVENUE: 'BigCrunchInterstitialAdRevenue',
|
|
102
|
+
|
|
103
|
+
// Rewarded events
|
|
104
|
+
REWARDED_AD_LOADED: 'BigCrunchRewardedAdLoaded',
|
|
105
|
+
REWARDED_AD_FAILED_TO_LOAD: 'BigCrunchRewardedAdFailedToLoad',
|
|
106
|
+
REWARDED_AD_IMPRESSION: 'BigCrunchRewardedAdImpression',
|
|
107
|
+
REWARDED_AD_CLICKED: 'BigCrunchRewardedAdClicked',
|
|
108
|
+
REWARDED_AD_OPENED: 'BigCrunchRewardedAdOpened',
|
|
109
|
+
REWARDED_AD_CLOSED: 'BigCrunchRewardedAdClosed',
|
|
110
|
+
REWARDED_AD_REVENUE: 'BigCrunchRewardedAdRevenue',
|
|
111
|
+
REWARDED_AD_EARNED: 'BigCrunchRewardedAdEarned',
|
|
112
|
+
|
|
113
|
+
// Configuration events
|
|
114
|
+
CONFIG_UPDATED: 'BigCrunchConfigUpdated',
|
|
115
|
+
CONFIG_FAILED: 'BigCrunchConfigFailed',
|
|
116
|
+
|
|
117
|
+
// Session events
|
|
118
|
+
SESSION_STARTED: 'BigCrunchSessionStarted',
|
|
119
|
+
SESSION_ENDED: 'BigCrunchSessionEnded',
|
|
120
|
+
} as const;
|