@ezoic/react-native-sdk 1.0.0 → 1.2.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/EzoicReactNativeSdk.podspec +1 -1
- package/android/build.gradle +1 -1
- package/android/src/main/java/com/ezoic/reactnative/EzoicAdsModule.kt +289 -0
- package/ios/EzoicAdsImpl.swift +287 -23
- package/ios/EzoicReactNativeSdk.h +4 -1
- package/ios/EzoicReactNativeSdk.mm +62 -0
- package/lib/module/EzoicInterstitialAd.js +108 -0
- package/lib/module/EzoicInterstitialAd.js.map +1 -0
- package/lib/module/EzoicRewardedAd.js +115 -0
- package/lib/module/EzoicRewardedAd.js.map +1 -0
- package/lib/module/NativeEzoicAds.js +8 -0
- package/lib/module/NativeEzoicAds.js.map +1 -1
- package/lib/module/helpers.js +13 -0
- package/lib/module/helpers.js.map +1 -1
- package/lib/module/index.js +2 -0
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/src/EzoicInterstitialAd.d.ts +51 -0
- package/lib/typescript/src/EzoicInterstitialAd.d.ts.map +1 -0
- package/lib/typescript/src/EzoicRewardedAd.d.ts +55 -0
- package/lib/typescript/src/EzoicRewardedAd.d.ts.map +1 -0
- package/lib/typescript/src/NativeEzoicAds.d.ts +17 -0
- package/lib/typescript/src/NativeEzoicAds.d.ts.map +1 -1
- package/lib/typescript/src/helpers.d.ts +13 -0
- package/lib/typescript/src/helpers.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +2 -0
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/EzoicInterstitialAd.ts +126 -0
- package/src/EzoicRewardedAd.ts +143 -0
- package/src/NativeEzoicAds.ts +19 -0
- package/src/helpers.ts +19 -0
- package/src/index.tsx +9 -0
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { NativeEventEmitter, type EmitterSubscription } from 'react-native';
|
|
2
|
+
import NativeEzoicAds from './NativeEzoicAds';
|
|
3
|
+
import { coerceAdUnitId } from './helpers';
|
|
4
|
+
|
|
5
|
+
/** Lifecycle callbacks for an interstitial ad. All are optional. */
|
|
6
|
+
export interface EzoicInterstitialAdListeners {
|
|
7
|
+
onShown?: () => void;
|
|
8
|
+
onFailedToShow?: (error: { message: string; code?: number }) => void;
|
|
9
|
+
onImpression?: () => void;
|
|
10
|
+
onClicked?: () => void;
|
|
11
|
+
onDismissed?: () => void;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/** The single native event name carrying every interstitial lifecycle signal. */
|
|
15
|
+
const INTERSTITIAL_EVENT = 'EzoicInterstitialAdEvent';
|
|
16
|
+
|
|
17
|
+
interface InterstitialNativeEvent {
|
|
18
|
+
adUnitIdentifier: string;
|
|
19
|
+
type: 'shown' | 'failedToShow' | 'impression' | 'clicked' | 'dismissed';
|
|
20
|
+
message?: string;
|
|
21
|
+
code?: number;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// A single shared emitter is sufficient — events are routed to the right
|
|
25
|
+
// instance by adUnitIdentifier below.
|
|
26
|
+
const emitter = new NativeEventEmitter(NativeEzoicAds as never);
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* An interstitial ad. Use the static `load` to fetch an ad ahead of time, then
|
|
30
|
+
* call `show()` to present it full-screen at a natural transition point.
|
|
31
|
+
* Interstitials carry no reward.
|
|
32
|
+
*
|
|
33
|
+
* ```ts
|
|
34
|
+
* const ad = await EzoicInterstitialAd.load('12345');
|
|
35
|
+
* ad.setListeners({ onDismissed: () => console.log('closed') });
|
|
36
|
+
* await ad.show();
|
|
37
|
+
* ```
|
|
38
|
+
*
|
|
39
|
+
* Mirrors the native `EzoicInterstitialAd` load/show lifecycle on both
|
|
40
|
+
* platforms. Interstitial ads are single-use — load a new one for the next
|
|
41
|
+
* opportunity.
|
|
42
|
+
*/
|
|
43
|
+
export class EzoicInterstitialAd {
|
|
44
|
+
/** The Ezoic ad unit identifier this ad was loaded for. */
|
|
45
|
+
readonly adUnitIdentifier: string;
|
|
46
|
+
|
|
47
|
+
private listeners: EzoicInterstitialAdListeners = {};
|
|
48
|
+
private subscription: EmitterSubscription | null = null;
|
|
49
|
+
|
|
50
|
+
private constructor(adUnitIdentifier: string) {
|
|
51
|
+
this.adUnitIdentifier = adUnitIdentifier;
|
|
52
|
+
this.subscription = emitter.addListener(
|
|
53
|
+
INTERSTITIAL_EVENT,
|
|
54
|
+
(raw: unknown) => {
|
|
55
|
+
const event = raw as InterstitialNativeEvent;
|
|
56
|
+
if (event.adUnitIdentifier !== this.adUnitIdentifier) return;
|
|
57
|
+
this.handleEvent(event);
|
|
58
|
+
}
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Loads an interstitial ad for the given Ezoic ad unit identifier. Resolves
|
|
64
|
+
* with a ready-to-show `EzoicInterstitialAd`, or rejects if no ad could be
|
|
65
|
+
* loaded.
|
|
66
|
+
*/
|
|
67
|
+
static async load(adUnitIdentifier: string): Promise<EzoicInterstitialAd> {
|
|
68
|
+
const id = coerceAdUnitId(adUnitIdentifier);
|
|
69
|
+
const ad = new EzoicInterstitialAd(id);
|
|
70
|
+
try {
|
|
71
|
+
await NativeEzoicAds.loadInterstitialAd(id);
|
|
72
|
+
return ad;
|
|
73
|
+
} catch (error) {
|
|
74
|
+
ad.destroy();
|
|
75
|
+
throw error;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** Registers lifecycle callbacks. Replaces any previously set listeners. */
|
|
80
|
+
setListeners(listeners: EzoicInterstitialAdListeners): void {
|
|
81
|
+
this.listeners = listeners;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Presents the interstitial ad full-screen. Resolves when the ad is
|
|
86
|
+
* dismissed. Rejects if the ad was not ready (load first) or failed to
|
|
87
|
+
* present.
|
|
88
|
+
*/
|
|
89
|
+
async show(): Promise<void> {
|
|
90
|
+
await NativeEzoicAds.showInterstitialAd(this.adUnitIdentifier);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/** Releases the event subscription. Safe to call multiple times. */
|
|
94
|
+
destroy(): void {
|
|
95
|
+
this.subscription?.remove();
|
|
96
|
+
this.subscription = null;
|
|
97
|
+
this.listeners = {};
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
private handleEvent(event: InterstitialNativeEvent): void {
|
|
101
|
+
switch (event.type) {
|
|
102
|
+
case 'shown':
|
|
103
|
+
this.listeners.onShown?.();
|
|
104
|
+
break;
|
|
105
|
+
case 'failedToShow':
|
|
106
|
+
this.listeners.onFailedToShow?.({
|
|
107
|
+
message: event.message ?? '',
|
|
108
|
+
code: event.code,
|
|
109
|
+
});
|
|
110
|
+
// Failure to show is terminal — the native ad is single-use.
|
|
111
|
+
this.destroy();
|
|
112
|
+
break;
|
|
113
|
+
case 'impression':
|
|
114
|
+
this.listeners.onImpression?.();
|
|
115
|
+
break;
|
|
116
|
+
case 'clicked':
|
|
117
|
+
this.listeners.onClicked?.();
|
|
118
|
+
break;
|
|
119
|
+
case 'dismissed':
|
|
120
|
+
this.listeners.onDismissed?.();
|
|
121
|
+
// Dismissal is terminal — the native ad is single-use.
|
|
122
|
+
this.destroy();
|
|
123
|
+
break;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { NativeEventEmitter, type EmitterSubscription } from 'react-native';
|
|
2
|
+
import NativeEzoicAds from './NativeEzoicAds';
|
|
3
|
+
import { coerceAdUnitId, mapRewardResult } from './helpers';
|
|
4
|
+
|
|
5
|
+
/** A reward earned by the user for completing a rewarded ad. */
|
|
6
|
+
export interface EzoicReward {
|
|
7
|
+
type: string;
|
|
8
|
+
amount: number;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/** Lifecycle callbacks for a rewarded ad. All are optional. */
|
|
12
|
+
export interface EzoicRewardedAdListeners {
|
|
13
|
+
onShown?: () => void;
|
|
14
|
+
onFailedToShow?: (error: { message: string; code?: number }) => void;
|
|
15
|
+
onImpression?: () => void;
|
|
16
|
+
onClicked?: () => void;
|
|
17
|
+
onDismissed?: () => void;
|
|
18
|
+
onUserEarnedReward?: (reward: EzoicReward) => void;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/** The single native event name carrying every rewarded lifecycle signal. */
|
|
22
|
+
const REWARDED_EVENT = 'EzoicRewardedAdEvent';
|
|
23
|
+
|
|
24
|
+
interface RewardedNativeEvent {
|
|
25
|
+
adUnitIdentifier: string;
|
|
26
|
+
type:
|
|
27
|
+
| 'shown'
|
|
28
|
+
| 'failedToShow'
|
|
29
|
+
| 'impression'
|
|
30
|
+
| 'clicked'
|
|
31
|
+
| 'dismissed'
|
|
32
|
+
| 'reward';
|
|
33
|
+
message?: string;
|
|
34
|
+
code?: number;
|
|
35
|
+
rewardType?: string;
|
|
36
|
+
rewardAmount?: number;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// A single shared emitter is sufficient — events are routed to the right
|
|
40
|
+
// instance by adUnitIdentifier below.
|
|
41
|
+
const emitter = new NativeEventEmitter(NativeEzoicAds as never);
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* A rewarded ad. Use the static `load` to fetch an ad ahead of time, then call
|
|
45
|
+
* `show()` to present it and grant the reward when the user finishes watching.
|
|
46
|
+
*
|
|
47
|
+
* ```ts
|
|
48
|
+
* const ad = await EzoicRewardedAd.load('12345');
|
|
49
|
+
* ad.setListeners({ onDismissed: () => console.log('closed') });
|
|
50
|
+
* const reward = await ad.show();
|
|
51
|
+
* if (reward) grantReward(reward.amount);
|
|
52
|
+
* ```
|
|
53
|
+
*
|
|
54
|
+
* Mirrors the native `EzoicRewardedAd` load/show lifecycle on both platforms.
|
|
55
|
+
* Rewarded ads are single-use — load a new one for the next opportunity.
|
|
56
|
+
*/
|
|
57
|
+
export class EzoicRewardedAd {
|
|
58
|
+
/** The Ezoic ad unit identifier this ad was loaded for. */
|
|
59
|
+
readonly adUnitIdentifier: string;
|
|
60
|
+
|
|
61
|
+
private listeners: EzoicRewardedAdListeners = {};
|
|
62
|
+
private subscription: EmitterSubscription | null = null;
|
|
63
|
+
|
|
64
|
+
private constructor(adUnitIdentifier: string) {
|
|
65
|
+
this.adUnitIdentifier = adUnitIdentifier;
|
|
66
|
+
this.subscription = emitter.addListener(REWARDED_EVENT, (raw: unknown) => {
|
|
67
|
+
const event = raw as RewardedNativeEvent;
|
|
68
|
+
if (event.adUnitIdentifier !== this.adUnitIdentifier) return;
|
|
69
|
+
this.handleEvent(event);
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Loads a rewarded ad for the given Ezoic ad unit identifier. Resolves with
|
|
75
|
+
* a ready-to-show `EzoicRewardedAd`, or rejects if no ad could be loaded.
|
|
76
|
+
*/
|
|
77
|
+
static async load(adUnitIdentifier: string): Promise<EzoicRewardedAd> {
|
|
78
|
+
const id = coerceAdUnitId(adUnitIdentifier);
|
|
79
|
+
const ad = new EzoicRewardedAd(id);
|
|
80
|
+
try {
|
|
81
|
+
await NativeEzoicAds.loadRewardedAd(id);
|
|
82
|
+
return ad;
|
|
83
|
+
} catch (error) {
|
|
84
|
+
ad.destroy();
|
|
85
|
+
throw error;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/** Registers lifecycle callbacks. Replaces any previously set listeners. */
|
|
90
|
+
setListeners(listeners: EzoicRewardedAdListeners): void {
|
|
91
|
+
this.listeners = listeners;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Presents the rewarded ad full-screen. Resolves with the earned reward, or
|
|
96
|
+
* `null` if the ad was dismissed before the reward was earned. Rejects if the
|
|
97
|
+
* ad was not ready (load first) or failed to present.
|
|
98
|
+
*/
|
|
99
|
+
async show(): Promise<EzoicReward | null> {
|
|
100
|
+
const result = await NativeEzoicAds.showRewardedAd(this.adUnitIdentifier);
|
|
101
|
+
return mapRewardResult(result);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/** Releases the event subscription. Safe to call multiple times. */
|
|
105
|
+
destroy(): void {
|
|
106
|
+
this.subscription?.remove();
|
|
107
|
+
this.subscription = null;
|
|
108
|
+
this.listeners = {};
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
private handleEvent(event: RewardedNativeEvent): void {
|
|
112
|
+
switch (event.type) {
|
|
113
|
+
case 'shown':
|
|
114
|
+
this.listeners.onShown?.();
|
|
115
|
+
break;
|
|
116
|
+
case 'failedToShow':
|
|
117
|
+
this.listeners.onFailedToShow?.({
|
|
118
|
+
message: event.message ?? '',
|
|
119
|
+
code: event.code,
|
|
120
|
+
});
|
|
121
|
+
// Failure to show is terminal — the native ad is single-use.
|
|
122
|
+
this.destroy();
|
|
123
|
+
break;
|
|
124
|
+
case 'impression':
|
|
125
|
+
this.listeners.onImpression?.();
|
|
126
|
+
break;
|
|
127
|
+
case 'clicked':
|
|
128
|
+
this.listeners.onClicked?.();
|
|
129
|
+
break;
|
|
130
|
+
case 'reward':
|
|
131
|
+
this.listeners.onUserEarnedReward?.({
|
|
132
|
+
type: event.rewardType ?? '',
|
|
133
|
+
amount: event.rewardAmount ?? 0,
|
|
134
|
+
});
|
|
135
|
+
break;
|
|
136
|
+
case 'dismissed':
|
|
137
|
+
this.listeners.onDismissed?.();
|
|
138
|
+
// Dismissal is terminal — the native ad is single-use.
|
|
139
|
+
this.destroy();
|
|
140
|
+
break;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
package/src/NativeEzoicAds.ts
CHANGED
|
@@ -10,12 +10,31 @@ export interface EzoicConfig {
|
|
|
10
10
|
testMode?: boolean;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
+
/**
|
|
14
|
+
* Result of `showRewardedAd`. `earned` is true when the user completed the ad
|
|
15
|
+
* and earned the reward; `type`/`amount` describe the granted reward (empty/0
|
|
16
|
+
* when the ad was dismissed without earning). The public `EzoicRewardedAd.show`
|
|
17
|
+
* maps this to `EzoicReward | null`.
|
|
18
|
+
*/
|
|
19
|
+
export interface EzoicRewardResult {
|
|
20
|
+
earned: boolean;
|
|
21
|
+
type: string;
|
|
22
|
+
amount: number;
|
|
23
|
+
}
|
|
24
|
+
|
|
13
25
|
export interface Spec extends TurboModule {
|
|
14
26
|
initialize(config: EzoicConfig): Promise<void>;
|
|
15
27
|
setGDPRConsent(applies: boolean, consentString?: string): void;
|
|
16
28
|
setGPPConsent(gppString?: string, sectionIds?: string): void;
|
|
17
29
|
setSubjectToCOPPA(value: boolean): void;
|
|
18
30
|
trackPageview(): Promise<boolean>;
|
|
31
|
+
loadRewardedAd(adUnitIdentifier: string): Promise<void>;
|
|
32
|
+
showRewardedAd(adUnitIdentifier: string): Promise<EzoicRewardResult>;
|
|
33
|
+
loadInterstitialAd(adUnitIdentifier: string): Promise<void>;
|
|
34
|
+
showInterstitialAd(adUnitIdentifier: string): Promise<void>;
|
|
35
|
+
// Required by NativeEventEmitter for the ad lifecycle events.
|
|
36
|
+
addListener(eventName: string): void;
|
|
37
|
+
removeListeners(count: number): void;
|
|
19
38
|
}
|
|
20
39
|
|
|
21
40
|
export default TurboModuleRegistry.getEnforcing<Spec>('EzoicReactNativeSdk');
|
package/src/helpers.ts
CHANGED
|
@@ -28,3 +28,22 @@ export function normalizeSize(size: string | undefined): string {
|
|
|
28
28
|
export function coerceAdUnitId(adUnitIdentifier: string): string {
|
|
29
29
|
return String(adUnitIdentifier);
|
|
30
30
|
}
|
|
31
|
+
|
|
32
|
+
export interface RewardResultLike {
|
|
33
|
+
earned: boolean;
|
|
34
|
+
type: string;
|
|
35
|
+
amount: number;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Maps the native `showRewardedAd` result to the public reward shape: the
|
|
40
|
+
* `{ type, amount }` reward when earned, otherwise `null` (dismissed unearned).
|
|
41
|
+
*/
|
|
42
|
+
export function mapRewardResult(
|
|
43
|
+
result: RewardResultLike | null | undefined
|
|
44
|
+
): { type: string; amount: number } | null {
|
|
45
|
+
if (result && result.earned) {
|
|
46
|
+
return { type: result.type, amount: result.amount };
|
|
47
|
+
}
|
|
48
|
+
return null;
|
|
49
|
+
}
|
package/src/index.tsx
CHANGED
|
@@ -4,6 +4,15 @@ import EzoicBannerNative from './EzoicBannerViewNativeComponent';
|
|
|
4
4
|
import { coerceAdUnitId, normalizeConfig, normalizeSize } from './helpers';
|
|
5
5
|
|
|
6
6
|
export type { EzoicConfig };
|
|
7
|
+
export {
|
|
8
|
+
EzoicRewardedAd,
|
|
9
|
+
type EzoicReward,
|
|
10
|
+
type EzoicRewardedAdListeners,
|
|
11
|
+
} from './EzoicRewardedAd';
|
|
12
|
+
export {
|
|
13
|
+
EzoicInterstitialAd,
|
|
14
|
+
type EzoicInterstitialAdListeners,
|
|
15
|
+
} from './EzoicInterstitialAd';
|
|
7
16
|
|
|
8
17
|
export const EzoicAds = {
|
|
9
18
|
initialize(config: EzoicConfig): Promise<void> {
|