react-native-firework-sdk 1.0.0-beta

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 (190) hide show
  1. package/README.md +39 -0
  2. package/android/build.gradle +193 -0
  3. package/android/gradle/wrapper/gradle-wrapper.jar +0 -0
  4. package/android/gradle/wrapper/gradle-wrapper.properties +5 -0
  5. package/android/gradle.properties +5 -0
  6. package/android/gradlew +185 -0
  7. package/android/gradlew.bat +89 -0
  8. package/android/publish.gradle +65 -0
  9. package/android/src/main/AndroidManifest.xml +16 -0
  10. package/android/src/main/java/com/reactnativefireworksdk/FireworkSDKPackage.kt +20 -0
  11. package/android/src/main/java/com/reactnativefireworksdk/components/videofeed/FWVideoFeed.kt +123 -0
  12. package/android/src/main/java/com/reactnativefireworksdk/constants/FWCommandConstant.kt +6 -0
  13. package/android/src/main/java/com/reactnativefireworksdk/constants/FWVideoPlayerConstant.kt +20 -0
  14. package/android/src/main/java/com/reactnativefireworksdk/manager/FWVideoFeedManager.kt +88 -0
  15. package/android/src/main/java/com/reactnativefireworksdk/models/FWEventName.kt +35 -0
  16. package/android/src/main/java/com/reactnativefireworksdk/models/FWVideoFeedConfigModel.kt +27 -0
  17. package/android/src/main/java/com/reactnativefireworksdk/models/FWVideoFeedItemDetailsModel.kt +11 -0
  18. package/android/src/main/java/com/reactnativefireworksdk/models/FWVideoFeedMode.kt +7 -0
  19. package/android/src/main/java/com/reactnativefireworksdk/models/FWVideoFeedSource.kt +7 -0
  20. package/android/src/main/java/com/reactnativefireworksdk/models/FWVideoFeedTitlePosition.kt +7 -0
  21. package/android/src/main/java/com/reactnativefireworksdk/models/FWVideoPlaybackDetails.kt +19 -0
  22. package/android/src/main/java/com/reactnativefireworksdk/models/FWVideoPlayerConfigModel.kt +20 -0
  23. package/android/src/main/java/com/reactnativefireworksdk/models/FWVideoShoppingInterface.kt +13 -0
  24. package/android/src/main/java/com/reactnativefireworksdk/models/FWVideoShoppingProduct.kt +34 -0
  25. package/android/src/main/java/com/reactnativefireworksdk/models/FireworkSDKInterface.kt +12 -0
  26. package/android/src/main/java/com/reactnativefireworksdk/module/FWVideoShoppingModule.kt +190 -0
  27. package/android/src/main/java/com/reactnativefireworksdk/module/FireworkSDKModule.kt +248 -0
  28. package/android/src/main/java/com/reactnativefireworksdk/pages/FWVideoShoppingCartActivity.kt +43 -0
  29. package/android/src/main/java/com/reactnativefireworksdk/utils/FWEventUtils.kt +127 -0
  30. package/android/src/main/java/com/reactnativefireworksdk/utils/FWJsonUtils.kt +57 -0
  31. package/android/src/main/java/com/reactnativefireworksdk/utils/FWLogUtils.kt +147 -0
  32. package/android/src/main/java/com/reactnativefireworksdk/utils/FWUrlUtils.kt +68 -0
  33. package/android/src/main/java/com/reactnativefireworksdk/utils/FWVideoPlayerUtils.kt +18 -0
  34. package/android/src/main/res/layout/fwrn_fragment_shoppingcart.xml +8 -0
  35. package/android/src/main/res/layout/fwrn_fragment_videofeed.xml +20 -0
  36. package/android/src/main/res/values/styles.xml +43 -0
  37. package/ios/Component/VideoFeed.swift +262 -0
  38. package/ios/Component/VideoFeedConfiguration.swift +32 -0
  39. package/ios/Component/VideoFeedManager.m +51 -0
  40. package/ios/Component/VideoFeedManager.swift +40 -0
  41. package/ios/Component/VideoPlayerConfiguration.swift +30 -0
  42. package/ios/FireworkSdk-Bridging-Header.h +6 -0
  43. package/ios/FireworkSdk.xcodeproj/project.pbxproj +291 -0
  44. package/ios/Models/FireworkJsEvent.swift +34 -0
  45. package/ios/Models/FireworkSDK+JsModel.swift +62 -0
  46. package/ios/Models/RCTConvert+FireworkSDKModule.swift +91 -0
  47. package/ios/Models/RCTConvert+Shopping.swift +49 -0
  48. package/ios/Models/RCTConvert+VideoFeed.swift +69 -0
  49. package/ios/Modules/FireworkSDKModule/FireworkSDKModule+CTA.swift +17 -0
  50. package/ios/Modules/FireworkSDKModule/FireworkSDKModule+EventTracking.swift +74 -0
  51. package/ios/Modules/FireworkSDKModule/FireworkSDKModule.m +19 -0
  52. package/ios/Modules/FireworkSDKModule/FireworkSDKModule.swift +106 -0
  53. package/ios/Modules/FireworkSDKModule/MobileADConfiguration.swift +17 -0
  54. package/ios/Modules/Shopping/CartViewController.swift +98 -0
  55. package/ios/Modules/Shopping/Product.swift +33 -0
  56. package/ios/Modules/Shopping/ProductInfoViewConfiguration.swift +24 -0
  57. package/ios/Modules/Shopping/ShoppingModule.m +19 -0
  58. package/ios/Modules/Shopping/ShoppingModule.swift +214 -0
  59. package/ios/Utils/String+Color.swift +38 -0
  60. package/ios/Utils/UIView+Constraints.swift +91 -0
  61. package/ios/Utils/UIView+ParentViewController.swift +21 -0
  62. package/ios/Utils/UIViewController+AttachChild.swift +69 -0
  63. package/lib/commonjs/FireworkSDK.js +171 -0
  64. package/lib/commonjs/FireworkSDK.js.map +1 -0
  65. package/lib/commonjs/VideoShopping.js +146 -0
  66. package/lib/commonjs/VideoShopping.js.map +1 -0
  67. package/lib/commonjs/components/CartContainer.js +35 -0
  68. package/lib/commonjs/components/CartContainer.js.map +1 -0
  69. package/lib/commonjs/components/FWVideoFeed.js +18 -0
  70. package/lib/commonjs/components/FWVideoFeed.js.map +1 -0
  71. package/lib/commonjs/components/VideoFeed.js +82 -0
  72. package/lib/commonjs/components/VideoFeed.js.map +1 -0
  73. package/lib/commonjs/constants/FWErrorMessage.js +15 -0
  74. package/lib/commonjs/constants/FWErrorMessage.js.map +1 -0
  75. package/lib/commonjs/index.js +44 -0
  76. package/lib/commonjs/index.js.map +1 -0
  77. package/lib/commonjs/models/ADConfig.js +2 -0
  78. package/lib/commonjs/models/ADConfig.js.map +1 -0
  79. package/lib/commonjs/models/AddToCartResult.js +2 -0
  80. package/lib/commonjs/models/AddToCartResult.js.map +1 -0
  81. package/lib/commonjs/models/FWError.js +2 -0
  82. package/lib/commonjs/models/FWError.js.map +1 -0
  83. package/lib/commonjs/models/FWEvents.js +20 -0
  84. package/lib/commonjs/models/FWEvents.js.map +1 -0
  85. package/lib/commonjs/models/FeedItemDetails.js +2 -0
  86. package/lib/commonjs/models/FeedItemDetails.js.map +1 -0
  87. package/lib/commonjs/models/Product.js +2 -0
  88. package/lib/commonjs/models/Product.js.map +1 -0
  89. package/lib/commonjs/models/ProductInfoViewConfiguration.js +2 -0
  90. package/lib/commonjs/models/ProductInfoViewConfiguration.js.map +1 -0
  91. package/lib/commonjs/models/ProductUnit.js +2 -0
  92. package/lib/commonjs/models/ProductUnit.js.map +1 -0
  93. package/lib/commonjs/models/VideoFeedConfiguration.js +2 -0
  94. package/lib/commonjs/models/VideoFeedConfiguration.js.map +1 -0
  95. package/lib/commonjs/models/VideoPlaybackDetails.js +2 -0
  96. package/lib/commonjs/models/VideoPlaybackDetails.js.map +1 -0
  97. package/lib/commonjs/models/VideoPlaybackEventName.js +23 -0
  98. package/lib/commonjs/models/VideoPlaybackEventName.js.map +1 -0
  99. package/lib/commonjs/models/VideoPlayerConfiguration.js +2 -0
  100. package/lib/commonjs/models/VideoPlayerConfiguration.js.map +1 -0
  101. package/lib/commonjs/modules/FireworkSDKModule.js +20 -0
  102. package/lib/commonjs/modules/FireworkSDKModule.js.map +1 -0
  103. package/lib/commonjs/modules/ShoppingModule.js +20 -0
  104. package/lib/commonjs/modules/ShoppingModule.js.map +1 -0
  105. package/lib/module/FireworkSDK.js +153 -0
  106. package/lib/module/FireworkSDK.js.map +1 -0
  107. package/lib/module/VideoShopping.js +134 -0
  108. package/lib/module/VideoShopping.js.map +1 -0
  109. package/lib/module/components/CartContainer.js +18 -0
  110. package/lib/module/components/CartContainer.js.map +1 -0
  111. package/lib/module/components/FWVideoFeed.js +8 -0
  112. package/lib/module/components/FWVideoFeed.js.map +1 -0
  113. package/lib/module/components/VideoFeed.js +66 -0
  114. package/lib/module/components/VideoFeed.js.map +1 -0
  115. package/lib/module/constants/FWErrorMessage.js +7 -0
  116. package/lib/module/constants/FWErrorMessage.js.map +1 -0
  117. package/lib/module/index.js +10 -0
  118. package/lib/module/index.js.map +1 -0
  119. package/lib/module/models/ADConfig.js +2 -0
  120. package/lib/module/models/ADConfig.js.map +1 -0
  121. package/lib/module/models/AddToCartResult.js +2 -0
  122. package/lib/module/models/AddToCartResult.js.map +1 -0
  123. package/lib/module/models/FWError.js +2 -0
  124. package/lib/module/models/FWError.js.map +1 -0
  125. package/lib/module/models/FWEvents.js +13 -0
  126. package/lib/module/models/FWEvents.js.map +1 -0
  127. package/lib/module/models/FeedItemDetails.js +2 -0
  128. package/lib/module/models/FeedItemDetails.js.map +1 -0
  129. package/lib/module/models/Product.js +2 -0
  130. package/lib/module/models/Product.js.map +1 -0
  131. package/lib/module/models/ProductInfoViewConfiguration.js +2 -0
  132. package/lib/module/models/ProductInfoViewConfiguration.js.map +1 -0
  133. package/lib/module/models/ProductUnit.js +2 -0
  134. package/lib/module/models/ProductUnit.js.map +1 -0
  135. package/lib/module/models/VideoFeedConfiguration.js +2 -0
  136. package/lib/module/models/VideoFeedConfiguration.js.map +1 -0
  137. package/lib/module/models/VideoPlaybackDetails.js +2 -0
  138. package/lib/module/models/VideoPlaybackDetails.js.map +1 -0
  139. package/lib/module/models/VideoPlaybackEventName.js +16 -0
  140. package/lib/module/models/VideoPlaybackEventName.js.map +1 -0
  141. package/lib/module/models/VideoPlayerConfiguration.js +2 -0
  142. package/lib/module/models/VideoPlayerConfiguration.js.map +1 -0
  143. package/lib/module/modules/FireworkSDKModule.js +10 -0
  144. package/lib/module/modules/FireworkSDKModule.js.map +1 -0
  145. package/lib/module/modules/ShoppingModule.js +10 -0
  146. package/lib/module/modules/ShoppingModule.js.map +1 -0
  147. package/lib/typescript/FireworkSDK.d.ts +74 -0
  148. package/lib/typescript/VideoShopping.d.ts +54 -0
  149. package/lib/typescript/components/CartContainer.d.ts +3 -0
  150. package/lib/typescript/components/FWVideoFeed.d.ts +2 -0
  151. package/lib/typescript/components/VideoFeed.d.ts +53 -0
  152. package/lib/typescript/constants/FWErrorMessage.d.ts +2 -0
  153. package/lib/typescript/index.d.ts +25 -0
  154. package/lib/typescript/models/ADConfig.d.ts +10 -0
  155. package/lib/typescript/models/AddToCartResult.d.ts +10 -0
  156. package/lib/typescript/models/FWError.d.ts +10 -0
  157. package/lib/typescript/models/FWEvents.d.ts +55 -0
  158. package/lib/typescript/models/FeedItemDetails.d.ts +14 -0
  159. package/lib/typescript/models/Product.d.ts +19 -0
  160. package/lib/typescript/models/ProductInfoViewConfiguration.d.ts +18 -0
  161. package/lib/typescript/models/ProductUnit.d.ts +22 -0
  162. package/lib/typescript/models/VideoFeedConfiguration.d.ts +32 -0
  163. package/lib/typescript/models/VideoPlaybackDetails.d.ts +31 -0
  164. package/lib/typescript/models/VideoPlaybackEventName.d.ts +39 -0
  165. package/lib/typescript/models/VideoPlayerConfiguration.d.ts +25 -0
  166. package/lib/typescript/modules/FireworkSDKModule.d.ts +12 -0
  167. package/lib/typescript/modules/ShoppingModule.d.ts +13 -0
  168. package/package.json +147 -0
  169. package/react-native-firework-sdk.podspec +22 -0
  170. package/src/FireworkSDK.ts +153 -0
  171. package/src/VideoShopping.ts +165 -0
  172. package/src/components/CartContainer.tsx +20 -0
  173. package/src/components/FWVideoFeed.tsx +10 -0
  174. package/src/components/VideoFeed.tsx +109 -0
  175. package/src/constants/FWErrorMessage.ts +11 -0
  176. package/src/index.tsx +109 -0
  177. package/src/models/ADConfig.ts +10 -0
  178. package/src/models/AddToCartResult.ts +10 -0
  179. package/src/models/FWError.ts +10 -0
  180. package/src/models/FWEvents.ts +63 -0
  181. package/src/models/FeedItemDetails.ts +14 -0
  182. package/src/models/Product.ts +20 -0
  183. package/src/models/ProductInfoViewConfiguration.ts +20 -0
  184. package/src/models/ProductUnit.ts +23 -0
  185. package/src/models/VideoFeedConfiguration.ts +35 -0
  186. package/src/models/VideoPlaybackDetails.ts +33 -0
  187. package/src/models/VideoPlaybackEventName.ts +40 -0
  188. package/src/models/VideoPlayerConfiguration.ts +26 -0
  189. package/src/modules/FireworkSDKModule.ts +27 -0
  190. package/src/modules/ShoppingModule.ts +29 -0
@@ -0,0 +1,248 @@
1
+ package com.reactnativefireworksdk.module
2
+
3
+ import android.annotation.SuppressLint
4
+ import android.content.pm.PackageManager
5
+ import android.provider.Settings
6
+ import com.facebook.react.bridge.*
7
+ import com.loopnow.fireworklibrary.FwSDK
8
+ import com.loopnow.fireworklibrary.SdkStatus
9
+ import com.loopnow.fireworklibrary.VideoEvent
10
+ import com.reactnativefireworksdk.models.FWVideoPlaybackDetails
11
+ import com.reactnativefireworksdk.models.FWVideoPlaybackSubEventName
12
+ import com.reactnativefireworksdk.models.FWVideoPlayerConfigModel
13
+ import com.reactnativefireworksdk.utils.*
14
+ import org.json.JSONObject
15
+ import com.facebook.react.bridge.ReactMethod
16
+ import com.reactnativefireworksdk.models.FireworkSDKInterface
17
+
18
+
19
+ class FireworkSDKModule(
20
+ reactContext: ReactApplicationContext
21
+ ) : ReactContextBaseJavaModule(reactContext), FireworkSDKInterface {
22
+
23
+ /**
24
+ * Initializes FW SDK
25
+ *
26
+ * You must add the appid to the AndroidManifest file.
27
+ * Please contact Firework business team, if you don't have one.
28
+ *
29
+ * This method will always return immediately and must be called on the main thread.
30
+ * It is recommended that you initialize FW SDK when application created. FW SDK must be initialized
31
+ * before using any of the features.
32
+ *
33
+ * @param userId an id to uniquely identify device or user. If you don't have a unique id
34
+ * We will use hashed Android_ID as it is
35
+ * If id passed is not unique, it will affect the quality of content recommended to the user.
36
+ */
37
+ @ReactMethod
38
+ override fun init(userId: String?, adConfig: ReadableMap?) {
39
+ init(userId)
40
+ }
41
+
42
+ /**
43
+ * play video from url with encoded parameters
44
+ *
45
+ * When user clicks on player_url shared @see setBasePlayerUrl and
46
+ * you handle the universal link in your app, you can launch the video playback
47
+ * based on the encodedParameters present in the link
48
+ * the custom player_url is in the format
49
+ * If you used https://example.com as base url the player_url will be in the following format
50
+ * https://example.com#fwplayer=eyJjaGFubmVsX2lkIjoiTFJZMUdYIiwiZmVlZF9pZCI6NDIwLCJmZWVkX3R5cGUiOiJkaXNjb3ZlciIsInYiOjEsInZpZGVvX2lkIjoiZ0syNmJkIn0
51
+ * @param url https://example.com#fwplayer=xxx
52
+ * @param config { NativeMap: {"playerStyle":"full","videoCompleteAction":"loop","showShareButton":false,"ctaButtonStyle":{"backgroundColor":"#0f7bdf","fontSize":14,"textColor":"#ffffff"}} }
53
+ */
54
+ @ReactMethod
55
+ override fun openVideoPlayer(url: String, config: ReadableMap?) {
56
+ val encodedParameters = FWUrlUtils.queryParamString(url, "fwplayer")
57
+ if (encodedParameters.isNullOrBlank()) {
58
+ FWLogUtils.e { "The parameter url is invalid" }
59
+ return
60
+ }
61
+
62
+ // set configuration
63
+ val configMap = config?.toHashMap()
64
+ val videoPlayerContentConfigModel = FWJsonUtils.fromMap(configMap, FWVideoPlayerConfigModel::class.java)
65
+ FWVideoPlayerUtils.setVideoPlayerConfig(videoPlayerContentConfigModel)
66
+
67
+ // open player
68
+ UiThreadUtil.runOnUiThread {
69
+ FwSDK.play(encodedParameters)
70
+ }
71
+ }
72
+
73
+ /**
74
+ * The function allows you to set the base url and query parameters to construct
75
+ * the player_url that is shared when user uses share feature.
76
+ * The custom url should only be used, if you want to support universal link and
77
+ * handle opening of the url in the app first before opening it in the web browser.
78
+ * @param url for example https://example.com
79
+ *
80
+ */
81
+ @ReactMethod
82
+ override fun setShareBaseURL(url: String?) {
83
+ if (!url.isNullOrBlank()) {
84
+ FwSDK.setBasePlayerUrl(url)
85
+ }
86
+ }
87
+
88
+ @ReactMethod
89
+ override fun setCustomCTAClickEnabled(value: Boolean?) {
90
+ FWVideoPlayerUtils.customCTAClickEnabled = value?:false
91
+ handleCustomCTAClick()
92
+ }
93
+
94
+ @ReactMethod
95
+ override fun setVideoPlaybackEventEnabled(value: Boolean?) {
96
+ FWVideoPlayerUtils.videoPlaybackEventEnabled = value?:false
97
+ handleVideoPlaybackEvent()
98
+ }
99
+
100
+ private fun init(userId: String?) {
101
+ val clientId = getAppid()
102
+ if (clientId.isNullOrBlank()) {
103
+ val errorMsg = "The appid is invalid"
104
+ FWLogUtils.e { errorMsg }
105
+ FWEventUtils.sendInitFailedEvent(reactApplicationContext, errorMsg)
106
+ return
107
+ }
108
+
109
+ val uid = if (userId.isNullOrBlank()) { getHashedAndroidId() } else userId
110
+
111
+ UiThreadUtil.runOnUiThread {
112
+ FwSDK.initialize(
113
+ reactApplicationContext,
114
+ clientId,
115
+ uid,
116
+ object : FwSDK.SdkStatusListener {
117
+ override fun currentStatus(status: SdkStatus, extra: String) {
118
+ when (status) {
119
+ SdkStatus.Initialized -> {
120
+ FWEventUtils.sendInitSuccessEvent(reactApplicationContext)
121
+ }
122
+ SdkStatus.InitializationFailed -> {
123
+ FWEventUtils.sendInitFailedEvent(reactApplicationContext, extra)
124
+ }
125
+ SdkStatus.RefreshTokenFailed -> {
126
+ FWEventUtils.sendInitFailedEvent(reactApplicationContext, extra)
127
+ }
128
+ SdkStatus.LoadingContent -> {
129
+ FWLogUtils.d { "LoadingContent" }
130
+ }
131
+ SdkStatus.LoadingContentFailed -> {
132
+ FWLogUtils.e { "LoadingContentFailed" }
133
+ }
134
+ SdkStatus.ContentLoaded -> {
135
+ FWLogUtils.d { "ContentLoaded" }
136
+ }
137
+ }
138
+ }
139
+ })
140
+ handleVideoPlaybackEvent()
141
+ }
142
+ }
143
+
144
+ private fun getAppid(): String? {
145
+ val ai = reactApplicationContext.packageManager.getApplicationInfo(
146
+ reactApplicationContext.packageName,
147
+ PackageManager.GET_META_DATA
148
+ )
149
+ val value = ai.metaData.get("Firework:Appid")
150
+ return value?.let {
151
+ it as String
152
+ } ?: run {
153
+ null
154
+ }
155
+ }
156
+
157
+ @SuppressLint("HardwareIds")
158
+ private fun getHashedAndroidId(): String {
159
+ val androidId = Settings.Secure.getString(
160
+ reactApplicationContext.contentResolver,
161
+ Settings.Secure.ANDROID_ID
162
+ )
163
+ return FwSDK.getHash(androidId)
164
+ }
165
+
166
+ private fun handleCustomCTAClick() {
167
+ if (!FWVideoPlayerUtils.customCTAClickEnabled) {
168
+ return
169
+ }
170
+ FwSDK.ctaClickHandler = object: FwSDK.CtaClickHandler {
171
+ override fun ctaClicked(label: String, actionUrl: String?): Boolean {
172
+ FWLogUtils.d { "ctaClicked" }
173
+ FWEventUtils.sendCustomCTAClickEvent(reactApplicationContext, actionUrl)
174
+ return FWVideoPlayerUtils.customCTAClickEnabled
175
+ }
176
+ }
177
+ }
178
+
179
+ private fun handleVideoPlaybackEvent() {
180
+ if (!FWVideoPlayerUtils.videoPlaybackEventEnabled) {
181
+ return
182
+ }
183
+ FwSDK.addVideoEventListener(object: FwSDK.VideoEventListener {
184
+ override fun event(event: String, jsonObject: JSONObject) {
185
+ val videoPlaybackDetails = FWJsonUtils.fromJson(jsonObject.toString(), FWVideoPlaybackDetails::class.java)
186
+
187
+ when (event) {
188
+ VideoEvent.videoImpression -> {
189
+ FWEventUtils.sendVideoPlaybackEvent(reactApplicationContext, FWVideoPlaybackSubEventName.Impression.rawValue, videoPlaybackDetails)
190
+ }
191
+ VideoEvent.videoStart -> {
192
+ FWEventUtils.sendVideoPlaybackEvent(reactApplicationContext, FWVideoPlaybackSubEventName.Start.rawValue, videoPlaybackDetails)
193
+ }
194
+ VideoEvent.videoFirstQuartile -> {
195
+ FWEventUtils.sendVideoPlaybackEvent(reactApplicationContext, FWVideoPlaybackSubEventName.FirstQuartile.rawValue, videoPlaybackDetails)
196
+ }
197
+ VideoEvent.videoMidpoint -> {
198
+ FWEventUtils.sendVideoPlaybackEvent(reactApplicationContext, FWVideoPlaybackSubEventName.Midpoint.rawValue, videoPlaybackDetails)
199
+ }
200
+ VideoEvent.videoThirdQuartile -> {
201
+ FWEventUtils.sendVideoPlaybackEvent(reactApplicationContext, FWVideoPlaybackSubEventName.ThirdQuartile.rawValue, videoPlaybackDetails)
202
+ }
203
+ VideoEvent.videoComplete -> {
204
+ FWEventUtils.sendVideoPlaybackEvent(reactApplicationContext, FWVideoPlaybackSubEventName.Complete.rawValue, videoPlaybackDetails)
205
+ }
206
+ VideoEvent.videoSession -> {
207
+
208
+ }
209
+ VideoEvent.videoAdStart -> {
210
+
211
+ }
212
+ VideoEvent.videoAdEnd -> {
213
+ FWEventUtils.sendVideoPlaybackEvent(reactApplicationContext, FWVideoPlaybackSubEventName.AdEnd.rawValue, videoPlaybackDetails)
214
+ }
215
+ VideoEvent.videoClickCta -> {
216
+ FWEventUtils.sendVideoPlaybackEvent(reactApplicationContext, FWVideoPlaybackSubEventName.ClickCTA.rawValue, videoPlaybackDetails)
217
+ }
218
+ VideoEvent.videoShare -> {
219
+ FWEventUtils.sendVideoPlaybackEvent(reactApplicationContext, FWVideoPlaybackSubEventName.ClickShare.rawValue, videoPlaybackDetails)
220
+ }
221
+ VideoEvent.videoStartError -> {
222
+
223
+ }
224
+ VideoEvent.videoAdStartError -> {
225
+
226
+ }
227
+ }
228
+ }
229
+ })
230
+ }
231
+
232
+ @ReactMethod
233
+ fun addListener(eventName: String?) {
234
+ // Set up any upstream listeners or background tasks as necessary
235
+ FWLogUtils.d { "addListener: $eventName" }
236
+ }
237
+
238
+ @ReactMethod
239
+ fun removeListeners(count: Int?) {
240
+ // Remove upstream listeners, stop unnecessary background tasks
241
+ FWLogUtils.d { "removeListeners: $count" }
242
+ }
243
+
244
+ override fun getName(): String {
245
+ return "FireworkSDK"
246
+ }
247
+
248
+ }
@@ -0,0 +1,43 @@
1
+ package com.reactnativefireworksdk.pages
2
+
3
+ import android.app.Activity
4
+ import android.content.Intent
5
+ import android.os.Bundle
6
+ import androidx.appcompat.app.AppCompatActivity
7
+ import androidx.fragment.app.Fragment
8
+ import com.reactnativefireworksdk.R
9
+ import com.facebook.react.ReactFragment
10
+ import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler
11
+
12
+
13
+ class FWVideoShoppingCartActivity : AppCompatActivity(), DefaultHardwareBackBtnHandler {
14
+
15
+ override fun onCreate(savedInstanceState: Bundle?) {
16
+ super.onCreate(savedInstanceState)
17
+ setContentView(R.layout.fwrn_fragment_shoppingcart)
18
+
19
+ val reactNativeFragment: Fragment = ReactFragment.Builder()
20
+ .setComponentName("FWShoppingCartPage")
21
+ .setLaunchOptions(null)
22
+ .build()
23
+
24
+ supportFragmentManager
25
+ .beginTransaction()
26
+ .add(R.id.shopping_cart_container, reactNativeFragment)
27
+ .commit()
28
+ }
29
+
30
+ companion object {
31
+
32
+ fun createIntent(activity: Activity): Intent {
33
+ val intent = Intent(activity, FWVideoShoppingCartActivity::class.java)
34
+ intent.flags = Intent.FLAG_ACTIVITY_NO_ANIMATION
35
+ activity.overridePendingTransition(0, 0)
36
+ return intent
37
+ }
38
+ }
39
+
40
+ override fun invokeDefaultOnBackPressed() {
41
+ super.onBackPressed();
42
+ }
43
+ }
@@ -0,0 +1,127 @@
1
+ package com.reactnativefireworksdk.utils
2
+
3
+ import com.facebook.react.bridge.Arguments
4
+ import com.facebook.react.bridge.ReactContext
5
+ import com.facebook.react.bridge.WritableMap
6
+ import com.facebook.react.modules.core.DeviceEventManagerModule
7
+ import com.facebook.react.uimanager.events.RCTEventEmitter
8
+ import com.reactnativefireworksdk.models.*
9
+
10
+ object FWEventUtils {
11
+
12
+ fun sendInitSuccessEvent(reactContext: ReactContext) {
13
+ sendEvent(reactContext, FWEventName.SDKIni.rawValue, Arguments.createMap())
14
+ }
15
+
16
+ fun sendInitFailedEvent(reactContext: ReactContext, reason: String?) {
17
+ val eventMap = Arguments.createMap()
18
+ val contentMap = Arguments.createMap()
19
+ contentMap.putString(FWSDKInitSubEventName.InitFailed.rawValue, reason?:"unknown")
20
+ eventMap.putMap("error", contentMap)
21
+ sendEvent(reactContext, FWEventName.SDKIni.rawValue, eventMap)
22
+ }
23
+
24
+ fun sendVideoFeedClickEvent(reactContext: ReactContext, info: FWVideoFeedItemDetailsModel) {
25
+ val eventMap = Arguments.createMap()
26
+ val contentMap = Arguments.createMap()
27
+ contentMap.putInt("index", info.index?:0)
28
+ contentMap.putString("videoId", info.id)
29
+ contentMap.putInt("duration", info.videoDuration?:0)
30
+ eventMap.putMap("info", contentMap)
31
+ sendEvent(reactContext, FWEventName.VideoFeedClick.rawValue, eventMap)
32
+ }
33
+
34
+ fun sendCustomCTAClickEvent(reactContext: ReactContext, url: String?) {
35
+ val eventMap = Arguments.createMap()
36
+ eventMap.putString("url", url)
37
+ sendEvent(reactContext, FWEventName.CustomCTAClick.rawValue, eventMap)
38
+ }
39
+
40
+ fun sendVideoPlaybackEvent(reactContext: ReactContext, eventName: String, info: FWVideoPlaybackDetails?) {
41
+ val eventMap = Arguments.createMap()
42
+ eventMap.putString("eventName", eventName)
43
+
44
+ val contentMap = Arguments.createMap()
45
+ if (!info?.videoId.isNullOrBlank()) {
46
+ contentMap.putString("videoId", info?.videoId)
47
+ }
48
+ if (info?.duration != null) {
49
+ contentMap.putDouble("duration", info.duration.toDouble())
50
+ }
51
+ if (info?.caption.isNullOrBlank()) {
52
+ contentMap.putString("caption", info?.caption)
53
+ }
54
+ if (info?.badge.isNullOrBlank()) {
55
+ contentMap.putString("badge", info?.badge)
56
+ }
57
+ if (info?.width != null || info?.height != null) {
58
+ val playerSizeMap = Arguments.createMap()
59
+ if (info.width != null) {
60
+ playerSizeMap.putInt("width", info.width)
61
+ }
62
+ if (info.height != null) {
63
+ playerSizeMap.putInt("height", info.height)
64
+ }
65
+ contentMap.putMap("playerSize", playerSizeMap)
66
+ }
67
+ if (info?.hasCta != null) {
68
+ contentMap.putBoolean("hasCTA", info.hasCta)
69
+ }
70
+ eventMap.putMap("info", contentMap)
71
+
72
+ sendEvent(reactContext, FWEventName.VideoPlayback.rawValue, eventMap)
73
+ }
74
+
75
+ fun sendAddToCartClickEvent(reactContext: ReactContext, productId: String?, unitId: String?, callbackId: Int?) {
76
+ val eventMap = Arguments.createMap()
77
+ eventMap.putString("productId", productId)
78
+ eventMap.putString("unitId", unitId)
79
+ eventMap.putInt("callbackId", callbackId?:0)
80
+ sendEvent(reactContext, FWVideoShoppingEventName.AddToCart.rawValue, eventMap)
81
+ }
82
+
83
+ fun sendCartIconClickEvent(reactContext: ReactContext, callbackId: Int?) {
84
+ val eventMap = Arguments.createMap()
85
+ eventMap.putInt("callbackId", callbackId?:0)
86
+ sendEvent(reactContext, FWVideoShoppingEventName.ClickCartIcon.rawValue, eventMap)
87
+ }
88
+
89
+ fun sendUpdateProductDetailsEvent(reactContext: ReactContext, productId: String?, callbackId: Int?) {
90
+ val eventMap = Arguments.createMap()
91
+ eventMap.putString("productId", productId)
92
+ eventMap.putInt("callbackId", callbackId?:0)
93
+ sendEvent(reactContext, FWVideoShoppingEventName.UpdateProductDetails.rawValue, eventMap)
94
+ }
95
+
96
+ private fun sendEvent(reactContext: ReactContext, eventName: String, params: WritableMap?) {
97
+ reactContext
98
+ .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
99
+ .emit(eventName, params)
100
+ }
101
+
102
+ fun receiveVideoFeedLoadFinished(reactContext: ReactContext, targetTag: Int, eventName: String, name: String?, reason: String?) {
103
+ val eventMap = Arguments.createMap()
104
+ eventMap.putString("name", name)
105
+ eventMap.putString("reason", reason)
106
+ receiveEvent(reactContext, targetTag, FWFeedViewEventName.VideoFeedLoadFinished.rawValue, eventMap)
107
+ }
108
+
109
+ private fun receiveEvent(reactContext: ReactContext, targetTag: Int, eventName: String, event: WritableMap?) {
110
+ reactContext.getJSModule(RCTEventEmitter::class.java).receiveEvent(
111
+ targetTag,
112
+ eventName,
113
+ event
114
+ )
115
+
116
+ /**
117
+ * ERROR Invariant Violation: Module RCTModernEventEmitter is not a registered callable module (calling receiveEvent). A frequent cause of the error is that the application entry file path is incorrect.
118
+ * This can also happen when the JS bundle is corrupt or there is an early initialization error when loading React Native.
119
+ */
120
+ // reactContext.getJSModule(RCTModernEventEmitter::class.java).receiveEvent(
121
+ // -1,
122
+ // id,
123
+ // "onVideoFeedLoadFinished",
124
+ // event
125
+ // )
126
+ }
127
+ }
@@ -0,0 +1,57 @@
1
+ package com.reactnativefireworksdk.utils
2
+
3
+ import android.os.Looper
4
+ import com.fasterxml.jackson.annotation.JsonInclude
5
+ import com.fasterxml.jackson.databind.DeserializationFeature
6
+ import com.fasterxml.jackson.databind.ObjectMapper
7
+ import com.fasterxml.jackson.databind.SerializationFeature
8
+ import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
9
+ import java.util.*
10
+
11
+ object FWJsonUtils {
12
+ val mapper: ObjectMapper by lazy {
13
+ jacksonObjectMapper()
14
+ // .setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE)
15
+ .configure(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_AS_NULL, true)
16
+ .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
17
+ .setSerializationInclusion(JsonInclude.Include.NON_NULL)
18
+ .configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false)
19
+ .configure(SerializationFeature.WRITE_DATES_WITH_ZONE_ID, true)
20
+ .setTimeZone(TimeZone.getDefault())
21
+ }
22
+
23
+ private fun logJsonError(e: Exception) {
24
+ val loggedError = RuntimeException("Json Read Error!", e)
25
+ if (Looper.myLooper() != Looper.getMainLooper()) {
26
+ throw loggedError
27
+ }
28
+ }
29
+
30
+ @JvmStatic
31
+ fun <T> fromMap(map: Map<*, *>?, cls: Class<T>): T? {
32
+ if (map.isNullOrEmpty()) {
33
+ return null
34
+ }
35
+ try {
36
+ return mapper.convertValue(map, cls)
37
+ } catch (e: Exception) {
38
+ e.printStackTrace()
39
+ logJsonError(e)
40
+ }
41
+ return null
42
+ }
43
+
44
+ @JvmStatic
45
+ fun <T> fromJson(json: String?, cls: Class<T>): T? {
46
+ if (json.isNullOrBlank()) {
47
+ return null
48
+ }
49
+ try {
50
+ return mapper.readValue(json, cls)
51
+ } catch (e: Exception) {
52
+ e.printStackTrace()
53
+ logJsonError(e)
54
+ }
55
+ return null
56
+ }
57
+ }
@@ -0,0 +1,147 @@
1
+ package com.reactnativefireworksdk.utils
2
+
3
+ import android.os.Looper
4
+ import android.os.SystemClock
5
+ import android.util.Log
6
+ import com.reactnativefireworksdk.BuildConfig
7
+ import kotlin.math.max
8
+
9
+ /**
10
+ * We need to set the [BuildConfig.LOG_LEVEL] to ensure that
11
+ * the log message whose log level is larger than [BuildConfig.LOG_LEVEL]
12
+ * can be printed in any environment (Debug / Release).
13
+ *
14
+ * P.S The value of [BuildConfig.LOG_LEVEL] is different in the Debug or Release environment.
15
+ * see the file - [build.gradle] for detail.
16
+ */
17
+ object FWLogUtils {
18
+
19
+ @JvmStatic
20
+ var logLevel: Int = BuildConfig.LOG_LEVEL
21
+
22
+ @JvmStatic
23
+ val isDebugEnabled: Boolean get() = logLevel <= Log.DEBUG
24
+
25
+ @JvmStatic
26
+ fun d(lazyMessage: () -> String?) {
27
+ log(Log.DEBUG, lazyMessage)
28
+ }
29
+
30
+ @JvmStatic
31
+ fun i(lazyMessage: () -> String?) {
32
+ log(Log.INFO, lazyMessage)
33
+ }
34
+
35
+ @JvmStatic
36
+ fun w(lazyMessage: () -> String?) {
37
+ log(Log.WARN, lazyMessage)
38
+ }
39
+
40
+ @JvmStatic
41
+ fun e(lazyMessage: () -> String?) {
42
+ log(Log.ERROR, lazyMessage)
43
+ }
44
+
45
+ @JvmStatic
46
+ fun d(e: Throwable?) {
47
+ log(Log.DEBUG, e = e)
48
+ }
49
+
50
+ @JvmStatic
51
+ fun i(e: Throwable?) {
52
+ log(Log.INFO, e = e)
53
+ }
54
+
55
+ @JvmStatic
56
+ fun w(e: Throwable?) {
57
+ log(Log.WARN, e = e)
58
+ }
59
+
60
+ @JvmStatic
61
+ @JvmOverloads
62
+ fun e(e: Throwable?, lazyMessage: (() -> String?)? = null) {
63
+ log(Log.ERROR, lazyMessage, e)
64
+ }
65
+
66
+ @JvmStatic
67
+ fun enableMainThreadLog() {
68
+ var mainThreadStartTime = -1L
69
+ Looper.getMainLooper().setMessageLogging {
70
+ if (it.startsWith(">>>>>")) {
71
+ mainThreadStartTime = SystemClock.uptimeMillis()
72
+ } else if (it.startsWith("<<<<<")) {
73
+ val time = SystemClock.uptimeMillis() - mainThreadStartTime
74
+ // 1000 / 50 = 20+ frames
75
+ if (time > 50) d {
76
+ "Using ${time}ms ${it.substring(6)}"
77
+ }
78
+ }
79
+ }
80
+ }
81
+
82
+ private fun log(level: Int, lazyMessage: (() -> String?)? = null, e: Throwable? = null) {
83
+ if (level >= logLevel) {
84
+ var message = lazyMessage?.let { it() }.orEmpty()
85
+ if (message.isEmpty()) {
86
+ if (e == null) {
87
+ return
88
+ } else {
89
+ message = "null"
90
+ }
91
+ }
92
+ val (tag, lineNumber) = generateTag()
93
+ val lineTag = when {
94
+ lineNumber < 10 -> "__$lineNumber"
95
+ lineNumber < 100 -> "_$lineNumber"
96
+ else -> "$lineNumber"
97
+ }
98
+ while (message.length > 4000) {
99
+ val subMessage = message.substring(0, 4000)
100
+ message = message.substring(4000)
101
+ when (level) {
102
+ Log.DEBUG -> {
103
+ Log.d(lineTag, "$tag: $subMessage")
104
+ }
105
+ Log.INFO -> {
106
+ Log.i(lineTag, "$tag: $subMessage")
107
+ }
108
+ Log.WARN -> {
109
+ Log.w(lineTag, "$tag: $subMessage")
110
+ }
111
+ Log.ERROR -> {
112
+ Log.e(lineTag, "$tag: $subMessage")
113
+ }
114
+ }
115
+ }
116
+ when (level) {
117
+ Log.DEBUG -> {
118
+ Log.d(lineTag, "$tag: $message", e)
119
+ }
120
+ Log.INFO -> {
121
+ Log.i(lineTag, "$tag: $message", e)
122
+ }
123
+ Log.WARN -> {
124
+ Log.w(lineTag, "$tag: $message", e)
125
+ }
126
+ Log.ERROR -> {
127
+ Log.e(lineTag, "$tag: $message", e)
128
+ }
129
+ }
130
+ }
131
+ }
132
+
133
+ private val NO_LOG_LIST = setOf(Thread::class.java.name, FWLogUtils::class.java.name)
134
+
135
+ internal fun generateTag(): Pair<String, Int> {
136
+ val stackTrace = Thread.currentThread().stackTrace
137
+ for (i in 2 until stackTrace.size) {
138
+ val className = stackTrace[i].className
139
+ val fileName = stackTrace[i].fileName
140
+ val lineNumber = stackTrace[i].lineNumber
141
+ if (className !in NO_LOG_LIST) {
142
+ return Pair(fileName.substring(0, max(fileName.lastIndexOf('.'), 0)), lineNumber)
143
+ }
144
+ }
145
+ return Pair(javaClass.simpleName, 0)
146
+ }
147
+ }
@@ -0,0 +1,68 @@
1
+ package com.reactnativefireworksdk.utils
2
+
3
+ import android.net.Uri
4
+
5
+ object FWUrlUtils {
6
+
7
+ /**
8
+ * Get parameters in URL
9
+ *
10
+ * @param urlStr url
11
+ * @param key key
12
+ * @return string
13
+ * e.g. queryParamString("https://www.example.com?a=1&c=2", "a") will return "1"
14
+ * e.g. queryParamString("https://www.example.com#a=1&c=2", "a") will return "1"
15
+ */
16
+ fun queryParamString(urlStr: String?, key: String?): String? {
17
+ if (urlStr.isNullOrBlank() || key.isNullOrBlank()) {
18
+ return null
19
+ }
20
+ return if (urlStr.contains("#")) {
21
+ queryHashParamString(urlStr, key)
22
+ } else {
23
+ queryBrowserParamString(urlStr, key)
24
+ }
25
+ }
26
+
27
+ /**
28
+ * Get browser parameters in URL
29
+ *
30
+ * @param urlStr url
31
+ * @param key key
32
+ * @return string
33
+ * e.g. queryParamString("https://www.example.com?a=1&c=2", "a") will return "1"
34
+ */
35
+ private fun queryBrowserParamString(urlStr: String?, key: String?): String? {
36
+ if (urlStr.isNullOrBlank() || key.isNullOrBlank()) {
37
+ return null
38
+ }
39
+ val uri = Uri.parse(urlStr)
40
+ return uri?.getQueryParameter(key)
41
+ }
42
+
43
+ /**
44
+ * Get hash parameters in URL
45
+ *
46
+ * @param urlStr url
47
+ * @param key key
48
+ * @return string
49
+ * e.g. queryParamString("https://www.example.com#a=1&c=2", "a") will return "1"
50
+ */
51
+ private fun queryHashParamString(urlStr: String?, key: String?): String? {
52
+ if (urlStr.isNullOrBlank() || key.isNullOrBlank()) {
53
+ return null
54
+ }
55
+ val urlParts = urlStr.split("#").filter(String::isNotEmpty)
56
+ if (urlParts.size < 2) {
57
+ return null
58
+ }
59
+ val query = urlParts[1]
60
+ val queryParts = query.split("&")
61
+
62
+ for (queryPart in queryParts) {
63
+ val paramParts = queryPart.split("=")
64
+ if (paramParts[0] == key) return paramParts[1]
65
+ }
66
+ return null
67
+ }
68
+ }