react-native-daro 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (245) hide show
  1. package/LICENSE +20 -0
  2. package/README.md +47 -0
  3. package/android/build.gradle +99 -0
  4. package/android/gradle.properties +5 -0
  5. package/android/src/main/AndroidManifest.xml +3 -0
  6. package/android/src/main/AndroidManifestNew.xml +7 -0
  7. package/android/src/main/java/com/darom/DaroMAdBannerViewManager.kt +114 -0
  8. package/android/src/main/java/com/darom/DaroMAdNativeViewManager.kt +133 -0
  9. package/android/src/main/java/com/darom/DaroMModule.kt +194 -0
  10. package/android/src/main/java/com/darom/DaroMPackage.kt +21 -0
  11. package/android/src/main/java/com/darom/constants/InternalDaroMBannerSize.kt +23 -0
  12. package/android/src/main/java/com/darom/event/DaroMEvent.kt +57 -0
  13. package/android/src/main/java/com/darom/impl/DaroMBannerViewModuleImpl.kt +10 -0
  14. package/android/src/main/java/com/darom/impl/DaroMInterstitialModuleImpl.kt +113 -0
  15. package/android/src/main/java/com/darom/impl/DaroMLightPopupModuleImpl.kt +149 -0
  16. package/android/src/main/java/com/darom/impl/DaroMRewardedAdModuleImpl.kt +128 -0
  17. package/android/src/main/java/com/darom/util/AdInfoUtil.kt +51 -0
  18. package/android/src/main/java/com/darom/util/EventEmitterUtil.kt +24 -0
  19. package/android/src/main/java/com/darom/view/DaroMAdBannerViewContainer.kt +132 -0
  20. package/android/src/main/java/com/darom/view/DaroMAdNativeViewContainer.kt +372 -0
  21. package/android/src/main/res/layout/layout_activity_transparent.xml +7 -0
  22. package/android/src/main/res/values/styles.xml +11 -0
  23. package/ios/Daro+Extensions.swift +196 -0
  24. package/ios/DaroM-Bridging-Header.h +6 -0
  25. package/ios/DaroMAdBannerViewManager.m +15 -0
  26. package/ios/DaroMAdBannerViewManager.swift +87 -0
  27. package/ios/DaroMModule+AppOpen.swift +98 -0
  28. package/ios/DaroMModule+Interstitial.swift +100 -0
  29. package/ios/DaroMModule+LightPopup.swift +166 -0
  30. package/ios/DaroMModule+Rewarded.swift +118 -0
  31. package/ios/DaroMModule.mm +45 -0
  32. package/ios/DaroMModule.swift +218 -0
  33. package/ios/DaroMNativeAdViewManager.m +26 -0
  34. package/ios/DaroMNativeAdViewManager.swift +291 -0
  35. package/lib/commonjs/AdBannerView.js +115 -0
  36. package/lib/commonjs/AdBannerView.js.map +1 -0
  37. package/lib/commonjs/AppOpenAd.js +92 -0
  38. package/lib/commonjs/AppOpenAd.js.map +1 -0
  39. package/lib/commonjs/ErrorCode.js +11 -0
  40. package/lib/commonjs/ErrorCode.js.map +1 -0
  41. package/lib/commonjs/EventEmitter.js +30 -0
  42. package/lib/commonjs/EventEmitter.js.map +1 -0
  43. package/lib/commonjs/InterstitialAd.js +92 -0
  44. package/lib/commonjs/InterstitialAd.js.map +1 -0
  45. package/lib/commonjs/LightPopupAd.js +135 -0
  46. package/lib/commonjs/LightPopupAd.js.map +1 -0
  47. package/lib/commonjs/RewardedAd.js +105 -0
  48. package/lib/commonjs/RewardedAd.js.map +1 -0
  49. package/lib/commonjs/index.js +126 -0
  50. package/lib/commonjs/index.js.map +1 -0
  51. package/lib/commonjs/nativeAd/NativeAdView.js +103 -0
  52. package/lib/commonjs/nativeAd/NativeAdView.js.map +1 -0
  53. package/lib/commonjs/nativeAd/NativeAdViewComponents.js +189 -0
  54. package/lib/commonjs/nativeAd/NativeAdViewComponents.js.map +1 -0
  55. package/lib/commonjs/nativeAd/NativeAdViewProvider.js +29 -0
  56. package/lib/commonjs/nativeAd/NativeAdViewProvider.js.map +1 -0
  57. package/lib/commonjs/types/AdBannerViewProps.js +6 -0
  58. package/lib/commonjs/types/AdBannerViewProps.js.map +1 -0
  59. package/lib/commonjs/types/AdEvent.js +6 -0
  60. package/lib/commonjs/types/AdEvent.js.map +1 -0
  61. package/lib/commonjs/types/AdInfo.js +6 -0
  62. package/lib/commonjs/types/AdInfo.js.map +1 -0
  63. package/lib/commonjs/types/AdProps.js +6 -0
  64. package/lib/commonjs/types/AdProps.js.map +1 -0
  65. package/lib/commonjs/types/AppOpenAd.js +6 -0
  66. package/lib/commonjs/types/AppOpenAd.js.map +1 -0
  67. package/lib/commonjs/types/DaroMMobileAds.js +2 -0
  68. package/lib/commonjs/types/DaroMMobileAds.js.map +1 -0
  69. package/lib/commonjs/types/FullScreenAd.js +6 -0
  70. package/lib/commonjs/types/FullScreenAd.js.map +1 -0
  71. package/lib/commonjs/types/InterstitialAd.js +6 -0
  72. package/lib/commonjs/types/InterstitialAd.js.map +1 -0
  73. package/lib/commonjs/types/LightPopupAd.js +6 -0
  74. package/lib/commonjs/types/LightPopupAd.js.map +1 -0
  75. package/lib/commonjs/types/NativeAdViewProps.js +6 -0
  76. package/lib/commonjs/types/NativeAdViewProps.js.map +1 -0
  77. package/lib/commonjs/types/RewardedAd.js +6 -0
  78. package/lib/commonjs/types/RewardedAd.js.map +1 -0
  79. package/lib/commonjs/types/index.js +61 -0
  80. package/lib/commonjs/types/index.js.map +1 -0
  81. package/lib/module/AdBannerView.js +111 -0
  82. package/lib/module/AdBannerView.js.map +1 -0
  83. package/lib/module/AppOpenAd.js +88 -0
  84. package/lib/module/AppOpenAd.js.map +1 -0
  85. package/lib/module/ErrorCode.js +7 -0
  86. package/lib/module/ErrorCode.js.map +1 -0
  87. package/lib/module/EventEmitter.js +24 -0
  88. package/lib/module/EventEmitter.js.map +1 -0
  89. package/lib/module/InterstitialAd.js +88 -0
  90. package/lib/module/InterstitialAd.js.map +1 -0
  91. package/lib/module/LightPopupAd.js +130 -0
  92. package/lib/module/LightPopupAd.js.map +1 -0
  93. package/lib/module/RewardedAd.js +101 -0
  94. package/lib/module/RewardedAd.js.map +1 -0
  95. package/lib/module/index.js +30 -0
  96. package/lib/module/index.js.map +1 -0
  97. package/lib/module/nativeAd/NativeAdView.js +99 -0
  98. package/lib/module/nativeAd/NativeAdView.js.map +1 -0
  99. package/lib/module/nativeAd/NativeAdViewComponents.js +179 -0
  100. package/lib/module/nativeAd/NativeAdViewComponents.js.map +1 -0
  101. package/lib/module/nativeAd/NativeAdViewProvider.js +23 -0
  102. package/lib/module/nativeAd/NativeAdViewProvider.js.map +1 -0
  103. package/lib/module/types/AdBannerViewProps.js +4 -0
  104. package/lib/module/types/AdBannerViewProps.js.map +1 -0
  105. package/lib/module/types/AdEvent.js +4 -0
  106. package/lib/module/types/AdEvent.js.map +1 -0
  107. package/lib/module/types/AdInfo.js +4 -0
  108. package/lib/module/types/AdInfo.js.map +1 -0
  109. package/lib/module/types/AdProps.js +4 -0
  110. package/lib/module/types/AdProps.js.map +1 -0
  111. package/lib/module/types/AppOpenAd.js +4 -0
  112. package/lib/module/types/AppOpenAd.js.map +1 -0
  113. package/lib/module/types/DaroMMobileAds.js +2 -0
  114. package/lib/module/types/DaroMMobileAds.js.map +1 -0
  115. package/lib/module/types/FullScreenAd.js +4 -0
  116. package/lib/module/types/FullScreenAd.js.map +1 -0
  117. package/lib/module/types/InterstitialAd.js +4 -0
  118. package/lib/module/types/InterstitialAd.js.map +1 -0
  119. package/lib/module/types/LightPopupAd.js +4 -0
  120. package/lib/module/types/LightPopupAd.js.map +1 -0
  121. package/lib/module/types/NativeAdViewProps.js +4 -0
  122. package/lib/module/types/NativeAdViewProps.js.map +1 -0
  123. package/lib/module/types/RewardedAd.js +4 -0
  124. package/lib/module/types/RewardedAd.js.map +1 -0
  125. package/lib/module/types/index.js +8 -0
  126. package/lib/module/types/index.js.map +1 -0
  127. package/lib/typescript/commonjs/package.json +1 -0
  128. package/lib/typescript/commonjs/src/AdBannerView.d.ts +12 -0
  129. package/lib/typescript/commonjs/src/AdBannerView.d.ts.map +1 -0
  130. package/lib/typescript/commonjs/src/AppOpenAd.d.ts +4 -0
  131. package/lib/typescript/commonjs/src/AppOpenAd.d.ts.map +1 -0
  132. package/lib/typescript/commonjs/src/ErrorCode.d.ts +4 -0
  133. package/lib/typescript/commonjs/src/ErrorCode.d.ts.map +1 -0
  134. package/lib/typescript/commonjs/src/EventEmitter.d.ts +4 -0
  135. package/lib/typescript/commonjs/src/EventEmitter.d.ts.map +1 -0
  136. package/lib/typescript/commonjs/src/InterstitialAd.d.ts +4 -0
  137. package/lib/typescript/commonjs/src/InterstitialAd.d.ts.map +1 -0
  138. package/lib/typescript/commonjs/src/LightPopupAd.d.ts +4 -0
  139. package/lib/typescript/commonjs/src/LightPopupAd.d.ts.map +1 -0
  140. package/lib/typescript/commonjs/src/RewardedAd.d.ts +4 -0
  141. package/lib/typescript/commonjs/src/RewardedAd.d.ts.map +1 -0
  142. package/lib/typescript/commonjs/src/index.d.ts +11 -0
  143. package/lib/typescript/commonjs/src/index.d.ts.map +1 -0
  144. package/lib/typescript/commonjs/src/nativeAd/NativeAdView.d.ts +6 -0
  145. package/lib/typescript/commonjs/src/nativeAd/NativeAdView.d.ts.map +1 -0
  146. package/lib/typescript/commonjs/src/nativeAd/NativeAdViewComponents.d.ts +7 -0
  147. package/lib/typescript/commonjs/src/nativeAd/NativeAdViewComponents.d.ts.map +1 -0
  148. package/lib/typescript/commonjs/src/nativeAd/NativeAdViewProvider.d.ts +14 -0
  149. package/lib/typescript/commonjs/src/nativeAd/NativeAdViewProvider.d.ts.map +1 -0
  150. package/lib/typescript/commonjs/src/types/AdBannerViewProps.d.ts +14 -0
  151. package/lib/typescript/commonjs/src/types/AdBannerViewProps.d.ts.map +1 -0
  152. package/lib/typescript/commonjs/src/types/AdEvent.d.ts +7 -0
  153. package/lib/typescript/commonjs/src/types/AdEvent.d.ts.map +1 -0
  154. package/lib/typescript/commonjs/src/types/AdInfo.d.ts +19 -0
  155. package/lib/typescript/commonjs/src/types/AdInfo.d.ts.map +1 -0
  156. package/lib/typescript/commonjs/src/types/AdProps.d.ts +11 -0
  157. package/lib/typescript/commonjs/src/types/AdProps.d.ts.map +1 -0
  158. package/lib/typescript/commonjs/src/types/AppOpenAd.d.ts +3 -0
  159. package/lib/typescript/commonjs/src/types/AppOpenAd.d.ts.map +1 -0
  160. package/lib/typescript/commonjs/src/types/DaroMMobileAds.d.ts +6 -0
  161. package/lib/typescript/commonjs/src/types/DaroMMobileAds.d.ts.map +1 -0
  162. package/lib/typescript/commonjs/src/types/FullScreenAd.d.ts +21 -0
  163. package/lib/typescript/commonjs/src/types/FullScreenAd.d.ts.map +1 -0
  164. package/lib/typescript/commonjs/src/types/InterstitialAd.d.ts +3 -0
  165. package/lib/typescript/commonjs/src/types/InterstitialAd.d.ts.map +1 -0
  166. package/lib/typescript/commonjs/src/types/LightPopupAd.d.ts +18 -0
  167. package/lib/typescript/commonjs/src/types/LightPopupAd.d.ts.map +1 -0
  168. package/lib/typescript/commonjs/src/types/NativeAdViewProps.d.ts +17 -0
  169. package/lib/typescript/commonjs/src/types/NativeAdViewProps.d.ts.map +1 -0
  170. package/lib/typescript/commonjs/src/types/RewardedAd.d.ts +9 -0
  171. package/lib/typescript/commonjs/src/types/RewardedAd.d.ts.map +1 -0
  172. package/lib/typescript/commonjs/src/types/index.d.ts +6 -0
  173. package/lib/typescript/commonjs/src/types/index.d.ts.map +1 -0
  174. package/lib/typescript/module/package.json +1 -0
  175. package/lib/typescript/module/src/AdBannerView.d.ts +12 -0
  176. package/lib/typescript/module/src/AdBannerView.d.ts.map +1 -0
  177. package/lib/typescript/module/src/AppOpenAd.d.ts +4 -0
  178. package/lib/typescript/module/src/AppOpenAd.d.ts.map +1 -0
  179. package/lib/typescript/module/src/ErrorCode.d.ts +4 -0
  180. package/lib/typescript/module/src/ErrorCode.d.ts.map +1 -0
  181. package/lib/typescript/module/src/EventEmitter.d.ts +4 -0
  182. package/lib/typescript/module/src/EventEmitter.d.ts.map +1 -0
  183. package/lib/typescript/module/src/InterstitialAd.d.ts +4 -0
  184. package/lib/typescript/module/src/InterstitialAd.d.ts.map +1 -0
  185. package/lib/typescript/module/src/LightPopupAd.d.ts +4 -0
  186. package/lib/typescript/module/src/LightPopupAd.d.ts.map +1 -0
  187. package/lib/typescript/module/src/RewardedAd.d.ts +4 -0
  188. package/lib/typescript/module/src/RewardedAd.d.ts.map +1 -0
  189. package/lib/typescript/module/src/index.d.ts +11 -0
  190. package/lib/typescript/module/src/index.d.ts.map +1 -0
  191. package/lib/typescript/module/src/nativeAd/NativeAdView.d.ts +6 -0
  192. package/lib/typescript/module/src/nativeAd/NativeAdView.d.ts.map +1 -0
  193. package/lib/typescript/module/src/nativeAd/NativeAdViewComponents.d.ts +7 -0
  194. package/lib/typescript/module/src/nativeAd/NativeAdViewComponents.d.ts.map +1 -0
  195. package/lib/typescript/module/src/nativeAd/NativeAdViewProvider.d.ts +14 -0
  196. package/lib/typescript/module/src/nativeAd/NativeAdViewProvider.d.ts.map +1 -0
  197. package/lib/typescript/module/src/types/AdBannerViewProps.d.ts +14 -0
  198. package/lib/typescript/module/src/types/AdBannerViewProps.d.ts.map +1 -0
  199. package/lib/typescript/module/src/types/AdEvent.d.ts +7 -0
  200. package/lib/typescript/module/src/types/AdEvent.d.ts.map +1 -0
  201. package/lib/typescript/module/src/types/AdInfo.d.ts +19 -0
  202. package/lib/typescript/module/src/types/AdInfo.d.ts.map +1 -0
  203. package/lib/typescript/module/src/types/AdProps.d.ts +11 -0
  204. package/lib/typescript/module/src/types/AdProps.d.ts.map +1 -0
  205. package/lib/typescript/module/src/types/AppOpenAd.d.ts +3 -0
  206. package/lib/typescript/module/src/types/AppOpenAd.d.ts.map +1 -0
  207. package/lib/typescript/module/src/types/DaroMMobileAds.d.ts +6 -0
  208. package/lib/typescript/module/src/types/DaroMMobileAds.d.ts.map +1 -0
  209. package/lib/typescript/module/src/types/FullScreenAd.d.ts +21 -0
  210. package/lib/typescript/module/src/types/FullScreenAd.d.ts.map +1 -0
  211. package/lib/typescript/module/src/types/InterstitialAd.d.ts +3 -0
  212. package/lib/typescript/module/src/types/InterstitialAd.d.ts.map +1 -0
  213. package/lib/typescript/module/src/types/LightPopupAd.d.ts +18 -0
  214. package/lib/typescript/module/src/types/LightPopupAd.d.ts.map +1 -0
  215. package/lib/typescript/module/src/types/NativeAdViewProps.d.ts +17 -0
  216. package/lib/typescript/module/src/types/NativeAdViewProps.d.ts.map +1 -0
  217. package/lib/typescript/module/src/types/RewardedAd.d.ts +9 -0
  218. package/lib/typescript/module/src/types/RewardedAd.d.ts.map +1 -0
  219. package/lib/typescript/module/src/types/index.d.ts +6 -0
  220. package/lib/typescript/module/src/types/index.d.ts.map +1 -0
  221. package/package.json +185 -0
  222. package/react-native-daro-m.podspec +44 -0
  223. package/src/AdBannerView.tsx +138 -0
  224. package/src/AppOpenAd.ts +113 -0
  225. package/src/ErrorCode.ts +4 -0
  226. package/src/EventEmitter.ts +25 -0
  227. package/src/InterstitialAd.ts +113 -0
  228. package/src/LightPopupAd.ts +161 -0
  229. package/src/RewardedAd.ts +130 -0
  230. package/src/index.tsx +37 -0
  231. package/src/nativeAd/NativeAdView.tsx +124 -0
  232. package/src/nativeAd/NativeAdViewComponents.tsx +239 -0
  233. package/src/nativeAd/NativeAdViewProvider.tsx +32 -0
  234. package/src/types/AdBannerViewProps.ts +15 -0
  235. package/src/types/AdEvent.ts +9 -0
  236. package/src/types/AdInfo.ts +37 -0
  237. package/src/types/AdProps.ts +18 -0
  238. package/src/types/AppOpenAd.ts +3 -0
  239. package/src/types/DaroMMobileAds.ts +8 -0
  240. package/src/types/FullScreenAd.ts +28 -0
  241. package/src/types/InterstitialAd.ts +3 -0
  242. package/src/types/LightPopupAd.ts +19 -0
  243. package/src/types/NativeAdViewProps.ts +18 -0
  244. package/src/types/RewardedAd.ts +15 -0
  245. package/src/types/index.ts +5 -0
@@ -0,0 +1,372 @@
1
+ package com.darom.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.ImageView
11
+ import androidx.annotation.IdRes
12
+ import androidx.core.view.children
13
+ import com.darom.event.AdViewEvent
14
+ import com.darom.util.AdInfoUtil
15
+ import com.darom.util.EventEmitterUtil.sendNativeViewEvent
16
+ import com.facebook.react.bridge.ReactContext
17
+ import com.facebook.react.views.text.ReactTextView
18
+ import com.facebook.react.views.view.ReactViewGroup
19
+ import droom.daro.core.adunit.DaroNativeAdUnit
20
+ import droom.daro.core.model.DaroAdInfo
21
+ import droom.daro.core.model.DaroAdLoadError
22
+ import droom.daro.core.model.DaroNativeAdBinder
23
+ import droom.daro.core.model.DaroViewAd
24
+ import droom.daro.view.DaroAdViewListener
25
+ import droom.daro.view.DaroNativeAdView
26
+ import kotlin.math.min
27
+ import kotlin.math.roundToInt
28
+
29
+
30
+ @SuppressLint("ViewConstructor")
31
+ class DaroMAdNativeViewContainer(val context: ReactContext) : ReactViewGroup(context),
32
+ DaroAdViewListener {
33
+
34
+ private val adViewContainer: ReactViewGroup = ReactViewGroup(context)
35
+
36
+ init {
37
+ post {
38
+ setOnClickListener {
39
+ adView?.performClick()
40
+ }
41
+ }
42
+ }
43
+
44
+ private var adView: DaroNativeAdView? = null
45
+
46
+ internal var adUnitId: String = ""
47
+
48
+ internal var loadOnMount: Boolean = true
49
+
50
+ private var isFirstLoad: Boolean = true
51
+
52
+ fun loadAd() {
53
+ (adView ?: buildAdView())?.apply {
54
+
55
+ adView = this
56
+
57
+ if (this.parent == null) {
58
+ this@DaroMAdNativeViewContainer.addView(this)
59
+ }
60
+
61
+ loadAd()
62
+ }
63
+ }
64
+
65
+ internal fun applyPrevSetting() {
66
+ if(adView!= null && adView!!.parent == null) addView(adView)
67
+ }
68
+
69
+ private fun buildAdView(): DaroNativeAdView? {
70
+ if (adUnitId.isEmpty()) {
71
+ return null
72
+ }
73
+
74
+ return DaroNativeAdView(
75
+ context,
76
+ DaroNativeAdUnit(
77
+ key = adUnitId,
78
+ placement = adUnitId,
79
+ adBinder = DaroNativeAdBinder
80
+ .Builder(adViewContainer)
81
+ .let { if (titleViewId != null) it.setTitleViewId(titleViewId!!) else it }
82
+ .let { if (bodyViewId != null) it.setBodyTextViewId(bodyViewId!!) else it }
83
+ .let { if (iconViewId != null) it.setIconViewId(iconViewId!!) else it }
84
+ .let { if (mediaViewId != null) it.setMediaViewGroupId(mediaViewId!!) else it }
85
+ .let { if (callToActionViewId != null) it.setCallToActionViewId(callToActionViewId!!) else it }
86
+ .build()
87
+ )
88
+ ).also { view ->
89
+ view.setListener(this)
90
+ view.setOnHierarchyChangeListener(
91
+ object : OnHierarchyChangeListener {
92
+ override fun onChildViewAdded(parent: View?, child: View?) {
93
+ if (child != null && parent != null) {
94
+ view.layoutParams = LayoutParams(
95
+ LayoutParams.WRAP_CONTENT,
96
+ LayoutParams.WRAP_CONTENT,
97
+ )
98
+ view.layout(0, 0, parent.width, parent.height)
99
+ }
100
+ }
101
+
102
+ override fun onChildViewRemoved(parent: View?, child: View?) {}
103
+ }
104
+ )
105
+ }
106
+ }
107
+
108
+ fun destroy() {
109
+ adView?.destroy()
110
+ }
111
+
112
+ override fun onAdLoadSuccess(
113
+ ad: DaroViewAd,
114
+ adInfo: DaroAdInfo,
115
+ ) {
116
+ sendNativeViewEvent(
117
+ reactContext = context,
118
+ event = AdViewEvent.ON_AD_LOADED,
119
+ params = AdInfoUtil.getAdInfo(adUnitId, adInfo)
120
+ )
121
+
122
+ post({
123
+ context.currentActivity?.window.let { window ->
124
+ window?.decorView?.requestLayout()
125
+ }
126
+ })
127
+ }
128
+
129
+ override fun onAdLoadFail(err: DaroAdLoadError) {
130
+ sendNativeViewEvent(
131
+ reactContext = context,
132
+ event = AdViewEvent.ON_AD_FAILED_TO_LOAD,
133
+ params = AdInfoUtil.getAdLoadFailedInfo(adUnitId, err)
134
+ )
135
+ }
136
+
137
+ override fun onAdClicked(adInfo: DaroAdInfo) {
138
+ sendNativeViewEvent(
139
+ reactContext = context,
140
+ event = AdViewEvent.ON_AD_CLICKED,
141
+ params = AdInfoUtil.getAdInfo(adUnitId, adInfo)
142
+ )
143
+ }
144
+
145
+ override fun onAdImpression(adInfo: DaroAdInfo) {
146
+ sendNativeViewEvent(
147
+ reactContext = context,
148
+ event = AdViewEvent.ON_AD_IMPRESSION,
149
+ params = AdInfoUtil.getAdInfo(adUnitId, adInfo)
150
+ )
151
+ }
152
+
153
+ private val loadAdHandler = Handler(Looper.getMainLooper())
154
+ private val loadAdTask = LoadAdTask(this)
155
+
156
+ private inner class LoadAdTask(private val nativeAdView: DaroMAdNativeViewContainer) :
157
+ Runnable {
158
+
159
+ override fun run() {
160
+ nativeAdView.loadAd()
161
+ nativeAdView.isFirstLoad = false
162
+ }
163
+ }
164
+
165
+ internal fun onSetProps() {
166
+ if (loadOnMount && isFirstLoad) {
167
+ loadAdHandler.removeCallbacksAndMessages(null)
168
+ loadAdHandler.postDelayed(loadAdTask, 50)
169
+ }
170
+ }
171
+
172
+ override fun requestLayout() {
173
+ super.requestLayout()
174
+
175
+ // https://stackoverflow.com/a/39838774/5477988
176
+ // This is required to ensure ad refreshes render correctly in RN Android due to known issue
177
+ // where `getWidth()` and `getHeight()` return 0 on attach
178
+ try {
179
+ adView?.measure(
180
+ MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
181
+ MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY)
182
+ )
183
+
184
+ adView?.layout(0, 0, width, height)
185
+
186
+ adViewContainer.parent?.let {
187
+ (it as ViewGroup).children.filter { it != adViewContainer && it is ViewGroup }.lastOrNull()
188
+ ?.let {
189
+ it.measure(
190
+ MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
191
+ MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY)
192
+ )
193
+
194
+ it.layout(0, 0, width, height)
195
+
196
+ findImageView(it as ViewGroup)?.let { adChoiceImageView ->
197
+ if ((adChoiceImageView.parent as View).measuredWidth == adChoiceImageView.measuredWidth) return@let
198
+
199
+ val ratio =
200
+ adChoiceImageView.drawable.intrinsicHeight.toFloat() / (adChoiceImageView.parent as View).height
201
+
202
+ val w = ((adChoiceImageView.parent as View).width * ratio).roundToInt()
203
+ val h = ((adChoiceImageView.parent as View).height * ratio).roundToInt()
204
+
205
+ it.measure(
206
+ MeasureSpec.makeMeasureSpec(w, MeasureSpec.EXACTLY),
207
+ MeasureSpec.makeMeasureSpec(h, MeasureSpec.EXACTLY)
208
+ )
209
+
210
+ it.layout(width - w, 0, width, height)
211
+
212
+ (adChoiceImageView.parent as View).let { v ->
213
+ v.measure(
214
+ MeasureSpec.makeMeasureSpec(w, MeasureSpec.EXACTLY),
215
+ MeasureSpec.makeMeasureSpec(h, MeasureSpec.EXACTLY)
216
+ )
217
+
218
+ v.layout(0, 0, w, h)
219
+ }
220
+ }
221
+ }
222
+ }
223
+
224
+ mediaViewId?.let { adViewContainer.findViewById<View>(it) }?.let {
225
+ (it as ViewGroup).children.forEach { child ->
226
+ val width = it.width
227
+ val height = it.height
228
+
229
+ child.measure(
230
+ MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
231
+ MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY)
232
+ )
233
+
234
+ child.layout(0, 0, width, height)
235
+ }
236
+ }
237
+
238
+ titleViewId?.let { adViewContainer.findViewById<ReactTextView>(it) }
239
+ ?.restoreSpannableFromMap()
240
+ bodyViewId?.let { adViewContainer.findViewById<ReactTextView>(it) }?.restoreSpannableFromMap()
241
+ callToActionViewId?.let { adViewContainer.findViewById<ReactTextView>(it) }
242
+ ?.restoreSpannableFromMap()
243
+
244
+ } catch (_: Exception) {
245
+ // Ignore
246
+ }
247
+ }
248
+
249
+ private fun findImageView(root: ViewGroup): ImageView? {
250
+ for (i in 0 until root.childCount) {
251
+ val child = root.getChildAt(i)
252
+ if (child is ImageView) {
253
+ return child
254
+ } else if (child is ViewGroup) {
255
+ val result = findImageView(child)
256
+ if (result != null) return result
257
+ }
258
+ }
259
+ return null
260
+ }
261
+
262
+ /*
263
+ * Mapping View
264
+ * */
265
+
266
+ @IdRes
267
+ private var titleViewId: Int? = null
268
+
269
+ @IdRes
270
+ private var bodyViewId: Int? = null
271
+
272
+ @IdRes
273
+ private var callToActionViewId: Int? = null
274
+
275
+ @IdRes
276
+ private var iconViewId: Int? = null
277
+
278
+ @IdRes
279
+ private var mediaViewId: Int? = null
280
+
281
+ fun setTitleView(tag: Int) {
282
+ if (titleViewId != null) return
283
+
284
+ this.titleViewId = tag
285
+ findViewById<ReactTextView>(tag)?.let {
286
+ it.moveViewsToAdViewContainer()
287
+ it.saveSpannableToMap()
288
+ }
289
+ }
290
+
291
+ fun setBodyView(tag: Int) {
292
+ if (bodyViewId != null) return
293
+
294
+ this.bodyViewId = tag
295
+ findViewById<ReactTextView>(tag)?.let {
296
+ it.moveViewsToAdViewContainer()
297
+ it.saveSpannableToMap()
298
+ }
299
+ }
300
+
301
+ fun setCallToActionView(tag: Int) {
302
+ if (callToActionViewId != null) return
303
+
304
+ this.callToActionViewId = tag
305
+ findViewById<ReactTextView>(tag)?.let {
306
+ it.moveViewsToAdViewContainer()
307
+ it.saveSpannableToMap()
308
+ }
309
+ }
310
+
311
+ fun setIconView(tag: Int) {
312
+ if (iconViewId != null) return
313
+
314
+ this.iconViewId = tag
315
+ findViewById<View>(tag)?.moveViewsToAdViewContainer()
316
+ }
317
+
318
+ fun setMediaView(tag: Int) {
319
+ if (mediaViewId != null) return
320
+
321
+ this.mediaViewId = tag
322
+ findViewById<View>(tag)?.moveViewsToAdViewContainer()
323
+ }
324
+
325
+ /*
326
+ * Setting View
327
+ * */
328
+
329
+ private fun View.moveViewsToAdViewContainer() {
330
+ val layoutParams = layoutParams
331
+
332
+ (this.parent as? ViewGroup)?.removeView(this)
333
+ adViewContainer.addView(this, layoutParams)
334
+ }
335
+
336
+ private val testSpanMap: MutableMap<Int, Spanned> = mutableMapOf()
337
+
338
+ private fun ReactTextView.saveSpannableToMap() {
339
+ val text: CharSequence? = getText()
340
+
341
+ if (text is Spanned) {
342
+ testSpanMap[id] = text
343
+ }
344
+ }
345
+
346
+ private fun ReactTextView.restoreSpannableFromMap() {
347
+ testSpanMap[id]?.let {
348
+ val newSpannable = replaceTextPreserveSpans(it, text.toString())
349
+ text = newSpannable
350
+ }
351
+ }
352
+
353
+ fun replaceTextPreserveSpans(oldSpanned: Spanned, newText: String): SpannableString {
354
+ val newSpannable = SpannableString(newText)
355
+
356
+ val spans = oldSpanned.getSpans<Any>(0, oldSpanned.length, Any::class.java)
357
+ for (span in spans) {
358
+ val start = oldSpanned.getSpanStart(span)
359
+ val end = oldSpanned.getSpanEnd(span)
360
+ val flags = oldSpanned.getSpanFlags(span)
361
+
362
+ val newStart = start.coerceAtMost(newText.length)
363
+ val newEnd = if (end == oldSpanned.length) newText.length else min(end, newText.length)
364
+
365
+ if (newStart < newEnd) {
366
+ newSpannable.setSpan(span, newStart, newEnd, flags)
367
+ }
368
+ }
369
+
370
+ return newSpannable
371
+ }
372
+ }
@@ -0,0 +1,7 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <LinearLayout
3
+ xmlns:android="http://schemas.android.com/apk/res/android"
4
+ android:layout_width="match_parent"
5
+ android:layout_height="match_parent"
6
+ android:orientation="vertical">
7
+ </LinearLayout>
@@ -0,0 +1,11 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <resources>
3
+ <style name="Theme.TransparentActivity" parent="Theme.AppCompat.NoActionBar">
4
+ <item name="android:windowBackground">@android:color/transparent</item>
5
+ <item name="android:windowIsTranslucent">true</item>
6
+ <item name="android:windowNoTitle">true</item>
7
+ <item name="android:statusBarColor">@android:color/transparent</item> <!-- 상태 바 투명 -->
8
+ <item name="android:windowDrawsSystemBarBackgrounds">true</item>
9
+ <item name="android:fitsSystemWindows">true</item>
10
+ </style>
11
+ </resources>
@@ -0,0 +1,196 @@
1
+ import UIKit
2
+
3
+ extension UIColor {
4
+ convenience init(hex: String) {
5
+ let hex = hex.trimmingCharacters(in: CharacterSet.alphanumerics.inverted)
6
+ var int = UInt64()
7
+ Scanner(string: hex).scanHexInt64(&int)
8
+ let a, r, g, b: UInt64
9
+ switch hex.count {
10
+ case 3: // RGB (12-bit)
11
+ (a, r, g, b) = (255, (int >> 8) * 17, (int >> 4 & 0xF) * 17, (int & 0xF) * 17)
12
+ case 6: // RGB (24-bit)
13
+ (a, r, g, b) = (255, int >> 16, int >> 8 & 0xFF, int & 0xFF)
14
+ case 8: // ARGB (32-bit)
15
+ (a, r, g, b) = (int >> 24, int >> 16 & 0xFF, int >> 8 & 0xFF, int & 0xFF)
16
+ default:
17
+ (a, r, g, b) = (255, 0, 0, 0)
18
+ }
19
+ self.init(red: CGFloat(r) / 255, green: CGFloat(g) / 255, blue: CGFloat(b) / 255, alpha: CGFloat(a) / 255)
20
+ }
21
+ }
22
+
23
+ extension UILabel {
24
+ func applyStyle(_ style: NSDictionary?) {
25
+ baseApplyStyle(style)
26
+ guard let style = style as? [String: Any] else { return }
27
+
28
+ if let fontSize = style["fontSize"] as? CGFloat {
29
+ self.font = self.font.withSize(fontSize)
30
+ }
31
+
32
+ if let fontWeight = style["fontWeight"] as? String {
33
+ let weight: UIFont.Weight
34
+ switch fontWeight {
35
+ case "100": weight = .ultraLight
36
+ case "200": weight = .thin
37
+ case "300": weight = .light
38
+ case "400", "normal": weight = .regular
39
+ case "500": weight = .medium
40
+ case "600": weight = .semibold
41
+ case "700", "bold": weight = .bold
42
+ case "800": weight = .heavy
43
+ case "900": weight = .black
44
+ default: weight = .regular
45
+ }
46
+ self.font = UIFont.systemFont(ofSize: self.font.pointSize, weight: weight)
47
+ }
48
+
49
+ if let fontFamily = style["fontFamily"] as? String {
50
+ if let fontSize = style["fontSize"] as? CGFloat {
51
+ self.font = UIFont(name: fontFamily, size: fontSize)
52
+ }
53
+ }
54
+
55
+ if let colorHex = style["color"] as? String {
56
+ self.textColor = UIColor(hex: colorHex)
57
+ }
58
+
59
+ if let backgroundColorHex = style["backgroundColor"] as? String {
60
+ self.backgroundColor = UIColor(hex: backgroundColorHex)
61
+ }
62
+
63
+ if let textAlign = style["textAlign"] as? String {
64
+ switch textAlign {
65
+ case "center":
66
+ self.textAlignment = .center
67
+ case "right":
68
+ self.textAlignment = .right
69
+ case "left":
70
+ self.textAlignment = .left
71
+ case "justify":
72
+ self.textAlignment = .justified
73
+ default:
74
+ self.textAlignment = .natural
75
+ }
76
+ }
77
+
78
+ if let numberOfLines = style["numberOfLines"] as? Int {
79
+ self.numberOfLines = numberOfLines
80
+ }
81
+
82
+ if let lineBreakMode = style["lineBreakMode"] as? String {
83
+ switch lineBreakMode {
84
+ case "head":
85
+ self.lineBreakMode = .byTruncatingHead
86
+ case "middle":
87
+ self.lineBreakMode = .byTruncatingMiddle
88
+ case "tail":
89
+ self.lineBreakMode = .byTruncatingTail
90
+ case "clip":
91
+ self.lineBreakMode = .byClipping
92
+ case "word-wrap":
93
+ self.lineBreakMode = .byWordWrapping
94
+ default:
95
+ self.lineBreakMode = .byTruncatingTail
96
+ }
97
+ }
98
+ }
99
+ }
100
+
101
+ extension UIImageView {
102
+ func applyStyle(_ style: NSDictionary?) {
103
+ baseApplyStyle(style)
104
+ guard let style = style as? [String: Any] else { return }
105
+
106
+ if let resizeMode = style["resizeMode"] as? String {
107
+ switch resizeMode {
108
+ case "cover":
109
+ self.contentMode = .scaleAspectFill
110
+ case "contain":
111
+ self.contentMode = .scaleAspectFit
112
+ case "stretch":
113
+ self.contentMode = .scaleToFill
114
+ case "repeat":
115
+ self.contentMode = .scaleToFill // iOS에서는 repeat이 없어서 scaleToFill로 대체
116
+ case "center":
117
+ self.contentMode = .center
118
+ default:
119
+ self.contentMode = .scaleAspectFill
120
+ }
121
+ }
122
+ if let aspectRatio = style["aspectRatio"] as? CGFloat {
123
+ self.contentMode = .scaleAspectFit
124
+ let constraint = NSLayoutConstraint(
125
+ item: self,
126
+ attribute: .width,
127
+ relatedBy: .equal,
128
+ toItem: self,
129
+ attribute: .height,
130
+ multiplier: aspectRatio,
131
+ constant: 0
132
+ )
133
+ self.addConstraint(constraint)
134
+ }
135
+ }
136
+ }
137
+
138
+ extension UIButton {
139
+ func applyStyle(_ style: NSDictionary?) {
140
+ titleLabel?.applyStyle(style)
141
+ baseApplyStyle(style)
142
+ guard let style = style as? [String: Any] else { return }
143
+ if let colorHex = style["color"] as? String {
144
+ setTitleColor(UIColor(hex: colorHex), for: .normal)
145
+ }
146
+ }
147
+ }
148
+
149
+ extension UIView {
150
+ func baseApplyStyle(_ style: NSDictionary?) {
151
+ guard let style = style as? [String: Any] else { return }
152
+ if let tintColorHex = style["tintColor"] as? String {
153
+ self.tintColor = UIColor(hex: tintColorHex)
154
+ }
155
+
156
+ if let cornerRadius = style["borderRadius"] as? CGFloat {
157
+ self.layer.cornerRadius = cornerRadius
158
+ self.clipsToBounds = true
159
+ }
160
+
161
+ if let backgroundColorHex = style["backgroundColor"] as? String {
162
+ self.backgroundColor = UIColor(hex: backgroundColorHex)
163
+ }
164
+
165
+ if let clipsToBounds = style["clipsToBounds"] as? Bool {
166
+ self.clipsToBounds = clipsToBounds
167
+ }
168
+
169
+ if let borderWidth = style["borderWidth"] as? CGFloat {
170
+ self.layer.borderWidth = borderWidth
171
+ }
172
+
173
+ if let borderColorHex = style["borderColor"] as? String {
174
+ self.layer.borderColor = UIColor(hex: borderColorHex).cgColor
175
+ }
176
+
177
+ if let shadowColorHex = style["shadowColor"] as? String {
178
+ self.layer.shadowColor = UIColor(hex: shadowColorHex).cgColor
179
+ }
180
+
181
+ if let shadowOffset = style["shadowOffset"] as? [String: CGFloat] {
182
+ self.layer.shadowOffset = CGSize(
183
+ width: shadowOffset["width"] ?? 0,
184
+ height: shadowOffset["height"] ?? 0
185
+ )
186
+ }
187
+
188
+ if let shadowOpacity = style["shadowOpacity"] as? Float {
189
+ self.layer.shadowOpacity = shadowOpacity
190
+ }
191
+
192
+ if let shadowRadius = style["shadowRadius"] as? CGFloat {
193
+ self.layer.shadowRadius = shadowRadius
194
+ }
195
+ }
196
+ }
@@ -0,0 +1,6 @@
1
+ #import <React/RCTViewManager.h>
2
+ #import <React/RCTBridgeModule.h>
3
+ #import <React/RCTEventEmitter.h>
4
+ #import <React/RCTUIManager.h>
5
+ #import <React/RCTImageView.h>
6
+ #import <React/RCTTextView.h>
@@ -0,0 +1,15 @@
1
+ #import <React/RCTViewManager.h>
2
+
3
+ @interface RCT_EXTERN_MODULE(DaroMAdBannerViewManager, RCTViewManager)
4
+
5
+ RCT_EXPORT_VIEW_PROPERTY(adUnitId, NSString)
6
+ RCT_EXPORT_VIEW_PROPERTY(adFormat, NSString)
7
+
8
+ RCT_EXPORT_VIEW_PROPERTY(onAdLoadedEvent, RCTDirectEventBlock)
9
+ RCT_EXPORT_VIEW_PROPERTY(onAdLoadFailedEvent, RCTDirectEventBlock)
10
+ RCT_EXPORT_VIEW_PROPERTY(onAdClickedEvent, RCTDirectEventBlock)
11
+ RCT_EXPORT_VIEW_PROPERTY(onAdImpressionRecordedEvent, RCTDirectEventBlock)
12
+
13
+ RCT_EXTERN_METHOD(loadAd)
14
+
15
+ @end
@@ -0,0 +1,87 @@
1
+ import Daro
2
+
3
+ @objc(DaroMAdBannerViewManager)
4
+ class DaroMAdBannerViewManager: RCTViewManager {
5
+ override func view() -> DaroMAdBannerView {
6
+ DaroMAdBannerView()
7
+ }
8
+
9
+ @objc override static func requiresMainQueueSetup() -> Bool {
10
+ false
11
+ }
12
+ }
13
+
14
+ final class DaroMAdBannerView: UIView {
15
+
16
+ var adBannerView: DaroAdBannerView?
17
+
18
+ @objc var adUnitId: String?
19
+ @objc var adFormat: String = DaroMModule.Constants.bannerAdFormatLabel.value
20
+
21
+ // MARK: - Events
22
+ @objc var onAdLoadedEvent: RCTDirectEventBlock?
23
+ @objc var onAdLoadFailedEvent: RCTDirectEventBlock?
24
+ @objc var onAdClickedEvent: RCTDirectEventBlock?
25
+ @objc var onAdImpressionRecordedEvent: RCTDirectEventBlock?
26
+
27
+ init() {
28
+ super.init(frame: CGRect.zero)
29
+ }
30
+
31
+ required init?(coder: NSCoder) {
32
+ fatalError("init(coder:) has not been implemented")
33
+ }
34
+
35
+ /// Invoked after all the JavaScript properties are set when mounting AdView
36
+ override func didSetProps(_ changedProps: [String]!) {
37
+ initialize()
38
+ adBannerView?.loadAd()
39
+ }
40
+
41
+ @objc
42
+ func loadAd() {
43
+ adBannerView?.loadAd()
44
+ }
45
+
46
+ @objc(initialize)
47
+ func initialize() {
48
+ guard adBannerView == nil else {
49
+ DaroMModule.logger.warning("AdView is already initialized")
50
+ return
51
+ }
52
+ guard let adUnitId else {
53
+ DaroMModule.logger.warning("AdUnitId is required")
54
+ return
55
+ }
56
+
57
+ let bannerSize = adFormat == DaroMModule.Constants.bannerAdFormatLabel.value ? DaroAdBannerSize.banner : DaroAdBannerSize.MREC
58
+ let adUnit = DaroAdUnit(unitId: adUnitId)
59
+ let adBannerView = DaroAdBannerView(unit: adUnit, bannerSize: bannerSize)
60
+ setupBannerListener(for: adBannerView)
61
+
62
+ adBannerView.translatesAutoresizingMaskIntoConstraints = false
63
+ addSubview(adBannerView)
64
+ self.adBannerView = adBannerView
65
+
66
+ NSLayoutConstraint.activate([
67
+ adBannerView.widthAnchor.constraint(equalToConstant: bannerSize.width),
68
+ adBannerView.heightAnchor.constraint(equalToConstant: bannerSize.height),
69
+ adBannerView.centerXAnchor.constraint(equalTo: self.centerXAnchor),
70
+ adBannerView.centerYAnchor.constraint(equalTo: self.centerYAnchor),
71
+ ])
72
+ }
73
+
74
+ private func setupBannerListener(for bannerView: DaroAdBannerView) {
75
+ bannerView.listener.onAdLoadSuccess = { [weak self] ad, adInfo in
76
+ self?.onAdLoadedEvent?(adInfo?.toBody)
77
+ }
78
+
79
+ bannerView.listener.onAdLoadFail = { [weak self] error in
80
+ self?.onAdLoadFailedEvent?(error.toBody)
81
+ }
82
+
83
+ bannerView.listener.onAdImpression = { [weak self] adInfo in
84
+ self?.onAdImpressionRecordedEvent?(adInfo?.toBody)
85
+ }
86
+ }
87
+ }