react-native-iap 13.0.4 → 14.0.0-rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (381) hide show
  1. package/NitroIap.podspec +33 -0
  2. package/README.md +163 -51
  3. package/android/CMakeLists.txt +32 -0
  4. package/android/build.gradle +107 -138
  5. package/android/fix-prefab.gradle +51 -0
  6. package/android/gradle.properties +5 -13
  7. package/android/src/main/AndroidManifest.xml +1 -4
  8. package/android/src/main/cpp/cpp-adapter.cpp +6 -0
  9. package/android/src/main/java/com/margelo/nitro/iap/HybridRnIap.kt +843 -0
  10. package/android/src/main/java/com/margelo/nitro/iap/NitroIapPackage.java +33 -0
  11. package/android/src/main/java/com/margelo/nitro/iap/Types.kt +173 -0
  12. package/ios/Bridge.h +8 -0
  13. package/ios/ErrorUtils.swift +153 -0
  14. package/ios/HybridRnIap.swift +1326 -0
  15. package/ios/ProductStore.swift +33 -0
  16. package/ios/reactnativeiap.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
  17. package/ios/reactnativeiap.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
  18. package/lib/module/helpers/subscription.js +56 -0
  19. package/lib/module/helpers/subscription.js.map +1 -0
  20. package/lib/module/hooks/useIAP.js +175 -123
  21. package/lib/module/hooks/useIAP.js.map +1 -1
  22. package/lib/module/index.js +1015 -9
  23. package/lib/module/index.js.map +1 -1
  24. package/lib/module/package.json +1 -0
  25. package/lib/module/specs/RnIap.nitro.js +4 -0
  26. package/lib/{commonjs/modules/common.js.map → module/specs/RnIap.nitro.js.map} +1 -1
  27. package/lib/module/types.js +187 -0
  28. package/lib/module/types.js.map +1 -0
  29. package/lib/module/utils/error.js +80 -0
  30. package/lib/module/utils/error.js.map +1 -0
  31. package/lib/module/utils/type-bridge.js +202 -0
  32. package/lib/module/utils/type-bridge.js.map +1 -0
  33. package/lib/typescript/package.json +1 -0
  34. package/lib/typescript/plugin/src/withIAP.d.ts +2 -7
  35. package/lib/typescript/plugin/src/withIAP.d.ts.map +1 -1
  36. package/lib/typescript/scripts/check-nitro-versions.d.ts +3 -0
  37. package/lib/typescript/scripts/check-nitro-versions.d.ts.map +1 -0
  38. package/lib/typescript/src/helpers/subscription.d.ts +14 -0
  39. package/lib/typescript/src/helpers/subscription.d.ts.map +1 -0
  40. package/lib/typescript/src/hooks/useIAP.d.ts +42 -26
  41. package/lib/typescript/src/hooks/useIAP.d.ts.map +1 -1
  42. package/lib/typescript/src/index.d.ts +356 -8
  43. package/lib/typescript/src/index.d.ts.map +1 -1
  44. package/lib/typescript/src/specs/RnIap.nitro.d.ts +404 -0
  45. package/lib/typescript/src/specs/RnIap.nitro.d.ts.map +1 -0
  46. package/lib/typescript/src/types.d.ts +544 -0
  47. package/lib/typescript/src/types.d.ts.map +1 -0
  48. package/lib/typescript/src/utils/error.d.ts +30 -0
  49. package/lib/typescript/src/utils/error.d.ts.map +1 -0
  50. package/lib/typescript/src/utils/type-bridge.d.ts +40 -0
  51. package/lib/typescript/src/utils/type-bridge.d.ts.map +1 -0
  52. package/nitro.json +17 -0
  53. package/nitrogen/generated/android/NitroIap+autolinking.cmake +80 -0
  54. package/nitrogen/generated/android/NitroIap+autolinking.gradle +27 -0
  55. package/nitrogen/generated/android/NitroIapOnLoad.cpp +50 -0
  56. package/nitrogen/generated/android/NitroIapOnLoad.hpp +25 -0
  57. package/nitrogen/generated/android/c++/JFunc_void_NitroProduct.hpp +78 -0
  58. package/nitrogen/generated/android/c++/JFunc_void_NitroPurchase.hpp +78 -0
  59. package/nitrogen/generated/android/c++/JFunc_void_NitroPurchaseResult.hpp +78 -0
  60. package/nitrogen/generated/android/c++/JHybridRnIapSpec.cpp +577 -0
  61. package/nitrogen/generated/android/c++/JHybridRnIapSpec.hpp +93 -0
  62. package/nitrogen/generated/android/c++/JNitroAndroidReceiptValidationOptions.hpp +66 -0
  63. package/nitrogen/generated/android/c++/JNitroAvailablePurchasesAndroidOptions.hpp +54 -0
  64. package/nitrogen/generated/android/c++/JNitroAvailablePurchasesIosOptions.hpp +65 -0
  65. package/nitrogen/generated/android/c++/JNitroAvailablePurchasesOptions.hpp +62 -0
  66. package/nitrogen/generated/android/c++/JNitroFinishTransactionAndroidParams.hpp +58 -0
  67. package/nitrogen/generated/android/c++/JNitroFinishTransactionIosParams.hpp +53 -0
  68. package/nitrogen/generated/android/c++/JNitroFinishTransactionParams.hpp +62 -0
  69. package/nitrogen/generated/android/c++/JNitroProduct.hpp +154 -0
  70. package/nitrogen/generated/android/c++/JNitroPurchase.hpp +122 -0
  71. package/nitrogen/generated/android/c++/JNitroPurchaseRequest.hpp +66 -0
  72. package/nitrogen/generated/android/c++/JNitroPurchaseResult.hpp +70 -0
  73. package/nitrogen/generated/android/c++/JNitroReceiptValidationParams.hpp +60 -0
  74. package/nitrogen/generated/android/c++/JNitroReceiptValidationResultAndroid.hpp +122 -0
  75. package/nitrogen/generated/android/c++/JNitroReceiptValidationResultIOS.hpp +68 -0
  76. package/nitrogen/generated/android/c++/JNitroRequestPurchaseAndroid.hpp +115 -0
  77. package/nitrogen/generated/android/c++/JNitroRequestPurchaseIos.hpp +84 -0
  78. package/nitrogen/generated/android/c++/JNitroSubscriptionOffer.hpp +57 -0
  79. package/nitrogen/generated/android/c++/JNitroSubscriptionRenewalInfo.hpp +74 -0
  80. package/nitrogen/generated/android/c++/JNitroSubscriptionStatus.hpp +64 -0
  81. package/nitrogen/generated/android/c++/JVariant_Boolean_NitroPurchaseResult.cpp +26 -0
  82. package/nitrogen/generated/android/c++/JVariant_Boolean_NitroPurchaseResult.hpp +71 -0
  83. package/nitrogen/generated/android/c++/JVariant_NitroReceiptValidationResultIOS_NitroReceiptValidationResultAndroid.cpp +26 -0
  84. package/nitrogen/generated/android/c++/JVariant_NitroReceiptValidationResultIOS_NitroReceiptValidationResultAndroid.hpp +75 -0
  85. package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/Func_void_NitroProduct.kt +81 -0
  86. package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/Func_void_NitroPurchase.kt +81 -0
  87. package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/Func_void_NitroPurchaseResult.kt +81 -0
  88. package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/HybridRnIapSpec.kt +198 -0
  89. package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/NitroAndroidReceiptValidationOptions.kt +38 -0
  90. package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/NitroAvailablePurchasesAndroidOptions.kt +29 -0
  91. package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/NitroAvailablePurchasesIosOptions.kt +38 -0
  92. package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/NitroAvailablePurchasesOptions.kt +32 -0
  93. package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/NitroFinishTransactionAndroidParams.kt +32 -0
  94. package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/NitroFinishTransactionIosParams.kt +29 -0
  95. package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/NitroFinishTransactionParams.kt +32 -0
  96. package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/NitroIapOnLoad.kt +35 -0
  97. package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/NitroProduct.kt +104 -0
  98. package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/NitroPurchase.kt +80 -0
  99. package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/NitroPurchaseRequest.kt +32 -0
  100. package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/NitroPurchaseResult.kt +41 -0
  101. package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/NitroReceiptValidationParams.kt +32 -0
  102. package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/NitroReceiptValidationResultAndroid.kt +80 -0
  103. package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/NitroReceiptValidationResultIOS.kt +38 -0
  104. package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/NitroRequestPurchaseAndroid.kt +47 -0
  105. package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/NitroRequestPurchaseIos.kt +41 -0
  106. package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/NitroSubscriptionOffer.kt +32 -0
  107. package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/NitroSubscriptionRenewalInfo.kt +44 -0
  108. package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/NitroSubscriptionStatus.kt +35 -0
  109. package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/Variant_Boolean_NitroPurchaseResult.kt +42 -0
  110. package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/Variant_NitroReceiptValidationResultIOS_NitroReceiptValidationResultAndroid.kt +42 -0
  111. package/nitrogen/generated/ios/NitroIap+autolinking.rb +60 -0
  112. package/nitrogen/generated/ios/NitroIap-Swift-Cxx-Bridge.cpp +152 -0
  113. package/nitrogen/generated/ios/NitroIap-Swift-Cxx-Bridge.hpp +1061 -0
  114. package/nitrogen/generated/ios/NitroIap-Swift-Cxx-Umbrella.hpp +107 -0
  115. package/nitrogen/generated/ios/NitroIapAutolinking.mm +33 -0
  116. package/nitrogen/generated/ios/NitroIapAutolinking.swift +25 -0
  117. package/nitrogen/generated/ios/c++/HybridRnIapSpecSwift.cpp +11 -0
  118. package/nitrogen/generated/ios/c++/HybridRnIapSpecSwift.hpp +355 -0
  119. package/nitrogen/generated/ios/swift/Func_void.swift +47 -0
  120. package/nitrogen/generated/ios/swift/Func_void_NitroProduct.swift +47 -0
  121. package/nitrogen/generated/ios/swift/Func_void_NitroPurchase.swift +47 -0
  122. package/nitrogen/generated/ios/swift/Func_void_NitroPurchaseResult.swift +47 -0
  123. package/nitrogen/generated/ios/swift/Func_void_bool.swift +47 -0
  124. package/nitrogen/generated/ios/swift/Func_void_std__exception_ptr.swift +47 -0
  125. package/nitrogen/generated/ios/swift/Func_void_std__optional_NitroProduct_.swift +54 -0
  126. package/nitrogen/generated/ios/swift/Func_void_std__optional_NitroPurchase_.swift +54 -0
  127. package/nitrogen/generated/ios/swift/Func_void_std__optional_std__string_.swift +54 -0
  128. package/nitrogen/generated/ios/swift/Func_void_std__optional_std__vector_NitroSubscriptionStatus__.swift +54 -0
  129. package/nitrogen/generated/ios/swift/Func_void_std__string.swift +47 -0
  130. package/nitrogen/generated/ios/swift/Func_void_std__variant_NitroReceiptValidationResultIOS__NitroReceiptValidationResultAndroid_.swift +59 -0
  131. package/nitrogen/generated/ios/swift/Func_void_std__variant_bool__NitroPurchaseResult_.swift +59 -0
  132. package/nitrogen/generated/ios/swift/Func_void_std__vector_NitroProduct_.swift +47 -0
  133. package/nitrogen/generated/ios/swift/Func_void_std__vector_NitroPurchase_.swift +47 -0
  134. package/nitrogen/generated/ios/swift/HybridRnIapSpec.swift +78 -0
  135. package/nitrogen/generated/ios/swift/HybridRnIapSpec_cxx.swift +750 -0
  136. package/nitrogen/generated/ios/swift/NitroAndroidReceiptValidationOptions.swift +80 -0
  137. package/nitrogen/generated/ios/swift/NitroAvailablePurchasesAndroidOptions.swift +54 -0
  138. package/nitrogen/generated/ios/swift/NitroAvailablePurchasesIosOptions.swift +116 -0
  139. package/nitrogen/generated/ios/swift/NitroAvailablePurchasesOptions.swift +84 -0
  140. package/nitrogen/generated/ios/swift/NitroFinishTransactionAndroidParams.swift +58 -0
  141. package/nitrogen/generated/ios/swift/NitroFinishTransactionIosParams.swift +35 -0
  142. package/nitrogen/generated/ios/swift/NitroFinishTransactionParams.swift +84 -0
  143. package/nitrogen/generated/ios/swift/NitroProduct.swift +653 -0
  144. package/nitrogen/generated/ios/swift/NitroPurchase.swift +453 -0
  145. package/nitrogen/generated/ios/swift/NitroPurchaseRequest.swift +84 -0
  146. package/nitrogen/generated/ios/swift/NitroPurchaseResult.swift +117 -0
  147. package/nitrogen/generated/ios/swift/NitroReceiptValidationParams.swift +65 -0
  148. package/nitrogen/generated/ios/swift/NitroReceiptValidationResultAndroid.swift +258 -0
  149. package/nitrogen/generated/ios/swift/NitroReceiptValidationResultIOS.swift +87 -0
  150. package/nitrogen/generated/ios/swift/NitroRequestPurchaseAndroid.swift +225 -0
  151. package/nitrogen/generated/ios/swift/NitroRequestPurchaseIos.swift +161 -0
  152. package/nitrogen/generated/ios/swift/NitroSubscriptionOffer.swift +46 -0
  153. package/nitrogen/generated/ios/swift/NitroSubscriptionRenewalInfo.swift +152 -0
  154. package/nitrogen/generated/ios/swift/NitroSubscriptionStatus.swift +76 -0
  155. package/nitrogen/generated/ios/swift/Variant_Bool_NitroPurchaseResult.swift +18 -0
  156. package/nitrogen/generated/ios/swift/Variant_NitroReceiptValidationResultIOS_NitroReceiptValidationResultAndroid.swift +18 -0
  157. package/nitrogen/generated/shared/c++/HybridRnIapSpec.cpp +50 -0
  158. package/nitrogen/generated/shared/c++/HybridRnIapSpec.hpp +125 -0
  159. package/nitrogen/generated/shared/c++/NitroAndroidReceiptValidationOptions.hpp +80 -0
  160. package/nitrogen/generated/shared/c++/NitroAvailablePurchasesAndroidOptions.hpp +68 -0
  161. package/nitrogen/generated/shared/c++/NitroAvailablePurchasesIosOptions.hpp +79 -0
  162. package/nitrogen/generated/shared/c++/NitroAvailablePurchasesOptions.hpp +76 -0
  163. package/nitrogen/generated/shared/c++/NitroFinishTransactionAndroidParams.hpp +72 -0
  164. package/nitrogen/generated/shared/c++/NitroFinishTransactionIosParams.hpp +67 -0
  165. package/nitrogen/generated/shared/c++/NitroFinishTransactionParams.hpp +76 -0
  166. package/nitrogen/generated/shared/c++/NitroProduct.hpp +168 -0
  167. package/nitrogen/generated/shared/c++/NitroPurchase.hpp +136 -0
  168. package/nitrogen/generated/shared/c++/NitroPurchaseRequest.hpp +76 -0
  169. package/nitrogen/generated/shared/c++/NitroPurchaseResult.hpp +84 -0
  170. package/nitrogen/generated/shared/c++/NitroReceiptValidationParams.hpp +74 -0
  171. package/nitrogen/generated/shared/c++/NitroReceiptValidationResultAndroid.hpp +136 -0
  172. package/nitrogen/generated/shared/c++/NitroReceiptValidationResultIOS.hpp +82 -0
  173. package/nitrogen/generated/shared/c++/NitroRequestPurchaseAndroid.hpp +95 -0
  174. package/nitrogen/generated/shared/c++/NitroRequestPurchaseIos.hpp +85 -0
  175. package/nitrogen/generated/shared/c++/NitroSubscriptionOffer.hpp +71 -0
  176. package/nitrogen/generated/shared/c++/NitroSubscriptionRenewalInfo.hpp +88 -0
  177. package/nitrogen/generated/shared/c++/NitroSubscriptionStatus.hpp +78 -0
  178. package/package.json +145 -104
  179. package/plugin/build/src/withIAP.d.ts +3 -0
  180. package/plugin/build/src/withIAP.js +81 -0
  181. package/plugin/build/tsconfig.tsbuildinfo +1 -0
  182. package/plugin/build/withIAP.d.ts +2 -7
  183. package/plugin/build/withIAP.js +62 -51
  184. package/plugin/src/withIAP.ts +119 -0
  185. package/plugin/tsconfig.json +18 -0
  186. package/plugin/tsconfig.tsbuildinfo +1 -0
  187. package/src/helpers/subscription.ts +65 -0
  188. package/src/hooks/useIAP.ts +361 -222
  189. package/src/index.ts +1194 -9
  190. package/src/specs/RnIap.nitro.ts +501 -0
  191. package/src/types.ts +680 -0
  192. package/src/utils/error.ts +97 -0
  193. package/src/utils/type-bridge.ts +209 -0
  194. package/LICENSE +0 -21
  195. package/RNIap.podspec +0 -36
  196. package/android/src/amazon/AndroidManifest.xml +0 -14
  197. package/android/src/amazon/java/com/dooboolab/rniap/EventSender.kt +0 -10
  198. package/android/src/amazon/java/com/dooboolab/rniap/PurchasingServiceProxy.kt +0 -29
  199. package/android/src/amazon/java/com/dooboolab/rniap/PurchasingServiceProxyAmazonImpl.kt +0 -31
  200. package/android/src/amazon/java/com/dooboolab/rniap/RNIapActivityListener.kt +0 -55
  201. package/android/src/amazon/java/com/dooboolab/rniap/RNIapAmazonListener.kt +0 -325
  202. package/android/src/amazon/java/com/dooboolab/rniap/RNIapAmazonModule.kt +0 -244
  203. package/android/src/amazon/java/com/dooboolab/rniap/RNIapPackage.kt +0 -17
  204. package/android/src/amazon/java/com/dooboolab/rniap/modifysubscription/RNIapAmazonModifySubscriptionListener.kt +0 -88
  205. package/android/src/amazon/java/com/dooboolab/rniap/utils/Extensions.kt +0 -22
  206. package/android/src/main/java/com/dooboolab/rniap/PromiseUtils.kt +0 -62
  207. package/android/src/main/java/com/dooboolab/rniap/PromiseUtlis.kt +0 -43
  208. package/android/src/play/java/com/dooboolab/rniap/PlayUtils.kt +0 -114
  209. package/android/src/play/java/com/dooboolab/rniap/RNIapActivityListener.kt +0 -15
  210. package/android/src/play/java/com/dooboolab/rniap/RNIapModule.kt +0 -911
  211. package/android/src/play/java/com/dooboolab/rniap/RNIapPackage.kt +0 -17
  212. package/android/src/testAmazon/java/com/dooboolab/rniap/RNIapAmazonModuleTest.kt +0 -170
  213. package/app.plugin.js +0 -1
  214. package/ios/IapSerializationUtils.swift +0 -290
  215. package/ios/IapTypes.swift +0 -56
  216. package/ios/IapUtils.swift +0 -40
  217. package/ios/LatestPromiseKeeper.swift +0 -52
  218. package/ios/RNIapIos-Bridging-Header.h +0 -2
  219. package/ios/RNIapIos.m +0 -69
  220. package/ios/RNIapIos.swift +0 -868
  221. package/ios/RNIapIos.xcodeproj/project.pbxproj +0 -289
  222. package/ios/RNIapIosSk2.m +0 -126
  223. package/ios/RNIapIosSk2.swift +0 -1413
  224. package/ios/ThreadSafe.swift +0 -18
  225. package/lib/commonjs/eventEmitter.js +0 -195
  226. package/lib/commonjs/eventEmitter.js.map +0 -1
  227. package/lib/commonjs/hooks/index.js +0 -17
  228. package/lib/commonjs/hooks/index.js.map +0 -1
  229. package/lib/commonjs/hooks/useIAP.js +0 -203
  230. package/lib/commonjs/hooks/useIAP.js.map +0 -1
  231. package/lib/commonjs/hooks/withIAPContext.js +0 -95
  232. package/lib/commonjs/hooks/withIAPContext.js.map +0 -1
  233. package/lib/commonjs/iap.js +0 -836
  234. package/lib/commonjs/iap.js.map +0 -1
  235. package/lib/commonjs/index.js +0 -105
  236. package/lib/commonjs/index.js.map +0 -1
  237. package/lib/commonjs/internal/enhancedFetch.js +0 -26
  238. package/lib/commonjs/internal/enhancedFetch.js.map +0 -1
  239. package/lib/commonjs/internal/fillProductsWithAdditionalData.js +0 -50
  240. package/lib/commonjs/internal/fillProductsWithAdditionalData.js.map +0 -1
  241. package/lib/commonjs/internal/index.js +0 -39
  242. package/lib/commonjs/internal/index.js.map +0 -1
  243. package/lib/commonjs/internal/platform.js +0 -119
  244. package/lib/commonjs/internal/platform.js.map +0 -1
  245. package/lib/commonjs/modules/amazon.js +0 -50
  246. package/lib/commonjs/modules/amazon.js.map +0 -1
  247. package/lib/commonjs/modules/android.js +0 -92
  248. package/lib/commonjs/modules/android.js.map +0 -1
  249. package/lib/commonjs/modules/common.js +0 -2
  250. package/lib/commonjs/modules/index.js +0 -50
  251. package/lib/commonjs/modules/index.js.map +0 -1
  252. package/lib/commonjs/modules/ios.js +0 -160
  253. package/lib/commonjs/modules/ios.js.map +0 -1
  254. package/lib/commonjs/modules/iosSk2.js +0 -113
  255. package/lib/commonjs/modules/iosSk2.js.map +0 -1
  256. package/lib/commonjs/purchaseError.js +0 -170
  257. package/lib/commonjs/purchaseError.js.map +0 -1
  258. package/lib/commonjs/types/amazon.js +0 -2
  259. package/lib/commonjs/types/amazon.js.map +0 -1
  260. package/lib/commonjs/types/android.js +0 -67
  261. package/lib/commonjs/types/android.js.map +0 -1
  262. package/lib/commonjs/types/apple.js +0 -24
  263. package/lib/commonjs/types/apple.js.map +0 -1
  264. package/lib/commonjs/types/appleSk2.js +0 -137
  265. package/lib/commonjs/types/appleSk2.js.map +0 -1
  266. package/lib/commonjs/types/index.js +0 -67
  267. package/lib/commonjs/types/index.js.map +0 -1
  268. package/lib/commonjs/utils/errorMapping.js +0 -83
  269. package/lib/commonjs/utils/errorMapping.js.map +0 -1
  270. package/lib/commonjs/utils/typeGuards.js +0 -74
  271. package/lib/commonjs/utils/typeGuards.js.map +0 -1
  272. package/lib/module/eventEmitter.js +0 -185
  273. package/lib/module/eventEmitter.js.map +0 -1
  274. package/lib/module/hooks/index.js +0 -2
  275. package/lib/module/hooks/index.js.map +0 -1
  276. package/lib/module/hooks/withIAPContext.js +0 -86
  277. package/lib/module/hooks/withIAPContext.js.map +0 -1
  278. package/lib/module/iap.js +0 -805
  279. package/lib/module/iap.js.map +0 -1
  280. package/lib/module/internal/enhancedFetch.js +0 -19
  281. package/lib/module/internal/enhancedFetch.js.map +0 -1
  282. package/lib/module/internal/fillProductsWithAdditionalData.js +0 -43
  283. package/lib/module/internal/fillProductsWithAdditionalData.js.map +0 -1
  284. package/lib/module/internal/index.js +0 -4
  285. package/lib/module/internal/index.js.map +0 -1
  286. package/lib/module/internal/platform.js +0 -102
  287. package/lib/module/internal/platform.js.map +0 -1
  288. package/lib/module/modules/amazon.js +0 -42
  289. package/lib/module/modules/amazon.js.map +0 -1
  290. package/lib/module/modules/android.js +0 -81
  291. package/lib/module/modules/android.js.map +0 -1
  292. package/lib/module/modules/common.js +0 -2
  293. package/lib/module/modules/common.js.map +0 -1
  294. package/lib/module/modules/index.js +0 -5
  295. package/lib/module/modules/index.js.map +0 -1
  296. package/lib/module/modules/ios.js +0 -145
  297. package/lib/module/modules/ios.js.map +0 -1
  298. package/lib/module/modules/iosSk2.js +0 -96
  299. package/lib/module/modules/iosSk2.js.map +0 -1
  300. package/lib/module/purchaseError.js +0 -164
  301. package/lib/module/purchaseError.js.map +0 -1
  302. package/lib/module/types/amazon.js +0 -2
  303. package/lib/module/types/amazon.js.map +0 -1
  304. package/lib/module/types/android.js +0 -63
  305. package/lib/module/types/android.js.map +0 -1
  306. package/lib/module/types/apple.js +0 -17
  307. package/lib/module/types/apple.js.map +0 -1
  308. package/lib/module/types/appleSk2.js +0 -129
  309. package/lib/module/types/appleSk2.js.map +0 -1
  310. package/lib/module/types/index.js +0 -75
  311. package/lib/module/types/index.js.map +0 -1
  312. package/lib/module/utils/errorMapping.js +0 -75
  313. package/lib/module/utils/errorMapping.js.map +0 -1
  314. package/lib/module/utils/typeGuards.js +0 -61
  315. package/lib/module/utils/typeGuards.js.map +0 -1
  316. package/lib/typescript/src/eventEmitter.d.ts +0 -151
  317. package/lib/typescript/src/eventEmitter.d.ts.map +0 -1
  318. package/lib/typescript/src/hooks/index.d.ts +0 -2
  319. package/lib/typescript/src/hooks/index.d.ts.map +0 -1
  320. package/lib/typescript/src/hooks/withIAPContext.d.ts +0 -27
  321. package/lib/typescript/src/hooks/withIAPContext.d.ts.map +0 -1
  322. package/lib/typescript/src/iap.d.ts +0 -503
  323. package/lib/typescript/src/iap.d.ts.map +0 -1
  324. package/lib/typescript/src/internal/enhancedFetch.d.ts +0 -6
  325. package/lib/typescript/src/internal/enhancedFetch.d.ts.map +0 -1
  326. package/lib/typescript/src/internal/fillProductsWithAdditionalData.d.ts +0 -7
  327. package/lib/typescript/src/internal/fillProductsWithAdditionalData.d.ts.map +0 -1
  328. package/lib/typescript/src/internal/index.d.ts +0 -4
  329. package/lib/typescript/src/internal/index.d.ts.map +0 -1
  330. package/lib/typescript/src/internal/platform.d.ts +0 -27
  331. package/lib/typescript/src/internal/platform.d.ts.map +0 -1
  332. package/lib/typescript/src/modules/amazon.d.ts +0 -55
  333. package/lib/typescript/src/modules/amazon.d.ts.map +0 -1
  334. package/lib/typescript/src/modules/android.d.ts +0 -74
  335. package/lib/typescript/src/modules/android.d.ts.map +0 -1
  336. package/lib/typescript/src/modules/common.d.ts +0 -14
  337. package/lib/typescript/src/modules/common.d.ts.map +0 -1
  338. package/lib/typescript/src/modules/index.d.ts +0 -5
  339. package/lib/typescript/src/modules/index.d.ts.map +0 -1
  340. package/lib/typescript/src/modules/ios.d.ts +0 -117
  341. package/lib/typescript/src/modules/ios.d.ts.map +0 -1
  342. package/lib/typescript/src/modules/iosSk2.d.ts +0 -140
  343. package/lib/typescript/src/modules/iosSk2.d.ts.map +0 -1
  344. package/lib/typescript/src/purchaseError.d.ts +0 -133
  345. package/lib/typescript/src/purchaseError.d.ts.map +0 -1
  346. package/lib/typescript/src/types/amazon.d.ts +0 -33
  347. package/lib/typescript/src/types/amazon.d.ts.map +0 -1
  348. package/lib/typescript/src/types/android.d.ts +0 -66
  349. package/lib/typescript/src/types/android.d.ts.map +0 -1
  350. package/lib/typescript/src/types/apple.d.ts +0 -27
  351. package/lib/typescript/src/types/apple.d.ts.map +0 -1
  352. package/lib/typescript/src/types/appleSk2.d.ts +0 -129
  353. package/lib/typescript/src/types/appleSk2.d.ts.map +0 -1
  354. package/lib/typescript/src/types/index.d.ts +0 -302
  355. package/lib/typescript/src/types/index.d.ts.map +0 -1
  356. package/lib/typescript/src/utils/errorMapping.d.ts +0 -29
  357. package/lib/typescript/src/utils/errorMapping.d.ts.map +0 -1
  358. package/lib/typescript/src/utils/typeGuards.d.ts +0 -53
  359. package/lib/typescript/src/utils/typeGuards.d.ts.map +0 -1
  360. package/src/eventEmitter.ts +0 -212
  361. package/src/hooks/index.ts +0 -1
  362. package/src/hooks/withIAPContext.tsx +0 -179
  363. package/src/iap.ts +0 -1046
  364. package/src/internal/enhancedFetch.ts +0 -25
  365. package/src/internal/fillProductsWithAdditionalData.ts +0 -47
  366. package/src/internal/index.ts +0 -3
  367. package/src/internal/platform.ts +0 -135
  368. package/src/modules/amazon.ts +0 -94
  369. package/src/modules/android.ts +0 -179
  370. package/src/modules/common.ts +0 -16
  371. package/src/modules/index.ts +0 -4
  372. package/src/modules/ios.ts +0 -229
  373. package/src/modules/iosSk2.ts +0 -194
  374. package/src/purchaseError.ts +0 -196
  375. package/src/types/amazon.ts +0 -40
  376. package/src/types/android.ts +0 -89
  377. package/src/types/apple.ts +0 -44
  378. package/src/types/appleSk2.ts +0 -275
  379. package/src/types/index.ts +0 -379
  380. package/src/utils/errorMapping.ts +0 -88
  381. package/src/utils/typeGuards.ts +0 -90
@@ -0,0 +1,843 @@
1
+ package com.margelo.nitro.iap
2
+
3
+ import android.app.Activity
4
+ import android.content.Context
5
+ import android.util.Log
6
+ import com.android.billingclient.api.*
7
+ import com.facebook.react.bridge.ReactApplicationContext
8
+ import com.google.android.gms.common.ConnectionResult
9
+ import com.google.android.gms.common.GoogleApiAvailability
10
+ import com.margelo.nitro.NitroModules
11
+ import com.margelo.nitro.core.Promise
12
+ import org.json.JSONArray
13
+ import org.json.JSONObject
14
+ import kotlinx.coroutines.Dispatchers
15
+ import kotlinx.coroutines.suspendCancellableCoroutine
16
+ import kotlinx.coroutines.withContext
17
+ import kotlin.coroutines.resume
18
+ import kotlin.coroutines.resumeWithException
19
+
20
+ class HybridRnIap : HybridRnIapSpec(), PurchasesUpdatedListener, BillingClientStateListener {
21
+ companion object {
22
+ const val TAG = "RnIap"
23
+ }
24
+
25
+ // Get ReactApplicationContext lazily from NitroModules
26
+ private val context: ReactApplicationContext by lazy {
27
+ NitroModules.applicationContext as ReactApplicationContext
28
+ }
29
+
30
+ private var billingClient: BillingClient? = null
31
+ private val skuDetailsCache = mutableMapOf<String, ProductDetails>()
32
+
33
+ // Event listeners
34
+ private val purchaseUpdatedListeners = mutableListOf<(NitroPurchase) -> Unit>()
35
+ private val purchaseErrorListeners = mutableListOf<(NitroPurchaseResult) -> Unit>()
36
+ private val promotedProductListenersIOS = mutableListOf<(NitroProduct) -> Unit>()
37
+
38
+
39
+ // Connection methods
40
+ override fun initConnection(): Promise<Boolean> {
41
+ return Promise.async {
42
+ if (billingClient?.isReady == true) {
43
+ return@async true
44
+ }
45
+
46
+ // Check if Google Play Services is available
47
+ val googleApiAvailability = GoogleApiAvailability.getInstance()
48
+ val resultCode = googleApiAvailability.isGooglePlayServicesAvailable(context)
49
+ if (resultCode != ConnectionResult.SUCCESS) {
50
+ val errorMsg = BillingUtils.getPlayServicesErrorMessage(resultCode)
51
+ val errorJson = BillingUtils.createErrorJson(
52
+ IapErrorCode.E_NOT_PREPARED,
53
+ errorMsg,
54
+ resultCode
55
+ )
56
+ throw Exception(errorJson)
57
+ }
58
+
59
+ withContext(Dispatchers.Main) {
60
+ initBillingClient()
61
+ }
62
+ }
63
+ }
64
+
65
+ override fun endConnection(): Promise<Boolean> {
66
+ return Promise.async {
67
+ billingClient?.endConnection()
68
+ billingClient = null
69
+ true
70
+ }
71
+ }
72
+
73
+ // Product methods
74
+ override fun fetchProducts(skus: Array<String>, type: String): Promise<Array<NitroProduct>> {
75
+ return Promise.async {
76
+ Log.d(TAG, "fetchProducts called with SKUs: ${skus.joinToString()}, type: $type")
77
+
78
+ // Validate SKU list
79
+ if (skus.isEmpty()) {
80
+ throw Exception(BillingUtils.createErrorJson(
81
+ IapErrorCode.E_EMPTY_SKU_LIST,
82
+ "SKU list is empty"
83
+ ))
84
+ }
85
+
86
+ // Initialize billing client if not already done
87
+ // Auto-reconnection will handle service disconnections automatically
88
+ if (billingClient == null) {
89
+ initConnection().await()
90
+ }
91
+
92
+ val productType = if (type == "subs") {
93
+ BillingClient.ProductType.SUBS
94
+ } else {
95
+ BillingClient.ProductType.INAPP
96
+ }
97
+
98
+ val productList = skus.map { sku ->
99
+ QueryProductDetailsParams.Product.newBuilder()
100
+ .setProductId(sku)
101
+ .setProductType(productType)
102
+ .build()
103
+ }
104
+
105
+ val params = QueryProductDetailsParams.newBuilder()
106
+ .setProductList(productList)
107
+ .build()
108
+
109
+ val result = suspendCancellableCoroutine<List<ProductDetails>> { continuation ->
110
+ billingClient?.queryProductDetailsAsync(params) { billingResult, productDetailsResult ->
111
+ Log.d(TAG, "queryProductDetailsAsync response: code=${billingResult.responseCode}")
112
+ if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
113
+ val productDetailsList = productDetailsResult.productDetailsList ?: emptyList()
114
+ Log.d(TAG, "Retrieved ${productDetailsList.size} products")
115
+ // Cache the product details
116
+ if (productDetailsList.isNotEmpty()) {
117
+ for (details in productDetailsList) {
118
+ Log.d(TAG, "Product: ${details.productId}, has offers: ${details.subscriptionOfferDetails?.size ?: 0}")
119
+ skuDetailsCache[details.productId] = details
120
+ }
121
+ continuation.resume(productDetailsList)
122
+ } else {
123
+ continuation.resume(emptyList())
124
+ }
125
+ } else {
126
+ continuation.resumeWithException(
127
+ Exception(getBillingErrorMessage(billingResult.responseCode))
128
+ )
129
+ }
130
+ }
131
+ }
132
+
133
+ Log.d(TAG, "Converting ${result.size} products to NitroProducts")
134
+
135
+ val nitroProducts = result.map { productDetails ->
136
+ convertToNitroProduct(productDetails, type)
137
+ }.toTypedArray()
138
+
139
+ Log.d(TAG, "Returning ${nitroProducts.size} NitroProducts to JS")
140
+ nitroProducts
141
+ }
142
+ }
143
+
144
+ // Purchase methods
145
+ // Purchase methods (Unified)
146
+ override fun requestPurchase(request: NitroPurchaseRequest): Promise<Unit> {
147
+ return Promise.async {
148
+ // Android implementation
149
+ val androidRequest = request.android ?: run {
150
+ sendPurchaseError(createPurchaseErrorResult(
151
+ IapErrorCode.E_USER_ERROR,
152
+ "No Android request provided"
153
+ ))
154
+ return@async
155
+ }
156
+
157
+ // Validate SKU list
158
+ if (androidRequest.skus.isEmpty()) {
159
+ sendPurchaseError(createPurchaseErrorResult(
160
+ IapErrorCode.E_EMPTY_SKU_LIST,
161
+ "SKU list is empty"
162
+ ))
163
+ return@async
164
+ }
165
+
166
+ try {
167
+ // Initialize billing client if not already done
168
+ if (billingClient == null) {
169
+ initConnection().await()
170
+ }
171
+
172
+ // Get current activity - this should be done on Main thread
173
+ val activity = withContext(Dispatchers.Main) {
174
+ context.currentActivity
175
+ } ?: run {
176
+ sendPurchaseError(createPurchaseErrorResult(
177
+ IapErrorCode.E_ACTIVITY_UNAVAILABLE,
178
+ "Current activity is null. Please ensure the app is in foreground."
179
+ ))
180
+ return@async
181
+ }
182
+
183
+ withContext(Dispatchers.Main) {
184
+ val productDetailsList = mutableListOf<BillingFlowParams.ProductDetailsParams>()
185
+
186
+ // Build product details list
187
+ for (sku in androidRequest.skus) {
188
+ val productDetails = skuDetailsCache[sku] ?: run {
189
+ sendPurchaseError(createPurchaseErrorResult(
190
+ IapErrorCode.E_SKU_NOT_FOUND,
191
+ "Product not found: $sku. Call requestProducts first.",
192
+ sku
193
+ ))
194
+ return@withContext
195
+ }
196
+
197
+ val productDetailsParams = BillingFlowParams.ProductDetailsParams.newBuilder()
198
+ .setProductDetails(productDetails)
199
+
200
+ // Add offer token for subscriptions
201
+ val subscriptionOffers = androidRequest.subscriptionOffers
202
+ if (!subscriptionOffers.isNullOrEmpty()) {
203
+ val offer = subscriptionOffers.find { it.sku == sku }
204
+ offer?.offerToken?.let { productDetailsParams.setOfferToken(it) }
205
+ }
206
+
207
+ productDetailsList.add(productDetailsParams.build())
208
+ }
209
+
210
+ val billingFlowParams = BillingFlowParams.newBuilder()
211
+ .setProductDetailsParamsList(productDetailsList)
212
+ .setIsOfferPersonalized(androidRequest.isOfferPersonalized ?: false)
213
+
214
+ // Set subscription update params if replacing
215
+ val purchaseToken = androidRequest.purchaseTokenAndroid
216
+ val replacementMode = androidRequest.replacementModeAndroid
217
+ if (!purchaseToken.isNullOrEmpty() && replacementMode != null) {
218
+ val updateParams = BillingFlowParams.SubscriptionUpdateParams.newBuilder()
219
+ .setOldPurchaseToken(purchaseToken)
220
+ .setSubscriptionReplacementMode(replacementMode.toInt())
221
+ .build()
222
+ billingFlowParams.setSubscriptionUpdateParams(updateParams)
223
+ }
224
+
225
+ // Set obfuscated identifiers
226
+ androidRequest.obfuscatedAccountIdAndroid?.let { billingFlowParams.setObfuscatedAccountId(it) }
227
+ androidRequest.obfuscatedProfileIdAndroid?.let { billingFlowParams.setObfuscatedProfileId(it) }
228
+
229
+ // Launch billing flow - results will be handled by onPurchasesUpdated
230
+ val billingResult = billingClient?.launchBillingFlow(activity, billingFlowParams.build())
231
+ if (billingResult?.responseCode != BillingClient.BillingResponseCode.OK) {
232
+ sendPurchaseError(createPurchaseErrorResult(
233
+ getBillingErrorCode(billingResult?.responseCode ?: -1),
234
+ getBillingErrorMessage(billingResult?.responseCode ?: -1)
235
+ ))
236
+ }
237
+
238
+ // Purchase results will be handled by onPurchasesUpdated callback
239
+ }
240
+ } catch (e: Exception) {
241
+ sendPurchaseError(createPurchaseErrorResult(
242
+ IapErrorCode.E_UNKNOWN,
243
+ e.message ?: "Unknown error occurred"
244
+ ))
245
+ }
246
+ }
247
+ }
248
+
249
+ // Purchase history methods (Unified)
250
+ override fun getAvailablePurchases(options: NitroAvailablePurchasesOptions?): Promise<Array<NitroPurchase>> {
251
+ return Promise.async {
252
+ // Android implementation
253
+ val androidOptions = options?.android
254
+ val type = androidOptions?.type ?: "inapp"
255
+
256
+ // Initialize billing client if not already done
257
+ // Auto-reconnection will handle service disconnections automatically
258
+ if (billingClient == null) {
259
+ initConnection().await()
260
+ }
261
+
262
+ val productType = if (type == "subs") {
263
+ BillingClient.ProductType.SUBS
264
+ } else {
265
+ BillingClient.ProductType.INAPP
266
+ }
267
+
268
+ val params = QueryPurchasesParams.newBuilder()
269
+ .setProductType(productType)
270
+ .build()
271
+
272
+ val result = suspendCancellableCoroutine<List<Purchase>> { continuation ->
273
+ billingClient?.queryPurchasesAsync(params) { billingResult, purchases ->
274
+ if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
275
+ continuation.resume(purchases)
276
+ } else {
277
+ continuation.resumeWithException(
278
+ Exception(getBillingErrorMessage(billingResult.responseCode))
279
+ )
280
+ }
281
+ }
282
+ }
283
+
284
+ result.map { purchase ->
285
+ convertToNitroPurchase(purchase)
286
+ }.toTypedArray()
287
+ }
288
+ }
289
+
290
+ // Transaction management methods (Unified)
291
+ override fun finishTransaction(params: NitroFinishTransactionParams): Promise<Variant_Boolean_NitroPurchaseResult> {
292
+ return Promise.async {
293
+ // Android implementation
294
+ val androidParams = params.android ?: return@async Variant_Boolean_NitroPurchaseResult.First(true)
295
+ val purchaseToken = androidParams.purchaseToken
296
+ val isConsumable = androidParams.isConsumable ?: false
297
+
298
+ // Initialize billing client if not already done
299
+ // Auto-reconnection will handle service disconnections automatically
300
+ if (billingClient == null) {
301
+ initConnection().await()
302
+ }
303
+
304
+ if (isConsumable) {
305
+ // Consume the purchase
306
+ val consumeParams = ConsumeParams.newBuilder()
307
+ .setPurchaseToken(purchaseToken)
308
+ .build()
309
+
310
+ val result = suspendCancellableCoroutine<Pair<BillingResult, String>> { continuation ->
311
+ billingClient?.consumeAsync(consumeParams) { billingResult, token ->
312
+ continuation.resume(Pair(billingResult, token))
313
+ }
314
+ }
315
+
316
+ Variant_Boolean_NitroPurchaseResult.Second(
317
+ NitroPurchaseResult(
318
+ responseCode = result.first.responseCode.toDouble(),
319
+ debugMessage = result.first.debugMessage,
320
+ code = result.first.responseCode.toString(),
321
+ message = getBillingErrorMessage(result.first.responseCode),
322
+ purchaseToken = result.second
323
+ )
324
+ )
325
+ } else {
326
+ // Acknowledge the purchase
327
+ val acknowledgeParams = AcknowledgePurchaseParams.newBuilder()
328
+ .setPurchaseToken(purchaseToken)
329
+ .build()
330
+
331
+ val result = suspendCancellableCoroutine<BillingResult> { continuation ->
332
+ billingClient?.acknowledgePurchase(acknowledgeParams) { billingResult ->
333
+ continuation.resume(billingResult)
334
+ }
335
+ }
336
+
337
+ Variant_Boolean_NitroPurchaseResult.Second(
338
+ NitroPurchaseResult(
339
+ responseCode = result.responseCode.toDouble(),
340
+ debugMessage = result.debugMessage,
341
+ code = result.responseCode.toString(),
342
+ message = getBillingErrorMessage(result.responseCode),
343
+ purchaseToken = purchaseToken
344
+ )
345
+ )
346
+ }
347
+ }
348
+ }
349
+
350
+ override val memorySize: Long
351
+ get() = 0L
352
+
353
+ // Event listener methods
354
+ override fun addPurchaseUpdatedListener(listener: (purchase: NitroPurchase) -> Unit) {
355
+ purchaseUpdatedListeners.add(listener)
356
+ }
357
+
358
+ override fun addPurchaseErrorListener(listener: (error: NitroPurchaseResult) -> Unit) {
359
+ purchaseErrorListeners.add(listener)
360
+ }
361
+
362
+ override fun removePurchaseUpdatedListener(listener: (purchase: NitroPurchase) -> Unit) {
363
+ // Note: Kotlin doesn't have easy closure comparison, so we'll clear all listeners
364
+ purchaseUpdatedListeners.clear()
365
+ }
366
+
367
+ override fun removePurchaseErrorListener(listener: (error: NitroPurchaseResult) -> Unit) {
368
+ // Note: Kotlin doesn't have easy closure comparison, so we'll clear all listeners
369
+ purchaseErrorListeners.clear()
370
+ }
371
+
372
+ override fun addPromotedProductListenerIOS(listener: (product: NitroProduct) -> Unit) {
373
+ // Promoted products are iOS-only, but we implement the interface for consistency
374
+ promotedProductListenersIOS.add(listener)
375
+ Log.w(TAG, "addPromotedProductListenerIOS called on Android - promoted products are iOS-only")
376
+ }
377
+
378
+ override fun removePromotedProductListenerIOS(listener: (product: NitroProduct) -> Unit) {
379
+ // Promoted products are iOS-only, but we implement the interface for consistency
380
+ promotedProductListenersIOS.clear()
381
+ Log.w(TAG, "removePromotedProductListenerIOS called on Android - promoted products are iOS-only")
382
+ }
383
+
384
+ // BillingClientStateListener implementation
385
+ override fun onBillingSetupFinished(billingResult: BillingResult) {
386
+ // Handled inline in initConnection
387
+ }
388
+
389
+ override fun onBillingServiceDisconnected() {
390
+ // Try to restart the connection on the next request
391
+ // For now, just log the disconnection
392
+ }
393
+
394
+ // PurchasesUpdatedListener implementation
395
+ override fun onPurchasesUpdated(billingResult: BillingResult, purchases: List<Purchase>?) {
396
+ Log.d(TAG, "onPurchasesUpdated: responseCode=${billingResult.responseCode}")
397
+
398
+ if (billingResult.responseCode == BillingClient.BillingResponseCode.OK && purchases != null) {
399
+ // Send successful purchases via events
400
+ for (purchase in purchases) {
401
+ sendPurchaseUpdate(convertToNitroPurchase(purchase))
402
+ }
403
+ } else {
404
+ // Send error via events
405
+ val errorCode = getBillingErrorCode(billingResult.responseCode)
406
+ val errorMessage = getBillingErrorMessage(billingResult.responseCode)
407
+ sendPurchaseError(createPurchaseErrorResult(
408
+ errorCode,
409
+ errorMessage,
410
+ null,
411
+ billingResult.responseCode,
412
+ billingResult.debugMessage
413
+ ))
414
+ }
415
+ }
416
+
417
+ // Helper methods
418
+
419
+ /**
420
+ * Send purchase update event to listeners
421
+ */
422
+ private fun sendPurchaseUpdate(purchase: NitroPurchase) {
423
+ for (listener in purchaseUpdatedListeners) {
424
+ listener(purchase)
425
+ }
426
+ }
427
+
428
+ /**
429
+ * Send purchase error event to listeners
430
+ */
431
+ private fun sendPurchaseError(error: NitroPurchaseResult) {
432
+ for (listener in purchaseErrorListeners) {
433
+ listener(error)
434
+ }
435
+ }
436
+
437
+ /**
438
+ * Create purchase error result with proper format
439
+ */
440
+ private fun createPurchaseErrorResult(
441
+ errorCode: String,
442
+ message: String,
443
+ sku: String? = null,
444
+ responseCode: Int? = null,
445
+ debugMessage: String? = null
446
+ ): NitroPurchaseResult {
447
+ return NitroPurchaseResult(
448
+ responseCode = responseCode?.toDouble() ?: -1.0,
449
+ debugMessage = debugMessage,
450
+ code = errorCode,
451
+ message = message,
452
+ purchaseToken = null
453
+ )
454
+ }
455
+
456
+ /**
457
+ * Convert billing response code to IAP error code
458
+ */
459
+ private fun getBillingErrorCode(responseCode: Int): String {
460
+ return when (responseCode) {
461
+ BillingClient.BillingResponseCode.USER_CANCELED -> IapErrorCode.E_USER_CANCELLED
462
+ BillingClient.BillingResponseCode.SERVICE_UNAVAILABLE -> IapErrorCode.E_SERVICE_ERROR
463
+ BillingClient.BillingResponseCode.BILLING_UNAVAILABLE -> IapErrorCode.E_NOT_PREPARED
464
+ BillingClient.BillingResponseCode.ITEM_UNAVAILABLE -> IapErrorCode.E_SKU_NOT_FOUND
465
+ BillingClient.BillingResponseCode.DEVELOPER_ERROR -> IapErrorCode.E_DEVELOPER_ERROR
466
+ BillingClient.BillingResponseCode.ERROR -> IapErrorCode.E_UNKNOWN
467
+ BillingClient.BillingResponseCode.ITEM_ALREADY_OWNED -> IapErrorCode.E_ALREADY_OWNED
468
+ BillingClient.BillingResponseCode.ITEM_NOT_OWNED -> IapErrorCode.E_ITEM_NOT_OWNED
469
+ BillingClient.BillingResponseCode.NETWORK_ERROR -> IapErrorCode.E_NETWORK_ERROR
470
+ else -> IapErrorCode.E_UNKNOWN
471
+ }
472
+ }
473
+
474
+ private suspend fun initBillingClient(): Boolean {
475
+ return suspendCancellableCoroutine { continuation ->
476
+ // For Google Play Billing v8.0.0+, use PendingPurchasesParams
477
+ val pendingPurchasesParams = PendingPurchasesParams.newBuilder()
478
+ .enableOneTimeProducts()
479
+ .build()
480
+
481
+ billingClient = BillingClient.newBuilder(context)
482
+ .setListener(this@HybridRnIap)
483
+ .enablePendingPurchases(pendingPurchasesParams)
484
+ .enableAutoServiceReconnection() // Automatically handle service disconnections
485
+ .build()
486
+
487
+ billingClient?.startConnection(object : BillingClientStateListener {
488
+ override fun onBillingSetupFinished(billingResult: BillingResult) {
489
+ if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
490
+ continuation.resume(true)
491
+ } else {
492
+ val errorData = BillingUtils.getBillingErrorData(billingResult.responseCode)
493
+ val errorJson = BillingUtils.createErrorJson(
494
+ errorData.code,
495
+ errorData.message,
496
+ billingResult.responseCode,
497
+ billingResult.debugMessage
498
+ )
499
+ continuation.resumeWithException(Exception(errorJson))
500
+ }
501
+ }
502
+
503
+ override fun onBillingServiceDisconnected() {
504
+ Log.i(TAG, "Billing service disconnected")
505
+ // Will try to reconnect on next operation
506
+ }
507
+ })
508
+ }
509
+ }
510
+
511
+ private fun convertToNitroProduct(productDetails: ProductDetails, type: String): NitroProduct {
512
+ // Get price info from either one-time purchase or subscription
513
+ val (currency, displayPrice, priceAmountMicros) = when {
514
+ productDetails.oneTimePurchaseOfferDetails != null -> {
515
+ val offer = productDetails.oneTimePurchaseOfferDetails!!
516
+ Triple(
517
+ offer.priceCurrencyCode,
518
+ offer.formattedPrice,
519
+ offer.priceAmountMicros
520
+ )
521
+ }
522
+ productDetails.subscriptionOfferDetails?.isNotEmpty() == true -> {
523
+ val firstOffer = productDetails.subscriptionOfferDetails!![0]
524
+ val firstPhase = firstOffer.pricingPhases.pricingPhaseList[0]
525
+ Triple(
526
+ firstPhase.priceCurrencyCode,
527
+ firstPhase.formattedPrice,
528
+ firstPhase.priceAmountMicros
529
+ )
530
+ }
531
+ else -> Triple("", "N/A", 0L)
532
+ }
533
+
534
+ // Convert subscription offer details to JSON string if available
535
+ val subscriptionOfferDetailsJson = productDetails.subscriptionOfferDetails?.let { offers ->
536
+ Log.d(TAG, "Product ${productDetails.productId} has ${offers.size} subscription offers")
537
+
538
+ val jsonArray = JSONArray().apply {
539
+ offers.forEach { offer ->
540
+ Log.d(TAG, "Offer: basePlanId=${offer.basePlanId}, offerId=${offer.offerId}, offerToken=${offer.offerToken}")
541
+
542
+ val offerJson = JSONObject().apply {
543
+ put("offerToken", offer.offerToken)
544
+ put("basePlanId", offer.basePlanId)
545
+ offer.offerId?.let { put("offerId", it) }
546
+
547
+ val pricingPhasesArray = JSONArray().apply {
548
+ offer.pricingPhases.pricingPhaseList.forEach { phase ->
549
+ put(JSONObject().apply {
550
+ put("formattedPrice", phase.formattedPrice)
551
+ put("priceCurrencyCode", phase.priceCurrencyCode)
552
+ put("priceAmountMicros", phase.priceAmountMicros)
553
+ put("billingCycleCount", phase.billingCycleCount)
554
+ put("billingPeriod", phase.billingPeriod)
555
+ put("recurrenceMode", phase.recurrenceMode)
556
+ })
557
+ }
558
+ }
559
+ put("pricingPhases", pricingPhasesArray)
560
+ }
561
+ put(offerJson)
562
+ }
563
+ }
564
+
565
+ val jsonString = jsonArray.toString()
566
+ Log.d(TAG, "Subscription offer details JSON: $jsonString")
567
+ jsonString
568
+ }
569
+
570
+ val nitroProduct = NitroProduct(
571
+ id = productDetails.productId,
572
+ title = productDetails.title,
573
+ description = productDetails.description,
574
+ type = type,
575
+ displayName = productDetails.name,
576
+ displayPrice = displayPrice,
577
+ currency = currency,
578
+ price = priceAmountMicros / 1000000.0,
579
+ platform = "android",
580
+ // iOS fields (null on Android)
581
+ isFamilyShareable = null,
582
+ jsonRepresentation = null,
583
+ subscriptionPeriodUnitIOS = null,
584
+ subscriptionPeriodNumberIOS = null,
585
+ introductoryPriceIOS = null,
586
+ introductoryPriceAsAmountIOS = null,
587
+ introductoryPricePaymentModeIOS = null,
588
+ introductoryPriceNumberOfPeriodsIOS = null,
589
+ introductoryPriceSubscriptionPeriodIOS = null,
590
+ // Android fields
591
+ originalPrice = productDetails.oneTimePurchaseOfferDetails?.formattedPrice,
592
+ originalPriceAmountMicros = productDetails.oneTimePurchaseOfferDetails?.priceAmountMicros?.toDouble(),
593
+ introductoryPriceValue = null, // TODO: Extract from subscription offers
594
+ introductoryPriceCycles = null,
595
+ introductoryPricePeriod = null,
596
+ subscriptionPeriod = null, // TODO: Extract from subscription offers
597
+ freeTrialPeriod = null,
598
+ subscriptionOfferDetailsAndroid = subscriptionOfferDetailsJson
599
+ )
600
+
601
+ Log.d(TAG, "Created NitroProduct for ${productDetails.productId}: has subscriptionOfferDetailsAndroid=${nitroProduct.subscriptionOfferDetailsAndroid != null}")
602
+
603
+ return nitroProduct
604
+ }
605
+
606
+ private fun convertToNitroPurchase(purchase: Purchase): NitroPurchase {
607
+ return NitroPurchase(
608
+ id = purchase.orderId ?: "",
609
+ productId = purchase.products.firstOrNull() ?: "",
610
+ transactionDate = purchase.purchaseTime.toDouble(),
611
+ purchaseToken = purchase.purchaseToken,
612
+ platform = "android",
613
+ // iOS fields
614
+ quantityIOS = null,
615
+ originalTransactionDateIOS = null,
616
+ originalTransactionIdentifierIOS = null,
617
+ appAccountToken = null,
618
+ // Android fields
619
+ purchaseTokenAndroid = purchase.purchaseToken,
620
+ dataAndroid = purchase.originalJson,
621
+ signatureAndroid = purchase.signature,
622
+ autoRenewingAndroid = purchase.isAutoRenewing,
623
+ purchaseStateAndroid = purchase.purchaseState.toDouble(),
624
+ isAcknowledgedAndroid = purchase.isAcknowledged,
625
+ packageNameAndroid = purchase.packageName,
626
+ obfuscatedAccountIdAndroid = purchase.accountIdentifiers?.obfuscatedAccountId,
627
+ obfuscatedProfileIdAndroid = purchase.accountIdentifiers?.obfuscatedProfileId
628
+ )
629
+ }
630
+
631
+ // Helper function for billing error messages
632
+ private fun getBillingErrorMessage(responseCode: Int): String {
633
+ val errorData = BillingUtils.getBillingErrorData(responseCode)
634
+ return errorData.message
635
+ }
636
+
637
+ // iOS-specific method - not supported on Android
638
+ override fun getStorefrontIOS(): Promise<String> {
639
+ return Promise.async {
640
+ val errorJson = BillingUtils.createErrorJson(
641
+ IapErrorCode.E_UNKNOWN,
642
+ "getStorefrontIOS is only available on iOS"
643
+ )
644
+ throw Exception(errorJson)
645
+ }
646
+ }
647
+
648
+ // iOS-specific method - not supported on Android
649
+ override fun getAppTransactionIOS(): Promise<String?> {
650
+ return Promise.async {
651
+ val errorJson = BillingUtils.createErrorJson(
652
+ IapErrorCode.E_UNKNOWN,
653
+ "getAppTransactionIOS is only available on iOS"
654
+ )
655
+ throw Exception(errorJson)
656
+ }
657
+ }
658
+
659
+ // iOS-specific method - not supported on Android
660
+ override fun requestPromotedProductIOS(): Promise<NitroProduct?> {
661
+ return Promise.async {
662
+ // Android doesn't have promoted products like iOS App Store
663
+ // Return null as this feature is iOS-only
664
+ null
665
+ }
666
+ }
667
+
668
+ override fun buyPromotedProductIOS(): Promise<Unit> {
669
+ return Promise.async {
670
+ // Android doesn't have promoted products like iOS App Store
671
+ // This is an iOS-only feature, so we do nothing on Android
672
+ }
673
+ }
674
+
675
+ override fun presentCodeRedemptionSheetIOS(): Promise<Boolean> {
676
+ return Promise.async {
677
+ // Android doesn't have a code redemption sheet like iOS App Store
678
+ // This is an iOS-only feature, so we return false on Android
679
+ false
680
+ }
681
+ }
682
+
683
+ override fun clearTransactionIOS(): Promise<Unit> {
684
+ return Promise.async {
685
+ // This is an iOS-only feature for clearing unfinished transactions
686
+ // On Android, we don't need to do anything
687
+ }
688
+ }
689
+
690
+ override fun beginRefundRequestIOS(sku: String): Promise<String?> {
691
+ return Promise.async {
692
+ // Android doesn't have in-app refund requests like iOS
693
+ // Refunds on Android are handled through Google Play Console
694
+ null
695
+ }
696
+ }
697
+
698
+ // Receipt validation
699
+ override fun validateReceipt(params: NitroReceiptValidationParams): Promise<Variant_NitroReceiptValidationResultIOS_NitroReceiptValidationResultAndroid> {
700
+ return Promise.async {
701
+ try {
702
+ // For Android, we need the androidOptions to be provided
703
+ val androidOptions = params.androidOptions
704
+ ?: throw Exception(BillingUtils.createErrorJson(
705
+ IapErrorCode.E_DEVELOPER_ERROR,
706
+ "Android receipt validation requires androidOptions parameter"
707
+ ))
708
+
709
+ // Android receipt validation would typically involve server-side validation
710
+ // using Google Play Developer API. Here we provide a simplified implementation
711
+ // that demonstrates the expected structure.
712
+
713
+ // In a real implementation, you would make an HTTP request to Google Play API
714
+ // using the androidOptions.accessToken, androidOptions.packageName, etc.
715
+
716
+ // For now, we'll return a mock successful validation result
717
+ // This should be replaced with actual Google Play Developer API calls
718
+ val currentTime = System.currentTimeMillis()
719
+
720
+ val result = NitroReceiptValidationResultAndroid(
721
+ autoRenewing = androidOptions.isSub ?: false,
722
+ betaProduct = false,
723
+ cancelDate = null,
724
+ cancelReason = "",
725
+ deferredDate = null,
726
+ deferredSku = null,
727
+ freeTrialEndDate = 0.0,
728
+ gracePeriodEndDate = 0.0,
729
+ parentProductId = params.sku,
730
+ productId = params.sku,
731
+ productType = if (androidOptions.isSub == true) "subs" else "inapp",
732
+ purchaseDate = currentTime.toDouble(),
733
+ quantity = 1.0,
734
+ receiptId = androidOptions.productToken,
735
+ renewalDate = if (androidOptions.isSub == true) (currentTime + (30L * 24 * 60 * 60 * 1000)).toDouble() else 0.0, // 30 days from now if subscription
736
+ term = if (androidOptions.isSub == true) "P1M" else "", // P1M = 1 month
737
+ termSku = params.sku,
738
+ testTransaction = false
739
+ )
740
+
741
+ Variant_NitroReceiptValidationResultIOS_NitroReceiptValidationResultAndroid.Second(result)
742
+
743
+ } catch (e: Exception) {
744
+ val errorJson = BillingUtils.createErrorJson(
745
+ IapErrorCode.E_RECEIPT_FAILED,
746
+ "Receipt validation failed: ${e.message}"
747
+ )
748
+ throw Exception(errorJson)
749
+ }
750
+ }
751
+ }
752
+
753
+ // iOS-specific methods - Not applicable on Android, return appropriate defaults
754
+ override fun subscriptionStatusIOS(sku: String): Promise<Array<NitroSubscriptionStatus>?> {
755
+ return Promise.async {
756
+ throw Exception(BillingUtils.createErrorJson(
757
+ IapErrorCode.E_FEATURE_NOT_SUPPORTED,
758
+ "subscriptionStatusIOS is only available on iOS platform"
759
+ ))
760
+ }
761
+ }
762
+
763
+ override fun currentEntitlementIOS(sku: String): Promise<NitroPurchase?> {
764
+ return Promise.async {
765
+ throw Exception(BillingUtils.createErrorJson(
766
+ IapErrorCode.E_FEATURE_NOT_SUPPORTED,
767
+ "currentEntitlementIOS is only available on iOS platform"
768
+ ))
769
+ }
770
+ }
771
+
772
+ override fun latestTransactionIOS(sku: String): Promise<NitroPurchase?> {
773
+ return Promise.async {
774
+ throw Exception(BillingUtils.createErrorJson(
775
+ IapErrorCode.E_FEATURE_NOT_SUPPORTED,
776
+ "latestTransactionIOS is only available on iOS platform"
777
+ ))
778
+ }
779
+ }
780
+
781
+ override fun getPendingTransactionsIOS(): Promise<Array<NitroPurchase>> {
782
+ return Promise.async {
783
+ throw Exception(BillingUtils.createErrorJson(
784
+ IapErrorCode.E_FEATURE_NOT_SUPPORTED,
785
+ "getPendingTransactionsIOS is only available on iOS platform"
786
+ ))
787
+ }
788
+ }
789
+
790
+ override fun syncIOS(): Promise<Boolean> {
791
+ return Promise.async {
792
+ throw Exception(BillingUtils.createErrorJson(
793
+ IapErrorCode.E_FEATURE_NOT_SUPPORTED,
794
+ "syncIOS is only available on iOS platform"
795
+ ))
796
+ }
797
+ }
798
+
799
+ override fun showManageSubscriptionsIOS(): Promise<Boolean> {
800
+ return Promise.async {
801
+ throw Exception(BillingUtils.createErrorJson(
802
+ IapErrorCode.E_FEATURE_NOT_SUPPORTED,
803
+ "showManageSubscriptionsIOS is only available on iOS platform"
804
+ ))
805
+ }
806
+ }
807
+
808
+ override fun isEligibleForIntroOfferIOS(groupID: String): Promise<Boolean> {
809
+ return Promise.async {
810
+ throw Exception(BillingUtils.createErrorJson(
811
+ IapErrorCode.E_FEATURE_NOT_SUPPORTED,
812
+ "isEligibleForIntroOfferIOS is only available on iOS platform"
813
+ ))
814
+ }
815
+ }
816
+
817
+ override fun getReceiptDataIOS(): Promise<String> {
818
+ return Promise.async {
819
+ throw Exception(BillingUtils.createErrorJson(
820
+ IapErrorCode.E_FEATURE_NOT_SUPPORTED,
821
+ "getReceiptDataIOS is only available on iOS platform"
822
+ ))
823
+ }
824
+ }
825
+
826
+ override fun isTransactionVerifiedIOS(sku: String): Promise<Boolean> {
827
+ return Promise.async {
828
+ throw Exception(BillingUtils.createErrorJson(
829
+ IapErrorCode.E_FEATURE_NOT_SUPPORTED,
830
+ "isTransactionVerifiedIOS is only available on iOS platform"
831
+ ))
832
+ }
833
+ }
834
+
835
+ override fun getTransactionJwsIOS(sku: String): Promise<String?> {
836
+ return Promise.async {
837
+ throw Exception(BillingUtils.createErrorJson(
838
+ IapErrorCode.E_FEATURE_NOT_SUPPORTED,
839
+ "getTransactionJwsIOS is only available on iOS platform"
840
+ ))
841
+ }
842
+ }
843
+ }