adwhale-sdk-react-native 2.7.204 → 2.7.400
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 +95 -91
- package/android/build.gradle +35 -1
- package/android/proguard-rules.pro +58 -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 +148 -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 +205 -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 +341 -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 +22 -0
- package/ios/RNAdWhaleMediationRewardAd.swift +206 -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 +221 -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 +63 -6
- 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 +10 -2
- 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 +317 -51
- 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 +35 -0
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
package com.adwhalesdkreactnative;
|
|
2
2
|
|
|
3
|
+
import android.app.Activity;
|
|
3
4
|
import android.util.Log;
|
|
4
5
|
|
|
5
6
|
import androidx.annotation.NonNull;
|
|
@@ -10,6 +11,8 @@ import com.facebook.react.bridge.ReactApplicationContext;
|
|
|
10
11
|
import com.facebook.react.bridge.ReactContextBaseJavaModule;
|
|
11
12
|
import com.facebook.react.bridge.ReactMethod;
|
|
12
13
|
import com.facebook.react.bridge.ReadableMap;
|
|
14
|
+
import com.facebook.react.bridge.ReadableArray;
|
|
15
|
+
import com.facebook.react.bridge.ReadableType;
|
|
13
16
|
import com.facebook.react.bridge.UiThreadUtil;
|
|
14
17
|
import com.facebook.react.bridge.WritableMap;
|
|
15
18
|
import com.facebook.react.modules.core.DeviceEventManagerModule;
|
|
@@ -30,12 +33,22 @@ import java.util.Map;
|
|
|
30
33
|
public class RNAdWhaleMediationRewardAd extends ReactContextBaseJavaModule implements AdWhaleMediationRewardedAdLoadCallback, AdWhaleMediationFullScreenContentCallback, AdWhaleMediationUserEarnedRewardListener {
|
|
31
34
|
|
|
32
35
|
public static final String REACT_CLASS_NAME = RNAdWhaleMediationRewardAd.class.getSimpleName();
|
|
36
|
+
|
|
37
|
+
// Flutter와 싱크: adId 기반 멀티 인스턴스 지원
|
|
38
|
+
private final Map<Integer, AdWhaleMediationRewardAd> adsById = new HashMap<>();
|
|
39
|
+
/** 멀티 로드 시 콜백마다 올바른 adId로 onAdEvent 를 보내기 위한 리스너 (공유 this + lastActiveAdId 는 경합) */
|
|
40
|
+
private final Map<Integer, PerAdRewardListener> rewardListenersById = new HashMap<>();
|
|
41
|
+
private int lastActiveAdId = 0;
|
|
42
|
+
|
|
33
43
|
private AdWhaleMediationRewardAd adWhaleMediationRewardAd;
|
|
34
44
|
private String placementUid;
|
|
35
45
|
private String placementName;
|
|
36
46
|
private String region;
|
|
37
47
|
private double lt;
|
|
38
48
|
private double lng;
|
|
49
|
+
// 보상형 SSV(서버 사이드 검증) 전용 옵션
|
|
50
|
+
private String userId;
|
|
51
|
+
private Map<String, String> customData;
|
|
39
52
|
private final ReactApplicationContext reactContext;
|
|
40
53
|
|
|
41
54
|
public RNAdWhaleMediationRewardAd(ReactApplicationContext context) {
|
|
@@ -75,21 +88,169 @@ public class RNAdWhaleMediationRewardAd extends ReactContextBaseJavaModule imple
|
|
|
75
88
|
}
|
|
76
89
|
}
|
|
77
90
|
|
|
91
|
+
/**
|
|
92
|
+
* 보상형 SSV(서버 사이드 검증)용 앱 사용자 id 설정.
|
|
93
|
+
* AdMob / AdManager SSV postback 의 user_id 로 전달됩니다. (그 외 네트워크에서는 무시)
|
|
94
|
+
*/
|
|
95
|
+
@ReactMethod
|
|
96
|
+
public void setUserId(String userId) {
|
|
97
|
+
Log.e(REACT_CLASS_NAME, "userId: " + userId);
|
|
98
|
+
this.userId = userId;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* 보상형 SSV(서버 사이드 검증)용 커스텀 데이터 설정.
|
|
103
|
+
* AdMob / AdManager SSV postback 의 custom_data 로 전달되며, SDK 내부에서 JSON 직렬화됩니다.
|
|
104
|
+
* (그 외 네트워크에서는 무시)
|
|
105
|
+
*/
|
|
106
|
+
@ReactMethod
|
|
107
|
+
public void setCustomData(ReadableMap customDataMap) {
|
|
108
|
+
Log.e(REACT_CLASS_NAME, "customData: " + customDataMap);
|
|
109
|
+
this.customData = toStringMap(customDataMap);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/** ReadableMap 을 SDK 가 요구하는 Map<String, String> 으로 변환 (값은 문자열로 강제) */
|
|
113
|
+
@Nullable
|
|
114
|
+
private static Map<String, String> toStringMap(@Nullable ReadableMap map) {
|
|
115
|
+
if (map == null) {
|
|
116
|
+
return null;
|
|
117
|
+
}
|
|
118
|
+
Map<String, String> result = new HashMap<>();
|
|
119
|
+
com.facebook.react.bridge.ReadableMapKeySetIterator it = map.keySetIterator();
|
|
120
|
+
while (it.hasNextKey()) {
|
|
121
|
+
String key = it.nextKey();
|
|
122
|
+
switch (map.getType(key)) {
|
|
123
|
+
case String:
|
|
124
|
+
result.put(key, map.getString(key));
|
|
125
|
+
break;
|
|
126
|
+
case Number:
|
|
127
|
+
result.put(key, String.valueOf(map.getDouble(key)));
|
|
128
|
+
break;
|
|
129
|
+
case Boolean:
|
|
130
|
+
result.put(key, String.valueOf(map.getBoolean(key)));
|
|
131
|
+
break;
|
|
132
|
+
default:
|
|
133
|
+
// null / Map / Array 등은 무시
|
|
134
|
+
break;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return result;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/** 보상형 SSV 옵션(userId / customData)을 SDK 인스턴스에 적용 */
|
|
141
|
+
private static void applySsvOptions(
|
|
142
|
+
@NonNull AdWhaleMediationRewardAd ad,
|
|
143
|
+
@Nullable String userId,
|
|
144
|
+
@Nullable Map<String, String> customData) {
|
|
145
|
+
try {
|
|
146
|
+
if (userId != null && !userId.isEmpty()) {
|
|
147
|
+
ad.setUserId(userId);
|
|
148
|
+
}
|
|
149
|
+
} catch (Throwable t) {
|
|
150
|
+
Log.w(REACT_CLASS_NAME, "setUserId failed: " + t.getMessage());
|
|
151
|
+
}
|
|
152
|
+
try {
|
|
153
|
+
if (customData != null && !customData.isEmpty()) {
|
|
154
|
+
ad.setCustomData(customData);
|
|
155
|
+
}
|
|
156
|
+
} catch (Throwable t) {
|
|
157
|
+
Log.w(REACT_CLASS_NAME, "setCustomData failed: " + t.getMessage());
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
78
161
|
@ReactMethod
|
|
79
162
|
public void loadAd(String placementUid) {
|
|
80
163
|
Log.e(REACT_CLASS_NAME, "loadAd()");
|
|
164
|
+
lastActiveAdId = 0;
|
|
81
165
|
this.placementUid = placementUid;
|
|
82
166
|
adWhaleMediationRewardAd = new AdWhaleMediationRewardAd(placementUid);
|
|
83
167
|
adWhaleMediationRewardAd.setAdWhaleMediationFullScreenContentCallback(this);
|
|
84
168
|
adWhaleMediationRewardAd.setPlacementName(placementName);
|
|
85
169
|
adWhaleMediationRewardAd.setRegion(region);
|
|
86
170
|
adWhaleMediationRewardAd.setGcoder(lt, lng);
|
|
171
|
+
// 보상형 SSV(서버 사이드 검증) 옵션 적용
|
|
172
|
+
applySsvOptions(adWhaleMediationRewardAd, userId, customData);
|
|
87
173
|
|
|
88
174
|
UiThreadUtil.runOnUiThread(() -> {
|
|
89
175
|
adWhaleMediationRewardAd.loadAd(this);
|
|
90
176
|
});
|
|
91
177
|
}
|
|
92
178
|
|
|
179
|
+
/**
|
|
180
|
+
* Flutter MethodChannel과 동일 네이밍:
|
|
181
|
+
* loadRewardAd({adId, placementUid, region, gcoder:[lt,lng], placementName})
|
|
182
|
+
*/
|
|
183
|
+
@ReactMethod
|
|
184
|
+
public void loadRewardAd(ReadableMap args) {
|
|
185
|
+
if (args == null) {
|
|
186
|
+
Log.e(REACT_CLASS_NAME, "loadRewardAd args is null");
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
if (!args.hasKey("adId") || args.getType("adId") != ReadableType.Number) {
|
|
190
|
+
Log.e(REACT_CLASS_NAME, "loadRewardAd missing adId (number)");
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
if (!args.hasKey("placementUid") || args.getType("placementUid") != ReadableType.String) {
|
|
194
|
+
Log.e(REACT_CLASS_NAME, "loadRewardAd missing placementUid (string)");
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
final int adId = args.getInt("adId");
|
|
198
|
+
final String placementUid = args.getString("placementUid");
|
|
199
|
+
|
|
200
|
+
final AdWhaleMediationRewardAd rewardAd = new AdWhaleMediationRewardAd(placementUid);
|
|
201
|
+
final PerAdRewardListener perAdListener = new PerAdRewardListener(adId);
|
|
202
|
+
rewardListenersById.put(adId, perAdListener);
|
|
203
|
+
rewardAd.setAdWhaleMediationFullScreenContentCallback(perAdListener);
|
|
204
|
+
|
|
205
|
+
try {
|
|
206
|
+
if (args.hasKey("region") && args.getType("region") == ReadableType.String) {
|
|
207
|
+
String r = args.getString("region");
|
|
208
|
+
if (r != null && !r.isEmpty()) rewardAd.setRegion(r);
|
|
209
|
+
}
|
|
210
|
+
} catch (Throwable t) {
|
|
211
|
+
Log.w(REACT_CLASS_NAME, "setRegion failed: " + t.getMessage());
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
try {
|
|
215
|
+
if (args.hasKey("placementName") && args.getType("placementName") == ReadableType.String) {
|
|
216
|
+
String pn = args.getString("placementName");
|
|
217
|
+
if (pn != null && !pn.isEmpty()) rewardAd.setPlacementName(pn);
|
|
218
|
+
}
|
|
219
|
+
} catch (Throwable t) {
|
|
220
|
+
Log.w(REACT_CLASS_NAME, "setPlacementName failed: " + t.getMessage());
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
try {
|
|
224
|
+
if (args.hasKey("gcoder") && args.getType("gcoder") == ReadableType.Array) {
|
|
225
|
+
ReadableArray arr = args.getArray("gcoder");
|
|
226
|
+
if (arr != null && arr.size() >= 2
|
|
227
|
+
&& arr.getType(0) == ReadableType.Number
|
|
228
|
+
&& arr.getType(1) == ReadableType.Number) {
|
|
229
|
+
double lat = arr.getDouble(0);
|
|
230
|
+
double lng = arr.getDouble(1);
|
|
231
|
+
rewardAd.setGcoder(lat, lng);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
} catch (Throwable t) {
|
|
235
|
+
Log.w(REACT_CLASS_NAME, "setGcoder failed: " + t.getMessage());
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// 보상형 SSV(서버 사이드 검증) 옵션: userId / customData
|
|
239
|
+
String ssvUserId = null;
|
|
240
|
+
if (args.hasKey("userId") && args.getType("userId") == ReadableType.String) {
|
|
241
|
+
ssvUserId = args.getString("userId");
|
|
242
|
+
}
|
|
243
|
+
Map<String, String> ssvCustomData = null;
|
|
244
|
+
if (args.hasKey("customData") && args.getType("customData") == ReadableType.Map) {
|
|
245
|
+
ssvCustomData = toStringMap(args.getMap("customData"));
|
|
246
|
+
}
|
|
247
|
+
applySsvOptions(rewardAd, ssvUserId, ssvCustomData);
|
|
248
|
+
|
|
249
|
+
adsById.put(adId, rewardAd);
|
|
250
|
+
|
|
251
|
+
UiThreadUtil.runOnUiThread(() -> rewardAd.loadAd(perAdListener));
|
|
252
|
+
}
|
|
253
|
+
|
|
93
254
|
@ReactMethod
|
|
94
255
|
public void showAd() {
|
|
95
256
|
Log.e(REACT_CLASS_NAME, "showAd()");
|
|
@@ -98,9 +259,63 @@ public class RNAdWhaleMediationRewardAd extends ReactContextBaseJavaModule imple
|
|
|
98
259
|
return;
|
|
99
260
|
}
|
|
100
261
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
262
|
+
lastActiveAdId = 0;
|
|
263
|
+
UiThreadUtil.runOnUiThread(() -> showRewardAdOnUi(adWhaleMediationRewardAd, this));
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/** Flutter 네이밍: showAdWithoutView(adId) */
|
|
267
|
+
@ReactMethod
|
|
268
|
+
public void showAdWithoutView(int adId) {
|
|
269
|
+
AdWhaleMediationRewardAd ad = adsById.get(adId);
|
|
270
|
+
if (ad == null) {
|
|
271
|
+
Log.e(REACT_CLASS_NAME, "showAdWithoutView: ad not found. adId=" + adId);
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
PerAdRewardListener listener = rewardListenersById.get(adId);
|
|
275
|
+
if (listener == null) {
|
|
276
|
+
Log.e(REACT_CLASS_NAME, "showAdWithoutView: listener not found. adId=" + adId);
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
UiThreadUtil.runOnUiThread(() -> showRewardAdOnUi(ad, listener));
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* SDK는 Activity 생명주기와 연동해 onAdDismissed / 보상 콜백을 지연·발행합니다.
|
|
284
|
+
* {@code showAd(Listener)}만 쓰면 현재 Activity를 못 잡아 콜백이 누락될 수 있어
|
|
285
|
+
* {@code showAd(Activity, Listener)}를 우선 사용합니다.
|
|
286
|
+
*/
|
|
287
|
+
/**
|
|
288
|
+
* @param listener 전면/로드/보상 콜백을 동일 adId로 보낼 리스턴스 (싱글턴은 {@code this})
|
|
289
|
+
*/
|
|
290
|
+
private void showRewardAdOnUi(
|
|
291
|
+
@NonNull AdWhaleMediationRewardAd ad,
|
|
292
|
+
@NonNull AdWhaleMediationUserEarnedRewardListener listener) {
|
|
293
|
+
Activity activity = getCurrentActivity();
|
|
294
|
+
if (activity != null && !activity.isFinishing()) {
|
|
295
|
+
try {
|
|
296
|
+
ad.showAd(activity, listener);
|
|
297
|
+
return;
|
|
298
|
+
} catch (Throwable t) {
|
|
299
|
+
Log.w(REACT_CLASS_NAME, "showAd(activity, listener) failed, fallback: " + t.getMessage());
|
|
300
|
+
}
|
|
301
|
+
} else {
|
|
302
|
+
Log.w(REACT_CLASS_NAME, "showRewardAdOnUi: no valid Activity, using showAd(listener)");
|
|
303
|
+
}
|
|
304
|
+
ad.showAd(listener);
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
/** Flutter 네이밍: destroyAd(adId) */
|
|
308
|
+
@ReactMethod
|
|
309
|
+
public void destroyAd(int adId) {
|
|
310
|
+
rewardListenersById.remove(adId);
|
|
311
|
+
AdWhaleMediationRewardAd ad = adsById.remove(adId);
|
|
312
|
+
if (ad != null) {
|
|
313
|
+
try {
|
|
314
|
+
ad.destroy();
|
|
315
|
+
} catch (Throwable t) {
|
|
316
|
+
Log.w(REACT_CLASS_NAME, "destroyAd failed: " + t.getMessage());
|
|
317
|
+
}
|
|
318
|
+
}
|
|
104
319
|
}
|
|
105
320
|
|
|
106
321
|
|
|
@@ -109,12 +324,17 @@ public class RNAdWhaleMediationRewardAd extends ReactContextBaseJavaModule imple
|
|
|
109
324
|
public void onAdClicked() {
|
|
110
325
|
Log.i(REACT_CLASS_NAME, "onAdClicked()");
|
|
111
326
|
sendEvnet("onRewardAdClicked", null);
|
|
327
|
+
sendAdEvent(lastActiveAdId, "onRewardAdClicked", null);
|
|
112
328
|
}
|
|
113
329
|
|
|
114
330
|
@Override
|
|
115
331
|
public void onAdDismissed() {
|
|
116
332
|
Log.i(REACT_CLASS_NAME, "onAdDismissed()");
|
|
117
333
|
sendEvnet("onRewardAdDismissed", null);
|
|
334
|
+
sendAdEvent(lastActiveAdId, "onRewardAdDismissed", null);
|
|
335
|
+
if (adsById.containsKey(lastActiveAdId)) {
|
|
336
|
+
destroyAd(lastActiveAdId);
|
|
337
|
+
}
|
|
118
338
|
}
|
|
119
339
|
|
|
120
340
|
@Override
|
|
@@ -123,6 +343,8 @@ public class RNAdWhaleMediationRewardAd extends ReactContextBaseJavaModule imple
|
|
|
123
343
|
WritableMap params = Arguments.createMap();
|
|
124
344
|
params.putInt("statusCode", statusCode);
|
|
125
345
|
params.putString("message", message);
|
|
346
|
+
// NOTE: emit() 이후에는 Map 이 consume 될 수 있으므로, payload 복사(sendAdEvent)를 먼저 수행
|
|
347
|
+
sendAdEvent(lastActiveAdId, "onRewardAdFailedToShow", params);
|
|
126
348
|
sendEvnet("onRewardAdFailedToShow", params);
|
|
127
349
|
}
|
|
128
350
|
|
|
@@ -130,6 +352,7 @@ public class RNAdWhaleMediationRewardAd extends ReactContextBaseJavaModule imple
|
|
|
130
352
|
public void onAdShowed() {
|
|
131
353
|
Log.i(REACT_CLASS_NAME, "onAdShowed()");
|
|
132
354
|
sendEvnet("onRewardAdShowed", null);
|
|
355
|
+
sendAdEvent(lastActiveAdId, "onRewardAdShowed", null);
|
|
133
356
|
}
|
|
134
357
|
|
|
135
358
|
/// AdWhaleMediationRewardedAdLoadCallback
|
|
@@ -137,6 +360,7 @@ public class RNAdWhaleMediationRewardAd extends ReactContextBaseJavaModule imple
|
|
|
137
360
|
public void onAdLoaded(AdWhaleMediationRewardAd adWhaleMediationRewardAd, String message) {
|
|
138
361
|
Log.i(REACT_CLASS_NAME, "onAdLoaded(+ " + message + ")");
|
|
139
362
|
sendEvnet("onRewardAdLoaded", null);
|
|
363
|
+
sendAdEvent(lastActiveAdId, "onRewardAdLoaded", null);
|
|
140
364
|
}
|
|
141
365
|
|
|
142
366
|
@Override
|
|
@@ -145,6 +369,8 @@ public class RNAdWhaleMediationRewardAd extends ReactContextBaseJavaModule imple
|
|
|
145
369
|
WritableMap params = Arguments.createMap();
|
|
146
370
|
params.putInt("statusCode", statusCode);
|
|
147
371
|
params.putString("message", message);
|
|
372
|
+
// NOTE: emit() 이후에는 Map 이 consume 될 수 있으므로, payload 복사(sendAdEvent)를 먼저 수행
|
|
373
|
+
sendAdEvent(lastActiveAdId, "onRewardAdFailedToLoad", params);
|
|
148
374
|
sendEvnet("onRewardAdFailedToLoad", params);
|
|
149
375
|
}
|
|
150
376
|
|
|
@@ -154,8 +380,14 @@ public class RNAdWhaleMediationRewardAd extends ReactContextBaseJavaModule imple
|
|
|
154
380
|
public void onUserRewarded(AdWhaleMediationRewardItem adWhaleMediationRewardItem) {
|
|
155
381
|
Log.i(REACT_CLASS_NAME, "onUserRewarded(" + adWhaleMediationRewardItem.toString() + ")");
|
|
156
382
|
WritableMap params = Arguments.createMap();
|
|
383
|
+
// Flutter와 동일 키: RewardType / RewardAmount (대소문자 포함)
|
|
384
|
+
params.putString("RewardType", adWhaleMediationRewardItem.getRewardType());
|
|
385
|
+
params.putInt("RewardAmount", adWhaleMediationRewardItem.getRewardAmount());
|
|
386
|
+
// 레거시 호환 키도 유지
|
|
157
387
|
params.putString("type", adWhaleMediationRewardItem.getRewardType());
|
|
158
388
|
params.putInt("amount", adWhaleMediationRewardItem.getRewardAmount());
|
|
389
|
+
// NOTE: emit() 이후에는 Map 이 consume 될 수 있으므로, payload 복사(sendAdEvent)를 먼저 수행
|
|
390
|
+
sendAdEvent(lastActiveAdId, "onUserRewarded", params);
|
|
159
391
|
sendEvnet("onUserRewarded", params);
|
|
160
392
|
}
|
|
161
393
|
|
|
@@ -167,9 +399,36 @@ public class RNAdWhaleMediationRewardAd extends ReactContextBaseJavaModule imple
|
|
|
167
399
|
}
|
|
168
400
|
|
|
169
401
|
private void sendEvnet(String eventName, @Nullable WritableMap params) {
|
|
170
|
-
getReactApplicationContext()
|
|
171
|
-
|
|
402
|
+
final ReactApplicationContext ctx = getReactApplicationContext();
|
|
403
|
+
if (ctx == null) {
|
|
404
|
+
return;
|
|
405
|
+
}
|
|
406
|
+
// SDK 콜백이 메인이 아닌 스레드에서 올 수 있어 RN 브리지는 UI 큐에서 emit
|
|
407
|
+
ctx.runOnUiQueueThread(() -> {
|
|
408
|
+
try {
|
|
409
|
+
ctx.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
|
|
172
410
|
.emit(eventName, params);
|
|
411
|
+
} catch (Throwable t) {
|
|
412
|
+
Log.w(REACT_CLASS_NAME, "emit failed: " + eventName + " — " + t.getMessage());
|
|
413
|
+
}
|
|
414
|
+
});
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
/**
|
|
418
|
+
* Flutter `onAdEvent` 스타일: payload에 eventName + adId 포함.
|
|
419
|
+
* payload: { adId, eventName, statusCode?, message?, RewardType?, RewardAmount? }
|
|
420
|
+
*/
|
|
421
|
+
private void sendAdEvent(int adId, @NonNull String eventName, @Nullable WritableMap original) {
|
|
422
|
+
WritableMap payload = Arguments.createMap();
|
|
423
|
+
payload.putInt("adId", adId);
|
|
424
|
+
payload.putString("eventName", eventName);
|
|
425
|
+
if (original != null) {
|
|
426
|
+
if (original.hasKey("statusCode")) payload.putInt("statusCode", original.getInt("statusCode"));
|
|
427
|
+
if (original.hasKey("message")) payload.putString("message", original.getString("message"));
|
|
428
|
+
if (original.hasKey("RewardType")) payload.putString("RewardType", original.getString("RewardType"));
|
|
429
|
+
if (original.hasKey("RewardAmount")) payload.putInt("RewardAmount", original.getInt("RewardAmount"));
|
|
430
|
+
}
|
|
431
|
+
sendEvnet("onAdEvent", payload);
|
|
173
432
|
}
|
|
174
433
|
|
|
175
434
|
@ReactMethod
|
|
@@ -178,7 +437,83 @@ public class RNAdWhaleMediationRewardAd extends ReactContextBaseJavaModule imple
|
|
|
178
437
|
}
|
|
179
438
|
|
|
180
439
|
@ReactMethod
|
|
181
|
-
|
|
440
|
+
public void removeListeners(Integer count) {
|
|
182
441
|
//TODO NOTHING
|
|
183
442
|
}
|
|
443
|
+
|
|
444
|
+
/**
|
|
445
|
+
* 멀티 보상형 인스턴스당 1개: 로드/전면/보상 콜백 모두 boundAdId 로 onAdEvent 전달.
|
|
446
|
+
*/
|
|
447
|
+
private final class PerAdRewardListener implements AdWhaleMediationRewardedAdLoadCallback,
|
|
448
|
+
AdWhaleMediationFullScreenContentCallback,
|
|
449
|
+
AdWhaleMediationUserEarnedRewardListener {
|
|
450
|
+
private final int boundAdId;
|
|
451
|
+
|
|
452
|
+
PerAdRewardListener(int boundAdId) {
|
|
453
|
+
this.boundAdId = boundAdId;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
@Override
|
|
457
|
+
public void onAdClicked() {
|
|
458
|
+
Log.i(REACT_CLASS_NAME, "onAdClicked() adId=" + boundAdId);
|
|
459
|
+
sendEvnet("onRewardAdClicked", null);
|
|
460
|
+
sendAdEvent(boundAdId, "onRewardAdClicked", null);
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
@Override
|
|
464
|
+
public void onAdDismissed() {
|
|
465
|
+
Log.i(REACT_CLASS_NAME, "onAdDismissed() adId=" + boundAdId);
|
|
466
|
+
sendEvnet("onRewardAdDismissed", null);
|
|
467
|
+
sendAdEvent(boundAdId, "onRewardAdDismissed", null);
|
|
468
|
+
if (adsById.containsKey(boundAdId)) {
|
|
469
|
+
destroyAd(boundAdId);
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
@Override
|
|
474
|
+
public void onFailedToShow(int statusCode, String message) {
|
|
475
|
+
Log.i(REACT_CLASS_NAME, "onFailedToShow(" + statusCode + ", " + message + ") adId=" + boundAdId);
|
|
476
|
+
WritableMap params = Arguments.createMap();
|
|
477
|
+
params.putInt("statusCode", statusCode);
|
|
478
|
+
params.putString("message", message);
|
|
479
|
+
sendAdEvent(boundAdId, "onRewardAdFailedToShow", params);
|
|
480
|
+
sendEvnet("onRewardAdFailedToShow", params);
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
@Override
|
|
484
|
+
public void onAdShowed() {
|
|
485
|
+
Log.i(REACT_CLASS_NAME, "onAdShowed() adId=" + boundAdId);
|
|
486
|
+
sendEvnet("onRewardAdShowed", null);
|
|
487
|
+
sendAdEvent(boundAdId, "onRewardAdShowed", null);
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
@Override
|
|
491
|
+
public void onAdLoaded(AdWhaleMediationRewardAd adWhaleMediationRewardAd, String message) {
|
|
492
|
+
Log.i(REACT_CLASS_NAME, "onAdLoaded(+ " + message + ") adId=" + boundAdId);
|
|
493
|
+
sendEvnet("onRewardAdLoaded", null);
|
|
494
|
+
sendAdEvent(boundAdId, "onRewardAdLoaded", null);
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
@Override
|
|
498
|
+
public void onAdFailedToLoad(int statusCode, String message) {
|
|
499
|
+
Log.i(REACT_CLASS_NAME, "onAdFailedToLoad(" + statusCode + ", " + message + ") adId=" + boundAdId);
|
|
500
|
+
WritableMap params = Arguments.createMap();
|
|
501
|
+
params.putInt("statusCode", statusCode);
|
|
502
|
+
params.putString("message", message);
|
|
503
|
+
sendAdEvent(boundAdId, "onRewardAdFailedToLoad", params);
|
|
504
|
+
sendEvnet("onRewardAdFailedToLoad", params);
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
@Override
|
|
508
|
+
public void onUserRewarded(AdWhaleMediationRewardItem adWhaleMediationRewardItem) {
|
|
509
|
+
Log.i(REACT_CLASS_NAME, "onUserRewarded(" + adWhaleMediationRewardItem + ") adId=" + boundAdId);
|
|
510
|
+
WritableMap params = Arguments.createMap();
|
|
511
|
+
params.putString("RewardType", adWhaleMediationRewardItem.getRewardType());
|
|
512
|
+
params.putInt("RewardAmount", adWhaleMediationRewardItem.getRewardAmount());
|
|
513
|
+
params.putString("type", adWhaleMediationRewardItem.getRewardType());
|
|
514
|
+
params.putInt("amount", adWhaleMediationRewardItem.getRewardAmount());
|
|
515
|
+
sendAdEvent(boundAdId, "onUserRewarded", params);
|
|
516
|
+
sendEvnet("onUserRewarded", params);
|
|
517
|
+
}
|
|
518
|
+
}
|
|
184
519
|
}
|