react-native-daro 1.0.15 → 2.0.0-rc.1

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 (241) hide show
  1. package/README.md +2 -5
  2. package/android/build.gradle +17 -14
  3. package/android/src/main/java/com/daro/reactnative/DaroMediaViewManager.kt +25 -0
  4. package/android/src/main/java/com/daro/reactnative/DaroRNAdBannerViewManager.kt +105 -0
  5. package/android/src/main/java/com/daro/reactnative/DaroRNAdNativeViewManager.kt +163 -0
  6. package/android/src/main/java/com/daro/reactnative/DaroRNModule.kt +376 -0
  7. package/android/src/main/java/com/daro/reactnative/DaroRNPackage.kt +45 -0
  8. package/android/src/main/java/com/daro/reactnative/DaroSdkBridge.kt +52 -0
  9. package/android/src/main/java/com/daro/reactnative/constants/{InternalDaroMBannerSize.kt → InternalDaroRNBannerSize.kt} +2 -2
  10. package/android/src/main/java/com/daro/reactnative/event/{DaroMEvent.kt → DaroRNEvent.kt} +22 -11
  11. package/android/src/main/java/com/daro/reactnative/impl/{DaroMBannerViewModuleImpl.kt → DaroRNBannerViewModuleImpl.kt} +3 -3
  12. package/android/src/main/java/com/daro/reactnative/impl/{DaroMInterstitialModuleImpl.kt → DaroRNInterstitialModuleImpl.kt} +4 -4
  13. package/android/src/main/java/com/daro/reactnative/impl/{DaroMLightPopupModuleImpl.kt → DaroRNLightPopupModuleImpl.kt} +4 -4
  14. package/android/src/main/java/com/daro/reactnative/impl/{DaroMRewardedAdModuleImpl.kt → DaroRNRewardedAdModuleImpl.kt} +4 -4
  15. package/android/src/main/java/com/daro/reactnative/util/AdInfoUtil.kt +12 -0
  16. package/android/src/main/java/com/daro/reactnative/util/DaroQaProbe.kt +147 -0
  17. package/android/src/main/java/com/daro/reactnative/util/EventEmitterUtil.kt +20 -7
  18. package/android/src/main/java/com/daro/reactnative/view/DaroMediaView.kt +123 -0
  19. package/android/src/main/java/com/daro/reactnative/view/{DaroMAdBannerViewContainer.kt → DaroRNAdBannerViewContainer.kt} +2 -3
  20. package/android/src/main/java/com/daro/reactnative/view/DaroRNAdNativeViewContainer.kt +623 -0
  21. package/android/src/newarch/java/com/daro/reactnative/DaroRNModuleSpec.kt +6 -0
  22. package/android/src/oldarch/java/com/daro/reactnative/DaroRNModuleSpec.kt +119 -0
  23. package/ios/{DaroMModule+AppOpen.swift → DaroRNModule+AppOpen.swift} +22 -20
  24. package/ios/DaroRNModule+Consent.swift +88 -0
  25. package/ios/{DaroMModule+Interstitial.swift → DaroRNModule+Interstitial.swift} +21 -18
  26. package/ios/{DaroMModule+LightPopup.swift → DaroRNModule+LightPopup.swift} +18 -15
  27. package/ios/DaroRNModule+Qa.swift +158 -0
  28. package/ios/{DaroMModule+Rewarded.swift → DaroRNModule+Rewarded.swift} +22 -19
  29. package/ios/DaroRNModule.mm +88 -0
  30. package/ios/{DaroMModule.swift → DaroRNModule.swift} +24 -10
  31. package/ios/Fabric/DaroRNAdBannerComponentView.mm +219 -0
  32. package/ios/Fabric/DaroRNFabricEventSink.mm +31 -0
  33. package/ios/Fabric/DaroRNFabricPropApplier.mm +123 -0
  34. package/ios/Fabric/DaroRNNativeAdComponentView.mm +306 -0
  35. package/ios/{DaroMAdBannerViewManager.m → Paper/DaroRNAdBannerViewManager.m} +4 -2
  36. package/ios/Paper/DaroRNAdBannerViewManager.swift +21 -0
  37. package/ios/{DaroMNativeAdViewManager.m → Paper/DaroRNNativeAdViewManager.m} +3 -2
  38. package/ios/Paper/DaroRNNativeAdViewManager.swift +22 -0
  39. package/ios/Shared/DaroMediationDebugger.swift +14 -0
  40. package/ios/{mediation/admob → Shared}/DaroMediationTypes.swift +1 -0
  41. package/ios/Shared/DaroRNAdEventSink.swift +24 -0
  42. package/ios/Shared/DaroRNBannerAdView.swift +188 -0
  43. package/ios/Shared/DaroRNNativeAdLoadCoordinator.swift +49 -0
  44. package/ios/Shared/DaroRNNativeAdView.swift +575 -0
  45. package/ios/Shared/DaroRNNativeAssetResolver.swift +53 -0
  46. package/lib/commonjs/AdBannerView.js +20 -41
  47. package/lib/commonjs/AdBannerView.js.map +1 -1
  48. package/lib/commonjs/AppOpenAd.js +45 -12
  49. package/lib/commonjs/AppOpenAd.js.map +1 -1
  50. package/lib/commonjs/DaroMediaViewNativeComponent.ts +9 -0
  51. package/lib/commonjs/DaroRNAdBannerViewNativeComponent.ts +50 -0
  52. package/lib/commonjs/DaroRNNativeAdViewNativeComponent.ts +65 -0
  53. package/lib/commonjs/EventEmitter.js +4 -5
  54. package/lib/commonjs/EventEmitter.js.map +1 -1
  55. package/lib/commonjs/InterstitialAd.js +9 -11
  56. package/lib/commonjs/InterstitialAd.js.map +1 -1
  57. package/lib/commonjs/LightPopupAd.js +11 -12
  58. package/lib/commonjs/LightPopupAd.js.map +1 -1
  59. package/lib/commonjs/NativeDaroModule.js +9 -0
  60. package/lib/commonjs/NativeDaroModule.js.map +1 -0
  61. package/lib/commonjs/RewardedAd.js +9 -11
  62. package/lib/commonjs/RewardedAd.js.map +1 -1
  63. package/lib/commonjs/codegen-env.d.js +2 -0
  64. package/lib/commonjs/codegen-env.d.js.map +1 -0
  65. package/lib/commonjs/hooks/useInterstitialAd.js +110 -0
  66. package/lib/commonjs/hooks/useInterstitialAd.js.map +1 -0
  67. package/lib/commonjs/hooks/useLightPopupAd.js +114 -0
  68. package/lib/commonjs/hooks/useLightPopupAd.js.map +1 -0
  69. package/lib/commonjs/hooks/useRewardedAd.js +113 -0
  70. package/lib/commonjs/hooks/useRewardedAd.js.map +1 -0
  71. package/lib/commonjs/index.js +150 -13
  72. package/lib/commonjs/index.js.map +1 -1
  73. package/lib/commonjs/nativeAd/NativeAdView.js +23 -22
  74. package/lib/commonjs/nativeAd/NativeAdView.js.map +1 -1
  75. package/lib/commonjs/nativeAd/NativeAdViewComponents.js +43 -31
  76. package/lib/commonjs/nativeAd/NativeAdViewComponents.js.map +1 -1
  77. package/lib/commonjs/nativeAd/NativeAdViewProvider.js +34 -7
  78. package/lib/commonjs/nativeAd/NativeAdViewProvider.js.map +1 -1
  79. package/lib/module/AdBannerView.js +19 -42
  80. package/lib/module/AdBannerView.js.map +1 -1
  81. package/lib/module/AppOpenAd.js +45 -13
  82. package/lib/module/AppOpenAd.js.map +1 -1
  83. package/lib/module/DaroMediaViewNativeComponent.ts +9 -0
  84. package/lib/module/DaroRNAdBannerViewNativeComponent.ts +50 -0
  85. package/lib/module/DaroRNNativeAdViewNativeComponent.ts +65 -0
  86. package/lib/module/EventEmitter.js +4 -6
  87. package/lib/module/EventEmitter.js.map +1 -1
  88. package/lib/module/InterstitialAd.js +8 -11
  89. package/lib/module/InterstitialAd.js.map +1 -1
  90. package/lib/module/LightPopupAd.js +11 -13
  91. package/lib/module/LightPopupAd.js.map +1 -1
  92. package/lib/module/NativeDaroModule.js +5 -0
  93. package/lib/module/NativeDaroModule.js.map +1 -0
  94. package/lib/module/RewardedAd.js +8 -11
  95. package/lib/module/RewardedAd.js.map +1 -1
  96. package/lib/module/codegen-env.d.js +2 -0
  97. package/lib/module/codegen-env.d.js.map +1 -0
  98. package/lib/module/hooks/useInterstitialAd.js +106 -0
  99. package/lib/module/hooks/useInterstitialAd.js.map +1 -0
  100. package/lib/module/hooks/useLightPopupAd.js +110 -0
  101. package/lib/module/hooks/useLightPopupAd.js.map +1 -0
  102. package/lib/module/hooks/useRewardedAd.js +109 -0
  103. package/lib/module/hooks/useRewardedAd.js.map +1 -0
  104. package/lib/module/index.js +108 -13
  105. package/lib/module/index.js.map +1 -1
  106. package/lib/module/nativeAd/NativeAdView.js +22 -23
  107. package/lib/module/nativeAd/NativeAdView.js.map +1 -1
  108. package/lib/module/nativeAd/NativeAdViewComponents.js +45 -34
  109. package/lib/module/nativeAd/NativeAdViewComponents.js.map +1 -1
  110. package/lib/module/nativeAd/NativeAdViewProvider.js +35 -8
  111. package/lib/module/nativeAd/NativeAdViewProvider.js.map +1 -1
  112. package/lib/typescript/commonjs/plugin/src/index.d.ts +2 -6
  113. package/lib/typescript/commonjs/plugin/src/index.d.ts.map +1 -1
  114. package/lib/typescript/commonjs/plugin/src/withAndroid.d.ts +2 -6
  115. package/lib/typescript/commonjs/plugin/src/withAndroid.d.ts.map +1 -1
  116. package/lib/typescript/commonjs/plugin/src/withIos.d.ts +2 -6
  117. package/lib/typescript/commonjs/plugin/src/withIos.d.ts.map +1 -1
  118. package/lib/typescript/commonjs/src/AdBannerView.d.ts +2 -2
  119. package/lib/typescript/commonjs/src/AdBannerView.d.ts.map +1 -1
  120. package/lib/typescript/commonjs/src/AppOpenAd.d.ts +2 -2
  121. package/lib/typescript/commonjs/src/AppOpenAd.d.ts.map +1 -1
  122. package/lib/typescript/commonjs/src/DaroMediaViewNativeComponent.d.ts +6 -0
  123. package/lib/typescript/commonjs/src/DaroMediaViewNativeComponent.d.ts.map +1 -0
  124. package/lib/typescript/commonjs/src/DaroRNAdBannerViewNativeComponent.d.ts +33 -0
  125. package/lib/typescript/commonjs/src/DaroRNAdBannerViewNativeComponent.d.ts.map +1 -0
  126. package/lib/typescript/commonjs/src/DaroRNNativeAdViewNativeComponent.d.ts +43 -0
  127. package/lib/typescript/commonjs/src/DaroRNNativeAdViewNativeComponent.d.ts.map +1 -0
  128. package/lib/typescript/commonjs/src/EventEmitter.d.ts.map +1 -1
  129. package/lib/typescript/commonjs/src/InterstitialAd.d.ts.map +1 -1
  130. package/lib/typescript/commonjs/src/LightPopupAd.d.ts.map +1 -1
  131. package/lib/typescript/commonjs/src/NativeDaroModule.d.ts +70 -0
  132. package/lib/typescript/commonjs/src/NativeDaroModule.d.ts.map +1 -0
  133. package/lib/typescript/commonjs/src/RewardedAd.d.ts.map +1 -1
  134. package/lib/typescript/commonjs/src/hooks/useInterstitialAd.d.ts +19 -0
  135. package/lib/typescript/commonjs/src/hooks/useInterstitialAd.d.ts.map +1 -0
  136. package/lib/typescript/commonjs/src/hooks/useLightPopupAd.d.ts +23 -0
  137. package/lib/typescript/commonjs/src/hooks/useLightPopupAd.d.ts.map +1 -0
  138. package/lib/typescript/commonjs/src/hooks/useRewardedAd.d.ts +20 -0
  139. package/lib/typescript/commonjs/src/hooks/useRewardedAd.d.ts.map +1 -0
  140. package/lib/typescript/commonjs/src/index.d.ts +86 -1
  141. package/lib/typescript/commonjs/src/index.d.ts.map +1 -1
  142. package/lib/typescript/commonjs/src/nativeAd/NativeAdView.d.ts +1 -0
  143. package/lib/typescript/commonjs/src/nativeAd/NativeAdView.d.ts.map +1 -1
  144. package/lib/typescript/commonjs/src/nativeAd/NativeAdViewComponents.d.ts.map +1 -1
  145. package/lib/typescript/commonjs/src/nativeAd/NativeAdViewProvider.d.ts +11 -5
  146. package/lib/typescript/commonjs/src/nativeAd/NativeAdViewProvider.d.ts.map +1 -1
  147. package/lib/typescript/commonjs/src/types/AdInfo.d.ts +15 -0
  148. package/lib/typescript/commonjs/src/types/AdInfo.d.ts.map +1 -1
  149. package/lib/typescript/commonjs/src/types/AdProps.d.ts +0 -1
  150. package/lib/typescript/commonjs/src/types/AdProps.d.ts.map +1 -1
  151. package/lib/typescript/commonjs/src/types/NativeAdViewProps.d.ts +2 -0
  152. package/lib/typescript/commonjs/src/types/NativeAdViewProps.d.ts.map +1 -1
  153. package/lib/typescript/module/plugin/src/index.d.ts +2 -6
  154. package/lib/typescript/module/plugin/src/index.d.ts.map +1 -1
  155. package/lib/typescript/module/plugin/src/withAndroid.d.ts +2 -6
  156. package/lib/typescript/module/plugin/src/withAndroid.d.ts.map +1 -1
  157. package/lib/typescript/module/plugin/src/withIos.d.ts +2 -6
  158. package/lib/typescript/module/plugin/src/withIos.d.ts.map +1 -1
  159. package/lib/typescript/module/src/AdBannerView.d.ts +2 -2
  160. package/lib/typescript/module/src/AdBannerView.d.ts.map +1 -1
  161. package/lib/typescript/module/src/AppOpenAd.d.ts +2 -2
  162. package/lib/typescript/module/src/AppOpenAd.d.ts.map +1 -1
  163. package/lib/typescript/module/src/DaroMediaViewNativeComponent.d.ts +6 -0
  164. package/lib/typescript/module/src/DaroMediaViewNativeComponent.d.ts.map +1 -0
  165. package/lib/typescript/module/src/DaroRNAdBannerViewNativeComponent.d.ts +33 -0
  166. package/lib/typescript/module/src/DaroRNAdBannerViewNativeComponent.d.ts.map +1 -0
  167. package/lib/typescript/module/src/DaroRNNativeAdViewNativeComponent.d.ts +43 -0
  168. package/lib/typescript/module/src/DaroRNNativeAdViewNativeComponent.d.ts.map +1 -0
  169. package/lib/typescript/module/src/EventEmitter.d.ts.map +1 -1
  170. package/lib/typescript/module/src/InterstitialAd.d.ts.map +1 -1
  171. package/lib/typescript/module/src/LightPopupAd.d.ts.map +1 -1
  172. package/lib/typescript/module/src/NativeDaroModule.d.ts +70 -0
  173. package/lib/typescript/module/src/NativeDaroModule.d.ts.map +1 -0
  174. package/lib/typescript/module/src/RewardedAd.d.ts.map +1 -1
  175. package/lib/typescript/module/src/hooks/useInterstitialAd.d.ts +19 -0
  176. package/lib/typescript/module/src/hooks/useInterstitialAd.d.ts.map +1 -0
  177. package/lib/typescript/module/src/hooks/useLightPopupAd.d.ts +23 -0
  178. package/lib/typescript/module/src/hooks/useLightPopupAd.d.ts.map +1 -0
  179. package/lib/typescript/module/src/hooks/useRewardedAd.d.ts +20 -0
  180. package/lib/typescript/module/src/hooks/useRewardedAd.d.ts.map +1 -0
  181. package/lib/typescript/module/src/index.d.ts +86 -1
  182. package/lib/typescript/module/src/index.d.ts.map +1 -1
  183. package/lib/typescript/module/src/nativeAd/NativeAdView.d.ts +1 -0
  184. package/lib/typescript/module/src/nativeAd/NativeAdView.d.ts.map +1 -1
  185. package/lib/typescript/module/src/nativeAd/NativeAdViewComponents.d.ts.map +1 -1
  186. package/lib/typescript/module/src/nativeAd/NativeAdViewProvider.d.ts +11 -5
  187. package/lib/typescript/module/src/nativeAd/NativeAdViewProvider.d.ts.map +1 -1
  188. package/lib/typescript/module/src/types/AdInfo.d.ts +15 -0
  189. package/lib/typescript/module/src/types/AdInfo.d.ts.map +1 -1
  190. package/lib/typescript/module/src/types/AdProps.d.ts +0 -1
  191. package/lib/typescript/module/src/types/AdProps.d.ts.map +1 -1
  192. package/lib/typescript/module/src/types/NativeAdViewProps.d.ts +2 -0
  193. package/lib/typescript/module/src/types/NativeAdViewProps.d.ts.map +1 -1
  194. package/package.json +12 -5
  195. package/plugin/build/index.d.ts +2 -6
  196. package/plugin/build/index.js +21 -56
  197. package/plugin/build/withAndroid.d.ts +2 -6
  198. package/plugin/build/withAndroid.js +123 -83
  199. package/plugin/build/withIos.d.ts +2 -6
  200. package/plugin/build/withIos.js +37 -34
  201. package/react-native-daro.podspec +4 -2
  202. package/src/AdBannerView.tsx +24 -63
  203. package/src/AppOpenAd.ts +48 -17
  204. package/src/DaroMediaViewNativeComponent.ts +9 -0
  205. package/src/DaroRNAdBannerViewNativeComponent.ts +50 -0
  206. package/src/DaroRNNativeAdViewNativeComponent.ts +65 -0
  207. package/src/EventEmitter.ts +4 -5
  208. package/src/InterstitialAd.ts +8 -10
  209. package/src/LightPopupAd.ts +11 -12
  210. package/src/NativeDaroModule.ts +106 -0
  211. package/src/RewardedAd.ts +8 -10
  212. package/src/codegen-env.d.ts +45 -0
  213. package/src/hooks/useInterstitialAd.ts +117 -0
  214. package/src/hooks/useLightPopupAd.ts +132 -0
  215. package/src/hooks/useRewardedAd.ts +122 -0
  216. package/src/index.tsx +157 -22
  217. package/src/nativeAd/NativeAdView.tsx +41 -54
  218. package/src/nativeAd/NativeAdViewComponents.tsx +80 -42
  219. package/src/nativeAd/NativeAdViewProvider.tsx +75 -17
  220. package/src/types/AdInfo.ts +17 -0
  221. package/src/types/AdProps.ts +0 -2
  222. package/src/types/NativeAdViewProps.ts +7 -0
  223. package/android/src/admob/java/com/daro/reactnative/DaroSdkBridge.kt +0 -23
  224. package/android/src/main/java/com/daro/reactnative/DaroMAdBannerViewManager.kt +0 -132
  225. package/android/src/main/java/com/daro/reactnative/DaroMAdNativeViewManager.kt +0 -136
  226. package/android/src/main/java/com/daro/reactnative/DaroMModule.kt +0 -202
  227. package/android/src/main/java/com/daro/reactnative/DaroMPackage.kt +0 -21
  228. package/android/src/main/java/com/daro/reactnative/view/DaroMAdNativeViewContainer.kt +0 -375
  229. package/ios/DaroMAdBannerViewManager.swift +0 -91
  230. package/ios/DaroMModule.mm +0 -45
  231. package/ios/DaroMNativeAdViewManager.swift +0 -291
  232. package/ios/mediation/admob/DaroMediationDebugger.swift +0 -11
  233. package/lib/commonjs/types/DaroMMobileAds.js +0 -2
  234. package/lib/commonjs/types/DaroMMobileAds.js.map +0 -1
  235. package/lib/module/types/DaroMMobileAds.js +0 -2
  236. package/lib/module/types/DaroMMobileAds.js.map +0 -1
  237. package/lib/typescript/commonjs/src/types/DaroMMobileAds.d.ts +0 -6
  238. package/lib/typescript/commonjs/src/types/DaroMMobileAds.d.ts.map +0 -1
  239. package/lib/typescript/module/src/types/DaroMMobileAds.d.ts +0 -6
  240. package/lib/typescript/module/src/types/DaroMMobileAds.d.ts.map +0 -1
  241. package/src/types/DaroMMobileAds.ts +0 -5
@@ -0,0 +1,623 @@
1
+ package com.daro.reactnative.view
2
+
3
+ import android.annotation.SuppressLint
4
+ import android.os.Handler
5
+ import android.os.Looper
6
+ import android.text.SpannableString
7
+ import android.text.Spanned
8
+ import android.view.View
9
+ import android.view.ViewGroup
10
+ import android.widget.FrameLayout
11
+ import android.widget.ImageView
12
+ import android.widget.TextView
13
+ import androidx.annotation.IdRes
14
+ import androidx.core.view.children
15
+ import com.daro.reactnative.event.AdViewEvent
16
+ import com.daro.reactnative.util.AdInfoUtil
17
+ import com.daro.reactnative.util.EventEmitterUtil.sendNativeViewEvent
18
+ import com.facebook.react.bridge.ReactContext
19
+ import com.facebook.react.views.text.ReactTextView
20
+ import com.facebook.react.views.view.ReactViewGroup
21
+ import droom.daro.core.adunit.DaroNativeAdUnit
22
+ import droom.daro.core.model.DaroAdInfo
23
+ import droom.daro.core.model.DaroAdLoadError
24
+ import droom.daro.core.model.DaroNativeAdBinder
25
+ import droom.daro.core.model.DaroNativeAdChoicePlacement
26
+ import droom.daro.core.model.DaroViewAd
27
+ import droom.daro.view.DaroAdViewListener
28
+ import droom.daro.view.DaroNativeAdView
29
+ import kotlin.math.min
30
+ import kotlin.math.roundToInt
31
+
32
+
33
+ @SuppressLint("ViewConstructor")
34
+ class DaroRNAdNativeViewContainer(val context: ReactContext) : ReactViewGroup(context),
35
+ DaroAdViewListener {
36
+
37
+ private companion object {
38
+ private const val MAX_LOAD_ASSET_VIEW_RETRY_COUNT = 40
39
+ private const val LOAD_ASSET_VIEW_RETRY_DELAY_MS = 50L
40
+ }
41
+
42
+ private val adViewContainer: ReactViewGroup = ReactViewGroup(context)
43
+
44
+ init {
45
+ post {
46
+ setOnClickListener {
47
+ adView?.performClick()
48
+ }
49
+ }
50
+ }
51
+
52
+ private var adView: DaroNativeAdView? = null
53
+
54
+ internal var adUnitId: String = ""
55
+
56
+ internal var loadOnMount: Boolean = true
57
+ private var adChoicesPosition: DaroNativeAdChoicePlacement =
58
+ DaroNativeAdChoicePlacement.BOTTOM_RIGHT
59
+
60
+ private var isFirstLoad: Boolean = true
61
+ private var isDestroyed: Boolean = false
62
+ private var pendingLoadAssetViewRetryCount: Int = 0
63
+
64
+ fun addReactSubview(child: View, index: Int) {
65
+ if (isDestroyed) return
66
+
67
+ if (index < 0 || index >= adViewContainer.childCount) {
68
+ adViewContainer.addView(child)
69
+ } else {
70
+ adViewContainer.addView(child, index)
71
+ }
72
+
73
+ scheduleInitialLoadIfNeeded()
74
+ }
75
+
76
+ fun getReactSubviewCount(): Int {
77
+ if (isDestroyed) return 0
78
+
79
+ return adViewContainer.childCount
80
+ }
81
+
82
+ fun getReactSubviewAt(index: Int): View {
83
+ return adViewContainer.getChildAt(index)
84
+ }
85
+
86
+ fun removeReactSubviewAt(index: Int) {
87
+ if (isDestroyed || index < 0 || index >= adViewContainer.childCount) return
88
+
89
+ adViewContainer.removeViewAt(index)
90
+ }
91
+
92
+ fun removeAllReactSubviews() {
93
+ if (isDestroyed) return
94
+
95
+ adViewContainer.removeAllViews()
96
+ }
97
+
98
+ fun loadAd(): Boolean {
99
+ if (isDestroyed) return false
100
+
101
+ if (!hasRegisteredAssetView()) {
102
+ scheduleLoadWhenAssetViewsMounted()
103
+ return false
104
+ }
105
+
106
+ if (!areRegisteredAssetViewsMounted()) {
107
+ scheduleLoadWhenAssetViewsMounted()
108
+ return false
109
+ }
110
+
111
+ pendingLoadAssetViewRetryCount = 0
112
+ captureRegisteredTextSpans()
113
+
114
+ return (adView ?: buildAdView())?.let { view ->
115
+
116
+ adView = view
117
+
118
+ if (view.parent == null) {
119
+ this@DaroRNAdNativeViewContainer.addView(view)
120
+ }
121
+
122
+ view.loadAd()
123
+ isFirstLoad = false
124
+ true
125
+ } ?: false
126
+ }
127
+
128
+ private fun buildAdView(): DaroNativeAdView? {
129
+ if (adUnitId.isEmpty()) {
130
+ return null
131
+ }
132
+
133
+ return DaroNativeAdView(
134
+ context,
135
+ DaroNativeAdUnit(
136
+ key = adUnitId,
137
+ )
138
+ ).also { view ->
139
+ view.setAdBinder(
140
+ DaroNativeAdBinder
141
+ .Builder(adViewContainer)
142
+ .let { if (titleViewId != null) it.setTitleViewId(titleViewId!!) else it }
143
+ .let { if (bodyViewId != null) it.setBodyTextViewId(bodyViewId!!) else it }
144
+ .let { if (iconViewId != null) it.setIconViewId(iconViewId!!) else it }
145
+ .let { builder ->
146
+ // 등록 누락 시 더미 뷰에 바인딩되지 않도록 DaroMediaView를 직접 찾아 폴백한다.
147
+ val mediaId = mediaViewId ?: findDaroMediaViewId()
148
+ if (mediaId != null) builder.setMediaViewGroupId(mediaId) else builder
149
+ }
150
+ .let { if (callToActionViewId != null) it.setCallToActionViewId(callToActionViewId!!) else it }
151
+ .setAdChoicePlacement(adChoicesPosition)
152
+ .build()
153
+ )
154
+
155
+ view.setListener(this)
156
+ view.setOnHierarchyChangeListener(
157
+ object : OnHierarchyChangeListener {
158
+ override fun onChildViewAdded(parent: View?, child: View?) {
159
+ if (child != null && parent != null) {
160
+ view.layoutParams = LayoutParams(
161
+ LayoutParams.WRAP_CONTENT,
162
+ LayoutParams.WRAP_CONTENT,
163
+ )
164
+ view.layout(0, 0, parent.width, parent.height)
165
+ }
166
+ }
167
+
168
+ override fun onChildViewRemoved(parent: View?, child: View?) {}
169
+ }
170
+ )
171
+ }
172
+ }
173
+
174
+ fun destroy() {
175
+ isDestroyed = true
176
+ loadAdHandler.removeCallbacksAndMessages(null)
177
+ setOnClickListener(null)
178
+
179
+ adView?.let { view ->
180
+ (view.parent as? ViewGroup)?.removeView(view)
181
+ view.destroy()
182
+ installFallbackAssetViews()
183
+ }
184
+ adView = null
185
+ pendingLoadAssetViewRetryCount = 0
186
+ removeAllViews()
187
+ testSpanMap.clear()
188
+ }
189
+
190
+ override fun onAttachedToWindow() {
191
+ super.onAttachedToWindow()
192
+ if (!isDestroyed) {
193
+ adView?.resume()
194
+ }
195
+ }
196
+
197
+ override fun onAdLoadSuccess(
198
+ ad: DaroViewAd,
199
+ adInfo: DaroAdInfo,
200
+ ) {
201
+ if (isDestroyed) return
202
+
203
+ sendNativeViewEvent(
204
+ reactContext = context,
205
+ event = AdViewEvent.ON_AD_LOADED,
206
+ params = AdInfoUtil.getAdInfo(adUnitId, adInfo)
207
+ )
208
+
209
+ post({
210
+ layoutMediaViewChildrenFallback()
211
+ context.currentActivity?.window.let { window ->
212
+ window?.decorView?.requestLayout()
213
+ }
214
+ })
215
+ }
216
+
217
+ override fun onAdLoadFail(err: DaroAdLoadError) {
218
+ if (isDestroyed) return
219
+
220
+ sendNativeViewEvent(
221
+ reactContext = context,
222
+ event = AdViewEvent.ON_AD_FAILED_TO_LOAD,
223
+ params = AdInfoUtil.getAdLoadFailedInfo(adUnitId, err)
224
+ )
225
+ }
226
+
227
+ override fun onAdClicked(adInfo: DaroAdInfo) {
228
+ if (isDestroyed) return
229
+
230
+ sendNativeViewEvent(
231
+ reactContext = context,
232
+ event = AdViewEvent.ON_AD_CLICKED,
233
+ params = AdInfoUtil.getAdInfo(adUnitId, adInfo)
234
+ )
235
+ }
236
+
237
+ override fun onAdImpression(adInfo: DaroAdInfo) {
238
+ if (isDestroyed) return
239
+
240
+ sendNativeViewEvent(
241
+ reactContext = context,
242
+ event = AdViewEvent.ON_AD_IMPRESSION,
243
+ params = AdInfoUtil.getAdInfo(adUnitId, adInfo)
244
+ )
245
+ }
246
+
247
+ private val loadAdHandler = Handler(Looper.getMainLooper())
248
+ private val loadAdTask = LoadAdTask(this)
249
+ private val retryLoadAdTask = Runnable {
250
+ if (!isDestroyed) {
251
+ loadAd()
252
+ }
253
+ }
254
+
255
+ private inner class LoadAdTask(private val nativeAdView: DaroRNAdNativeViewContainer) :
256
+ Runnable {
257
+
258
+ override fun run() {
259
+ nativeAdView.loadAd()
260
+ }
261
+ }
262
+
263
+ internal fun onSetProps() {
264
+ if (isDestroyed) return
265
+
266
+ scheduleInitialLoadIfNeeded()
267
+ }
268
+
269
+ private fun scheduleInitialLoadIfNeeded() {
270
+ loadAdHandler.removeCallbacks(loadAdTask)
271
+
272
+ if (loadOnMount && isFirstLoad && adUnitId.isNotEmpty() && hasRegisteredAssetView()) {
273
+ loadAdHandler.postDelayed(loadAdTask, 50)
274
+ }
275
+ }
276
+
277
+ override fun requestLayout() {
278
+ super.requestLayout()
279
+
280
+ // https://stackoverflow.com/a/39838774/5477988
281
+ // This is required to ensure ad refreshes render correctly in RN Android due to known issue
282
+ // where `getWidth()` and `getHeight()` return 0 on attach
283
+ try {
284
+ adView?.measure(
285
+ MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
286
+ MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY)
287
+ )
288
+
289
+ adView?.layout(0, 0, width, height)
290
+ } catch (_: Exception) {
291
+ // Ignore
292
+ }
293
+
294
+ try {
295
+ adViewContainer.parent?.let {
296
+ (it as ViewGroup).children.filter { it != adViewContainer && it is ViewGroup }.lastOrNull()
297
+ ?.let {
298
+ it.measure(
299
+ MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
300
+ MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY)
301
+ )
302
+
303
+ it.layout(0, 0, width, height)
304
+
305
+ findImageView(it as ViewGroup)?.let { adChoiceImageView ->
306
+ if ((adChoiceImageView.parent as View).measuredWidth == adChoiceImageView.measuredWidth) return@let
307
+
308
+ val adChoiceDrawable = adChoiceImageView.drawable ?: return@let
309
+
310
+ val ratio =
311
+ adChoiceDrawable.intrinsicHeight.toFloat() / (adChoiceImageView.parent as View).height
312
+
313
+ val w = ((adChoiceImageView.parent as View).width * ratio).roundToInt()
314
+ val h = ((adChoiceImageView.parent as View).height * ratio).roundToInt()
315
+
316
+ it.measure(
317
+ MeasureSpec.makeMeasureSpec(w, MeasureSpec.EXACTLY),
318
+ MeasureSpec.makeMeasureSpec(h, MeasureSpec.EXACTLY)
319
+ )
320
+
321
+ it.layout(width - w, 0, width, height)
322
+
323
+ (adChoiceImageView.parent as View).let { v ->
324
+ v.measure(
325
+ MeasureSpec.makeMeasureSpec(w, MeasureSpec.EXACTLY),
326
+ MeasureSpec.makeMeasureSpec(h, MeasureSpec.EXACTLY)
327
+ )
328
+
329
+ v.layout(0, 0, w, h)
330
+ }
331
+ }
332
+ }
333
+ }
334
+ } catch (_: Exception) {
335
+ // Ignore
336
+ }
337
+
338
+ try {
339
+ layoutMediaViewChildrenFallback()
340
+ } catch (_: Exception) {
341
+ // Ignore
342
+ }
343
+
344
+ try {
345
+ restoreRegisteredTextSpans()
346
+ } catch (_: Exception) {
347
+ // Ignore
348
+ }
349
+ }
350
+
351
+ private fun findImageView(root: ViewGroup): ImageView? {
352
+ for (i in 0 until root.childCount) {
353
+ val child = root.getChildAt(i)
354
+ if (child is ImageView) {
355
+ return child
356
+ } else if (child is ViewGroup) {
357
+ val result = findImageView(child)
358
+ if (result != null) return result
359
+ }
360
+ }
361
+ return null
362
+ }
363
+
364
+ // 미디어 그룹이 DaroMediaView가 아닌 경우(구버전 JS 조합)용 직계 자식 폴백.
365
+ private fun layoutMediaViewChildrenFallback() {
366
+ val mediaViewGroup = getMediaViewGroup() ?: return
367
+ if (mediaViewGroup is DaroMediaView) return
368
+
369
+ val width = mediaViewGroup.width
370
+ val height = mediaViewGroup.height
371
+
372
+ if (width <= 0 || height <= 0) return
373
+
374
+ mediaViewGroup.children.forEach { child ->
375
+ child.measure(
376
+ MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
377
+ MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY)
378
+ )
379
+
380
+ child.layout(0, 0, width, height)
381
+ }
382
+ }
383
+
384
+ private fun findDaroMediaViewId(): Int? {
385
+ return findDaroMediaView(adViewContainer)?.id?.takeIf { it != View.NO_ID }
386
+ }
387
+
388
+ private fun findDaroMediaView(root: ViewGroup): DaroMediaView? {
389
+ root.children.forEach { child ->
390
+ if (child is DaroMediaView) return child
391
+ if (child is ViewGroup) findDaroMediaView(child)?.let { return it }
392
+ }
393
+ return null
394
+ }
395
+
396
+ private fun getMediaViewGroup(): ViewGroup? {
397
+ return mediaViewId?.let { findRegisteredAssetView(it) as? ViewGroup }
398
+ }
399
+
400
+ private fun hasRegisteredAssetView(): Boolean {
401
+ return titleViewId != null ||
402
+ bodyViewId != null ||
403
+ callToActionViewId != null ||
404
+ iconViewId != null ||
405
+ mediaViewId != null
406
+ }
407
+
408
+ private fun areRegisteredAssetViewsMounted(): Boolean {
409
+ if (!hasRegisteredAssetView()) return false
410
+
411
+ titleViewId?.let {
412
+ if (findRegisteredAssetView(it) !is TextView) return false
413
+ }
414
+
415
+ bodyViewId?.let {
416
+ if (findRegisteredAssetView(it) !is TextView) return false
417
+ }
418
+
419
+ callToActionViewId?.let {
420
+ if (findRegisteredAssetView(it) !is TextView) return false
421
+ }
422
+
423
+ iconViewId?.let {
424
+ if (findRegisteredAssetView(it) !is ImageView) return false
425
+ }
426
+
427
+ mediaViewId?.let {
428
+ if (findRegisteredAssetView(it) !is ViewGroup) return false
429
+ }
430
+
431
+ return true
432
+ }
433
+
434
+ private fun findRegisteredAssetView(@IdRes id: Int): View? {
435
+ return adViewContainer.findViewById(id)
436
+ }
437
+
438
+ private fun scheduleLoadWhenAssetViewsMounted() {
439
+ if (pendingLoadAssetViewRetryCount >= MAX_LOAD_ASSET_VIEW_RETRY_COUNT) {
440
+ pendingLoadAssetViewRetryCount = 0
441
+ return
442
+ }
443
+
444
+ pendingLoadAssetViewRetryCount += 1
445
+ loadAdHandler.removeCallbacks(retryLoadAdTask)
446
+ loadAdHandler.postDelayed(retryLoadAdTask, LOAD_ASSET_VIEW_RETRY_DELAY_MS)
447
+ }
448
+
449
+ private fun cancelPendingLoadIfNoRegisteredAssetView() {
450
+ if (hasRegisteredAssetView()) return
451
+
452
+ pendingLoadAssetViewRetryCount = 0
453
+ loadAdHandler.removeCallbacks(loadAdTask)
454
+ loadAdHandler.removeCallbacks(retryLoadAdTask)
455
+ }
456
+
457
+ /*
458
+ * Mapping View
459
+ * */
460
+
461
+ @IdRes
462
+ private var titleViewId: Int? = null
463
+
464
+ @IdRes
465
+ private var bodyViewId: Int? = null
466
+
467
+ @IdRes
468
+ private var callToActionViewId: Int? = null
469
+
470
+ @IdRes
471
+ private var iconViewId: Int? = null
472
+
473
+ @IdRes
474
+ private var mediaViewId: Int? = null
475
+
476
+ fun setTitleView(tag: Int) {
477
+ if (tag == View.NO_ID || tag == 0) {
478
+ titleViewId = null
479
+ cancelPendingLoadIfNoRegisteredAssetView()
480
+ return
481
+ }
482
+
483
+ if (titleViewId == tag) return
484
+
485
+ this.titleViewId = tag
486
+ adViewContainer.findViewById<ReactTextView>(tag)?.let {
487
+ it.saveSpannableToMap()
488
+ }
489
+ scheduleInitialLoadIfNeeded()
490
+ }
491
+
492
+ fun setBodyView(tag: Int) {
493
+ if (tag == View.NO_ID || tag == 0) {
494
+ bodyViewId = null
495
+ cancelPendingLoadIfNoRegisteredAssetView()
496
+ return
497
+ }
498
+
499
+ if (bodyViewId == tag) return
500
+
501
+ this.bodyViewId = tag
502
+ adViewContainer.findViewById<ReactTextView>(tag)?.let {
503
+ it.saveSpannableToMap()
504
+ }
505
+ scheduleInitialLoadIfNeeded()
506
+ }
507
+
508
+ fun setCallToActionView(tag: Int) {
509
+ if (tag == View.NO_ID || tag == 0) {
510
+ callToActionViewId = null
511
+ cancelPendingLoadIfNoRegisteredAssetView()
512
+ return
513
+ }
514
+
515
+ if (callToActionViewId == tag) return
516
+
517
+ this.callToActionViewId = tag
518
+ adViewContainer.findViewById<ReactTextView>(tag)?.let {
519
+ it.saveSpannableToMap()
520
+ }
521
+ scheduleInitialLoadIfNeeded()
522
+ }
523
+
524
+ fun setIconView(tag: Int) {
525
+ if (tag == View.NO_ID || tag == 0) {
526
+ iconViewId = null
527
+ cancelPendingLoadIfNoRegisteredAssetView()
528
+ return
529
+ }
530
+
531
+ if (iconViewId == tag) return
532
+
533
+ this.iconViewId = tag
534
+ scheduleInitialLoadIfNeeded()
535
+ }
536
+
537
+ fun setMediaView(tag: Int) {
538
+ if (tag == View.NO_ID || tag == 0) {
539
+ mediaViewId = null
540
+ cancelPendingLoadIfNoRegisteredAssetView()
541
+ return
542
+ }
543
+
544
+ if (mediaViewId == tag) return
545
+
546
+ this.mediaViewId = tag
547
+ scheduleInitialLoadIfNeeded()
548
+ }
549
+
550
+ fun setAdChoicesPosition(value: String?) {
551
+ adChoicesPosition = when (value) {
552
+ "topLeft" -> DaroNativeAdChoicePlacement.TOP_LEFT
553
+ "topRight" -> DaroNativeAdChoicePlacement.TOP_RIGHT
554
+ "bottomLeft" -> DaroNativeAdChoicePlacement.BOTTOM_LEFT
555
+ else -> DaroNativeAdChoicePlacement.BOTTOM_RIGHT
556
+ }
557
+ }
558
+
559
+ /*
560
+ * Setting View
561
+ * */
562
+
563
+ private fun installFallbackAssetViews() {
564
+ adViewContainer.removeAllViews()
565
+
566
+ titleViewId?.let { adViewContainer.addView(TextView(context).apply { id = it }) }
567
+ bodyViewId?.let { adViewContainer.addView(TextView(context).apply { id = it }) }
568
+ callToActionViewId?.let { adViewContainer.addView(TextView(context).apply { id = it }) }
569
+ iconViewId?.let { adViewContainer.addView(ImageView(context).apply { id = it }) }
570
+ mediaViewId?.let { adViewContainer.addView(FrameLayout(context).apply { id = it }) }
571
+ }
572
+
573
+ private val testSpanMap: MutableMap<Int, Spanned> = mutableMapOf()
574
+
575
+ private fun captureRegisteredTextSpans() {
576
+ titleViewId?.let { adViewContainer.findViewById<ReactTextView>(it) }?.saveSpannableToMap()
577
+ bodyViewId?.let { adViewContainer.findViewById<ReactTextView>(it) }?.saveSpannableToMap()
578
+ callToActionViewId?.let { adViewContainer.findViewById<ReactTextView>(it) }
579
+ ?.saveSpannableToMap()
580
+ }
581
+
582
+ private fun restoreRegisteredTextSpans() {
583
+ titleViewId?.let { adViewContainer.findViewById<ReactTextView>(it) }?.restoreSpannableFromMap()
584
+ bodyViewId?.let { adViewContainer.findViewById<ReactTextView>(it) }?.restoreSpannableFromMap()
585
+ callToActionViewId?.let { adViewContainer.findViewById<ReactTextView>(it) }
586
+ ?.restoreSpannableFromMap()
587
+ }
588
+
589
+ private fun ReactTextView.saveSpannableToMap() {
590
+ val text: CharSequence? = getText()
591
+
592
+ if (text is Spanned) {
593
+ testSpanMap[id] = text
594
+ }
595
+ }
596
+
597
+ private fun ReactTextView.restoreSpannableFromMap() {
598
+ testSpanMap[id]?.let {
599
+ val newSpannable = replaceTextPreserveSpans(it, text.toString())
600
+ text = newSpannable
601
+ }
602
+ }
603
+
604
+ fun replaceTextPreserveSpans(oldSpanned: Spanned, newText: String): SpannableString {
605
+ val newSpannable = SpannableString(newText)
606
+
607
+ val spans = oldSpanned.getSpans<Any>(0, oldSpanned.length, Any::class.java)
608
+ for (span in spans) {
609
+ val start = oldSpanned.getSpanStart(span)
610
+ val end = oldSpanned.getSpanEnd(span)
611
+ val flags = oldSpanned.getSpanFlags(span)
612
+
613
+ val newStart = start.coerceAtMost(newText.length)
614
+ val newEnd = if (end == oldSpanned.length) newText.length else min(end, newText.length)
615
+
616
+ if (newStart < newEnd) {
617
+ newSpannable.setSpan(span, newStart, newEnd, flags)
618
+ }
619
+ }
620
+
621
+ return newSpannable
622
+ }
623
+ }
@@ -0,0 +1,6 @@
1
+ package com.daro.reactnative
2
+
3
+ import com.facebook.react.bridge.ReactApplicationContext
4
+
5
+ abstract class DaroRNModuleSpec(reactContext: ReactApplicationContext) :
6
+ NativeDaroModuleSpec(reactContext)