react-native-firework-sdk 2.13.0 → 2.14.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 (96) hide show
  1. package/android/.idea/codeStyles/Project.xml +124 -0
  2. package/android/.idea/codeStyles/codeStyleConfig.xml +5 -0
  3. package/android/gradle.properties +1 -1
  4. package/android/src/main/java/com/fireworksdk/bridge/models/FWLiveStreamEventDetailsModel.kt +1 -0
  5. package/android/src/main/java/com/fireworksdk/bridge/models/FWVideoFeedConfigModel.kt +1 -0
  6. package/android/src/main/java/com/fireworksdk/bridge/models/FWVideoFeedConfigModelDeserializer.kt +3 -0
  7. package/android/src/main/java/com/fireworksdk/bridge/models/FWVideoFeedConfigModelSerializer.kt +2 -0
  8. package/android/src/main/java/com/fireworksdk/bridge/models/enums/FWDataTrackingLevel.kt +7 -0
  9. package/android/src/main/java/com/fireworksdk/bridge/models/enums/FWEventName.kt +2 -1
  10. package/android/src/main/java/com/fireworksdk/bridge/models/enums/FWSwitchLanguageBehavior.kt +6 -0
  11. package/android/src/main/java/com/fireworksdk/bridge/reactnative/FWReactNativeSDK.kt +19 -7
  12. package/android/src/main/java/com/fireworksdk/bridge/reactnative/models/FireworkSDKInterface.kt +1 -0
  13. package/android/src/main/java/com/fireworksdk/bridge/reactnative/module/FWLiveStreamModule.kt +6 -4
  14. package/android/src/main/java/com/fireworksdk/bridge/reactnative/module/FWVideoShoppingModule.kt +29 -19
  15. package/android/src/main/java/com/fireworksdk/bridge/reactnative/module/FireworkSDKModule.kt +41 -17
  16. package/android/src/main/java/com/fireworksdk/bridge/reactnative/utils/FWEventUtils.kt +25 -13
  17. package/android/src/main/java/com/fireworksdk/bridge/utils/FWConfigUtil.kt +4 -0
  18. package/android/src/main/java/com/fireworksdk/bridge/utils/FWGlobalDataUtil.kt +5 -0
  19. package/android/src/main/java/com/fireworksdk/bridge/utils/FWLanguageUtil.kt +57 -15
  20. package/android/src/main/java/com/fireworksdk/bridge/utils/FWModelUtils.kt +9 -1
  21. package/ios/FireworkSdk.xcodeproj/project.pbxproj +4 -0
  22. package/ios/Models/NativeToRN/FireworkEventName.swift +1 -0
  23. package/ios/Models/NativeToRN/FireworkSDK+Json.swift +6 -2
  24. package/ios/Models/RNToNative/RCTConvert+FireworkSDKModule.swift +13 -0
  25. package/ios/Modules/FireworkSDKModule/FireworkSDKModule+CTA.swift +8 -16
  26. package/ios/Modules/FireworkSDKModule/FireworkSDKModule+EventTracking.swift +9 -1
  27. package/ios/Modules/FireworkSDKModule/FireworkSDKModule.m +1 -0
  28. package/ios/Modules/FireworkSDKModule/FireworkSDKModule.swift +96 -31
  29. package/ios/Modules/Shopping/ShoppingModule.swift +12 -3
  30. package/ios/Utils/Extensions/NumberFormatter+AppLanguage.swift +27 -0
  31. package/lib/commonjs/FireworkSDK.js +66 -12
  32. package/lib/commonjs/FireworkSDK.js.map +1 -1
  33. package/lib/commonjs/VideoShopping.js +15 -0
  34. package/lib/commonjs/VideoShopping.js.map +1 -1
  35. package/lib/commonjs/components/StoryBlock.js +6 -0
  36. package/lib/commonjs/components/StoryBlock.js.map +1 -1
  37. package/lib/commonjs/components/VideoFeed.js +14 -6
  38. package/lib/commonjs/components/VideoFeed.js.map +1 -1
  39. package/lib/commonjs/index.js +14 -6
  40. package/lib/commonjs/index.js.map +1 -1
  41. package/lib/commonjs/models/DataTrackingLevel.js +2 -0
  42. package/lib/commonjs/models/DataTrackingLevel.js.map +1 -0
  43. package/lib/commonjs/models/FWComponentType.js +14 -0
  44. package/lib/commonjs/models/FWComponentType.js.map +1 -0
  45. package/lib/commonjs/models/FWEventName.js +1 -0
  46. package/lib/commonjs/models/FWEventName.js.map +1 -1
  47. package/lib/commonjs/modules/FireworkSDKModule.js.map +1 -1
  48. package/lib/commonjs/utils/FWGlobalState.js +2 -0
  49. package/lib/commonjs/utils/FWGlobalState.js.map +1 -1
  50. package/lib/module/FireworkSDK.js +64 -11
  51. package/lib/module/FireworkSDK.js.map +1 -1
  52. package/lib/module/VideoShopping.js +15 -0
  53. package/lib/module/VideoShopping.js.map +1 -1
  54. package/lib/module/components/StoryBlock.js +5 -0
  55. package/lib/module/components/StoryBlock.js.map +1 -1
  56. package/lib/module/components/VideoFeed.js +13 -6
  57. package/lib/module/components/VideoFeed.js.map +1 -1
  58. package/lib/module/index.js +6 -5
  59. package/lib/module/index.js.map +1 -1
  60. package/lib/module/models/DataTrackingLevel.js +2 -0
  61. package/lib/module/models/DataTrackingLevel.js.map +1 -0
  62. package/lib/module/models/FWComponentType.js +7 -0
  63. package/lib/module/models/FWComponentType.js.map +1 -0
  64. package/lib/module/models/FWEventName.js +1 -0
  65. package/lib/module/models/FWEventName.js.map +1 -1
  66. package/lib/module/modules/FireworkSDKModule.js.map +1 -1
  67. package/lib/module/utils/FWGlobalState.js +2 -0
  68. package/lib/module/utils/FWGlobalState.js.map +1 -1
  69. package/lib/typescript/FireworkSDK.d.ts +22 -1
  70. package/lib/typescript/VideoShopping.d.ts +8 -1
  71. package/lib/typescript/index.d.ts +15 -13
  72. package/lib/typescript/models/DataTrackingLevel.d.ts +1 -0
  73. package/lib/typescript/models/FWComponentType.d.ts +4 -0
  74. package/lib/typescript/models/FWEventName.d.ts +2 -1
  75. package/lib/typescript/models/FWEvents.d.ts +18 -1
  76. package/lib/typescript/models/FeedItemDetails.d.ts +0 -1
  77. package/lib/typescript/models/LiveStreamEventDetails.d.ts +1 -0
  78. package/lib/typescript/models/VideoFeedConfiguration.d.ts +0 -1
  79. package/lib/typescript/modules/FireworkSDKModule.d.ts +2 -0
  80. package/lib/typescript/utils/FWGlobalState.d.ts +2 -0
  81. package/package.json +1 -1
  82. package/react-native-firework-sdk.podspec +4 -3
  83. package/src/FireworkSDK.ts +59 -14
  84. package/src/VideoShopping.ts +24 -0
  85. package/src/components/StoryBlock.tsx +8 -0
  86. package/src/components/VideoFeed.tsx +11 -1
  87. package/src/index.ts +38 -30
  88. package/src/models/DataTrackingLevel.ts +1 -0
  89. package/src/models/FWComponentType.ts +4 -0
  90. package/src/models/FWEventName.ts +1 -0
  91. package/src/models/FWEvents.ts +19 -1
  92. package/src/models/FeedItemDetails.ts +0 -1
  93. package/src/models/LiveStreamEventDetails.ts +1 -0
  94. package/src/models/VideoFeedConfiguration.ts +0 -1
  95. package/src/modules/FireworkSDKModule.ts +2 -0
  96. package/src/utils/FWGlobalState.ts +3 -0
@@ -4,6 +4,7 @@ import android.app.Activity
4
4
  import android.content.Context
5
5
  import androidx.fragment.app.FragmentActivity
6
6
  import com.fireworksdk.bridge.components.base.FWBaseFragment
7
+
7
8
  import java.util.Locale
8
9
 
9
10
  class FWLanguageUtil private constructor(context: Context) {
@@ -14,12 +15,38 @@ class FWLanguageUtil private constructor(context: Context) {
14
15
 
15
16
  private val initAppLocale: Locale = Locale.getDefault()
16
17
 
18
+ /**
19
+ * local string, e.g. ar, ar-AE, pt-BR
20
+ */
17
21
  private var localeString: String? = null
18
22
 
19
23
  init {
20
24
  localeString = sharedPreferences.getString(LOCALE_KEY, null)
21
25
  }
22
26
 
27
+ fun getCurrentSettingLocale(): Locale {
28
+ val localeLanguage = localeString
29
+ if (localeLanguage.isNullOrBlank()) {
30
+ return Locale(initAppLocale.language, initAppLocale.country)
31
+ } else {
32
+ if (localeLanguage.contains("-")) {
33
+ val locales = localeLanguage.split("-")
34
+ if (locales.size > 1) {
35
+ return Locale(locales[0], locales[1])
36
+ }
37
+ }
38
+ return Locale(localeLanguage)
39
+ }
40
+ }
41
+
42
+ fun shouldOverrideLanguage(language: String): Boolean {
43
+ if (localeString.isNullOrBlank()) {
44
+ // not update language in local string
45
+ return false
46
+ }
47
+ return !localeString.equals(language, true)
48
+ }
49
+
23
50
  fun updateBaseContextLocale(baseContext: Context): Context {
24
51
  val currentLocaleString = localeString
25
52
 
@@ -28,29 +55,45 @@ class FWLanguageUtil private constructor(context: Context) {
28
55
  return updateResourcesLocale(baseContext, initAppLocale)
29
56
  }
30
57
 
31
- val localeStrings = currentLocaleString.split("-")
32
- val locale = if (localeStrings.size > 1) {
33
- Locale(localeStrings[0], localeStrings[1])
34
- } else {
35
- Locale(currentLocaleString)
36
- }
58
+ val locale = getLocaleByLanguage(currentLocaleString)
59
+
37
60
  Locale.setDefault(locale)
38
61
  return updateResourcesLocale(baseContext, locale)
39
62
  }
40
63
 
64
+ private fun getLocaleByLanguage(language: String): Locale {
65
+ if (language.contains("-")) {
66
+ val locales = language.split("-")
67
+ if (locales.size > 1) {
68
+ return Locale(locales[0], locales[1])
69
+ }
70
+ }
71
+ return Locale(language)
72
+ }
73
+
41
74
  private fun updateResourcesLocale(context: Context, locale: Locale): Context {
42
75
  val resources = context.resources
43
76
  val configuration = resources.configuration
44
77
  configuration.setLocale(locale)
45
78
  configuration.setLayoutDirection(locale)
46
- return context.createConfigurationContext(configuration)
79
+ val newContext = context.createConfigurationContext(configuration)
80
+ context.resources.updateConfiguration(configuration, context.resources.displayMetrics)
81
+ return newContext
47
82
  }
48
83
 
49
- fun changeLanguage(inputLocaleString: String?, activity: Activity?): Boolean {
50
- // no change
51
- if ((inputLocaleString.isNullOrBlank() && localeString.isNullOrBlank())
84
+ /**
85
+ * return
86
+ * true: need to execute change language.
87
+ * false: don't need to execute change language.
88
+ */
89
+ fun isSameLanguageWithCache(inputLocaleString: String?): Boolean {
90
+ return (inputLocaleString.isNullOrBlank() && localeString.isNullOrBlank())
52
91
  || localeString == inputLocaleString
53
- ) {
92
+ }
93
+
94
+ fun changeLanguage(inputLocaleString: String?): Boolean {
95
+ // no change
96
+ if (isSameLanguageWithCache(inputLocaleString)) {
54
97
  return true
55
98
  }
56
99
 
@@ -58,7 +101,6 @@ class FWLanguageUtil private constructor(context: Context) {
58
101
  if (inputLocaleString.isNullOrBlank()) {
59
102
  localeString = null
60
103
  updateSpLanguage(inputLocaleString)
61
- restartActivity(activity)
62
104
  return true
63
105
  }
64
106
 
@@ -70,7 +112,6 @@ class FWLanguageUtil private constructor(context: Context) {
70
112
  // update locale
71
113
  localeString = inputLocaleString
72
114
  updateSpLanguage(inputLocaleString)
73
- restartActivity(activity)
74
115
  return true
75
116
  }
76
117
 
@@ -86,7 +127,7 @@ class FWLanguageUtil private constructor(context: Context) {
86
127
  }
87
128
  }
88
129
 
89
- private fun restartActivity(activity: Activity?) {
130
+ fun restartActivity(activity: Activity?) {
90
131
  if (activity is FragmentActivity) {
91
132
  val fragments = activity.supportFragmentManager.fragments
92
133
  for (f in fragments) {
@@ -98,7 +139,7 @@ class FWLanguageUtil private constructor(context: Context) {
98
139
  activity?.recreate()
99
140
  }
100
141
 
101
- private fun isValidLocale(locale: String?) : Boolean {
142
+ private fun isValidLocale(locale: String?): Boolean {
102
143
  locale ?: return false
103
144
  val list = Locale.getAvailableLocales()
104
145
  if (locale.contains("-")) {
@@ -114,4 +155,5 @@ class FWLanguageUtil private constructor(context: Context) {
114
155
  private const val LOCALE_SP = "fw_locale_sp"
115
156
  private const val LOCALE_KEY = "fw_locale_key"
116
157
  }
158
+
117
159
  }
@@ -4,6 +4,7 @@ import com.firework.analyticsevents.VideoInfo
4
4
  import com.firework.analyticsevents.cta.CtaButtonClickAnalyticsEvent
5
5
  import com.firework.analyticsevents.player.PlayerLifecycleAnalyticsEvent
6
6
  import com.firework.analyticsevents.share.ShareButtonAnalyticsEvent
7
+ import com.fireworksdk.bridge.models.FWLiveStreamEventDetailsModel
7
8
  import com.fireworksdk.bridge.models.FWVideoPlaybackDetails
8
9
 
9
10
  object FWModelUtils {
@@ -20,6 +21,13 @@ object FWModelUtils {
20
21
  )
21
22
  }
22
23
 
24
+ fun convertVideoInfo2LivestreamDetails(videoInfo: VideoInfo): FWLiveStreamEventDetailsModel {
25
+ return FWLiveStreamEventDetailsModel(
26
+ id = videoInfo.id,
27
+ feedId = videoInfo.feedId,
28
+ )
29
+ }
30
+
23
31
  fun convertCtaEvent2PlaybackDetails(event: CtaButtonClickAnalyticsEvent): FWVideoPlaybackDetails {
24
32
  return FWVideoPlaybackDetails(
25
33
  badge = event.videoInfo.badge,
@@ -61,4 +69,4 @@ object FWModelUtils {
61
69
  )
62
70
  }
63
71
 
64
- }
72
+ }
@@ -7,6 +7,7 @@
7
7
  objects = {
8
8
 
9
9
  /* Begin PBXBuildFile section */
10
+ 890B6B402BF5F9B4007E5762 /* NumberFormatter+AppLanguage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 890B6B3F2BF5F9B4007E5762 /* NumberFormatter+AppLanguage.swift */; };
10
11
  891F4AF62A67E12800A9E8DA /* FWRNContainerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 891F4AF52A67E12800A9E8DA /* FWRNContainerViewController.swift */; };
11
12
  891F4AF82A68DEDF00A9E8DA /* PushRNContainerParams.swift in Sources */ = {isa = PBXBuildFile; fileRef = 891F4AF72A68DEDF00A9E8DA /* PushRNContainerParams.swift */; };
12
13
  891F4AFA2A68DF2B00A9E8DA /* RCTConvert+FWNavigatorModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 891F4AF92A68DF2B00A9E8DA /* RCTConvert+FWNavigatorModule.swift */; };
@@ -98,6 +99,7 @@
98
99
 
99
100
  /* Begin PBXFileReference section */
100
101
  1F6F718A2771B48100224AF3 /* FireworkSdk-Bridging-Header.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "FireworkSdk-Bridging-Header.h"; sourceTree = "<group>"; };
102
+ 890B6B3F2BF5F9B4007E5762 /* NumberFormatter+AppLanguage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NumberFormatter+AppLanguage.swift"; sourceTree = "<group>"; };
101
103
  891F4AF52A67E12800A9E8DA /* FWRNContainerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FWRNContainerViewController.swift; sourceTree = "<group>"; };
102
104
  891F4AF72A68DEDF00A9E8DA /* PushRNContainerParams.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PushRNContainerParams.swift; sourceTree = "<group>"; };
103
105
  891F4AF92A68DF2B00A9E8DA /* RCTConvert+FWNavigatorModule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "RCTConvert+FWNavigatorModule.swift"; sourceTree = "<group>"; };
@@ -183,6 +185,7 @@
183
185
  898873122A0A8E7E0089CD1C /* Extensions */ = {
184
186
  isa = PBXGroup;
185
187
  children = (
188
+ 890B6B3F2BF5F9B4007E5762 /* NumberFormatter+AppLanguage.swift */,
186
189
  89C105642BAD2C1D00E47CDD /* UIWindowScene+Swizzle.swift */,
187
190
  898873132A0A8E7E0089CD1C /* UIViewController+AttachChild.swift */,
188
191
  898873142A0A8E7E0089CD1C /* UIView+Constraints.swift */,
@@ -424,6 +427,7 @@
424
427
  8988735B2A0A8E7E0089CD1C /* FireworkSDKModule.m in Sources */,
425
428
  8988736A2A0A8E7E0089CD1C /* VideoFeedConfiguration.swift in Sources */,
426
429
  8975238D2817DEF80070EBB6 /* (null) in Sources */,
430
+ 890B6B402BF5F9B4007E5762 /* NumberFormatter+AppLanguage.swift in Sources */,
427
431
  8975238C2817DEF80070EBB6 /* (null) in Sources */,
428
432
  8988736B2A0A8E7E0089CD1C /* VideoFeed.swift in Sources */,
429
433
  891F4AF62A67E12800A9E8DA /* FWRNContainerViewController.swift in Sources */,
@@ -45,6 +45,7 @@ enum ShoppingEventName: String, CaseIterable {
45
45
  case logMessage = "fw:log-message"
46
46
  case customLinkButtonClick = "fw:shopping:custom-link-button-click"
47
47
  case customProductCardTap = "fw:shopping:custom-product-card-tap"
48
+ case productClick = "fw:shopping:product-click"
48
49
  }
49
50
 
50
51
  /// Live stream event
@@ -72,7 +72,8 @@ extension FeedEventDetails {
72
72
  var result: [String: Any] = [
73
73
  "index": index,
74
74
  "id": id,
75
- "duration": duration
75
+ "duration": duration,
76
+ "feedId": feedId
76
77
  ]
77
78
  if let title = caption {
78
79
  result["title"] = title
@@ -112,7 +113,10 @@ extension FeedEventDetails {
112
113
 
113
114
  extension LiveStreamEventDetails {
114
115
  var jsObject: [String: Any] {
115
- return ["id": id]
116
+ return [
117
+ "id": videoID,
118
+ "feedId": feedID
119
+ ]
116
120
  }
117
121
  }
118
122
 
@@ -113,4 +113,17 @@ extension RCTConvert {
113
113
 
114
114
  return result
115
115
  }
116
+
117
+ static func dataTrackingLevel(_ level: String) -> FireworkVideo.DataTrackingLevel? {
118
+ switch level {
119
+ case "all":
120
+ return FireworkVideo.DataTrackingLevel.all
121
+ case "essentialOnly":
122
+ return FireworkVideo.DataTrackingLevel.essentialOnly
123
+ case "none":
124
+ return FireworkVideo.DataTrackingLevel.none
125
+ default:
126
+ return nil
127
+ }
128
+ }
116
129
  }
@@ -8,27 +8,19 @@
8
8
  import FireworkVideo
9
9
  import Foundation
10
10
 
11
- var gVideoDetailsForTappingCTAButton: VideoDetails?
12
-
13
11
  extension FireworkSDKModule: FireworkVideoCTADelegate {
14
- func handleCustomCTAClick(_ viewController: PlayerViewController, url: URL) -> Bool {
12
+ func handleCustomCTAClick(_ viewController: PlayerViewController, url: URL, for video: VideoDetails) -> Bool {
15
13
  let callbackId = UUID().uuidString
16
14
  playerMap.setObject(viewController, forKey: callbackId as NSString)
17
15
 
18
- DispatchQueue.main.async { [weak self] in
19
- var body: [String: Any?] = [
20
- "url": url.absoluteString,
21
- "callbackId": callbackId
22
- ]
23
-
24
- if let video = gVideoDetailsForTappingCTAButton {
25
- body["video"] = video.jsObject
26
- gVideoDetailsForTappingCTAButton = nil
27
- }
16
+ let body: [String: Any?] = [
17
+ "url": url.absoluteString,
18
+ "callbackId": callbackId,
19
+ "video": video.jsObject
20
+ ]
28
21
 
29
- self?.sendEvent(withName: FWEventName.customCTAClick.rawValue,
30
- body: body)
31
- }
22
+ self.sendEvent(withName: FWEventName.customCTAClick.rawValue,
23
+ body: body)
32
24
 
33
25
  return customCTAClickEnabled
34
26
  }
@@ -110,7 +110,6 @@ extension FireworkSDKModule: FireworkVideoPlaybackDelegate {
110
110
  }
111
111
 
112
112
  func fireworkVideoDidTapCTAButton(_ videoPlayback: VideoPlaybackDetails) {
113
- gVideoDetailsForTappingCTAButton = videoPlayback
114
113
  guard enableVideoPlayBackEvent else { return }
115
114
  sendEvent(
116
115
  withName: FWEventName.videoPlayback.rawValue,
@@ -137,3 +136,12 @@ extension FireworkSDKModule: FireworkVideoFeedDelegate {
137
136
  withName: FWEventName.videoFeedClick.rawValue, body: ["info": eventDetails.jsObject])
138
137
  }
139
138
  }
139
+
140
+ extension FireworkSDKModule {
141
+ @objc(setDataTrackingLevel:)
142
+ func setDataTrackingLevel(_ level: String) {
143
+ if let dataTrackingLevel = RCTConvert.dataTrackingLevel(level) {
144
+ FireworkVideoSDK.dataTrackingLevel = dataTrackingLevel
145
+ }
146
+ }
147
+ }
@@ -22,5 +22,6 @@ RCT_EXTERN_METHOD(trackPurchase:(NSDictionary *)parameters)
22
22
  RCT_EXTERN_METHOD(changeAppLanguage:(NSString * __nullable)language resolver: (RCTPromiseResolveBlock)resolver rejecter:(RCTPromiseRejectBlock)rejecter)
23
23
  RCT_EXTERN_METHOD(pausePlayer:(NSString *)callbackId)
24
24
  RCT_EXTERN_METHOD(resumePlayer:(NSString *)callbackId)
25
+ RCT_EXTERN_METHOD(setDataTrackingLevel:(NSString *)level)
25
26
 
26
27
  @end
@@ -28,9 +28,11 @@ class FireworkSDKModule: RCTEventEmitter, FireworkVideoSDKDelegate {
28
28
  // player view controller
29
29
  var playerMap: NSMapTable<NSString, UIViewController> = NSMapTable.strongToWeakObjects()
30
30
 
31
- private var hasCalledSDKInitFromNative: Bool = false
31
+ private var hasCalledSDKInit: Bool = false
32
32
  private var argumentsForInitEvent: [String: Any]?
33
33
  private var hasListeners = false
34
+ private let monitor = NWPathMonitor()
35
+ private var scheduledInitializingSDKClosure: (() -> Void)?
34
36
 
35
37
  override init() {
36
38
  super.init()
@@ -45,6 +47,8 @@ class FireworkSDKModule: RCTEventEmitter, FireworkVideoSDKDelegate {
45
47
  NotificationCenter.default.addObserver(
46
48
  self, selector: #selector(Self.onAppLanguageChanged),
47
49
  name: AppLanguageManager.NotificationName.AppLanguageChanged, object: nil)
50
+ startMonitoringNetworkStatus()
51
+ swizzleMethodsForAppLanguage()
48
52
  }
49
53
 
50
54
  override func supportedEvents() -> [String]! {
@@ -86,33 +90,44 @@ class FireworkSDKModule: RCTEventEmitter, FireworkVideoSDKDelegate {
86
90
  func markInitCalled(
87
91
  _ resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock
88
92
  ) {
89
- if hasCalledSDKInitFromNative,
90
- let argumentsForInitEvent = argumentsForInitEvent {
93
+ if let argumentsForInitEvent = argumentsForInitEvent {
91
94
  // The sdk init event was received before.
92
95
  sendEvent(withName: FWEventName.sdkInit.rawValue, body: argumentsForInitEvent)
93
96
  }
94
97
 
95
- resolver(hasCalledSDKInitFromNative)
98
+ resolver(hasCalledSDKInit)
96
99
  }
97
100
 
98
101
  func initializeSDK(_ options: SDKInitOptions?, _ fromNative: Bool) {
99
- if hasCalledSDKInitFromNative && !fromNative {
102
+ if hasCalledSDKInit {
100
103
  if let argumentsForInitEvent = argumentsForInitEvent {
101
104
  // The sdk init event was received before.
102
105
  sendEvent(withName: FWEventName.sdkInit.rawValue, body: argumentsForInitEvent)
103
106
  }
104
107
  } else {
105
- gVideoLaunchBehavior = options?.videoLaunchBehavior
108
+ let initializingSDKClosure = {
109
+ gVideoLaunchBehavior = options?.videoLaunchBehavior
106
110
 
107
- FireworkVideoSDK.initializeSDK(delegate: self, userID: options?.userId)
108
- FireworkVideoSDK.ctaDelegate = self
109
- FireworkVideoSDK.eventTracking.videoPlaybackDelegate = self
110
- FireworkVideoSDK.eventTracking.feedDelegate = self
111
- }
111
+ FireworkVideoSDK.initializeSDK(delegate: self, userID: options?.userId)
112
+ FireworkVideoSDK.ctaDelegate = self
113
+ FireworkVideoSDK.eventTracking.videoPlaybackDelegate = self
114
+ FireworkVideoSDK.eventTracking.feedDelegate = self
115
+ }
112
116
 
113
- if fromNative {
114
- hasCalledSDKInitFromNative = true
117
+ if monitor.currentPath.status == .satisfied {
118
+ #if DEBUG
119
+ print("call initializingSDKClosure directly")
120
+ #endif
121
+ initializingSDKClosure()
122
+ } else {
123
+ #if DEBUG
124
+ print("schedule initializingSDKClosure")
125
+ #endif
126
+ self.scheduledInitializingSDKClosure = initializingSDKClosure
127
+ }
115
128
  }
129
+
130
+ hasCalledSDKInit = true
116
131
  }
117
132
 
118
133
  @objc(openVideoPlayer:config:)
@@ -213,7 +228,7 @@ class FireworkSDKModule: RCTEventEmitter, FireworkVideoSDKDelegate {
213
228
  rejecter: @escaping RCTPromiseRejectBlock
214
229
  ) {
215
230
  let result = AppLanguageManager.shared.changeAppLanguage(language)
216
-
231
+ swizzleMethodsForAppLanguage()
217
232
  resolver(result)
218
233
  }
219
234
 
@@ -229,33 +244,83 @@ class FireworkSDKModule: RCTEventEmitter, FireworkVideoSDKDelegate {
229
244
 
230
245
  // MARK: - FireworkVideoSDKDelegate
231
246
  func fireworkVideoDidLoadSuccessfully() {
232
- argumentsForInitEvent = [:]
233
-
234
- if hasListeners {
235
- sendEvent(withName: FWEventName.sdkInit.rawValue, body: argumentsForInitEvent)
247
+ DispatchQueue.main.async {
248
+ self.argumentsForInitEvent = [:]
249
+
250
+ if self.hasListeners {
251
+ self.sendEvent(
252
+ withName: FWEventName.sdkInit.rawValue,
253
+ body: self.argumentsForInitEvent
254
+ )
255
+ }
236
256
  }
237
257
  }
238
258
 
239
259
  func fireworkVideoDidLoadWith(error: FireworkVideoSDKError) {
240
- argumentsForInitEvent = [
241
- "error": [
242
- "name": error.jsErrorName, "reason": error.recoverySuggestion ?? "default"
260
+ DispatchQueue.main.async {
261
+ self.argumentsForInitEvent = [
262
+ "error": [
263
+ "name": error.jsErrorName, "reason": error.recoverySuggestion ?? "default"
264
+ ]
243
265
  ]
244
- ]
245
266
 
246
- if hasListeners {
247
- sendEvent(
248
- withName: FWEventName.sdkInit.rawValue,
249
- body: argumentsForInitEvent)
267
+ if self.hasListeners {
268
+ self.sendEvent(
269
+ withName: FWEventName.sdkInit.rawValue,
270
+ body: self.argumentsForInitEvent
271
+ )
272
+ }
250
273
  }
251
274
  }
252
275
 
253
276
  @objc func onAppLanguageChanged() {
254
- sendEvent(
255
- withName: FWEventName.nativeAppLanguageUpdated.rawValue,
256
- body: [
257
- "appLanguage": AppLanguageManager.shared.appLanguage ?? ""
258
- ])
277
+ if self.hasListeners {
278
+ sendEvent(
279
+ withName: FWEventName.nativeAppLanguageUpdated.rawValue,
280
+ body: [
281
+ "appLanguage": AppLanguageManager.shared.appLanguage ?? ""
282
+ ])
283
+ }
284
+ }
285
+
286
+ func startMonitoringNetworkStatus() {
287
+ monitor.pathUpdateHandler = { path in
288
+ if path.status == .satisfied {
289
+ #if DEBUG
290
+ print("Network access is allowed.")
291
+ #endif
292
+ DispatchQueue.main.async {
293
+ if let initializingSDKClosure = self.scheduledInitializingSDKClosure {
294
+ #if DEBUG
295
+ print("call scheduledInitializingSDKClosure")
296
+ #endif
297
+ initializingSDKClosure()
298
+ self.scheduledInitializingSDKClosure = nil
299
+ }
300
+ }
301
+ } else {
302
+ #if DEBUG
303
+ print("Network access is not allowed.")
304
+ #endif
305
+ }
306
+ }
307
+ let queue = DispatchQueue(label: "FWNetworkMonitor")
308
+ monitor.start(queue: queue)
309
+ }
310
+
311
+ func cancelMonitoringNetworkStatus() {
312
+ monitor.pathUpdateHandler = nil
313
+ monitor.cancel()
314
+ }
315
+
316
+ func swizzleMethodsForAppLanguage() {
317
+ if AppLanguageManager.shared.appLanguage == nil {
318
+ return
319
+ }
320
+
321
+ DispatchQueue.once {
322
+ NumberFormatter.swizzleNumberFormatterMethodsForAppLanguage()
323
+ }
259
324
  }
260
325
  }
261
326
 
@@ -238,12 +238,15 @@ class ShoppingModule: RCTEventEmitter, FireworkVideoShoppingDelegate {
238
238
  func fireworkShopping(
239
239
  _ fireworkShopping: FireworkVideoShopping,
240
240
  didTapLinkButtonAt item: SelectedProductVariant,
241
+ fromVideo video: VideoDetails,
241
242
  withURL itemURL: String
242
243
  ) -> Bool {
243
244
  if customClickLinkButtonEnabled {
245
+ var body = item.jsObject
246
+ body["video"] = video.jsObject
244
247
  sendEvent(
245
248
  withName: ShoppingEventName.customLinkButtonClick.rawValue,
246
- body: item.jsObject)
249
+ body: body)
247
250
  }
248
251
  return customClickLinkButtonEnabled
249
252
  }
@@ -263,10 +266,11 @@ class ShoppingModule: RCTEventEmitter, FireworkVideoShoppingDelegate {
263
266
  didTapProductVariant item: SelectedProductVariant,
264
267
  forVideo video: VideoDetails
265
268
  ) -> Bool {
269
+ var body = item.jsObject
270
+ body["video"] = video.jsObject
271
+
266
272
  if customTapProductCardEnabled {
267
273
  let callbackId = ShoppingModule.generateCallbackId()
268
- var body = item.jsObject
269
- body["video"] = video.jsObject
270
274
  body["callbackId"] = callbackId as NSNumber
271
275
  if let presentedVC = RCTPresentedViewController(),
272
276
  let playerViewController = ShoppingModule.getTopPlayerViewController(presentedVC) {
@@ -277,6 +281,11 @@ class ShoppingModule: RCTEventEmitter, FireworkVideoShoppingDelegate {
277
281
  body: body)
278
282
 
279
283
  }
284
+
285
+ sendEvent(
286
+ withName: ShoppingEventName.productClick.rawValue,
287
+ body: body)
288
+
280
289
  return customTapProductCardEnabled
281
290
  }
282
291
  }
@@ -0,0 +1,27 @@
1
+ //
2
+ // NumberFormatter+FWAppLanguage.swift
3
+ //
4
+ // Created by linjie jiang on 2023/2/20.
5
+ //
6
+
7
+ import Foundation
8
+ import FireworkVideoUI
9
+
10
+ extension NumberFormatter {
11
+ static func swizzleNumberFormatterMethodsForAppLanguage() {
12
+ Swizzle.swizzleSelector(
13
+ cls: self,
14
+ originalSelector: #selector(NumberFormatter.string(from:)),
15
+ customSelector: #selector(NumberFormatter.fw_string(from:)))
16
+ }
17
+
18
+ @objc func fw_string(from number: NSNumber) -> String? {
19
+ if let language = AppLanguageManager.shared.appLanguage,
20
+ self.locale == Locale.current ||
21
+ self.locale == Locale.autoupdatingCurrent {
22
+ self.locale = Locale(identifier: language)
23
+ }
24
+
25
+ return fw_string(from: number)
26
+ }
27
+ }