adwhale-sdk-react-native 2.7.203 → 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.
Files changed (109) hide show
  1. package/AdwhaleSdkReactNative.podspec +22 -0
  2. package/README.md +105 -39
  3. package/android/build.gradle +15 -15
  4. package/android/proguard-rules.pro +52 -107
  5. package/android/src/main/java/com/adwhalesdkreactnative/AdWhaleCustomNativeBinderFactory.java +18 -0
  6. package/android/src/main/java/com/adwhalesdkreactnative/AdwhaleSdkReactNativePackage.java +51 -6
  7. package/android/src/main/java/com/adwhalesdkreactnative/BinderFactory.java +9 -0
  8. package/android/src/main/java/com/adwhalesdkreactnative/RNAdWhaleMediationAdSettingModule.java +149 -42
  9. package/android/src/main/java/com/adwhalesdkreactnative/RNAdWhaleMediationAdView.java +60 -30
  10. package/android/src/main/java/com/adwhalesdkreactnative/RNAdWhaleMediationAppOpenAd.java +136 -0
  11. package/android/src/main/java/com/adwhalesdkreactnative/RNAdWhaleMediationCustomNativeAdView.java +37 -46
  12. package/android/src/main/java/com/adwhalesdkreactnative/RNAdWhaleMediationExitPopupAd.java +240 -0
  13. package/android/src/main/java/com/adwhalesdkreactnative/RNAdWhaleMediationInterstitialAd.java +189 -0
  14. package/android/src/main/java/com/adwhalesdkreactnative/RNAdWhaleMediationLoggerModule.java +2 -1
  15. package/android/src/main/java/com/adwhalesdkreactnative/RNAdWhaleMediationNativeAdViewListenerBridge.java +83 -0
  16. package/android/src/main/java/com/adwhalesdkreactnative/RNAdWhaleMediationRewardAd.java +255 -6
  17. package/android/src/main/java/com/adwhalesdkreactnative/RNAdWhaleMediationTemplateNativeAdView.java +191 -70
  18. package/android/src/main/java/com/adwhalesdkreactnative/RNAdWhaleMediationTransitionPopupAd.java +218 -0
  19. package/android/src/main/java/com/adwhalesdkreactnative/RNWrapperView.java +137 -0
  20. package/android/src/main/java/com/adwhalesdkreactnative/SimpleBinderFactory.java +1 -1
  21. package/android/src/main/java/com/adwhalesdkreactnative/common/RNMethodArgConst.java +112 -0
  22. package/android/src/main/java/com/adwhalesdkreactnative/common/RNMethodCallConst.java +113 -0
  23. package/android/src/main/java/com/adwhalesdkreactnative/common/RNMethodResultConst.java +28 -0
  24. package/build/generated/ios/ReactAppDependencyProvider.podspec +34 -0
  25. package/ios/AdWhaleNativeCustomViewFactoryRegistry.swift +56 -0
  26. package/ios/AdwhaleSdkReactNative.mm +96 -5
  27. package/ios/AdwhaleSdkReactNativeModule.swift +148 -0
  28. package/ios/RNAdWhaleMediationAdViewManager.m +38 -0
  29. package/ios/RNAdWhaleMediationAdViewManager.swift +14 -0
  30. package/ios/RNAdWhaleMediationAppOpenAd.m +18 -0
  31. package/ios/RNAdWhaleMediationAppOpenAd.swift +175 -0
  32. package/ios/RNAdWhaleMediationCustomNativeAdViewManager.m +22 -0
  33. package/ios/RNAdWhaleMediationCustomNativeAdViewManager.swift +239 -0
  34. package/ios/RNAdWhaleMediationInterstitialAd.m +18 -0
  35. package/ios/RNAdWhaleMediationInterstitialAd.swift +161 -0
  36. package/ios/RNAdWhaleMediationRewardAd.m +18 -0
  37. package/ios/RNAdWhaleMediationRewardAd.swift +172 -0
  38. package/ios/WhaleMediationBannerContainer.swift +182 -0
  39. package/lib/module/AdWhaleAdView.js +80 -1
  40. package/lib/module/AdWhaleAdView.js.map +1 -1
  41. package/lib/module/AdWhaleAppOpenAd.js +223 -25
  42. package/lib/module/AdWhaleAppOpenAd.js.map +1 -1
  43. package/lib/module/AdWhaleExitPopupAd.js +93 -0
  44. package/lib/module/AdWhaleExitPopupAd.js.map +1 -0
  45. package/lib/module/AdWhaleInterstitialAd.js +146 -22
  46. package/lib/module/AdWhaleInterstitialAd.js.map +1 -1
  47. package/lib/module/AdWhaleMediationAds.js +75 -4
  48. package/lib/module/AdWhaleMediationAds.js.map +1 -1
  49. package/lib/module/AdWhaleNativeCustomView.js +59 -8
  50. package/lib/module/AdWhaleNativeCustomView.js.map +1 -1
  51. package/lib/module/AdWhaleNativeTemplateView.js +37 -19
  52. package/lib/module/AdWhaleNativeTemplateView.js.map +1 -1
  53. package/lib/module/AdWhaleRewardAd.js +169 -24
  54. package/lib/module/AdWhaleRewardAd.js.map +1 -1
  55. package/lib/module/AdWhaleTransitionPopupAd.js +87 -0
  56. package/lib/module/AdWhaleTransitionPopupAd.js.map +1 -0
  57. package/lib/module/NativeAdwhaleSdkReactNative.js +16 -1
  58. package/lib/module/NativeAdwhaleSdkReactNative.js.map +1 -1
  59. package/lib/module/constants/AdWhaleMethodArgConst.js +53 -0
  60. package/lib/module/constants/AdWhaleMethodArgConst.js.map +1 -0
  61. package/lib/module/constants/AdWhaleMethodCallConst.js +56 -0
  62. package/lib/module/constants/AdWhaleMethodCallConst.js.map +1 -0
  63. package/lib/module/constants/AdWhaleMethodResultConst.js +16 -0
  64. package/lib/module/constants/AdWhaleMethodResultConst.js.map +1 -0
  65. package/lib/module/index.js +10 -1
  66. package/lib/module/index.js.map +1 -1
  67. package/lib/typescript/src/AdWhaleAdView.d.ts +46 -2
  68. package/lib/typescript/src/AdWhaleAdView.d.ts.map +1 -1
  69. package/lib/typescript/src/AdWhaleAppOpenAd.d.ts +10 -0
  70. package/lib/typescript/src/AdWhaleAppOpenAd.d.ts.map +1 -1
  71. package/lib/typescript/src/AdWhaleExitPopupAd.d.ts +36 -0
  72. package/lib/typescript/src/AdWhaleExitPopupAd.d.ts.map +1 -0
  73. package/lib/typescript/src/AdWhaleInterstitialAd.d.ts +16 -0
  74. package/lib/typescript/src/AdWhaleInterstitialAd.d.ts.map +1 -1
  75. package/lib/typescript/src/AdWhaleMediationAds.d.ts +14 -5
  76. package/lib/typescript/src/AdWhaleMediationAds.d.ts.map +1 -1
  77. package/lib/typescript/src/AdWhaleNativeCustomView.d.ts +7 -4
  78. package/lib/typescript/src/AdWhaleNativeCustomView.d.ts.map +1 -1
  79. package/lib/typescript/src/AdWhaleNativeTemplateView.d.ts +20 -7
  80. package/lib/typescript/src/AdWhaleNativeTemplateView.d.ts.map +1 -1
  81. package/lib/typescript/src/AdWhaleRewardAd.d.ts +18 -2
  82. package/lib/typescript/src/AdWhaleRewardAd.d.ts.map +1 -1
  83. package/lib/typescript/src/AdWhaleTransitionPopupAd.d.ts +33 -0
  84. package/lib/typescript/src/AdWhaleTransitionPopupAd.d.ts.map +1 -0
  85. package/lib/typescript/src/NativeAdwhaleSdkReactNative.d.ts +33 -6
  86. package/lib/typescript/src/NativeAdwhaleSdkReactNative.d.ts.map +1 -1
  87. package/lib/typescript/src/constants/AdWhaleMethodArgConst.d.ts +51 -0
  88. package/lib/typescript/src/constants/AdWhaleMethodArgConst.d.ts.map +1 -0
  89. package/lib/typescript/src/constants/AdWhaleMethodCallConst.d.ts +53 -0
  90. package/lib/typescript/src/constants/AdWhaleMethodCallConst.d.ts.map +1 -0
  91. package/lib/typescript/src/constants/AdWhaleMethodResultConst.d.ts +14 -0
  92. package/lib/typescript/src/constants/AdWhaleMethodResultConst.d.ts.map +1 -0
  93. package/lib/typescript/src/index.d.ts +10 -2
  94. package/lib/typescript/src/index.d.ts.map +1 -1
  95. package/package.json +1 -1
  96. package/src/AdWhaleAdView.tsx +126 -9
  97. package/src/AdWhaleAppOpenAd.ts +293 -38
  98. package/src/AdWhaleExitPopupAd.ts +183 -0
  99. package/src/AdWhaleInterstitialAd.ts +206 -36
  100. package/src/AdWhaleMediationAds.ts +109 -5
  101. package/src/AdWhaleNativeCustomView.tsx +85 -23
  102. package/src/AdWhaleNativeTemplateView.tsx +79 -42
  103. package/src/AdWhaleRewardAd.ts +245 -43
  104. package/src/AdWhaleTransitionPopupAd.ts +171 -0
  105. package/src/NativeAdwhaleSdkReactNative.ts +36 -6
  106. package/src/constants/AdWhaleMethodArgConst.ts +50 -0
  107. package/src/constants/AdWhaleMethodCallConst.ts +60 -0
  108. package/src/constants/AdWhaleMethodResultConst.ts +13 -0
  109. package/src/index.ts +34 -1
@@ -7,7 +7,8 @@ import android.view.View;
7
7
  import androidx.annotation.NonNull;
8
8
  import androidx.annotation.Nullable;
9
9
 
10
- import com.facebook.react.bridge.Arguments;
10
+ import com.adwhalesdkreactnative.common.RNMethodArgConst;
11
+ import com.adwhalesdkreactnative.common.RNMethodCallConst;
11
12
  import com.facebook.react.bridge.ReactContext;
12
13
  import com.facebook.react.bridge.ReadableArray;
13
14
  import com.facebook.react.bridge.ReadableMap;
@@ -18,9 +19,7 @@ import com.facebook.react.uimanager.ThemedReactContext;
18
19
  import com.facebook.react.uimanager.annotations.ReactProp;
19
20
  import com.facebook.react.uimanager.events.RCTEventEmitter;
20
21
 
21
- import net.adwhale.sdk.mediation.ads.AdWhaleMediationAdView;
22
22
  import net.adwhale.sdk.mediation.ads.AdWhaleMediationNativeAdView;
23
- import net.adwhale.sdk.mediation.ads.AdWhaleMediationNativeAdViewListener;
24
23
  import net.adwhale.sdk.mediation.ads.AdWhaleNativeAdBinder;
25
24
 
26
25
  import java.util.Map;
@@ -47,40 +46,40 @@ public class RNAdWhaleMediationCustomNativeAdView extends SimpleViewManager<RNWr
47
46
  return new RNWrapperView(reactContext);
48
47
  }
49
48
 
50
- @ReactProp(name = "placementUid")
49
+ @ReactProp(name = RNMethodCallConst.PLACEMENT_UID)
51
50
  public void setPlacementUid(RNWrapperView view, @Nullable String pid) {
52
51
  this.placementUid = pid;
53
52
  }
54
53
 
55
- @ReactProp(name = "factoryId")
54
+ @ReactProp(name = RNMethodCallConst.FACTORY_ID)
56
55
  public void setFactoryId(RNWrapperView view, @Nullable String id) {
57
56
  this.factoryId = id;
58
57
  }
59
58
 
60
59
 
61
- @ReactProp(name = "placementName")
60
+ @ReactProp(name = RNMethodArgConst.RECEIVE_PLACEMENT_NAME)
62
61
  public void setPlacementName(RNWrapperView view, String placementName) {
63
- Log.e(REACT_CLASS_NAME, "placementName: " + placementName);
62
+ Log.e(REACT_CLASS_NAME, RNMethodArgConst.RECEIVE_PLACEMENT_NAME + ": " + placementName);
64
63
  this.placementName = placementName;
65
64
  }
66
65
 
67
- @ReactProp(name = "region")
66
+ @ReactProp(name = RNMethodArgConst.RECEIVE_REGION)
68
67
  public void setRegion(RNWrapperView view, String region) {
69
- Log.e(REACT_CLASS_NAME, "region: " + region);
68
+ Log.e(REACT_CLASS_NAME, RNMethodArgConst.RECEIVE_REGION + ": " + region);
70
69
  AdWhaleMediationNativeAdView adView = getAdWhaleMediationNativeAdView(view);
71
70
  if (adView != null) {
72
71
  adView.setRegion(region);
73
72
  }
74
73
  }
75
74
 
76
- @ReactProp(name = "gcoder")
75
+ @ReactProp(name = RNMethodArgConst.RECEIVE_GCODER)
77
76
  public void setGcoder(RNWrapperView view, ReadableMap gcoderMap) {
78
- Log.e(REACT_CLASS_NAME, "gcoderMap: " + gcoderMap);
77
+ Log.e(REACT_CLASS_NAME, RNMethodArgConst.RECEIVE_GCODER + ": " + gcoderMap);
79
78
  AdWhaleMediationNativeAdView adView = getAdWhaleMediationNativeAdView(view);
80
79
 
81
80
  if (adView != null && gcoderMap != null) {
82
- double lt = gcoderMap.hasKey("lt") ? gcoderMap.getDouble("lt") : 0.0;
83
- double lng = gcoderMap.hasKey("lng") ? gcoderMap.getDouble("lng") : 0.0;
81
+ double lt = gcoderMap.hasKey(RNMethodArgConst.RECEIVE_LT) ? gcoderMap.getDouble(RNMethodArgConst.RECEIVE_LT) : 0.0;
82
+ double lng = gcoderMap.hasKey(RNMethodArgConst.RECEIVE_LNG) ? gcoderMap.getDouble(RNMethodArgConst.RECEIVE_LNG) : 0.0;
84
83
 
85
84
  adView.setGcoder(lt, lng);
86
85
  }
@@ -90,18 +89,21 @@ public class RNAdWhaleMediationCustomNativeAdView extends SimpleViewManager<RNWr
90
89
  @Override
91
90
  public Map<String, Integer> getCommandsMap() {
92
91
  return MapBuilder.of(
93
- "loadAd", COMMAND_LOAD_AD,
94
- "showAd", COMMAND_SHOW_AD
92
+ RNMethodCallConst.LOAD_AD, COMMAND_LOAD_AD,
93
+ RNMethodCallConst.SHOW_AD, COMMAND_SHOW_AD
95
94
  );
96
95
  }
97
96
 
98
97
  @Nullable
99
98
  @Override
100
99
  public Map<String, Object> getExportedCustomDirectEventTypeConstants() {
101
- return MapBuilder.of(
102
- "onAdLoaded", MapBuilder.of("registrationName", "onAdLoaded"),
103
- "onAdFailedToLoad", MapBuilder.of("registrationName", "onAdFailedToLoad")
104
- );
100
+ MapBuilder.Builder<String, Object> builder = MapBuilder.builder();
101
+ builder.put(RNMethodCallConst.ON_NATIVE_AD_LOADED, MapBuilder.of(RNMethodArgConst.SEND_REGISTRATION_NAME, RNMethodCallConst.ON_NATIVE_AD_LOADED));
102
+ builder.put(RNMethodCallConst.ON_NATIVE_AD_FAILED_TO_LOAD, MapBuilder.of(RNMethodArgConst.SEND_REGISTRATION_NAME, RNMethodCallConst.ON_NATIVE_AD_FAILED_TO_LOAD));
103
+ builder.put(RNMethodCallConst.ON_NATIVE_AD_SHOW_FAILED, MapBuilder.of(RNMethodArgConst.SEND_REGISTRATION_NAME, RNMethodCallConst.ON_NATIVE_AD_SHOW_FAILED));
104
+ builder.put(RNMethodCallConst.ON_NATIVE_AD_CLICKED, MapBuilder.of(RNMethodArgConst.SEND_REGISTRATION_NAME, RNMethodCallConst.ON_NATIVE_AD_CLICKED));
105
+ builder.put(RNMethodCallConst.ON_NATIVE_AD_CLOSED, MapBuilder.of(RNMethodArgConst.SEND_REGISTRATION_NAME, RNMethodCallConst.ON_NATIVE_AD_CLOSED));
106
+ return builder.build();
105
107
  }
106
108
 
107
109
  @Override
@@ -120,13 +122,17 @@ public class RNAdWhaleMediationCustomNativeAdView extends SimpleViewManager<RNWr
120
122
  private void loadAd(RNWrapperView root) {
121
123
  if (placementUid == null || placementUid.isEmpty()) {
122
124
  Log.e(REACT_CLASS_NAME, "Placement UID is not set.");
123
- dispatchEvent(root, "onAdFailedToLoad", createErrorEvent(-1, "Placement UID is not set."));
125
+ dispatchEvent(root, RNMethodCallConst.ON_NATIVE_AD_FAILED_TO_LOAD,
126
+ RNAdWhaleMediationNativeAdViewListenerBridge.createErrorPayload(-1, "Placement UID is not set."));
124
127
  return;
125
128
  }
126
129
 
127
130
  if (factoryId == null || factoryId.isEmpty()) {
128
131
  Log.e(REACT_CLASS_NAME, "Factory ID is not set.");
129
- dispatchEvent(root, "onAdFailedToLoad", createErrorEvent(-1, "Factory ID is not set."));
132
+ dispatchEvent(root, RNMethodCallConst.ON_NATIVE_AD_FAILED_TO_LOAD,
133
+ RNAdWhaleMediationNativeAdViewListenerBridge.createErrorPayload(
134
+ RNAdWhaleMediationNativeAdViewListenerBridge.NATIVE_BINDER_CONFIGURATION_ERROR_CODE,
135
+ "Native custom binder: factoryId is required."));
130
136
  return;
131
137
  }
132
138
 
@@ -135,7 +141,8 @@ public class RNAdWhaleMediationCustomNativeAdView extends SimpleViewManager<RNWr
135
141
 
136
142
  if (currentActivity == null) {
137
143
  Log.e(REACT_CLASS_NAME, "Could not get current Activity.");
138
- dispatchEvent(root, "onAdFailedToLoad", createErrorEvent(-1, "Could not get current Activity."));
144
+ dispatchEvent(root, RNMethodCallConst.ON_NATIVE_AD_FAILED_TO_LOAD,
145
+ RNAdWhaleMediationNativeAdViewListenerBridge.createErrorPayload(-1, "Could not get current Activity."));
139
146
  return;
140
147
  }
141
148
 
@@ -143,7 +150,10 @@ public class RNAdWhaleMediationCustomNativeAdView extends SimpleViewManager<RNWr
143
150
  if (binderFactory == null) {
144
151
  String errorMessage = "BinderFactory not found for factoryId: " + factoryId;
145
152
  Log.e(REACT_CLASS_NAME, errorMessage);
146
- dispatchEvent(root, "onAdFailedToLoad", createErrorEvent(-1, errorMessage));
153
+ dispatchEvent(root, RNMethodCallConst.ON_NATIVE_AD_FAILED_TO_LOAD,
154
+ RNAdWhaleMediationNativeAdViewListenerBridge.createErrorPayload(
155
+ RNAdWhaleMediationNativeAdViewListenerBridge.NATIVE_BINDER_CONFIGURATION_ERROR_CODE,
156
+ errorMessage));
147
157
  return;
148
158
  }
149
159
 
@@ -154,22 +164,10 @@ public class RNAdWhaleMediationCustomNativeAdView extends SimpleViewManager<RNWr
154
164
  AdWhaleMediationNativeAdView adView = new AdWhaleMediationNativeAdView(currentActivity);
155
165
  root.addView(adView); // Add the SDK's view to our wrapper view
156
166
 
157
- adView.setAdWhaleMediationNativeAdViewListener(new AdWhaleMediationNativeAdViewListener() {
158
- @Override
159
- public void onNativeAdLoaded() {
160
- Log.d(REACT_CLASS_NAME, "Ad loaded successfully. Ready to show.");
161
- dispatchEvent(root, "onAdLoaded", null);
162
- }
163
-
164
- @Override
165
- public void onNativeAdFailedToLoad(int errorCode, String errorMessage) {
166
- Log.e(REACT_CLASS_NAME, "Ad failed to load: " + errorMessage);
167
- dispatchEvent(root, "onAdFailedToLoad", createErrorEvent(errorCode, errorMessage));
168
- }
169
- @Override public void onNativeAdClicked() {}
170
- @Override public void onNativeAdClosed() {}
171
- @Override public void onNativeAdShowFailed(int i, @NonNull String s) {}
172
- });
167
+ adView.setAdWhaleMediationNativeAdViewListener(
168
+ new RNAdWhaleMediationNativeAdViewListenerBridge(REACT_CLASS_NAME, (eventName, payload) -> {
169
+ dispatchEvent(root, eventName, payload);
170
+ }));
173
171
 
174
172
  AdWhaleNativeAdBinder binder = binderFactory.createBinder(currentActivity);
175
173
  adView.setPlacementUid(placementUid);
@@ -204,13 +202,6 @@ public class RNAdWhaleMediationCustomNativeAdView extends SimpleViewManager<RNWr
204
202
  return null;
205
203
  }
206
204
 
207
- private WritableMap createErrorEvent(int errorCode, String errorMessage) {
208
- WritableMap event = Arguments.createMap();
209
- event.putInt("errorCode", errorCode);
210
- event.putString("errorMessage", errorMessage);
211
- return event;
212
- }
213
-
214
205
  private void dispatchEvent(View view, String eventName, @Nullable WritableMap event) {
215
206
  ReactContext reactContext = (ReactContext) view.getContext();
216
207
  reactContext.getJSModule(RCTEventEmitter.class).receiveEvent(view.getId(), eventName, event);
@@ -0,0 +1,240 @@
1
+ package com.adwhalesdkreactnative;
2
+
3
+ import android.app.Activity;
4
+ import android.util.Log;
5
+
6
+ import androidx.annotation.NonNull;
7
+ import androidx.annotation.Nullable;
8
+ import androidx.fragment.app.FragmentActivity;
9
+ import androidx.fragment.app.FragmentManager;
10
+
11
+ import com.facebook.react.bridge.Arguments;
12
+ import com.facebook.react.bridge.ReactApplicationContext;
13
+ import com.facebook.react.bridge.ReactContextBaseJavaModule;
14
+ import com.facebook.react.bridge.ReactMethod;
15
+ import com.facebook.react.bridge.ReadableMap;
16
+ import com.facebook.react.bridge.UiThreadUtil;
17
+ import com.facebook.react.bridge.WritableMap;
18
+ import com.facebook.react.modules.core.DeviceEventManagerModule;
19
+
20
+ import net.adwhale.sdk.mediation.ads.ADWHALE_POPUP_AD_CLOSE_REASON;
21
+ import net.adwhale.sdk.mediation.ads.AdWhaleMediationExitPopupAd;
22
+ import net.adwhale.sdk.mediation.ads.AdWhaleMediationExitPopupAdListener;
23
+ import net.adwhale.sdk.utils.AdWhaleLog;
24
+
25
+ import java.util.HashMap;
26
+ import java.util.Map;
27
+
28
+ public class RNAdWhaleMediationExitPopupAd extends ReactContextBaseJavaModule implements AdWhaleMediationExitPopupAdListener {
29
+
30
+ public static final String REACT_CLASS_NAME = RNAdWhaleMediationExitPopupAd.class.getSimpleName();
31
+ private AdWhaleMediationExitPopupAd adWhaleMediationExitPopupAd;
32
+ private ReactApplicationContext reactContext;
33
+ private String placementUid;
34
+ private String placementName;
35
+ private String region;
36
+ private double lt;
37
+ private double lng;
38
+
39
+ private String primaryButtonText;
40
+
41
+ private String secondaryButtonText;
42
+
43
+ private String descriptionText;
44
+
45
+ public RNAdWhaleMediationExitPopupAd(ReactApplicationContext context) {
46
+ super(context);
47
+ reactContext = context;
48
+ }
49
+
50
+ @NonNull
51
+ @Override
52
+ public String getName() {
53
+ return REACT_CLASS_NAME;
54
+ }
55
+
56
+ @ReactMethod
57
+ public void setPlacementName(String placementName) {
58
+ Log.d(REACT_CLASS_NAME, "placementName: " + placementName);
59
+ this.placementName = placementName;
60
+ }
61
+
62
+ @ReactMethod
63
+ public void setRegion(String region) {
64
+ Log.d(REACT_CLASS_NAME, "region: " + region);
65
+ this.region = region;
66
+ }
67
+
68
+ @ReactMethod
69
+ public void setGcoder(ReadableMap gcoderMap) {
70
+ Log.d(REACT_CLASS_NAME, "gcoderMap: " + gcoderMap);
71
+
72
+ if (gcoderMap != null) {
73
+ double lt = gcoderMap.hasKey("lt") ? gcoderMap.getDouble("lt") : 0.0;
74
+ double lng = gcoderMap.hasKey("lng") ? gcoderMap.getDouble("lng") : 0.0;
75
+
76
+ this.lt = lt;
77
+ this.lng = lng;
78
+ }
79
+ }
80
+
81
+ @ReactMethod
82
+ public void setCustomizeButtonText(String primaryButtonText, String secondaryButtonText) {
83
+ Log.d(REACT_CLASS_NAME, "setCustomizeButtonText: " + primaryButtonText + ", " + secondaryButtonText);
84
+ this.primaryButtonText = primaryButtonText;
85
+ this.secondaryButtonText = secondaryButtonText;
86
+ }
87
+
88
+ @ReactMethod
89
+ public void setCustomDescription(String descriptionText) {
90
+ Log.d(REACT_CLASS_NAME, "setCustomDescription: " + descriptionText);
91
+ this.descriptionText = descriptionText;
92
+ }
93
+
94
+ @ReactMethod
95
+ public void loadAd(String placementUid) {
96
+ Log.e(REACT_CLASS_NAME, ".loadAd()");
97
+ this.placementUid = placementUid;
98
+ adWhaleMediationExitPopupAd = new AdWhaleMediationExitPopupAd(placementUid);
99
+ adWhaleMediationExitPopupAd.setAdWhaleMediationExitPopupAdListener(this);
100
+ adWhaleMediationExitPopupAd.setPlacementName(placementName);
101
+ adWhaleMediationExitPopupAd.setRegion(region);
102
+ adWhaleMediationExitPopupAd.setGcoder(lt, lng);
103
+ adWhaleMediationExitPopupAd.setCustomizeButtonText(primaryButtonText, secondaryButtonText);
104
+ adWhaleMediationExitPopupAd.setCustomDescription(descriptionText);
105
+
106
+ UiThreadUtil.runOnUiThread(() -> {
107
+ adWhaleMediationExitPopupAd.loadAd();
108
+ });
109
+ }
110
+
111
+ @ReactMethod
112
+ public void showAd() {
113
+ if (adWhaleMediationExitPopupAd == null) {
114
+ AdWhaleLog.d(REACT_CLASS_NAME +" Error showing exit popup - the exit popup ad wasn't loaded yet.");
115
+ return;
116
+ }
117
+
118
+ UiThreadUtil.runOnUiThread(() -> {
119
+ Activity activity = reactContext.getCurrentActivity();
120
+ if (activity == null) {
121
+ AdWhaleLog.d(REACT_CLASS_NAME + " Tried to show exit popup before activity was bound to the plugin.");
122
+ return;
123
+ }
124
+
125
+ try {
126
+ if (!(activity instanceof FragmentActivity)) {
127
+ AdWhaleLog.d(REACT_CLASS_NAME + " Activity must be FragmentActivity to show ExitPopupAd.");
128
+ return;
129
+ }
130
+
131
+ FragmentManager fragmentManager =
132
+ ((FragmentActivity) activity).getSupportFragmentManager();
133
+ adWhaleMediationExitPopupAd.showAd(activity, fragmentManager);
134
+ } catch (Throwable t) {
135
+ AdWhaleLog.d(REACT_CLASS_NAME +".showAd() failed. " + t.getMessage());
136
+ }
137
+ });
138
+ }
139
+
140
+ @ReactMethod
141
+ public void destroy() {
142
+ try {
143
+ if (adWhaleMediationExitPopupAd != null) {
144
+ adWhaleMediationExitPopupAd.destroy();
145
+ }
146
+ } catch (Throwable t) {
147
+ AdWhaleLog.d(REACT_CLASS_NAME +".destroy() failed. " + t.getMessage());
148
+ } finally {
149
+ adWhaleMediationExitPopupAd = null;
150
+ }
151
+ }
152
+
153
+ @ReactMethod
154
+ public void resume() {
155
+ Activity activity = reactContext.getCurrentActivity();
156
+ if (activity == null) {
157
+ AdWhaleLog.d(REACT_CLASS_NAME + " Tried to resume exit popup before activity was bound to the plugin.");
158
+ return;
159
+ }
160
+
161
+ try {
162
+ if (adWhaleMediationExitPopupAd != null) {
163
+ adWhaleMediationExitPopupAd.resume(activity);
164
+ }
165
+ } catch (Throwable t) {
166
+ AdWhaleLog.d(REACT_CLASS_NAME +".resume() failed. " + t.getMessage());
167
+ } finally {
168
+ adWhaleMediationExitPopupAd = null;
169
+ }
170
+ }
171
+
172
+ @Override
173
+ public void onAdLoaded() {
174
+ Log.i(REACT_CLASS_NAME, "onAdLoaded()");
175
+ sendEvent("onExitPopupAdLoaded", null);
176
+ }
177
+
178
+ @Override
179
+ public void onAdLoadFailed(int statusCode, String message) {
180
+ Log.i(REACT_CLASS_NAME, "onAdLoadFailed(" + statusCode + ", " + message + ")");
181
+ WritableMap params = Arguments.createMap();
182
+ params.putInt("statusCode", statusCode);
183
+ params.putString("message", message);
184
+ sendEvent("onExitPopupAdLoadFailed", params);
185
+ }
186
+
187
+ @Override
188
+ public void onAdShowed() {
189
+ Log.i(REACT_CLASS_NAME, "onAdShowed()");
190
+ sendEvent("onExitPopupAdShowed", null);
191
+ }
192
+
193
+ @Override
194
+ public void onAdClicked() {
195
+ Log.i(REACT_CLASS_NAME, "onAdClicked()");
196
+ sendEvent("onExitPopupAdClicked", null);
197
+ }
198
+
199
+ @Override
200
+ public void onAdShowFailed(int statusCode, String message) {
201
+ Log.i(REACT_CLASS_NAME, "onAdShowFailed(" + statusCode + ", " + message + ")");
202
+ WritableMap params = Arguments.createMap();
203
+ params.putInt("statusCode", statusCode);
204
+ params.putString("message", message);
205
+ sendEvent("onExitPopupAdShowFailed", params);
206
+ }
207
+
208
+ @Override
209
+ public void onAdClosed(ADWHALE_POPUP_AD_CLOSE_REASON adwhalePopupAdCloseReason) {
210
+ Log.i(REACT_CLASS_NAME, "onAdClosed()");
211
+ WritableMap params = Arguments.createMap();
212
+ params.putInt("reasonId", adwhalePopupAdCloseReason.getIdx());
213
+ params.putString("reasonMessage", adwhalePopupAdCloseReason.getCloseReasonTypeString());
214
+ sendEvent("onExitPopupAdClosed", params);
215
+ }
216
+
217
+ @Nullable
218
+ @Override
219
+ public Map<String, Object> getConstants() {
220
+ final Map<String, Object> constants = new HashMap<>();
221
+ return constants;
222
+ }
223
+
224
+ private void sendEvent(String eventName, @Nullable WritableMap params) {
225
+ getReactApplicationContext()
226
+ .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
227
+ .emit(eventName, params);
228
+ }
229
+
230
+ @ReactMethod
231
+ public void addListener(String eventName) {
232
+ // NativeEventEmitter 요구사항 (이벤트는 RCTDeviceEventEmitter로 전달)
233
+ }
234
+
235
+ @ReactMethod
236
+ public void removeListeners(Integer count) {
237
+ // NativeEventEmitter 요구사항
238
+ }
239
+
240
+ }
@@ -11,6 +11,8 @@ import com.facebook.react.bridge.ReactContextBaseJavaModule;
11
11
  import com.facebook.react.bridge.ReactMethod;
12
12
  import com.facebook.react.bridge.ReadableMap;
13
13
  import com.facebook.react.bridge.UiThreadUtil;
14
+ import com.facebook.react.bridge.ReadableType;
15
+ import com.facebook.react.bridge.ReadableArray;
14
16
  import com.facebook.react.bridge.WritableMap;
15
17
  import com.facebook.react.modules.core.DeviceEventManagerModule;
16
18
 
@@ -27,6 +29,13 @@ import java.util.Map;
27
29
  public class RNAdWhaleMediationInterstitialAd extends ReactContextBaseJavaModule implements AdWhaleMediationInterstitialAdListener {
28
30
 
29
31
  public static final String REACT_CLASS_NAME = RNAdWhaleMediationInterstitialAd.class.getSimpleName();
32
+
33
+ // Flutter와 싱크: adId 기반 멀티 인스턴스 지원 (RN에서도 여러 placement 동시 운용 가능)
34
+ private final Map<Integer, AdWhaleMediationInterstitialAd> adsById = new HashMap<>();
35
+
36
+ // 마지막으로 콜백이 발생한 광고 id (SDK Listener가 adId를 직접 주지 않아서 우회)
37
+ private int lastActiveAdId = 0;
38
+
30
39
  private AdWhaleMediationInterstitialAd adWhaleMediationInterstitialAd;
31
40
  private String placementUid;
32
41
  private String placementName;
@@ -72,6 +81,8 @@ public class RNAdWhaleMediationInterstitialAd extends ReactContextBaseJavaModule
72
81
  @ReactMethod
73
82
  public void loadAd(String placementUid) {
74
83
  Log.e(REACT_CLASS_NAME, ".loadAd()");
84
+ // 싱글턴 load 경로: onAdEvent(adId) 는 0으로 고정 (멀티 로드 후 lastActiveAdId 오염 방지)
85
+ lastActiveAdId = 0;
75
86
  this.placementUid = placementUid;
76
87
  adWhaleMediationInterstitialAd = new AdWhaleMediationInterstitialAd(placementUid);
77
88
  adWhaleMediationInterstitialAd.setAdWhaleMediationInterstitialAdListener(this);
@@ -84,6 +95,69 @@ public class RNAdWhaleMediationInterstitialAd extends ReactContextBaseJavaModule
84
95
  });
85
96
  }
86
97
 
98
+ /**
99
+ * Flutter MethodChannel과 동일 네이밍:
100
+ * loadInterstitialAd({adId, placementUid, region, gcoder:[lt,lng], placementName})
101
+ */
102
+ @ReactMethod
103
+ public void loadInterstitialAd(ReadableMap args) {
104
+ if (args == null) {
105
+ Log.e(REACT_CLASS_NAME, "loadInterstitialAd args is null");
106
+ return;
107
+ }
108
+ if (!args.hasKey("adId") || args.getType("adId") != ReadableType.Number) {
109
+ Log.e(REACT_CLASS_NAME, "loadInterstitialAd missing adId (number)");
110
+ return;
111
+ }
112
+ if (!args.hasKey("placementUid") || args.getType("placementUid") != ReadableType.String) {
113
+ Log.e(REACT_CLASS_NAME, "loadInterstitialAd missing placementUid (string)");
114
+ return;
115
+ }
116
+ final int adId = args.getInt("adId");
117
+ final String placementUid = args.getString("placementUid");
118
+
119
+ final AdWhaleMediationInterstitialAd interstitialAd = new AdWhaleMediationInterstitialAd(placementUid);
120
+ // 멀티 인스턴스: 인스턴스마다 adId를 캡처한 리스너 (공유 this + lastActiveAdId 는 경합으로 마지막 id만 남음)
121
+ interstitialAd.setAdWhaleMediationInterstitialAdListener(new PerAdInterstitialListener(adId));
122
+
123
+ try {
124
+ if (args.hasKey("region") && args.getType("region") == ReadableType.String) {
125
+ String r = args.getString("region");
126
+ if (r != null && !r.isEmpty()) interstitialAd.setRegion(r);
127
+ }
128
+ } catch (Throwable t) {
129
+ Log.w(REACT_CLASS_NAME, "setRegion failed: " + t.getMessage());
130
+ }
131
+
132
+ try {
133
+ if (args.hasKey("placementName") && args.getType("placementName") == ReadableType.String) {
134
+ String pn = args.getString("placementName");
135
+ if (pn != null && !pn.isEmpty()) interstitialAd.setPlacementName(pn);
136
+ }
137
+ } catch (Throwable t) {
138
+ Log.w(REACT_CLASS_NAME, "setPlacementName failed: " + t.getMessage());
139
+ }
140
+
141
+ try {
142
+ if (args.hasKey("gcoder") && args.getType("gcoder") == ReadableType.Array) {
143
+ ReadableArray arr = args.getArray("gcoder");
144
+ if (arr != null && arr.size() >= 2
145
+ && arr.getType(0) == ReadableType.Number
146
+ && arr.getType(1) == ReadableType.Number) {
147
+ double lat = arr.getDouble(0);
148
+ double lng = arr.getDouble(1);
149
+ interstitialAd.setGcoder(lat, lng);
150
+ }
151
+ }
152
+ } catch (Throwable t) {
153
+ Log.w(REACT_CLASS_NAME, "setGcoder failed: " + t.getMessage());
154
+ }
155
+
156
+ adsById.put(adId, interstitialAd);
157
+
158
+ UiThreadUtil.runOnUiThread(interstitialAd::loadAd);
159
+ }
160
+
87
161
  @ReactMethod
88
162
  public void showAd() {
89
163
  Log.e(REACT_CLASS_NAME, "showAd()");
@@ -92,15 +166,42 @@ public class RNAdWhaleMediationInterstitialAd extends ReactContextBaseJavaModule
92
166
  return;
93
167
  }
94
168
 
169
+ lastActiveAdId = 0;
95
170
  UiThreadUtil.runOnUiThread(() -> {
96
171
  adWhaleMediationInterstitialAd.showAd();
97
172
  });
98
173
  }
99
174
 
175
+ /** Flutter 네이밍: showAdWithoutView(adId) */
176
+ @ReactMethod
177
+ public void showAdWithoutView(int adId) {
178
+ AdWhaleMediationInterstitialAd ad = adsById.get(adId);
179
+ if (ad == null) {
180
+ Log.e(REACT_CLASS_NAME, "showAdWithoutView: ad not found. adId=" + adId);
181
+ return;
182
+ }
183
+ lastActiveAdId = adId;
184
+ UiThreadUtil.runOnUiThread(ad::showAd);
185
+ }
186
+
187
+ /** Flutter 네이밍: destroyAd(adId) */
188
+ @ReactMethod
189
+ public void destroyAd(int adId) {
190
+ AdWhaleMediationInterstitialAd ad = adsById.remove(adId);
191
+ if (ad != null) {
192
+ try {
193
+ ad.destroy();
194
+ } catch (Throwable t) {
195
+ Log.w(REACT_CLASS_NAME, "destroyAd failed: " + t.getMessage());
196
+ }
197
+ }
198
+ }
199
+
100
200
  @Override
101
201
  public void onAdLoaded() {
102
202
  Log.i(REACT_CLASS_NAME, "onAdLoaded()");
103
203
  sendEvent("onInterstitialAdLoaded", null);
204
+ sendAdEvent(lastActiveAdId, "onInterstitialAdLoaded", null);
104
205
 
105
206
  }
106
207
 
@@ -111,12 +212,14 @@ public class RNAdWhaleMediationInterstitialAd extends ReactContextBaseJavaModule
111
212
  params.putInt("statusCode", statusCode);
112
213
  params.putString("message", message);
113
214
  sendEvent("onInterstitialAdLoadFailed", params);
215
+ sendAdEvent(lastActiveAdId, "onInterstitialAdLoadFailed", params);
114
216
  }
115
217
 
116
218
  @Override
117
219
  public void onAdShowed() {
118
220
  Log.i(REACT_CLASS_NAME, "onAdShowed()");
119
221
  sendEvent("onInterstitialAdShowed", null);
222
+ sendAdEvent(lastActiveAdId, "onInterstitialAdShowed", null);
120
223
  }
121
224
 
122
225
  @Override
@@ -126,18 +229,26 @@ public class RNAdWhaleMediationInterstitialAd extends ReactContextBaseJavaModule
126
229
  params.putInt("statusCode", statusCode);
127
230
  params.putString("message", message);
128
231
  sendEvent("onInterstitialAdShowFailed", params);
232
+ sendAdEvent(lastActiveAdId, "onInterstitialAdShowFailed", params);
129
233
  }
130
234
 
131
235
  @Override
132
236
  public void onAdClosed() {
133
237
  Log.i(REACT_CLASS_NAME, "onAdClosed()");
134
238
  sendEvent("onInterstitialAdClosed", null);
239
+ sendAdEvent(lastActiveAdId, "onInterstitialAdClosed", null);
240
+
241
+ // Flutter 구현과 유사하게 닫힘 후 destroy 권장: 자동 정리(선택)
242
+ if (adsById.containsKey(lastActiveAdId)) {
243
+ destroyAd(lastActiveAdId);
244
+ }
135
245
  }
136
246
 
137
247
  @Override
138
248
  public void onAdClicked() {
139
249
  Log.i(REACT_CLASS_NAME, "onAdClicked()");
140
250
  sendEvent("onInterstitialAdClicked", null);
251
+ sendAdEvent(lastActiveAdId, "onInterstitialAdClicked", null);
141
252
  }
142
253
 
143
254
  @Nullable
@@ -153,6 +264,21 @@ public class RNAdWhaleMediationInterstitialAd extends ReactContextBaseJavaModule
153
264
  .emit(eventName, params);
154
265
  }
155
266
 
267
+ /**
268
+ * Flutter의 `onAdEvent`와 동일한 단일 이벤트 채널 형태.
269
+ * payload: { adId, eventName, ...statusCode/message... }
270
+ */
271
+ private void sendAdEvent(int adId, @NonNull String eventName, @Nullable WritableMap original) {
272
+ WritableMap payload = Arguments.createMap();
273
+ payload.putInt("adId", adId);
274
+ payload.putString("eventName", eventName);
275
+ if (original != null) {
276
+ if (original.hasKey("statusCode")) payload.putInt("statusCode", original.getInt("statusCode"));
277
+ if (original.hasKey("message")) payload.putString("message", original.getString("message"));
278
+ }
279
+ sendEvent("onAdEvent", payload);
280
+ }
281
+
156
282
  @ReactMethod
157
283
  public void addListener(String eventName) {
158
284
  //TODO NOTHING
@@ -162,4 +288,67 @@ public class RNAdWhaleMediationInterstitialAd extends ReactContextBaseJavaModule
162
288
  public void removeListeners(Integer count) {
163
289
  //TODO NOTHING
164
290
  }
291
+
292
+ /**
293
+ * adId별 전면 인스턴스 전용 리스너. 여러 개를 동시에 로드할 때 공유 리스너 + lastActiveAdId 만으로는
294
+ * 콜백이 모두 마지막 id로만 전달되는 문제가 있다.
295
+ */
296
+ private final class PerAdInterstitialListener implements AdWhaleMediationInterstitialAdListener {
297
+ private final int boundAdId;
298
+
299
+ PerAdInterstitialListener(int boundAdId) {
300
+ this.boundAdId = boundAdId;
301
+ }
302
+
303
+ @Override
304
+ public void onAdLoaded() {
305
+ Log.i(REACT_CLASS_NAME, "onAdLoaded() adId=" + boundAdId);
306
+ sendEvent("onInterstitialAdLoaded", null);
307
+ sendAdEvent(boundAdId, "onInterstitialAdLoaded", null);
308
+ }
309
+
310
+ @Override
311
+ public void onAdLoadFailed(int statusCode, String message) {
312
+ Log.i(REACT_CLASS_NAME, "onAdLoadFailed(" + statusCode + ", " + message + ") adId=" + boundAdId);
313
+ WritableMap params = Arguments.createMap();
314
+ params.putInt("statusCode", statusCode);
315
+ params.putString("message", message);
316
+ sendEvent("onInterstitialAdLoadFailed", params);
317
+ sendAdEvent(boundAdId, "onInterstitialAdLoadFailed", params);
318
+ }
319
+
320
+ @Override
321
+ public void onAdShowed() {
322
+ Log.i(REACT_CLASS_NAME, "onAdShowed() adId=" + boundAdId);
323
+ sendEvent("onInterstitialAdShowed", null);
324
+ sendAdEvent(boundAdId, "onInterstitialAdShowed", null);
325
+ }
326
+
327
+ @Override
328
+ public void onAdShowFailed(int statusCode, String message) {
329
+ Log.i(REACT_CLASS_NAME, "onAdShowFailed(" + statusCode + ", " + message + ") adId=" + boundAdId);
330
+ WritableMap params = Arguments.createMap();
331
+ params.putInt("statusCode", statusCode);
332
+ params.putString("message", message);
333
+ sendEvent("onInterstitialAdShowFailed", params);
334
+ sendAdEvent(boundAdId, "onInterstitialAdShowFailed", params);
335
+ }
336
+
337
+ @Override
338
+ public void onAdClosed() {
339
+ Log.i(REACT_CLASS_NAME, "onAdClosed() adId=" + boundAdId);
340
+ sendEvent("onInterstitialAdClosed", null);
341
+ sendAdEvent(boundAdId, "onInterstitialAdClosed", null);
342
+ if (adsById.containsKey(boundAdId)) {
343
+ destroyAd(boundAdId);
344
+ }
345
+ }
346
+
347
+ @Override
348
+ public void onAdClicked() {
349
+ Log.i(REACT_CLASS_NAME, "onAdClicked() adId=" + boundAdId);
350
+ sendEvent("onInterstitialAdClicked", null);
351
+ sendAdEvent(boundAdId, "onInterstitialAdClicked", null);
352
+ }
353
+ }
165
354
  }