@tyrads.com/tyrads-sdk 3.0.0-beta.0 → 3.1.0-beta.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 (225) hide show
  1. package/android/build.gradle +1 -1
  2. package/android/src/main/java/com/tyradssdk/TyradsSdkModule.kt +21 -4
  3. package/ios/Tyrads/InitModel.swift +3 -0
  4. package/ios/Tyrads/Tyrads.swift +106 -191
  5. package/ios/Tyrads/WebViewController.swift +171 -0
  6. package/ios/Tyrads/helpers/device_details.swift +58 -0
  7. package/ios/TyradsSdk.mm +7 -1
  8. package/ios/TyradsSdk.swift +42 -27
  9. package/lib/commonjs/acmo/core/helpers/launcher.js +20 -0
  10. package/lib/commonjs/acmo/core/helpers/launcher.js.map +1 -0
  11. package/lib/commonjs/acmo/modules/dashboard/components/active_offers_button.js +76 -0
  12. package/lib/commonjs/acmo/modules/dashboard/components/active_offers_button.js.map +1 -0
  13. package/lib/commonjs/acmo/modules/dashboard/components/custom_card.js +7 -10
  14. package/lib/commonjs/acmo/modules/dashboard/components/custom_card.js.map +1 -1
  15. package/lib/commonjs/acmo/modules/dashboard/components/custom_scroller.js +141 -0
  16. package/lib/commonjs/acmo/modules/dashboard/components/custom_scroller.js.map +1 -0
  17. package/lib/commonjs/acmo/{core/marquee.js → modules/dashboard/components/custom_shimmer.js} +46 -34
  18. package/lib/commonjs/acmo/modules/dashboard/components/custom_shimmer.js.map +1 -0
  19. package/lib/commonjs/acmo/modules/dashboard/components/offer_card.js +264 -0
  20. package/lib/commonjs/acmo/modules/dashboard/components/offer_card.js.map +1 -0
  21. package/lib/commonjs/acmo/modules/dashboard/components/offer_list_item.js +197 -0
  22. package/lib/commonjs/acmo/modules/dashboard/components/offer_list_item.js.map +1 -0
  23. package/lib/commonjs/acmo/modules/dashboard/components/premium_empty_widget.js +83 -0
  24. package/lib/commonjs/acmo/modules/dashboard/components/premium_empty_widget.js.map +1 -0
  25. package/lib/commonjs/acmo/modules/dashboard/components/premium_header.js +12 -10
  26. package/lib/commonjs/acmo/modules/dashboard/components/premium_header.js.map +1 -1
  27. package/lib/commonjs/acmo/modules/dashboard/components/premium_loading.js +118 -0
  28. package/lib/commonjs/acmo/modules/dashboard/components/premium_loading.js.map +1 -0
  29. package/lib/commonjs/acmo/modules/dashboard/repository.js +108 -32
  30. package/lib/commonjs/acmo/modules/dashboard/repository.js.map +1 -1
  31. package/lib/commonjs/acmo/modules/dashboard/top_offers.js +70 -63
  32. package/lib/commonjs/acmo/modules/dashboard/top_offers.js.map +1 -1
  33. package/lib/commonjs/assets/images/angle_up.png +0 -0
  34. package/lib/commonjs/assets/images/diamond.png +0 -0
  35. package/lib/commonjs/assets/images/info.png +0 -0
  36. package/lib/commonjs/assets/images/info_icon.png +0 -0
  37. package/lib/commonjs/assets/images/premium-emptybg.jpeg +0 -0
  38. package/lib/commonjs/assets/images/rank_1.png +0 -0
  39. package/lib/commonjs/assets/images/rank_2.png +0 -0
  40. package/lib/commonjs/assets/images/rank_3.png +0 -0
  41. package/lib/commonjs/assets/images/rank_4.png +0 -0
  42. package/lib/commonjs/assets/images/rank_5.png +0 -0
  43. package/lib/commonjs/index.js +11 -11
  44. package/lib/commonjs/index.js.map +1 -1
  45. package/lib/module/acmo/core/helpers/launcher.js +15 -0
  46. package/lib/module/acmo/core/helpers/launcher.js.map +1 -0
  47. package/lib/module/acmo/modules/dashboard/components/active_offers_button.js +70 -0
  48. package/lib/module/acmo/modules/dashboard/components/active_offers_button.js.map +1 -0
  49. package/lib/module/acmo/modules/dashboard/components/custom_card.js +7 -10
  50. package/lib/module/acmo/modules/dashboard/components/custom_card.js.map +1 -1
  51. package/lib/module/acmo/modules/dashboard/components/custom_scroller.js +135 -0
  52. package/lib/module/acmo/modules/dashboard/components/custom_scroller.js.map +1 -0
  53. package/lib/module/acmo/modules/dashboard/components/custom_shimmer.js +66 -0
  54. package/lib/module/acmo/modules/dashboard/components/custom_shimmer.js.map +1 -0
  55. package/lib/module/acmo/modules/dashboard/components/offer_card.js +257 -0
  56. package/lib/module/acmo/modules/dashboard/components/offer_card.js.map +1 -0
  57. package/lib/module/acmo/modules/dashboard/components/offer_list_item.js +191 -0
  58. package/lib/module/acmo/modules/dashboard/components/offer_list_item.js.map +1 -0
  59. package/lib/module/acmo/modules/dashboard/components/premium_empty_widget.js +78 -0
  60. package/lib/module/acmo/modules/dashboard/components/premium_empty_widget.js.map +1 -0
  61. package/lib/module/acmo/modules/dashboard/components/premium_header.js +12 -10
  62. package/lib/module/acmo/modules/dashboard/components/premium_header.js.map +1 -1
  63. package/lib/module/acmo/modules/dashboard/components/premium_loading.js +113 -0
  64. package/lib/module/acmo/modules/dashboard/components/premium_loading.js.map +1 -0
  65. package/lib/module/acmo/modules/dashboard/repository.js +105 -30
  66. package/lib/module/acmo/modules/dashboard/repository.js.map +1 -1
  67. package/lib/module/acmo/modules/dashboard/top_offers.js +71 -64
  68. package/lib/module/acmo/modules/dashboard/top_offers.js.map +1 -1
  69. package/lib/module/assets/images/angle_up.png +0 -0
  70. package/lib/module/assets/images/diamond.png +0 -0
  71. package/lib/module/assets/images/info.png +0 -0
  72. package/lib/module/assets/images/info_icon.png +0 -0
  73. package/lib/module/assets/images/premium-emptybg.jpeg +0 -0
  74. package/lib/module/assets/images/rank_1.png +0 -0
  75. package/lib/module/assets/images/rank_2.png +0 -0
  76. package/lib/module/assets/images/rank_3.png +0 -0
  77. package/lib/module/assets/images/rank_4.png +0 -0
  78. package/lib/module/assets/images/rank_5.png +0 -0
  79. package/lib/module/index.js +11 -11
  80. package/lib/module/index.js.map +1 -1
  81. package/lib/typescript/commonjs/src/acmo/core/helpers/launcher.d.ts +3 -0
  82. package/lib/typescript/commonjs/src/acmo/core/helpers/launcher.d.ts.map +1 -0
  83. package/lib/typescript/commonjs/src/acmo/core/storage/storage.d.ts.map +1 -1
  84. package/lib/typescript/commonjs/src/acmo/modules/dashboard/components/active_offers_button.d.ts +9 -0
  85. package/lib/typescript/commonjs/src/acmo/modules/dashboard/components/active_offers_button.d.ts.map +1 -0
  86. package/lib/typescript/commonjs/src/acmo/modules/dashboard/components/custom_card.d.ts.map +1 -1
  87. package/lib/typescript/commonjs/src/acmo/modules/dashboard/components/custom_scroller.d.ts +17 -0
  88. package/lib/typescript/commonjs/src/acmo/modules/dashboard/components/custom_scroller.d.ts.map +1 -0
  89. package/lib/typescript/commonjs/src/acmo/modules/dashboard/components/custom_shimmer.d.ts +11 -0
  90. package/lib/typescript/commonjs/src/acmo/modules/dashboard/components/custom_shimmer.d.ts.map +1 -0
  91. package/lib/typescript/commonjs/src/acmo/modules/dashboard/components/offer_card.d.ts +12 -0
  92. package/lib/typescript/commonjs/src/acmo/modules/dashboard/components/offer_card.d.ts.map +1 -0
  93. package/lib/typescript/commonjs/src/acmo/modules/dashboard/components/offer_list_item.d.ts +15 -0
  94. package/lib/typescript/commonjs/src/acmo/modules/dashboard/components/offer_list_item.d.ts.map +1 -0
  95. package/lib/typescript/commonjs/src/acmo/modules/dashboard/components/premium_empty_widget.d.ts +7 -0
  96. package/lib/typescript/commonjs/src/acmo/modules/dashboard/components/premium_empty_widget.d.ts.map +1 -0
  97. package/lib/typescript/commonjs/src/acmo/modules/dashboard/components/premium_loading.d.ts +9 -0
  98. package/lib/typescript/commonjs/src/acmo/modules/dashboard/components/premium_loading.d.ts.map +1 -0
  99. package/lib/typescript/commonjs/src/acmo/modules/dashboard/repository.d.ts +2 -1
  100. package/lib/typescript/commonjs/src/acmo/modules/dashboard/repository.d.ts.map +1 -1
  101. package/lib/typescript/commonjs/src/acmo/modules/dashboard/top_offers.d.ts +8 -7
  102. package/lib/typescript/commonjs/src/acmo/modules/dashboard/top_offers.d.ts.map +1 -1
  103. package/lib/typescript/commonjs/src/index.d.ts +4 -6
  104. package/lib/typescript/commonjs/src/index.d.ts.map +1 -1
  105. package/lib/typescript/module/src/acmo/core/helpers/launcher.d.ts +3 -0
  106. package/lib/typescript/module/src/acmo/core/helpers/launcher.d.ts.map +1 -0
  107. package/lib/typescript/module/src/acmo/core/storage/storage.d.ts.map +1 -1
  108. package/lib/typescript/module/src/acmo/modules/dashboard/components/active_offers_button.d.ts +9 -0
  109. package/lib/typescript/module/src/acmo/modules/dashboard/components/active_offers_button.d.ts.map +1 -0
  110. package/lib/typescript/module/src/acmo/modules/dashboard/components/custom_card.d.ts.map +1 -1
  111. package/lib/typescript/module/src/acmo/modules/dashboard/components/custom_scroller.d.ts +17 -0
  112. package/lib/typescript/module/src/acmo/modules/dashboard/components/custom_scroller.d.ts.map +1 -0
  113. package/lib/typescript/module/src/acmo/modules/dashboard/components/custom_shimmer.d.ts +11 -0
  114. package/lib/typescript/module/src/acmo/modules/dashboard/components/custom_shimmer.d.ts.map +1 -0
  115. package/lib/typescript/module/src/acmo/modules/dashboard/components/offer_card.d.ts +12 -0
  116. package/lib/typescript/module/src/acmo/modules/dashboard/components/offer_card.d.ts.map +1 -0
  117. package/lib/typescript/module/src/acmo/modules/dashboard/components/offer_list_item.d.ts +15 -0
  118. package/lib/typescript/module/src/acmo/modules/dashboard/components/offer_list_item.d.ts.map +1 -0
  119. package/lib/typescript/module/src/acmo/modules/dashboard/components/premium_empty_widget.d.ts +7 -0
  120. package/lib/typescript/module/src/acmo/modules/dashboard/components/premium_empty_widget.d.ts.map +1 -0
  121. package/lib/typescript/module/src/acmo/modules/dashboard/components/premium_loading.d.ts +9 -0
  122. package/lib/typescript/module/src/acmo/modules/dashboard/components/premium_loading.d.ts.map +1 -0
  123. package/lib/typescript/module/src/acmo/modules/dashboard/repository.d.ts +2 -1
  124. package/lib/typescript/module/src/acmo/modules/dashboard/repository.d.ts.map +1 -1
  125. package/lib/typescript/module/src/acmo/modules/dashboard/top_offers.d.ts +8 -7
  126. package/lib/typescript/module/src/acmo/modules/dashboard/top_offers.d.ts.map +1 -1
  127. package/lib/typescript/module/src/index.d.ts +4 -6
  128. package/lib/typescript/module/src/index.d.ts.map +1 -1
  129. package/package.json +3 -2
  130. package/readme.md +8 -8
  131. package/src/acmo/core/helpers/launcher.ts +14 -0
  132. package/src/acmo/core/types/types.d.ts +11 -13
  133. package/src/acmo/modules/dashboard/components/active_offers_button.tsx +61 -0
  134. package/src/acmo/modules/dashboard/components/custom_card.tsx +5 -8
  135. package/src/acmo/modules/dashboard/components/custom_scroller.tsx +164 -0
  136. package/src/acmo/modules/dashboard/components/custom_shimmer.tsx +75 -0
  137. package/src/acmo/modules/dashboard/components/offer_card.tsx +248 -0
  138. package/src/acmo/modules/dashboard/components/offer_list_item.tsx +225 -0
  139. package/src/acmo/modules/dashboard/components/premium_empty_widget.tsx +76 -0
  140. package/src/acmo/modules/dashboard/components/premium_header.tsx +8 -8
  141. package/src/acmo/modules/dashboard/components/premium_loading.tsx +78 -0
  142. package/src/acmo/modules/dashboard/repository.ts +121 -46
  143. package/src/acmo/modules/dashboard/top_offers.tsx +89 -52
  144. package/src/assets/images/angle_up.png +0 -0
  145. package/src/assets/images/diamond.png +0 -0
  146. package/src/assets/images/info.png +0 -0
  147. package/src/assets/images/info_icon.png +0 -0
  148. package/src/assets/images/premium-emptybg.jpeg +0 -0
  149. package/src/assets/images/rank_1.png +0 -0
  150. package/src/assets/images/rank_2.png +0 -0
  151. package/src/assets/images/rank_3.png +0 -0
  152. package/src/assets/images/rank_4.png +0 -0
  153. package/src/assets/images/rank_5.png +0 -0
  154. package/src/index.tsx +15 -18
  155. package/lib/commonjs/acmo/core/marquee.js.map +0 -1
  156. package/lib/commonjs/acmo/modules/dashboard/components/auto_scroller.js +0 -87
  157. package/lib/commonjs/acmo/modules/dashboard/components/auto_scroller.js.map +0 -1
  158. package/lib/commonjs/acmo/modules/dashboard/components/my_games_button.js +0 -48
  159. package/lib/commonjs/acmo/modules/dashboard/components/my_games_button.js.map +0 -1
  160. package/lib/commonjs/acmo/modules/dashboard/components/offer_info_section.js +0 -158
  161. package/lib/commonjs/acmo/modules/dashboard/components/offer_info_section.js.map +0 -1
  162. package/lib/commonjs/acmo/modules/dashboard/components/premium_option_1.js +0 -180
  163. package/lib/commonjs/acmo/modules/dashboard/components/premium_option_1.js.map +0 -1
  164. package/lib/commonjs/acmo/modules/dashboard/components/premium_option_2.js +0 -102
  165. package/lib/commonjs/acmo/modules/dashboard/components/premium_option_2.js.map +0 -1
  166. package/lib/commonjs/acmo/modules/dashboard/components/premium_option_3.js +0 -41
  167. package/lib/commonjs/acmo/modules/dashboard/components/premium_option_3.js.map +0 -1
  168. package/lib/commonjs/acmo/modules/dashboard/components/premium_option_4.js +0 -214
  169. package/lib/commonjs/acmo/modules/dashboard/components/premium_option_4.js.map +0 -1
  170. package/lib/module/acmo/core/marquee.js +0 -54
  171. package/lib/module/acmo/core/marquee.js.map +0 -1
  172. package/lib/module/acmo/modules/dashboard/components/auto_scroller.js +0 -81
  173. package/lib/module/acmo/modules/dashboard/components/auto_scroller.js.map +0 -1
  174. package/lib/module/acmo/modules/dashboard/components/my_games_button.js +0 -43
  175. package/lib/module/acmo/modules/dashboard/components/my_games_button.js.map +0 -1
  176. package/lib/module/acmo/modules/dashboard/components/offer_info_section.js +0 -153
  177. package/lib/module/acmo/modules/dashboard/components/offer_info_section.js.map +0 -1
  178. package/lib/module/acmo/modules/dashboard/components/premium_option_1.js +0 -174
  179. package/lib/module/acmo/modules/dashboard/components/premium_option_1.js.map +0 -1
  180. package/lib/module/acmo/modules/dashboard/components/premium_option_2.js +0 -97
  181. package/lib/module/acmo/modules/dashboard/components/premium_option_2.js.map +0 -1
  182. package/lib/module/acmo/modules/dashboard/components/premium_option_3.js +0 -36
  183. package/lib/module/acmo/modules/dashboard/components/premium_option_3.js.map +0 -1
  184. package/lib/module/acmo/modules/dashboard/components/premium_option_4.js +0 -209
  185. package/lib/module/acmo/modules/dashboard/components/premium_option_4.js.map +0 -1
  186. package/lib/typescript/commonjs/src/acmo/core/marquee.d.ts +0 -11
  187. package/lib/typescript/commonjs/src/acmo/core/marquee.d.ts.map +0 -1
  188. package/lib/typescript/commonjs/src/acmo/modules/dashboard/components/auto_scroller.d.ts +0 -10
  189. package/lib/typescript/commonjs/src/acmo/modules/dashboard/components/auto_scroller.d.ts.map +0 -1
  190. package/lib/typescript/commonjs/src/acmo/modules/dashboard/components/my_games_button.d.ts +0 -8
  191. package/lib/typescript/commonjs/src/acmo/modules/dashboard/components/my_games_button.d.ts.map +0 -1
  192. package/lib/typescript/commonjs/src/acmo/modules/dashboard/components/offer_info_section.d.ts +0 -11
  193. package/lib/typescript/commonjs/src/acmo/modules/dashboard/components/offer_info_section.d.ts.map +0 -1
  194. package/lib/typescript/commonjs/src/acmo/modules/dashboard/components/premium_option_1.d.ts +0 -9
  195. package/lib/typescript/commonjs/src/acmo/modules/dashboard/components/premium_option_1.d.ts.map +0 -1
  196. package/lib/typescript/commonjs/src/acmo/modules/dashboard/components/premium_option_2.d.ts +0 -9
  197. package/lib/typescript/commonjs/src/acmo/modules/dashboard/components/premium_option_2.d.ts.map +0 -1
  198. package/lib/typescript/commonjs/src/acmo/modules/dashboard/components/premium_option_3.d.ts +0 -9
  199. package/lib/typescript/commonjs/src/acmo/modules/dashboard/components/premium_option_3.d.ts.map +0 -1
  200. package/lib/typescript/commonjs/src/acmo/modules/dashboard/components/premium_option_4.d.ts +0 -9
  201. package/lib/typescript/commonjs/src/acmo/modules/dashboard/components/premium_option_4.d.ts.map +0 -1
  202. package/lib/typescript/module/src/acmo/core/marquee.d.ts +0 -11
  203. package/lib/typescript/module/src/acmo/core/marquee.d.ts.map +0 -1
  204. package/lib/typescript/module/src/acmo/modules/dashboard/components/auto_scroller.d.ts +0 -10
  205. package/lib/typescript/module/src/acmo/modules/dashboard/components/auto_scroller.d.ts.map +0 -1
  206. package/lib/typescript/module/src/acmo/modules/dashboard/components/my_games_button.d.ts +0 -8
  207. package/lib/typescript/module/src/acmo/modules/dashboard/components/my_games_button.d.ts.map +0 -1
  208. package/lib/typescript/module/src/acmo/modules/dashboard/components/offer_info_section.d.ts +0 -11
  209. package/lib/typescript/module/src/acmo/modules/dashboard/components/offer_info_section.d.ts.map +0 -1
  210. package/lib/typescript/module/src/acmo/modules/dashboard/components/premium_option_1.d.ts +0 -9
  211. package/lib/typescript/module/src/acmo/modules/dashboard/components/premium_option_1.d.ts.map +0 -1
  212. package/lib/typescript/module/src/acmo/modules/dashboard/components/premium_option_2.d.ts +0 -9
  213. package/lib/typescript/module/src/acmo/modules/dashboard/components/premium_option_2.d.ts.map +0 -1
  214. package/lib/typescript/module/src/acmo/modules/dashboard/components/premium_option_3.d.ts +0 -9
  215. package/lib/typescript/module/src/acmo/modules/dashboard/components/premium_option_3.d.ts.map +0 -1
  216. package/lib/typescript/module/src/acmo/modules/dashboard/components/premium_option_4.d.ts +0 -9
  217. package/lib/typescript/module/src/acmo/modules/dashboard/components/premium_option_4.d.ts.map +0 -1
  218. package/src/acmo/core/marquee.tsx +0 -62
  219. package/src/acmo/modules/dashboard/components/auto_scroller.tsx +0 -85
  220. package/src/acmo/modules/dashboard/components/my_games_button.tsx +0 -40
  221. package/src/acmo/modules/dashboard/components/offer_info_section.tsx +0 -139
  222. package/src/acmo/modules/dashboard/components/premium_option_1.tsx +0 -163
  223. package/src/acmo/modules/dashboard/components/premium_option_2.tsx +0 -100
  224. package/src/acmo/modules/dashboard/components/premium_option_3.tsx +0 -42
  225. package/src/acmo/modules/dashboard/components/premium_option_4.tsx +0 -185
@@ -112,6 +112,6 @@ dependencies {
112
112
  implementation "com.facebook.react:react-native:+"
113
113
  implementation 'com.google.code.gson:gson:+'
114
114
 
115
- implementation 'com.github.tyrads-com:tyrads-sdk-android:28eccaa687'
115
+ implementation 'com.github.tyrads-com:tyrads-sdk-android:debd5714c1'
116
116
  }
117
117
 
@@ -48,10 +48,27 @@ class TyradsSdkModule(reactContext: ReactApplicationContext) :
48
48
  }
49
49
  }
50
50
  @ReactMethod
51
- fun showOffers(route: String? = null, campaignID: Int? = null) {
52
- Tyrads.getInstance().tyradScope.launch {
53
- Tyrads.getInstance().showOffers(route = route, campaignID = campaignID)
54
- }
51
+ fun showOffers(route: String? = null, promise: Promise) {
52
+ Tyrads.getInstance().tyradScope.launch {
53
+ try {
54
+ Tyrads.getInstance().showOffers(route = route, campaignID = null)
55
+ promise.resolve(true)
56
+ } catch (e: Exception) {
57
+ promise.reject("SHOW_OFFERS_ERROR", e.message)
58
+ }
59
+ }
60
+ }
61
+
62
+ @ReactMethod
63
+ fun showOfferDetails(route: String? = null, campaignID: Int? = null, promise: Promise) {
64
+ Tyrads.getInstance().tyradScope.launch {
65
+ try {
66
+ Tyrads.getInstance().showOffers(route = route, campaignID = campaignID)
67
+ promise.resolve(true)
68
+ } catch (e: Exception) {
69
+ promise.reject("SHOW_OFFERS_ERROR", e.message)
70
+ }
71
+ }
55
72
  }
56
73
 
57
74
  companion object {
@@ -15,11 +15,13 @@ struct UserData: Codable {
15
15
  let newRegisteredUser: Bool
16
16
  let user: User
17
17
  let publisherApp: PublisherApp
18
+ let token: String
18
19
 
19
20
  enum CodingKeys: String, CodingKey {
20
21
  case newRegisteredUser = "newRegisteredUser"
21
22
  case user
22
23
  case publisherApp
24
+ case token
23
25
  }
24
26
 
25
27
  init(from decoder: Decoder) throws {
@@ -27,6 +29,7 @@ struct UserData: Codable {
27
29
  newRegisteredUser = try container.decodeIfPresent(Bool.self, forKey: .newRegisteredUser) ?? false
28
30
  user = try container.decode(User.self, forKey: .user)
29
31
  publisherApp = try container.decode(PublisherApp.self, forKey: .publisherApp)
32
+ token = try container.decode(String.self, forKey: .token)
30
33
  }
31
34
  }
32
35
 
@@ -15,10 +15,12 @@ public class Tyrads : NSObject {
15
15
  private var apiSecret: String = ""
16
16
  private var encKey: String?
17
17
  private var publisherUserID: String = ""
18
+ private var token: String = ""
18
19
  private var currentLanguage: String = "en"
19
20
  private var newUser: Bool = false
20
21
  private var loginData: AcmoInitModel?
21
22
  var initializationWait = DispatchSemaphore(value: 0)
23
+ private var initializationContinuation: CheckedContinuation<Void, Never>?
22
24
  private var debugMode: Bool = false
23
25
 
24
26
  private var _isSecure: Bool = false
@@ -33,6 +35,14 @@ public class Tyrads : NSObject {
33
35
  NSLog(message)
34
36
  }
35
37
  }
38
+
39
+ private func ensureInitialized() async {
40
+ guard self.token.isEmpty else { return }
41
+
42
+ await withCheckedContinuation { continuation in
43
+ self.initializationContinuation = continuation
44
+ }
45
+ }
36
46
 
37
47
  /// Configures the Tyrads SDK with the provided API key and secret key.
38
48
  ///
@@ -51,136 +61,115 @@ public class Tyrads : NSObject {
51
61
  /// Logs in the user with the provided user ID or retrieves the user ID from UserDefaults.
52
62
  ///
53
63
  /// - Parameter userID: Optional. The user ID to log in with. If nil, the SDK will attempt to retrieve the user ID from UserDefaults.
54
- public func loginUser(_ userID: String? = nil, completion: @escaping (ApiHeaders?) -> Void) {
64
+ public func loginUser(_ userID: String? = nil) async throws -> ApiHeaders? {
55
65
  let userId = userID ?? UserDefaults.standard.string(forKey: "acmo-tyrads-sdk-user-id") ?? ""
56
-
57
66
  let identifierType = "IDFA"
58
67
  var advertisingId = ""
59
68
 
60
- func finalizeLogin() {
61
- let fd: [String: Any] = [
62
- "publisherUserId": userId,
63
- "platform": "iOS",
64
- "identifierType": identifierType,
65
- "identifier": advertisingId
66
- ]
67
-
68
- self.log("Initializing with data: \(fd)")
69
-
70
- guard let url = URL(string: AcmoConfig.BASE_URL + "initialize") else {
71
- self.log("Failed to create URL")
72
- completion(nil)
73
- return
74
- }
75
-
76
- var request = URLRequest(url: url)
77
- request.httpMethod = "POST"
78
- request.setValue(AcmoConfig.SDK_PLATFORM, forHTTPHeaderField: "X-SDK-Platform")
79
- request.setValue(AcmoConfig.SDK_VERSION, forHTTPHeaderField: "X-SDK-Version")
80
- request.setValue("application/json", forHTTPHeaderField: "Content-Type")
81
- request.setValue(self.apiKey, forHTTPHeaderField: "X-API-Key")
82
- request.setValue(self.apiSecret, forHTTPHeaderField: "X-API-Secret")
83
- request.setValue(_isSecure ? "BASIC" : "PLAIN", forHTTPHeaderField: "X-Secure-Mode")
84
-
85
- do {
86
- let requestBody = _isSecure && !(encKey ?? "").isEmpty
87
- ? try AcmoEncrypt(encKey!).encryptDataAESGCM(data: fd)
88
- : fd
89
-
90
- print("Req Body: \(requestBody)")
91
-
92
- request.httpBody = try JSONSerialization.data(withJSONObject: requestBody)
93
- } catch {
94
- self.log("Failed to serialize request body: \(error)")
95
- completion(nil)
96
- return
97
- }
98
-
99
- let task = URLSession.shared.dataTask(with: request) { data, response, error in
100
- if let error = error {
101
- self.log("Network request failed: \(error)")
102
- completion(nil)
103
- return
104
- }
105
-
106
- guard let data = data else {
107
- self.log("No data received from the server")
108
- completion(nil)
109
- return
110
- }
111
-
112
- if let responseString = String(data: data, encoding: .utf8) {
113
- self.log("Received response: \(responseString)")
114
-
115
- guard let jsonData = responseString.data(using: .utf8),
116
- let acmoInitModel = try? JSONDecoder().decode(AcmoInitModel.self, from: jsonData) else {
117
- self.log("Failed to decode response")
118
- completion(nil)
119
- return
120
- }
121
-
122
- self.loginData = acmoInitModel
123
- self.publisherUserID = acmoInitModel.data.user.publisherUserId
124
- self.newUser = acmoInitModel.data.newRegisteredUser
125
- self.log("Login successful. Publisher User ID: \(self.publisherUserID), New User: \(self.newUser)")
126
- self.initializationWait.signal()
127
-
128
- // Build ApiHeaders object
129
- let headers = ApiHeaders(
130
- xApiKey: self.apiKey,
131
- xApiSecret: self.apiSecret,
132
- xUserId: self.publisherUserID,
133
- xSdkPlatform: AcmoConfig.SDK_PLATFORM,
134
- xSdkVersion: AcmoConfig.SDK_VERSION,
135
- userAgent: UIDevice.current.systemName + "/" + UIDevice.current.systemVersion,
136
- languageCode: Locale.current.languageCode ?? "en",
137
- premiumColor: acmoInitModel.data.publisherApp.premiumColor,
138
- headerColor: acmoInitModel.data.publisherApp.headerColor,
139
- mainColor: acmoInitModel.data.publisherApp.mainColor
140
- )
141
-
142
- completion(headers)
143
- }
144
- }
145
-
146
- task.resume()
147
- self.log("Network request started")
148
- }
149
-
150
69
  if #available(iOS 14, *) {
151
70
  self.log("Requesting tracking authorization for iOS 14+")
152
- ATTrackingManager.requestTrackingAuthorization { status in
153
- switch status {
154
- case .authorized:
155
- advertisingId = ASIdentifierManager.shared().advertisingIdentifier.uuidString
156
- self.log("Tracking authorized. Advertising ID: \(advertisingId)")
157
- case .denied, .restricted, .notDetermined:
158
- advertisingId = ""
159
- self.log("Tracking not authorized or restricted")
160
- @unknown default:
161
- self.log("Unknown tracking status")
162
- }
163
- finalizeLogin()
71
+ let status = await ATTrackingManager.requestTrackingAuthorization()
72
+ switch status {
73
+ case .authorized:
74
+ advertisingId = ASIdentifierManager.shared().advertisingIdentifier.uuidString
75
+ self.log("Tracking authorized. Advertising ID: \(advertisingId)")
76
+ case .denied, .restricted, .notDetermined:
77
+ advertisingId = ""
78
+ self.log("Tracking not authorized or restricted")
79
+ @unknown default:
80
+ self.log("Unknown tracking status")
164
81
  }
165
82
  } else {
166
83
  advertisingId = ASIdentifierManager.shared().advertisingIdentifier.uuidString
167
84
  self.log("iOS version < 14. Advertising ID: \(advertisingId)")
168
- finalizeLogin()
169
85
  }
170
- }
171
-
172
86
 
87
+ let deviceDetails = getDeviceDetails()
88
+ let fd: [String: Any] = [
89
+ "publisherUserId": userId,
90
+ "platform": "iOS",
91
+ "identifierType": identifierType,
92
+ "identifier": advertisingId,
93
+ "deviceData": deviceDetails
94
+ ]
95
+
96
+ self.log("Initializing with data: \(fd)")
97
+ guard let url = URL(string: AcmoConfig.BASE_URL + "initialize") else {
98
+ self.log("Failed to create URL")
99
+ throw NSError(domain: "TyradsSdk", code: 1, userInfo: [NSLocalizedDescriptionKey: "Invalid URL"])
100
+ }
173
101
 
102
+ var request = URLRequest(url: url)
103
+ request.httpMethod = "POST"
104
+ request.setValue(AcmoConfig.SDK_PLATFORM, forHTTPHeaderField: "X-SDK-Platform")
105
+ request.setValue(AcmoConfig.SDK_VERSION, forHTTPHeaderField: "X-SDK-Version")
106
+ request.setValue("application/json", forHTTPHeaderField: "Content-Type")
107
+ request.setValue(self.apiKey, forHTTPHeaderField: "X-API-Key")
108
+ request.setValue(self.apiSecret, forHTTPHeaderField: "X-API-Secret")
109
+ request.setValue(_isSecure ? "BASIC" : "PLAIN", forHTTPHeaderField: "X-Secure-Mode")
110
+
111
+ do {
112
+ let requestBody = _isSecure && !(encKey ?? "").isEmpty ? try AcmoEncrypt(encKey!).encryptDataAESGCM(data: fd) : fd
113
+ request.httpBody = try JSONSerialization.data(withJSONObject: requestBody)
114
+ } catch {
115
+ self.log("Failed to serialize request body: \(error)")
116
+ throw error
117
+ }
118
+
119
+ // Use the async URLSession API to get data
120
+ let (data, _) = try await URLSession.shared.data(for: request)
121
+
122
+ let responseString = String(data: data, encoding: .utf8)
123
+ self.log("Received response: \(responseString ?? "nil")")
174
124
 
175
- public func showOffers(_ launchMode: Int = 3, route: String? = nil, campaignID: Int? = nil) {
176
- self.initializationWait.wait()
177
- var campaignIDString: String = "0"
178
- if let campaignIDValue = campaignID {
179
- campaignIDString = String(campaignIDValue)
125
+ guard let acmoInitModel = try? JSONDecoder().decode(AcmoInitModel.self, from: data) else {
126
+ self.log("Failed to decode response")
127
+ throw NSError(domain: "TyradsSdk", code: 2, userInfo: [NSLocalizedDescriptionKey: "Failed to decode response"])
180
128
  }
181
- let urlString =
182
- "https://websdk.tyrads.com/?apiKey=\(Tyrads.instance.apiKey)&apiSecret=\(Tyrads.instance.apiSecret)&encKey=\(Tyrads.instance.encKey ?? "")&userID=\(Tyrads.instance.publisherUserID)&newUser=\(Tyrads.instance.newUser)&platform=\(AcmoConfig.SDK_PLATFORM)&hc=\(Tyrads.instance.loginData?.data.publisherApp.headerColor ?? "")&mc=\(Tyrads.instance.loginData?.data.publisherApp.mainColor ?? "")&pc=\(Tyrads.instance.loginData?.data.publisherApp.premiumColor ?? "")&launchMode=\(launchMode)&route=\(route ?? "")&campaignID=\(campaignIDString)&lang=\(Tyrads.instance.currentLanguage)&av=\(AcmoConfig.ACMO_VERSION)&sdkVersion=\(AcmoConfig.SDK_VERSION)"
183
129
 
130
+ self.loginData = acmoInitModel
131
+ self.publisherUserID = acmoInitModel.data.user.publisherUserId
132
+ self.newUser = acmoInitModel.data.newRegisteredUser
133
+ self.token = acmoInitModel.data.token
134
+ self.log("Login successful. Publisher User ID: \(self.publisherUserID), New User: \(self.newUser)")
135
+
136
+ let headers = await ApiHeaders(
137
+ xApiKey: self.apiKey,
138
+ xApiSecret: self.apiSecret,
139
+ xUserId: self.publisherUserID,
140
+ xSdkPlatform: AcmoConfig.SDK_PLATFORM,
141
+ xSdkVersion: AcmoConfig.SDK_VERSION,
142
+ userAgent: UIDevice.current.systemName + "/" + UIDevice.current.systemVersion,
143
+ languageCode: Locale.current.languageCode ?? "en",
144
+ premiumColor: acmoInitModel.data.publisherApp.premiumColor,
145
+ headerColor: acmoInitModel.data.publisherApp.headerColor,
146
+ mainColor: acmoInitModel.data.publisherApp.mainColor
147
+ )
148
+ return headers
149
+ }
150
+
151
+
152
+
153
+
154
+ public func showOffers(_ launchMode: Int = 3, route: String? = nil, campaignID: Int? = nil) async {
155
+ // self.initializationWait.wait()
156
+ await ensureInitialized()
157
+ var components = URLComponents()
158
+ components.scheme = "https"
159
+ components.host = "sdk.tyrads.com"
160
+ // components.path = "/\(route ?? "")"
161
+ components.queryItems = [
162
+ URLQueryItem(name: "token", value: self.token),
163
+ URLQueryItem(name: "to", value: campaignID != nil ? "\(route ?? "")/\(campaignID!)" : route)
164
+ ]
165
+ var urlString: String = ""
166
+ if let url = components.url {
167
+ urlString = url.absoluteString
168
+ print(urlString)
169
+ } else {
170
+ print("Failed to create URL with components: \(components)")
171
+ }
172
+
184
173
  do {
185
174
  guard let url = URL(string: urlString) else {
186
175
  throw NSError(domain: "TyradsSdk", code: 1, userInfo: [NSLocalizedDescriptionKey: "Invalid URL"])
@@ -189,27 +178,11 @@ public class Tyrads : NSObject {
189
178
  switch launchMode {
190
179
  case 1, 2:
191
180
  DispatchQueue.main.async {
192
- let config = WKWebViewConfiguration()
193
- let userContentController = WKUserContentController()
194
-
195
- userContentController.add(self, name: "clickHandler")
196
- config.userContentController = userContentController
197
-
198
- let webView = WKWebView(frame: UIScreen.main.bounds, configuration: config)
199
- webView.navigationDelegate = self
200
-
201
- if #available(iOS 16.4, *) {
202
- webView.isInspectable = true
203
- }
204
-
205
- let viewController = UIViewController()
206
- viewController.view = webView
207
- viewController.modalPresentationStyle = .fullScreen
208
-
209
- webView.load(URLRequest(url: url))
181
+ let acmoVC = AcmoWebViewController(url: url)
182
+ acmoVC.modalPresentationStyle = .fullScreen
210
183
 
211
184
  if let rootViewController = UIApplication.shared.windows.first?.rootViewController {
212
- rootViewController.present(viewController, animated: true, completion: nil)
185
+ rootViewController.present(acmoVC, animated: true, completion: nil)
213
186
  }
214
187
  }
215
188
  case 3:
@@ -226,61 +199,3 @@ public class Tyrads : NSObject {
226
199
  }
227
200
  }
228
201
  }
229
-
230
-
231
- extension Tyrads: WKScriptMessageHandler {
232
- public func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
233
- guard message.name == "clickHandler",
234
- let messageDict = message.body as? [String: Any] else {
235
- return
236
- }
237
- print("Message data: \(messageDict)")
238
-
239
- if let action = messageDict["action"] as? String {
240
- switch action {
241
- case "closeWebview":
242
- DispatchQueue.main.async {
243
- UIApplication.shared.windows.first?.rootViewController?.dismiss(animated: true)
244
- }
245
-
246
- case "changeLanguage":
247
- if let langCode = messageDict["languageCode"] as? String {
248
- // Handle language change
249
- self.currentLanguage = langCode
250
- }
251
-
252
- default:
253
- print("Unknown command: \(action)")
254
- }
255
- }
256
- }
257
- }
258
-
259
- extension Tyrads: WKNavigationDelegate {
260
- public func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
261
- let js = """
262
- window.addEventListener('message', (event) => {
263
- try {
264
- const message = typeof event.data === 'string'
265
- ? JSON.parse(event.data)
266
- : event.data;
267
- if (message && message.command === 'webview_command') {
268
- window.webkit.messageHandlers.clickHandler.postMessage({
269
- command: message.command,
270
- action: message.action,
271
- languageCode: message.languageCode
272
- });
273
- }
274
- } catch (error) {
275
- console.log('Message handling error:', error);
276
- }
277
- });
278
- """
279
-
280
- webView.evaluateJavaScript(js) { _, error in
281
- if let error = error {
282
- print("JavaScript injection failed: \(error)")
283
- }
284
- }
285
- }
286
- }
@@ -0,0 +1,171 @@
1
+ import UIKit
2
+ @preconcurrency import WebKit
3
+
4
+ class AcmoWebViewController: UIViewController, WKNavigationDelegate, WKScriptMessageHandler, WKUIDelegate {
5
+
6
+ var webView: WKWebView!
7
+ var initialURL: URL
8
+
9
+ private let internalDomains: [String] = ["sdk.tyrads.com", "acmo.in"]
10
+
11
+ private func log(_ message: String) {
12
+ NSLog("AcmoWebViewController: \(message)")
13
+ }
14
+
15
+ init(url: URL) {
16
+ self.initialURL = url
17
+ super.init(nibName: nil, bundle: nil)
18
+ }
19
+
20
+ required init?(coder: NSCoder) {
21
+ fatalError("init(coder:) has not been implemented")
22
+ }
23
+
24
+ override func viewDidLoad() {
25
+ super.viewDidLoad()
26
+ log("viewDidLoad called")
27
+
28
+ let config = WKWebViewConfiguration()
29
+ let userContentController = WKUserContentController()
30
+
31
+ userContentController.add(self, name: "clickHandler")
32
+ config.userContentController = userContentController
33
+
34
+ webView = WKWebView(frame: self.view.bounds, configuration: config)
35
+ webView.navigationDelegate = self
36
+ webView.uiDelegate = self
37
+ self.view.addSubview(webView)
38
+
39
+ webView.translatesAutoresizingMaskIntoConstraints = false
40
+ NSLayoutConstraint.activate([
41
+ webView.topAnchor.constraint(equalTo: self.view.topAnchor),
42
+ webView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor),
43
+ webView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor),
44
+ webView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor)
45
+ ])
46
+
47
+ if #available(iOS 16.4, *) {
48
+ webView.isInspectable = true
49
+ }
50
+
51
+ webView.load(URLRequest(url: initialURL))
52
+ log("WebView loaded URL: \(initialURL.absoluteString)")
53
+ }
54
+
55
+ public func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
56
+ guard message.name == "clickHandler",
57
+ let messageDict = message.body as? [String: Any] else {
58
+ log("Received unknown message or invalid format.")
59
+ return
60
+ }
61
+
62
+ log("Message data from webview: \(messageDict)")
63
+
64
+ if let action = messageDict["action"] as? String {
65
+ switch action {
66
+ case "closeWebView":
67
+ log("Action: closeWebView received. Dismissing view controller.")
68
+ DispatchQueue.main.async {
69
+ self.dismiss(animated: true) {
70
+ self.log("ViewController dismissed successfully.")
71
+ }
72
+ }
73
+
74
+ case "changeLanguage":
75
+ if let langCode = messageDict["languageCode"] as? String {
76
+ log("Action: changeLanguage received. Language Code: \(langCode)")
77
+ }
78
+
79
+ default:
80
+ log("Unknown command: \(action)")
81
+ }
82
+ }
83
+ }
84
+
85
+ public func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
86
+ if let url = webView.url {
87
+ print("Page loaded successfully. Final URL: \(url.absoluteString)")
88
+ }
89
+
90
+ let js = """
91
+ window.addEventListener('message', (event) => {
92
+ try {
93
+ // Safely parse JSON if event.data is a string, otherwise use directly
94
+ const message = typeof event.data === 'string'
95
+ ? JSON.parse(event.data)
96
+ : event.data;
97
+ if (message) {
98
+ // Post the message to the native side using the registered handler name
99
+ window.webkit.messageHandlers.clickHandler.postMessage(message);
100
+ }
101
+ } catch (error) {
102
+ console.error('Error handling message from WebView:', error);
103
+ }
104
+ });
105
+ """
106
+
107
+ webView.evaluateJavaScript(js) { _, error in
108
+ if let error = error {
109
+ self.log("JavaScript injection failed: \(error.localizedDescription)")
110
+ } else {
111
+ self.log("JavaScript listener injected successfully.")
112
+ }
113
+ }
114
+ }
115
+
116
+ func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
117
+
118
+ guard let url = navigationAction.request.url, let host = url.host else {
119
+ decisionHandler(.cancel)
120
+ return
121
+ }
122
+
123
+ if host == "about:blank" {
124
+ decisionHandler(.allow)
125
+ return
126
+ }
127
+
128
+ let isInternalDomain = internalDomains.contains(where: { host.hasSuffix($0) })
129
+
130
+ if host != webView.url?.host && !isInternalDomain {
131
+ log("Intercepted external URL via navigation action: \(url.absoluteString). Opening externally.")
132
+ UIApplication.shared.open(url, options: [:], completionHandler: nil)
133
+ decisionHandler(.cancel)
134
+ return
135
+ }
136
+
137
+ log("Allowed navigation to: \(url.absoluteString)")
138
+ decisionHandler(.allow)
139
+ }
140
+
141
+ func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? {
142
+
143
+ guard let url = navigationAction.request.url else {
144
+ return nil
145
+ }
146
+
147
+ let isInternalDomain = internalDomains.contains(where: { url.host?.hasSuffix($0) ?? false })
148
+
149
+ if !isInternalDomain {
150
+ log("Intercepted new window via UI delegate: \(url.absoluteString). Opening externally.")
151
+ UIApplication.shared.open(url, options: [:], completionHandler: nil)
152
+ return nil
153
+ }
154
+
155
+ log("Allowed new window for internal domain: \(url.absoluteString)")
156
+ return nil
157
+ }
158
+
159
+ public func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
160
+ log("WebView navigation failed with error: \(error.localizedDescription)")
161
+ }
162
+
163
+ public func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) {
164
+ log("WebView provisional navigation failed with error: \(error.localizedDescription)")
165
+ }
166
+
167
+ deinit {
168
+ webView.configuration.userContentController.removeScriptMessageHandler(forName: "clickHandler")
169
+ log("AcmoWebViewController deinitialized. Message handler removed.")
170
+ }
171
+ }
@@ -0,0 +1,58 @@
1
+ import UIKit
2
+
3
+ func getDeviceDetails() -> [String: Any] {
4
+ var fd = [String: Any]()
5
+
6
+ let device = UIDevice.current
7
+ let bundle = Bundle.main
8
+ let locale = Locale.current
9
+
10
+ // Device basic info
11
+ fd["deviceId"] = device.identifierForVendor?.uuidString ?? "Unknown"
12
+ fd["device"] = device.model.lowercased().contains("ipad") ? "iPad" : "iPhone"
13
+ fd["deviceName"] = device.name
14
+ fd["brand"] = "Apple"
15
+ fd["model"] = device.model
16
+ fd["baseOs"] = device.systemName
17
+ fd["releaseVersion"] = device.systemVersion
18
+
19
+ // App info
20
+ fd["version"] = bundle.infoDictionary?["CFBundleShortVersionString"] as? String ?? "Unknown"
21
+ fd["build"] = bundle.infoDictionary?["CFBundleVersion"] as? String ?? "Unknown"
22
+ fd["package"] = bundle.bundleIdentifier ?? "Unknown"
23
+ fd["installerStore"] = "App Store"
24
+
25
+ fd["osLang"] = locale.languageCode ?? "en"
26
+
27
+ // security and virtual check
28
+ fd["rooted"] = isJailBroken()
29
+ fd["virtual"] = isRunningOnSimulator()
30
+
31
+ return fd
32
+ }
33
+
34
+ func isRunningOnSimulator() -> Bool {
35
+ return ProcessInfo().environment["SIMULATOR_DEVICE_NAME"] != nil
36
+ }
37
+
38
+ func isJailBroken() -> Bool {
39
+ #if targetEnvironment(simulator)
40
+ return false
41
+ #else
42
+ let paths = [
43
+ "/Applications/Cydia.app",
44
+ "/Library/MobileSubstrate/MobileSubstrate.dylib",
45
+ "/bin/bash",
46
+ "/usr/sbin/sshd",
47
+ "/etc/apt",
48
+ "/private/var/lib/apt/"
49
+ ]
50
+ for path in paths {
51
+ if FileManager.default.fileExists(atPath: path) {
52
+ return true
53
+ }
54
+ }
55
+ return false
56
+ #endif
57
+ }
58
+
package/ios/TyradsSdk.mm CHANGED
@@ -11,6 +11,12 @@ RCT_EXTERN_METHOD(loginUser:(NSString *)userId
11
11
  rejecter:(RCTPromiseRejectBlock)reject)
12
12
  RCT_EXTERN_METHOD(showOffers:(NSInteger)launchMode
13
13
  route:(NSString)route
14
- campaignID:(NSInteger)campaignID)
14
+ resolver:(RCTPromiseResolveBlock)resolve
15
+ rejecter:(RCTPromiseRejectBlock)reject)
16
+ RCT_EXTERN_METHOD(showOfferDetails:(NSInteger)launchMode
17
+ route:(NSString)route
18
+ campaignID:(NSInteger)campaignID
19
+ resolver:(RCTPromiseResolveBlock)resolve
20
+ rejecter:(RCTPromiseRejectBlock)reject)
15
21
 
16
22
  @end