adwhale-sdk-react-native 2.7.204 → 2.7.300
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/AdwhaleSdkReactNative.podspec +22 -0
- package/README.md +80 -37
- package/android/proguard-rules.pro +56 -0
- package/android/src/main/java/com/adwhalesdkreactnative/AdWhaleCustomNativeBinderFactory.java +18 -0
- package/android/src/main/java/com/adwhalesdkreactnative/AdwhaleSdkReactNativePackage.java +51 -6
- package/android/src/main/java/com/adwhalesdkreactnative/BinderFactory.java +9 -0
- package/android/src/main/java/com/adwhalesdkreactnative/RNAdWhaleMediationAdSettingModule.java +148 -49
- package/android/src/main/java/com/adwhalesdkreactnative/RNAdWhaleMediationAdView.java +46 -27
- package/android/src/main/java/com/adwhalesdkreactnative/RNAdWhaleMediationAppOpenAd.java +136 -0
- package/android/src/main/java/com/adwhalesdkreactnative/RNAdWhaleMediationCustomNativeAdView.java +37 -46
- package/android/src/main/java/com/adwhalesdkreactnative/RNAdWhaleMediationExitPopupAd.java +240 -0
- package/android/src/main/java/com/adwhalesdkreactnative/RNAdWhaleMediationInterstitialAd.java +189 -0
- package/android/src/main/java/com/adwhalesdkreactnative/RNAdWhaleMediationLoggerModule.java +2 -1
- package/android/src/main/java/com/adwhalesdkreactnative/RNAdWhaleMediationNativeAdViewListenerBridge.java +83 -0
- package/android/src/main/java/com/adwhalesdkreactnative/RNAdWhaleMediationRewardAd.java +255 -6
- package/android/src/main/java/com/adwhalesdkreactnative/RNAdWhaleMediationTemplateNativeAdView.java +191 -70
- package/android/src/main/java/com/adwhalesdkreactnative/RNAdWhaleMediationTransitionPopupAd.java +218 -0
- package/android/src/main/java/com/adwhalesdkreactnative/RNWrapperView.java +137 -0
- package/android/src/main/java/com/adwhalesdkreactnative/SimpleBinderFactory.java +1 -1
- package/android/src/main/java/com/adwhalesdkreactnative/common/RNMethodArgConst.java +112 -0
- package/android/src/main/java/com/adwhalesdkreactnative/common/RNMethodCallConst.java +113 -0
- package/android/src/main/java/com/adwhalesdkreactnative/common/RNMethodResultConst.java +28 -0
- package/build/generated/ios/ReactAppDependencyProvider.podspec +34 -0
- package/ios/AdWhaleNativeCustomViewFactoryRegistry.swift +56 -0
- package/ios/AdwhaleSdkReactNative.mm +96 -5
- package/ios/AdwhaleSdkReactNativeModule.swift +148 -0
- package/ios/RNAdWhaleMediationAdViewManager.m +38 -0
- package/ios/RNAdWhaleMediationAdViewManager.swift +14 -0
- package/ios/RNAdWhaleMediationAppOpenAd.m +18 -0
- package/ios/RNAdWhaleMediationAppOpenAd.swift +175 -0
- package/ios/RNAdWhaleMediationCustomNativeAdViewManager.m +22 -0
- package/ios/RNAdWhaleMediationCustomNativeAdViewManager.swift +239 -0
- package/ios/RNAdWhaleMediationInterstitialAd.m +18 -0
- package/ios/RNAdWhaleMediationInterstitialAd.swift +161 -0
- package/ios/RNAdWhaleMediationRewardAd.m +18 -0
- package/ios/RNAdWhaleMediationRewardAd.swift +172 -0
- package/ios/WhaleMediationBannerContainer.swift +182 -0
- package/lib/module/AdWhaleAdView.js +58 -3
- package/lib/module/AdWhaleAdView.js.map +1 -1
- package/lib/module/AdWhaleAppOpenAd.js +223 -25
- package/lib/module/AdWhaleAppOpenAd.js.map +1 -1
- package/lib/module/AdWhaleExitPopupAd.js +93 -0
- package/lib/module/AdWhaleExitPopupAd.js.map +1 -0
- package/lib/module/AdWhaleInterstitialAd.js +146 -22
- package/lib/module/AdWhaleInterstitialAd.js.map +1 -1
- package/lib/module/AdWhaleMediationAds.js +75 -4
- package/lib/module/AdWhaleMediationAds.js.map +1 -1
- package/lib/module/AdWhaleNativeCustomView.js +59 -8
- package/lib/module/AdWhaleNativeCustomView.js.map +1 -1
- package/lib/module/AdWhaleNativeTemplateView.js +37 -19
- package/lib/module/AdWhaleNativeTemplateView.js.map +1 -1
- package/lib/module/AdWhaleRewardAd.js +169 -24
- package/lib/module/AdWhaleRewardAd.js.map +1 -1
- package/lib/module/AdWhaleTransitionPopupAd.js +87 -0
- package/lib/module/AdWhaleTransitionPopupAd.js.map +1 -0
- package/lib/module/NativeAdwhaleSdkReactNative.js +16 -1
- package/lib/module/NativeAdwhaleSdkReactNative.js.map +1 -1
- package/lib/module/constants/AdWhaleMethodArgConst.js +53 -0
- package/lib/module/constants/AdWhaleMethodArgConst.js.map +1 -0
- package/lib/module/constants/AdWhaleMethodCallConst.js +56 -0
- package/lib/module/constants/AdWhaleMethodCallConst.js.map +1 -0
- package/lib/module/constants/AdWhaleMethodResultConst.js +16 -0
- package/lib/module/constants/AdWhaleMethodResultConst.js.map +1 -0
- package/lib/module/index.js +10 -1
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/src/AdWhaleAdView.d.ts +20 -2
- package/lib/typescript/src/AdWhaleAdView.d.ts.map +1 -1
- package/lib/typescript/src/AdWhaleAppOpenAd.d.ts +10 -0
- package/lib/typescript/src/AdWhaleAppOpenAd.d.ts.map +1 -1
- package/lib/typescript/src/AdWhaleExitPopupAd.d.ts +36 -0
- package/lib/typescript/src/AdWhaleExitPopupAd.d.ts.map +1 -0
- package/lib/typescript/src/AdWhaleInterstitialAd.d.ts +16 -0
- package/lib/typescript/src/AdWhaleInterstitialAd.d.ts.map +1 -1
- package/lib/typescript/src/AdWhaleMediationAds.d.ts +13 -5
- package/lib/typescript/src/AdWhaleMediationAds.d.ts.map +1 -1
- package/lib/typescript/src/AdWhaleNativeCustomView.d.ts +7 -4
- package/lib/typescript/src/AdWhaleNativeCustomView.d.ts.map +1 -1
- package/lib/typescript/src/AdWhaleNativeTemplateView.d.ts +20 -7
- package/lib/typescript/src/AdWhaleNativeTemplateView.d.ts.map +1 -1
- package/lib/typescript/src/AdWhaleRewardAd.d.ts +18 -2
- package/lib/typescript/src/AdWhaleRewardAd.d.ts.map +1 -1
- package/lib/typescript/src/AdWhaleTransitionPopupAd.d.ts +33 -0
- package/lib/typescript/src/AdWhaleTransitionPopupAd.d.ts.map +1 -0
- package/lib/typescript/src/NativeAdwhaleSdkReactNative.d.ts +28 -6
- package/lib/typescript/src/NativeAdwhaleSdkReactNative.d.ts.map +1 -1
- package/lib/typescript/src/constants/AdWhaleMethodArgConst.d.ts +51 -0
- package/lib/typescript/src/constants/AdWhaleMethodArgConst.d.ts.map +1 -0
- package/lib/typescript/src/constants/AdWhaleMethodCallConst.d.ts +53 -0
- package/lib/typescript/src/constants/AdWhaleMethodCallConst.d.ts.map +1 -0
- package/lib/typescript/src/constants/AdWhaleMethodResultConst.d.ts +14 -0
- package/lib/typescript/src/constants/AdWhaleMethodResultConst.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +9 -1
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/AdWhaleAdView.tsx +92 -4
- package/src/AdWhaleAppOpenAd.ts +293 -38
- package/src/AdWhaleExitPopupAd.ts +183 -0
- package/src/AdWhaleInterstitialAd.ts +206 -36
- package/src/AdWhaleMediationAds.ts +108 -4
- package/src/AdWhaleNativeCustomView.tsx +85 -23
- package/src/AdWhaleNativeTemplateView.tsx +79 -42
- package/src/AdWhaleRewardAd.ts +245 -43
- package/src/AdWhaleTransitionPopupAd.ts +171 -0
- package/src/NativeAdwhaleSdkReactNative.ts +30 -6
- package/src/constants/AdWhaleMethodArgConst.ts +50 -0
- package/src/constants/AdWhaleMethodCallConst.ts +60 -0
- package/src/constants/AdWhaleMethodResultConst.ts +13 -0
- package/src/index.ts +33 -0
|
@@ -22,22 +22,37 @@ export interface AdWhaleInterstitialGcoder {
|
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
interface RNAdWhaleMediationInterstitialAdNativeModule {
|
|
25
|
-
setPlacementName(placementName: string): void;
|
|
26
|
-
setRegion(region: string): void;
|
|
27
|
-
setGcoder(gcoder: { lt: number; lng: number }): void;
|
|
28
|
-
loadAd(placementUid: string): void;
|
|
29
|
-
showAd(): void;
|
|
25
|
+
setPlacementName?(placementName: string): void;
|
|
26
|
+
setRegion?(region: string): void;
|
|
27
|
+
setGcoder?(gcoder: { lt: number; lng: number }): void;
|
|
28
|
+
loadAd?(placementUid: string): void;
|
|
29
|
+
showAd?(): void;
|
|
30
|
+
/** Flutter와 동일 네이밍: adId 기반 로드 */
|
|
31
|
+
loadInterstitialAd?(args: {
|
|
32
|
+
adId: number;
|
|
33
|
+
placementUid: string;
|
|
34
|
+
placementName?: string;
|
|
35
|
+
region?: string;
|
|
36
|
+
gcoder?: [number, number];
|
|
37
|
+
}): void;
|
|
38
|
+
/** Flutter와 동일 네이밍: adId 기반 show */
|
|
39
|
+
showAdWithoutView?(adId: number): void;
|
|
40
|
+
/** Flutter와 동일 네이밍: adId 기반 destroy */
|
|
41
|
+
destroyAd?(adId: number): void;
|
|
30
42
|
addListener(eventName: string): void;
|
|
31
43
|
removeListeners(count: number): void;
|
|
32
44
|
}
|
|
33
45
|
|
|
46
|
+
const LINKING_ERROR =
|
|
47
|
+
'RNAdWhaleMediationInterstitialAd native module is not linked on this platform.';
|
|
48
|
+
|
|
34
49
|
const { RNAdWhaleMediationInterstitialAd } = NativeModules as {
|
|
35
|
-
RNAdWhaleMediationInterstitialAd
|
|
50
|
+
RNAdWhaleMediationInterstitialAd?: RNAdWhaleMediationInterstitialAdNativeModule;
|
|
36
51
|
};
|
|
37
52
|
|
|
38
|
-
const interstitialEmitter =
|
|
39
|
-
RNAdWhaleMediationInterstitialAd
|
|
40
|
-
|
|
53
|
+
const interstitialEmitter = RNAdWhaleMediationInterstitialAd
|
|
54
|
+
? new NativeEventEmitter(RNAdWhaleMediationInterstitialAd)
|
|
55
|
+
: null;
|
|
41
56
|
|
|
42
57
|
export const AdWhaleInterstitialAd = {
|
|
43
58
|
loadAd(
|
|
@@ -48,34 +63,124 @@ export const AdWhaleInterstitialAd = {
|
|
|
48
63
|
gcoder?: AdWhaleInterstitialGcoder;
|
|
49
64
|
},
|
|
50
65
|
) {
|
|
66
|
+
if (!RNAdWhaleMediationInterstitialAd) {
|
|
67
|
+
console.warn(LINKING_ERROR);
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
51
70
|
// 먼저 옵션들을 설정
|
|
52
71
|
if (options?.placementName) {
|
|
53
|
-
RNAdWhaleMediationInterstitialAd.setPlacementName(options.placementName);
|
|
72
|
+
RNAdWhaleMediationInterstitialAd.setPlacementName?.(options.placementName);
|
|
54
73
|
}
|
|
55
74
|
if (options?.region) {
|
|
56
|
-
RNAdWhaleMediationInterstitialAd.setRegion(options.region);
|
|
75
|
+
RNAdWhaleMediationInterstitialAd.setRegion?.(options.region);
|
|
57
76
|
}
|
|
58
77
|
if (options?.gcoder) {
|
|
59
|
-
RNAdWhaleMediationInterstitialAd.setGcoder(options.gcoder);
|
|
78
|
+
RNAdWhaleMediationInterstitialAd.setGcoder?.(options.gcoder);
|
|
79
|
+
}
|
|
80
|
+
// 네이티브 구현 차이 대응: loadAd 우선, 없으면 adId 기반 API로 폴백
|
|
81
|
+
if (RNAdWhaleMediationInterstitialAd.loadAd) {
|
|
82
|
+
RNAdWhaleMediationInterstitialAd.loadAd(placementUid);
|
|
83
|
+
return;
|
|
60
84
|
}
|
|
61
|
-
|
|
62
|
-
|
|
85
|
+
if (RNAdWhaleMediationInterstitialAd.loadInterstitialAd) {
|
|
86
|
+
RNAdWhaleMediationInterstitialAd.loadInterstitialAd({
|
|
87
|
+
adId: 0,
|
|
88
|
+
placementUid,
|
|
89
|
+
placementName: options?.placementName,
|
|
90
|
+
region: options?.region,
|
|
91
|
+
gcoder: options?.gcoder
|
|
92
|
+
? [options.gcoder.lt, options.gcoder.lng]
|
|
93
|
+
: undefined,
|
|
94
|
+
});
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
console.warn(
|
|
98
|
+
'[AdWhaleInterstitialAd] Native module missing both loadAd and loadInterstitialAd.',
|
|
99
|
+
);
|
|
63
100
|
},
|
|
64
101
|
|
|
65
102
|
showAd() {
|
|
66
|
-
RNAdWhaleMediationInterstitialAd
|
|
103
|
+
if (!RNAdWhaleMediationInterstitialAd) {
|
|
104
|
+
console.warn(LINKING_ERROR);
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
// 네이티브 구현 차이 대응: showAd 우선, 없으면 adId 기반 API로 폴백
|
|
108
|
+
if (RNAdWhaleMediationInterstitialAd.showAd) {
|
|
109
|
+
RNAdWhaleMediationInterstitialAd.showAd();
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
if (RNAdWhaleMediationInterstitialAd.showAdWithoutView) {
|
|
113
|
+
RNAdWhaleMediationInterstitialAd.showAdWithoutView(0);
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
console.warn(
|
|
117
|
+
'[AdWhaleInterstitialAd] Native module missing both showAd and showAdWithoutView.',
|
|
118
|
+
);
|
|
119
|
+
},
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Flutter와 동일한 형태로 맞춘 신규 API (권장).
|
|
123
|
+
* - 광고를 여러 개 동시에 운용하려면 adId를 사용하세요.
|
|
124
|
+
*/
|
|
125
|
+
loadInterstitialAd(
|
|
126
|
+
adId: number,
|
|
127
|
+
placementUid: string,
|
|
128
|
+
options?: {
|
|
129
|
+
placementName?: string;
|
|
130
|
+
region?: string;
|
|
131
|
+
gcoder?: AdWhaleInterstitialGcoder;
|
|
132
|
+
},
|
|
133
|
+
) {
|
|
134
|
+
if (!RNAdWhaleMediationInterstitialAd) {
|
|
135
|
+
console.warn(LINKING_ERROR);
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
if (!RNAdWhaleMediationInterstitialAd.loadInterstitialAd) {
|
|
139
|
+
// 네이티브가 아직 업데이트되지 않은 경우: 기존 싱글 인스턴스 경로로 폴백
|
|
140
|
+
this.loadAd(placementUid, options);
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
RNAdWhaleMediationInterstitialAd.loadInterstitialAd({
|
|
144
|
+
adId,
|
|
145
|
+
placementUid,
|
|
146
|
+
placementName: options?.placementName,
|
|
147
|
+
region: options?.region,
|
|
148
|
+
gcoder: options?.gcoder ? [options.gcoder.lt, options.gcoder.lng] : undefined,
|
|
149
|
+
});
|
|
150
|
+
},
|
|
151
|
+
|
|
152
|
+
showAdWithoutView(adId: number) {
|
|
153
|
+
if (!RNAdWhaleMediationInterstitialAd) {
|
|
154
|
+
console.warn(LINKING_ERROR);
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
if (!RNAdWhaleMediationInterstitialAd.showAdWithoutView) {
|
|
158
|
+
// 폴백: 싱글 인스턴스 show
|
|
159
|
+
this.showAd();
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
RNAdWhaleMediationInterstitialAd.showAdWithoutView(adId);
|
|
163
|
+
},
|
|
164
|
+
|
|
165
|
+
destroyAd(adId: number) {
|
|
166
|
+
RNAdWhaleMediationInterstitialAd?.destroyAd?.(adId);
|
|
67
167
|
},
|
|
68
168
|
|
|
69
169
|
addEventListeners(listeners: AdWhaleInterstitialEvents): EmitterSubscription[] {
|
|
170
|
+
if (!interstitialEmitter) {
|
|
171
|
+
console.warn(LINKING_ERROR);
|
|
172
|
+
return [];
|
|
173
|
+
}
|
|
70
174
|
const subs: EmitterSubscription[] = [];
|
|
175
|
+
let directShowedReceived = false;
|
|
71
176
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
)
|
|
78
|
-
|
|
177
|
+
subs.push(
|
|
178
|
+
interstitialEmitter.addListener('onInterstitialAdLoaded', () => {
|
|
179
|
+
directShowedReceived = false;
|
|
180
|
+
console.log('AdWhaleInterstitialAd.ts Interstitial onLoaded');
|
|
181
|
+
listeners.onLoaded?.();
|
|
182
|
+
}),
|
|
183
|
+
);
|
|
79
184
|
if (listeners.onLoadFailed) {
|
|
80
185
|
subs.push(
|
|
81
186
|
interstitialEmitter.addListener(
|
|
@@ -84,13 +189,13 @@ export const AdWhaleInterstitialAd = {
|
|
|
84
189
|
),
|
|
85
190
|
);
|
|
86
191
|
}
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
)
|
|
93
|
-
|
|
192
|
+
subs.push(
|
|
193
|
+
interstitialEmitter.addListener('onInterstitialAdShowed', () => {
|
|
194
|
+
directShowedReceived = true;
|
|
195
|
+
console.log('AdWhaleInterstitialAd.ts Interstitial onAdShowed');
|
|
196
|
+
listeners.onShowed?.();
|
|
197
|
+
}),
|
|
198
|
+
);
|
|
94
199
|
if (listeners.onShowFailed) {
|
|
95
200
|
subs.push(
|
|
96
201
|
interstitialEmitter.addListener(
|
|
@@ -99,13 +204,23 @@ export const AdWhaleInterstitialAd = {
|
|
|
99
204
|
),
|
|
100
205
|
);
|
|
101
206
|
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
)
|
|
108
|
-
|
|
207
|
+
subs.push(
|
|
208
|
+
interstitialEmitter.addListener('onInterstitialAdClosed', () => {
|
|
209
|
+
directShowedReceived = false;
|
|
210
|
+
console.log('AdWhaleInterstitialAd.ts Interstitial onAdClosed');
|
|
211
|
+
listeners.onClosed?.();
|
|
212
|
+
}),
|
|
213
|
+
);
|
|
214
|
+
subs.push(
|
|
215
|
+
interstitialEmitter.addListener('onAdEvent', (payload: any) => {
|
|
216
|
+
if (payload?.eventName !== 'onInterstitialAdShowed' || directShowedReceived) {
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
directShowedReceived = true;
|
|
220
|
+
console.log('AdWhaleInterstitialAd.ts Interstitial onAdShowed');
|
|
221
|
+
listeners.onShowed?.();
|
|
222
|
+
}),
|
|
223
|
+
);
|
|
109
224
|
if (listeners.onClicked) {
|
|
110
225
|
subs.push(
|
|
111
226
|
interstitialEmitter.addListener('onInterstitialAdClicked', () => {
|
|
@@ -116,4 +231,59 @@ export const AdWhaleInterstitialAd = {
|
|
|
116
231
|
|
|
117
232
|
return subs;
|
|
118
233
|
},
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Flutter `onAdEvent` 스타일: payload에 eventName + adId를 포함.
|
|
237
|
+
* 네이티브가 지원하는 경우, 특정 adId만 필터링해서 이벤트를 받을 수 있습니다.
|
|
238
|
+
*/
|
|
239
|
+
addAdEventListenersById(
|
|
240
|
+
adId: number,
|
|
241
|
+
listeners: AdWhaleInterstitialEvents,
|
|
242
|
+
): EmitterSubscription[] {
|
|
243
|
+
if (!interstitialEmitter) {
|
|
244
|
+
console.warn(LINKING_ERROR);
|
|
245
|
+
return [];
|
|
246
|
+
}
|
|
247
|
+
const subs: EmitterSubscription[] = [];
|
|
248
|
+
|
|
249
|
+
const handle = (eventName: string, cb?: (e?: any) => void) => {
|
|
250
|
+
if (!cb) return;
|
|
251
|
+
subs.push(
|
|
252
|
+
interstitialEmitter.addListener('onAdEvent', (payload: any) => {
|
|
253
|
+
if (!payload || payload.adId !== adId || payload.eventName !== eventName) {
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
cb(payload);
|
|
257
|
+
}),
|
|
258
|
+
);
|
|
259
|
+
};
|
|
260
|
+
|
|
261
|
+
handle('onInterstitialAdLoaded', () => {
|
|
262
|
+
console.log('AdWhaleInterstitialAd.ts Interstitial onLoaded');
|
|
263
|
+
listeners.onLoaded?.();
|
|
264
|
+
});
|
|
265
|
+
handle('onInterstitialAdLoadFailed', p =>
|
|
266
|
+
listeners.onLoadFailed?.({
|
|
267
|
+
statusCode: Number(p?.statusCode ?? -1),
|
|
268
|
+
message: String(p?.message ?? ''),
|
|
269
|
+
}),
|
|
270
|
+
);
|
|
271
|
+
handle('onInterstitialAdShowed', () => {
|
|
272
|
+
console.log('AdWhaleInterstitialAd.ts Interstitial onAdShowed');
|
|
273
|
+
listeners.onShowed?.();
|
|
274
|
+
});
|
|
275
|
+
handle('onInterstitialAdShowFailed', p =>
|
|
276
|
+
listeners.onShowFailed?.({
|
|
277
|
+
statusCode: Number(p?.statusCode ?? -1),
|
|
278
|
+
message: String(p?.message ?? ''),
|
|
279
|
+
}),
|
|
280
|
+
);
|
|
281
|
+
handle('onInterstitialAdClosed', () => {
|
|
282
|
+
console.log('AdWhaleInterstitialAd.ts Interstitial onAdClosed');
|
|
283
|
+
listeners.onClosed?.();
|
|
284
|
+
});
|
|
285
|
+
handle('onInterstitialAdClicked', () => listeners.onClicked?.());
|
|
286
|
+
|
|
287
|
+
return subs;
|
|
288
|
+
},
|
|
119
289
|
};
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
// src/AdWhaleMediationAds.ts
|
|
2
2
|
import { NativeModules, Platform } from 'react-native';
|
|
3
|
-
import NativeAdwhaleSdkReactNative, {
|
|
3
|
+
import NativeAdwhaleSdkReactNative, {
|
|
4
|
+
type AdInspectorResult,
|
|
5
|
+
type GdprConsentResult,
|
|
6
|
+
type InitializeResult,
|
|
7
|
+
} from './NativeAdwhaleSdkReactNative';
|
|
4
8
|
|
|
5
9
|
const LINKING_ERROR =
|
|
6
10
|
`AdWhale Mediation SDK native modules not linked.\n` +
|
|
@@ -10,6 +14,9 @@ const LINKING_ERROR =
|
|
|
10
14
|
` • Web 환경에서 실행 중이 아닌지\n` +
|
|
11
15
|
`Platform: ${Platform.OS}`;
|
|
12
16
|
|
|
17
|
+
const IOS_UNSUPPORTED_LOGGER =
|
|
18
|
+
'[AdWhaleMediationAds] setLoggerEnabled: iOS에서는 RN 로거 모듈(RNAdWhaleMediationLoggerModule)을 지원하지 않습니다.';
|
|
19
|
+
|
|
13
20
|
interface RNAdWhaleMediationLoggerModule {
|
|
14
21
|
setLogLevel?(enabled: boolean): void;
|
|
15
22
|
getLogLevel?(): Promise<string>;
|
|
@@ -19,7 +26,6 @@ const { RNAdWhaleMediationLoggerModule } = NativeModules as {
|
|
|
19
26
|
RNAdWhaleMediationLoggerModule?: RNAdWhaleMediationLoggerModule;
|
|
20
27
|
};
|
|
21
28
|
|
|
22
|
-
// TurboModule spec을 통해 접근
|
|
23
29
|
const AdwhaleSdkReactNative = NativeAdwhaleSdkReactNative;
|
|
24
30
|
|
|
25
31
|
if (!AdwhaleSdkReactNative) {
|
|
@@ -32,22 +38,46 @@ if (!AdwhaleSdkReactNative) {
|
|
|
32
38
|
hasResetGdprConsentStatus: !!AdwhaleSdkReactNative.resetGdprConsentStatus,
|
|
33
39
|
hasSetGdpr: !!AdwhaleSdkReactNative.setGdpr,
|
|
34
40
|
hasSetCoppa: !!AdwhaleSdkReactNative.setCoppa,
|
|
41
|
+
hasSetTagForUnderAgeOfConsent:
|
|
42
|
+
!!AdwhaleSdkReactNative.setTagForUnderAgeOfConsent,
|
|
43
|
+
hasSetMaxAdContentRating: !!AdwhaleSdkReactNative.setMaxAdContentRating,
|
|
44
|
+
hasSetTestDeviceIdentifiers:
|
|
45
|
+
!!AdwhaleSdkReactNative.setTestDeviceIdentifiers,
|
|
46
|
+
hasShowAdInspector: !!AdwhaleSdkReactNative.showAdInspector,
|
|
47
|
+
hasSetAppMuted: !!AdwhaleSdkReactNative.setAppMuted,
|
|
48
|
+
hasSetAppVolume: !!AdwhaleSdkReactNative.setAppVolume,
|
|
35
49
|
});
|
|
36
50
|
}
|
|
37
51
|
|
|
38
52
|
export const AdWhaleMediationAds = {
|
|
53
|
+
/**
|
|
54
|
+
* Flutter `AdWhaleMediationAds.instance.initialize()` 와 동일.
|
|
55
|
+
* 네이티브 TurboModule 은 codegen 에 따라 `initialize` 를 호출하며, 성공 맵은 `statusCode` + `message` 만 반환합니다.
|
|
56
|
+
*/
|
|
39
57
|
initialize(): Promise<InitializeResult> {
|
|
40
58
|
if (!AdwhaleSdkReactNative?.initialize) {
|
|
41
59
|
return Promise.reject(new Error(LINKING_ERROR));
|
|
42
60
|
}
|
|
43
|
-
return AdwhaleSdkReactNative.initialize()
|
|
61
|
+
return AdwhaleSdkReactNative.initialize().catch((e: unknown) => ({
|
|
62
|
+
statusCode: -1,
|
|
63
|
+
message: e instanceof Error ? e.message : String(e),
|
|
64
|
+
}));
|
|
44
65
|
},
|
|
45
66
|
|
|
46
67
|
setLoggerEnabled(enabled: boolean) {
|
|
68
|
+
if (Platform.OS === 'ios') {
|
|
69
|
+
console.warn(IOS_UNSUPPORTED_LOGGER);
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
47
72
|
RNAdWhaleMediationLoggerModule?.setLogLevel?.(enabled);
|
|
48
73
|
},
|
|
49
74
|
|
|
50
75
|
getLogLevel(): Promise<string> {
|
|
76
|
+
if (Platform.OS === 'ios') {
|
|
77
|
+
return Promise.reject(
|
|
78
|
+
new Error('getLogLevel is not supported on iOS (Android 전용).')
|
|
79
|
+
);
|
|
80
|
+
}
|
|
51
81
|
if (!RNAdWhaleMediationLoggerModule?.getLogLevel) {
|
|
52
82
|
return Promise.reject(
|
|
53
83
|
new Error('getLogLevel is not implemented in native module')
|
|
@@ -65,7 +95,7 @@ export const AdWhaleMediationAds = {
|
|
|
65
95
|
AdwhaleSdkReactNative.setCoppa(enabled);
|
|
66
96
|
},
|
|
67
97
|
|
|
68
|
-
requestGdprConsent(): Promise<
|
|
98
|
+
requestGdprConsent(): Promise<GdprConsentResult> {
|
|
69
99
|
console.log('[AdWhaleMediationAds] requestGdprConsent called');
|
|
70
100
|
if (!AdwhaleSdkReactNative?.requestGdprConsent) {
|
|
71
101
|
const error = new Error('requestGdprConsent is not implemented in native module');
|
|
@@ -100,10 +130,84 @@ export const AdWhaleMediationAds = {
|
|
|
100
130
|
|
|
101
131
|
setGdpr(consent: boolean) {
|
|
102
132
|
console.log('[AdWhaleMediationAds] setGdpr called:', consent);
|
|
133
|
+
if (Platform.OS === 'ios') {
|
|
134
|
+
console.warn(
|
|
135
|
+
'[AdWhaleMediationAds] setGdpr: iOS AdWhale SDK 에 대응 API가 없어 지원하지 않습니다 (Android 전용).'
|
|
136
|
+
);
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
103
139
|
if (!AdwhaleSdkReactNative?.setGdpr) {
|
|
104
140
|
console.warn('[AdWhaleMediationAds] setGdpr is not implemented in native module');
|
|
105
141
|
return;
|
|
106
142
|
}
|
|
107
143
|
AdwhaleSdkReactNative.setGdpr(consent);
|
|
108
144
|
},
|
|
145
|
+
|
|
146
|
+
setTagForUnderAgeOfConsent(tag: boolean) {
|
|
147
|
+
if (!AdwhaleSdkReactNative?.setTagForUnderAgeOfConsent) {
|
|
148
|
+
console.warn(
|
|
149
|
+
'[AdWhaleMediationAds] setTagForUnderAgeOfConsent is not implemented in native module'
|
|
150
|
+
);
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
AdwhaleSdkReactNative.setTagForUnderAgeOfConsent(tag);
|
|
154
|
+
},
|
|
155
|
+
|
|
156
|
+
setMaxAdContentRating(rating: string | null | undefined) {
|
|
157
|
+
if (!AdwhaleSdkReactNative?.setMaxAdContentRating) {
|
|
158
|
+
console.warn(
|
|
159
|
+
'[AdWhaleMediationAds] setMaxAdContentRating is not implemented in native module'
|
|
160
|
+
);
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
if (rating === undefined || rating === '') {
|
|
164
|
+
AdwhaleSdkReactNative.setMaxAdContentRating(null);
|
|
165
|
+
} else {
|
|
166
|
+
AdwhaleSdkReactNative.setMaxAdContentRating(rating);
|
|
167
|
+
}
|
|
168
|
+
},
|
|
169
|
+
|
|
170
|
+
setTestDeviceIdentifiers(testDeviceIds: string[] | null | undefined) {
|
|
171
|
+
if (testDeviceIds == null) {
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
if (!AdwhaleSdkReactNative?.setTestDeviceIdentifiers) {
|
|
175
|
+
console.warn(
|
|
176
|
+
'[AdWhaleMediationAds] setTestDeviceIdentifiers is not implemented in native module'
|
|
177
|
+
);
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
AdwhaleSdkReactNative.setTestDeviceIdentifiers(testDeviceIds);
|
|
181
|
+
},
|
|
182
|
+
|
|
183
|
+
showAdInspector(): Promise<AdInspectorResult> {
|
|
184
|
+
if (!AdwhaleSdkReactNative?.showAdInspector) {
|
|
185
|
+
return Promise.reject(
|
|
186
|
+
new Error('showAdInspector is not implemented in native module')
|
|
187
|
+
);
|
|
188
|
+
}
|
|
189
|
+
return AdwhaleSdkReactNative.showAdInspector();
|
|
190
|
+
},
|
|
191
|
+
|
|
192
|
+
setAppMuted(isMuted: boolean) {
|
|
193
|
+
if (!AdwhaleSdkReactNative?.setAppMuted) {
|
|
194
|
+
console.warn(
|
|
195
|
+
'[AdWhaleMediationAds] setAppMuted is not implemented in native module'
|
|
196
|
+
);
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
AdwhaleSdkReactNative.setAppMuted(isMuted);
|
|
200
|
+
},
|
|
201
|
+
|
|
202
|
+
setAppVolume(volume: number) {
|
|
203
|
+
if (!AdwhaleSdkReactNative?.setAppVolume) {
|
|
204
|
+
console.warn(
|
|
205
|
+
'[AdWhaleMediationAds] setAppVolume is not implemented in native module'
|
|
206
|
+
);
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
AdwhaleSdkReactNative.setAppVolume(volume);
|
|
210
|
+
},
|
|
109
211
|
};
|
|
212
|
+
|
|
213
|
+
export type { InitializeResult, GdprConsentResult, AdInspectorResult };
|
|
@@ -8,8 +8,8 @@ import type {
|
|
|
8
8
|
} from 'react-native';
|
|
9
9
|
|
|
10
10
|
export interface AdWhaleNativeCustomError {
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
statusCode: number;
|
|
12
|
+
message: string;
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
export interface AdWhaleNativeCustomGcoder {
|
|
@@ -25,8 +25,11 @@ export interface AdWhaleNativeCustomViewProps {
|
|
|
25
25
|
region?: string;
|
|
26
26
|
gcoder?: AdWhaleNativeCustomGcoder;
|
|
27
27
|
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
onNativeAdLoaded?: () => void;
|
|
29
|
+
onNativeAdFailedToLoad?: (event: AdWhaleNativeCustomError) => void;
|
|
30
|
+
onNativeAdShowFailed?: (event: AdWhaleNativeCustomError) => void;
|
|
31
|
+
onNativeAdClicked?: () => void;
|
|
32
|
+
onNativeAdClosed?: () => void;
|
|
30
33
|
}
|
|
31
34
|
|
|
32
35
|
export interface AdWhaleNativeCustomHandle {
|
|
@@ -37,11 +40,16 @@ export interface AdWhaleNativeCustomHandle {
|
|
|
37
40
|
type NativeErrorEvent = NativeSyntheticEvent<AdWhaleNativeCustomError>;
|
|
38
41
|
|
|
39
42
|
interface NativeProps
|
|
40
|
-
extends Omit<
|
|
41
|
-
|
|
43
|
+
extends Omit<
|
|
44
|
+
AdWhaleNativeCustomViewProps,
|
|
45
|
+
'onNativeAdFailedToLoad' | 'onNativeAdShowFailed'
|
|
46
|
+
> {
|
|
47
|
+
onNativeAdFailedToLoad?: (e: NativeErrorEvent) => void;
|
|
48
|
+
onNativeAdShowFailed?: (e: NativeErrorEvent) => void;
|
|
42
49
|
}
|
|
43
50
|
|
|
44
51
|
const VIEW_MANAGER_NAME = 'RNAdWhaleMediationCustomNativeAdView';
|
|
52
|
+
const LOG_PREFIX = '[adwhale_sdk_react_native] AdWhaleNativeCustomView.tsx';
|
|
45
53
|
|
|
46
54
|
const NativeComponent =
|
|
47
55
|
requireNativeComponent<NativeProps>(VIEW_MANAGER_NAME);
|
|
@@ -55,41 +63,95 @@ export const AdWhaleNativeCustomView = forwardRef<
|
|
|
55
63
|
useImperativeHandle(ref, () => ({
|
|
56
64
|
loadAd() {
|
|
57
65
|
const handle = findNodeHandle(innerRef.current);
|
|
58
|
-
|
|
66
|
+
console.log(`${LOG_PREFIX} loadAd() called handle=${String(handle)}`);
|
|
67
|
+
if (!handle) {
|
|
68
|
+
console.log(`${LOG_PREFIX} loadAd() skipped: handle is null`);
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
59
71
|
const config = UIManager.getViewManagerConfig(VIEW_MANAGER_NAME) as
|
|
60
72
|
| { Commands?: { loadAd?: number; showAd?: number } }
|
|
61
73
|
| undefined;
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
74
|
+
const loadCommand = config?.Commands?.loadAd;
|
|
75
|
+
if (loadCommand != null) {
|
|
76
|
+
console.log(`${LOG_PREFIX} dispatch loadAd commandId=${String(loadCommand)}`);
|
|
77
|
+
UIManager.dispatchViewManagerCommand(handle, loadCommand, []);
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
console.log(`${LOG_PREFIX} loadAd commandId missing, fallback to string command`);
|
|
81
|
+
try {
|
|
82
|
+
(UIManager as any).dispatchViewManagerCommand(handle, 'loadAd', []);
|
|
83
|
+
} catch (error) {
|
|
84
|
+
console.log(
|
|
85
|
+
`${LOG_PREFIX} loadAd fallback dispatch failed: ${String(error)}`,
|
|
86
|
+
);
|
|
87
|
+
}
|
|
68
88
|
},
|
|
69
89
|
showAd() {
|
|
70
90
|
const handle = findNodeHandle(innerRef.current);
|
|
71
|
-
|
|
91
|
+
console.log(`${LOG_PREFIX} showAd() called handle=${String(handle)}`);
|
|
92
|
+
if (!handle) {
|
|
93
|
+
console.log(`${LOG_PREFIX} showAd() skipped: handle is null`);
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
72
96
|
const config = UIManager.getViewManagerConfig(VIEW_MANAGER_NAME) as
|
|
73
97
|
| { Commands?: { loadAd?: number; showAd?: number } }
|
|
74
98
|
| undefined;
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
99
|
+
const showCommand = config?.Commands?.showAd;
|
|
100
|
+
if (showCommand != null) {
|
|
101
|
+
console.log(`${LOG_PREFIX} dispatch showAd commandId=${String(showCommand)}`);
|
|
102
|
+
UIManager.dispatchViewManagerCommand(handle, showCommand, []);
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
console.log(`${LOG_PREFIX} showAd commandId missing, fallback to string command`);
|
|
106
|
+
try {
|
|
107
|
+
(UIManager as any).dispatchViewManagerCommand(handle, 'showAd', []);
|
|
108
|
+
} catch (error) {
|
|
109
|
+
console.log(
|
|
110
|
+
`${LOG_PREFIX} showAd fallback dispatch failed: ${String(error)}`,
|
|
111
|
+
);
|
|
112
|
+
}
|
|
81
113
|
},
|
|
82
114
|
}));
|
|
83
115
|
|
|
84
|
-
const handleFailedToLoad: NativeProps['
|
|
85
|
-
|
|
116
|
+
const handleFailedToLoad: NativeProps['onNativeAdFailedToLoad'] = e => {
|
|
117
|
+
const ev = e.nativeEvent;
|
|
118
|
+
queueMicrotask(() => props.onNativeAdFailedToLoad?.(ev));
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
const handleShowFailed: NativeProps['onNativeAdShowFailed'] = e => {
|
|
122
|
+
const ev = e.nativeEvent;
|
|
123
|
+
queueMicrotask(() => props.onNativeAdShowFailed?.(ev));
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
const handleLoaded = () => {
|
|
127
|
+
console.log('AdWhaleNativeCustomView.tsx CustomNative onLoaded');
|
|
128
|
+
// 네이티브 직접 이벤트가 레이아웃/커밋 중 동기 호출되면 setState 가 먹지 않는 경우가 있어 한 틱 미룸
|
|
129
|
+
queueMicrotask(() => props.onNativeAdLoaded?.());
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
const handleClicked = () => {
|
|
133
|
+
console.log('AdWhaleNativeCustomView.tsx CustomNative onClicked');
|
|
134
|
+
queueMicrotask(() => props.onNativeAdClicked?.());
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
const handleClosed = () => {
|
|
138
|
+
console.log('AdWhaleNativeCustomView.tsx CustomNative onClosed');
|
|
139
|
+
queueMicrotask(() => props.onNativeAdClosed?.());
|
|
86
140
|
};
|
|
87
141
|
|
|
88
142
|
return (
|
|
89
143
|
<NativeComponent
|
|
90
144
|
ref={innerRef}
|
|
91
145
|
{...props}
|
|
92
|
-
|
|
146
|
+
onNativeAdLoaded={handleLoaded}
|
|
147
|
+
onNativeAdFailedToLoad={
|
|
148
|
+
props.onNativeAdFailedToLoad ? handleFailedToLoad : undefined
|
|
149
|
+
}
|
|
150
|
+
onNativeAdShowFailed={
|
|
151
|
+
props.onNativeAdShowFailed ? handleShowFailed : undefined
|
|
152
|
+
}
|
|
153
|
+
onNativeAdClicked={handleClicked}
|
|
154
|
+
onNativeAdClosed={handleClosed}
|
|
93
155
|
/>
|
|
94
156
|
);
|
|
95
157
|
});
|