react-native-iap 15.2.4 → 15.3.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.
- package/README.md +29 -49
- package/android/build.gradle +92 -22
- package/android/gradle.properties +5 -1
- package/android/src/main/java/com/margelo/nitro/iap/HybridRnIap.kt +1 -1
- package/android/src/main/java/com/margelo/nitro/iap/RnIapLog.kt +3 -1
- package/ios/HybridRnIap.swift +12 -6
- package/lib/module/index.js +73 -158
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/src/hooks/useIAP.d.ts +15 -15
- package/lib/typescript/src/index.d.ts +59 -88
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/specs/RnIap.nitro.d.ts +2 -15
- package/lib/typescript/src/specs/RnIap.nitro.d.ts.map +1 -1
- package/lib/typescript/src/types.d.ts +47 -47
- package/nitro.json +0 -1
- package/nitrogen/generated/android/c++/JHybridRnIapSpec.cpp +7 -7
- package/nitrogen/generated/android/c++/JHybridRnIapSpec.hpp +1 -1
- package/nitrogen/generated/android/c++/{JNitroPurchaseUpdatedListenerOptions.hpp → JPurchaseUpdatedListenerOptions.hpp} +10 -10
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/HybridRnIapSpec.kt +2 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/{NitroPurchaseUpdatedListenerOptions.kt → PurchaseUpdatedListenerOptions.kt} +5 -5
- package/nitrogen/generated/ios/NitroIap-Swift-Cxx-Bridge.hpp +10 -10
- package/nitrogen/generated/ios/NitroIap-Swift-Cxx-Umbrella.hpp +3 -3
- package/nitrogen/generated/ios/c++/HybridRnIapSpecSwift.hpp +4 -4
- package/nitrogen/generated/ios/swift/HybridRnIapSpec.swift +1 -1
- package/nitrogen/generated/ios/swift/HybridRnIapSpec_cxx.swift +1 -1
- package/nitrogen/generated/ios/swift/{NitroPurchaseUpdatedListenerOptions.swift → PurchaseUpdatedListenerOptions.swift} +5 -5
- package/nitrogen/generated/shared/c++/HybridRnIapSpec.hpp +4 -4
- package/nitrogen/generated/shared/c++/{NitroPurchaseUpdatedListenerOptions.hpp → PurchaseUpdatedListenerOptions.hpp} +11 -11
- package/openiap-versions.json +2 -2
- package/package.json +4 -6
- package/src/hooks/useIAP.ts +15 -15
- package/src/index.ts +93 -204
- package/src/specs/RnIap.nitro.ts +2 -15
- package/src/types.ts +47 -47
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# React Native IAP
|
|
2
2
|
|
|
3
3
|
<div align="center">
|
|
4
|
-
<img src="https://
|
|
4
|
+
<img src="https://openiap.dev/frameworks/react-native.webp" alt="React Native IAP Logo" width="150" />
|
|
5
5
|
|
|
6
6
|
[](https://npmjs.org/package/react-native-iap)
|
|
7
7
|
[](https://npmjs.org/package/react-native-iap)
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
|
|
34
34
|
## 📚 Documentation
|
|
35
35
|
|
|
36
|
-
**[📖 Visit our comprehensive documentation site →](https://
|
|
36
|
+
**[📖 Visit our comprehensive documentation site →](https://openiap.dev/docs/setup/react-native)**
|
|
37
37
|
|
|
38
38
|
## ⚠️ Notice
|
|
39
39
|
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
- Seeing Swift 6 C++ interop errors in Nitro (e.g., `AnyMap.swift` with `cppPart.pointee.*`)? Temporarily pin Swift to **5.10** for the `NitroModules` pod (see Installation docs) or upgrade RN and Nitro deps.
|
|
47
47
|
- Recommended: upgrade to RN 0.79+, update `react-native-nitro-modules`/`nitro-codegen`, then `pod install` and clean build.
|
|
48
48
|
|
|
49
|
-
More details and the Podfile snippet are in the docs: https://
|
|
49
|
+
More details and the Podfile snippet are in the docs: https://openiap.dev/docs/setup/react-native#ios
|
|
50
50
|
|
|
51
51
|
## ✨ Features
|
|
52
52
|
|
|
@@ -55,7 +55,7 @@ More details and the Podfile snippet are in the docs: https://hyochan.github.io/
|
|
|
55
55
|
- 🎯 **TypeScript First**: Full TypeScript support with comprehensive type definitions
|
|
56
56
|
- 🛡️ **Centralized Error Handling**: Unified error management with platform-specific error code mapping
|
|
57
57
|
- 🎣 **React Hooks**: Modern React hooks API with `useIAP`
|
|
58
|
-
- 📱 **
|
|
58
|
+
- 📱 **React Native Focused**: Use `expo-iap` for Expo projects
|
|
59
59
|
- 🔍 **Receipt Validation**: Built-in receipt validation for both platforms
|
|
60
60
|
- 💎 **Products & Subscriptions**: Support for both one-time purchases and subscriptions
|
|
61
61
|
- 🚀 **Performance Optimized**: Efficient caching and minimal re-renders
|
|
@@ -68,7 +68,7 @@ npm install react-native-iap react-native-nitro-modules
|
|
|
68
68
|
yarn add react-native-iap react-native-nitro-modules
|
|
69
69
|
```
|
|
70
70
|
|
|
71
|
-
**[📖 See the complete installation guide and quick start tutorial →](https://
|
|
71
|
+
**[📖 See the complete installation guide and quick start tutorial →](https://openiap.dev/docs/setup/react-native#installation)**
|
|
72
72
|
|
|
73
73
|
## 🏗️ Architecture
|
|
74
74
|
|
|
@@ -82,13 +82,13 @@ React Native IAP is built with a modern architecture that emphasizes:
|
|
|
82
82
|
|
|
83
83
|
## 📱 Platform Support
|
|
84
84
|
|
|
85
|
-
| Platform | Support | Notes
|
|
86
|
-
| ----------------- | ------- |
|
|
87
|
-
| iOS | ✅ | StoreKit 2 (requires iOS 15+)
|
|
88
|
-
| Android | ✅ | Google Play Billing v8.0.0+
|
|
89
|
-
| Expo Go | ❌ |
|
|
90
|
-
| Expo Dev Client |
|
|
91
|
-
| Bare React Native | ✅ | Full support
|
|
85
|
+
| Platform | Support | Notes |
|
|
86
|
+
| ----------------- | ------- | --------------------------------- |
|
|
87
|
+
| iOS | ✅ | StoreKit 2 (requires iOS 15+) |
|
|
88
|
+
| Android | ✅ | Google Play Billing v8.0.0+ |
|
|
89
|
+
| Expo Go | ❌ | Use `expo-iap` for Expo projects |
|
|
90
|
+
| Expo Dev Client | ❌ | Use `expo-iap` for Expo projects |
|
|
91
|
+
| Bare React Native | ✅ | Full support |
|
|
92
92
|
|
|
93
93
|
## 📦 Installation & Configuration
|
|
94
94
|
|
|
@@ -96,7 +96,7 @@ React Native IAP is built with a modern architecture that emphasizes:
|
|
|
96
96
|
|
|
97
97
|
Before installing React Native IAP, make sure you have:
|
|
98
98
|
|
|
99
|
-
- React Native 0.64 or later
|
|
99
|
+
- React Native 0.64 or later
|
|
100
100
|
- Node.js 16 or later
|
|
101
101
|
- iOS 15+ for iOS apps (StoreKit 2 requirement)
|
|
102
102
|
- Android API level 21+ for Android apps
|
|
@@ -112,7 +112,7 @@ In your root `android/build.gradle`:
|
|
|
112
112
|
```gradle
|
|
113
113
|
buildscript {
|
|
114
114
|
ext {
|
|
115
|
-
kotlinVersion = "2.
|
|
115
|
+
kotlinVersion = "2.2.0"
|
|
116
116
|
}
|
|
117
117
|
dependencies {
|
|
118
118
|
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion"
|
|
@@ -134,59 +134,39 @@ buildscript {
|
|
|
134
134
|
- Go to "Signing & Capabilities"
|
|
135
135
|
- Click "+ Capability" and add "In-App Purchase"
|
|
136
136
|
|
|
137
|
-
#### Expo
|
|
138
|
-
|
|
139
|
-
For Expo projects, add the plugin to your `app.json` or `expo.json`:
|
|
140
|
-
|
|
141
|
-
```json
|
|
142
|
-
{
|
|
143
|
-
"expo": {
|
|
144
|
-
"plugins": [
|
|
145
|
-
"react-native-iap",
|
|
146
|
-
[
|
|
147
|
-
"expo-build-properties",
|
|
148
|
-
{
|
|
149
|
-
"android": {
|
|
150
|
-
"kotlinVersion": "2.2.0"
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
]
|
|
154
|
-
]
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
```
|
|
137
|
+
#### Expo Projects
|
|
158
138
|
|
|
159
|
-
|
|
139
|
+
Use [`expo-iap`](https://github.com/hyodotdev/openiap/tree/main/libraries/expo-iap) for Expo apps. This package targets bare React Native/Nitro projects.
|
|
160
140
|
|
|
161
141
|
### Store Configuration
|
|
162
142
|
|
|
163
143
|
React Native IAP is **OpenIAP compliant**. For detailed store configuration:
|
|
164
144
|
|
|
165
|
-
- **[iOS Setup →](https://
|
|
166
|
-
- **[Android Setup →](https://
|
|
145
|
+
- **[iOS Setup →](https://openiap.dev/docs/ios-setup)** - App Store Connect configuration
|
|
146
|
+
- **[Android Setup →](https://openiap.dev/docs/android-setup)** - Google Play Console configuration
|
|
167
147
|
|
|
168
148
|
## 🤖 Using with AI Assistants
|
|
169
149
|
|
|
170
150
|
React Native IAP provides AI-friendly documentation for Cursor, GitHub Copilot, Claude, and ChatGPT.
|
|
171
151
|
|
|
172
|
-
**[📖 AI Assistants Guide →](https://
|
|
152
|
+
**[📖 AI Assistants Guide →](https://openiap.dev/docs/guides/ai-assistants)**
|
|
173
153
|
|
|
174
154
|
Quick links:
|
|
175
155
|
|
|
176
|
-
- [llms.txt](https://
|
|
177
|
-
- [llms-full.txt](https://
|
|
156
|
+
- [llms.txt](https://openiap.dev/llms.txt) - Quick reference
|
|
157
|
+
- [llms-full.txt](https://openiap.dev/llms-full.txt) - Full API reference
|
|
178
158
|
|
|
179
159
|
## 🎯 What's Next?
|
|
180
160
|
|
|
181
|
-
**[📖 Visit our comprehensive documentation site →](https://
|
|
161
|
+
**[📖 Visit our comprehensive documentation site →](https://openiap.dev/docs/setup/react-native)**
|
|
182
162
|
|
|
183
163
|
### Key Resources
|
|
184
164
|
|
|
185
|
-
- **[Installation & Quick Start](https://
|
|
186
|
-
- **[API Reference](https://
|
|
187
|
-
- **[Examples](https://
|
|
188
|
-
- **[Error Handling](https://
|
|
189
|
-
- **[Troubleshooting](https://
|
|
165
|
+
- **[Installation & Quick Start](https://openiap.dev/docs/setup/react-native#installation)** - Get started in minutes
|
|
166
|
+
- **[API Reference](https://openiap.dev/docs/apis)** - Complete useIAP hook documentation
|
|
167
|
+
- **[Examples](https://openiap.dev/docs/example)** - Production-ready implementations
|
|
168
|
+
- **[Error Handling](https://openiap.dev/docs/errors)** - OpenIAP compliant error codes
|
|
169
|
+
- **[Troubleshooting](https://openiap.dev/docs/features/debugging)** - Common issues and solutions
|
|
190
170
|
|
|
191
171
|
## Powered by OpenIAP
|
|
192
172
|
|
|
@@ -217,10 +197,10 @@ Other libraries built on OpenIAP: [expo-iap](https://github.com/hyodotdev/openia
|
|
|
217
197
|
|
|
218
198
|
<div style="display: flex; align-items:center; gap: 10px;">
|
|
219
199
|
<a href="https://namiml.com" style="opacity: 50%">
|
|
220
|
-
<img src="https://
|
|
200
|
+
<img src="https://openiap.dev/sponsors/nami.webp" alt="Nami ML" width="140"/>
|
|
221
201
|
</a>
|
|
222
202
|
<a href="https://www.courier.com/?utm_source=react-native-iap&utm_campaign=osssponsors" style="opacity: 50%;">
|
|
223
|
-
<img width="80" alt="courier_dot_com" src="https://
|
|
203
|
+
<img width="80" alt="courier_dot_com" src="https://openiap.dev/sponsors/courier.webp" />
|
|
224
204
|
</a>
|
|
225
205
|
</div>
|
|
226
206
|
|
package/android/build.gradle
CHANGED
|
@@ -1,14 +1,50 @@
|
|
|
1
1
|
import groovy.json.JsonSlurper
|
|
2
|
+
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
|
2
3
|
|
|
3
4
|
buildscript {
|
|
5
|
+
def googleRootBuildFile = [
|
|
6
|
+
new File(projectDir, '../../../packages/google/build.gradle.kts'),
|
|
7
|
+
new File(rootDir, '../../../packages/google/build.gradle.kts'),
|
|
8
|
+
new File(rootProject.projectDir, '../../../packages/google/build.gradle.kts')
|
|
9
|
+
].find { it.exists() }
|
|
10
|
+
|
|
11
|
+
def googlePluginVersion = { pluginId ->
|
|
12
|
+
if (googleRootBuildFile == null) {
|
|
13
|
+
return null
|
|
14
|
+
}
|
|
15
|
+
def marker = "id(\"${pluginId}\") version \""
|
|
16
|
+
def line = googleRootBuildFile.readLines().find { it.contains(marker) }
|
|
17
|
+
if (line == null) {
|
|
18
|
+
return null
|
|
19
|
+
}
|
|
20
|
+
def matcher = line =~ /version "([^"]+)"/
|
|
21
|
+
return matcher.find() ? matcher.group(1) : null
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
def configuredVersion = { extName, propertyName ->
|
|
25
|
+
if (rootProject.ext.has(extName)) {
|
|
26
|
+
return rootProject.ext.get(extName).toString()
|
|
27
|
+
}
|
|
28
|
+
def propertyValue = project.findProperty(propertyName)
|
|
29
|
+
if (propertyValue == null || propertyValue.toString().trim().isEmpty()) {
|
|
30
|
+
throw new GradleException("react-native-iap: missing ${propertyName} in android/gradle.properties")
|
|
31
|
+
}
|
|
32
|
+
return propertyValue.toString()
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
def androidGradlePluginVersion = googlePluginVersion('com.android.library')
|
|
36
|
+
?: configuredVersion('androidGradlePluginVersion', 'NitroIap_androidGradlePluginVersion')
|
|
37
|
+
def kotlinGradlePluginVersion = googlePluginVersion('org.jetbrains.kotlin.android')
|
|
38
|
+
?: configuredVersion('kotlinVersion', 'NitroIap_kotlinVersion')
|
|
39
|
+
|
|
4
40
|
repositories {
|
|
5
41
|
google()
|
|
6
42
|
mavenCentral()
|
|
7
43
|
}
|
|
8
44
|
|
|
9
45
|
dependencies {
|
|
10
|
-
classpath "com.android.tools.build:gradle
|
|
11
|
-
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin
|
|
46
|
+
classpath "com.android.tools.build:gradle:$androidGradlePluginVersion"
|
|
47
|
+
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinGradlePluginVersion"
|
|
12
48
|
}
|
|
13
49
|
}
|
|
14
50
|
|
|
@@ -45,9 +81,6 @@ def googleVersionString = googleVersion.trim()
|
|
|
45
81
|
apply plugin: "com.android.library"
|
|
46
82
|
apply plugin: 'org.jetbrains.kotlin.android'
|
|
47
83
|
|
|
48
|
-
// Get kotlinVersion from root project or use default
|
|
49
|
-
def kotlinVersion = rootProject.ext.has('kotlinVersion') ? rootProject.ext.get('kotlinVersion') : '2.0.21'
|
|
50
|
-
|
|
51
84
|
// Only apply Nitro autolinking if the file exists
|
|
52
85
|
def nitroAutolinkingFile = file('../nitrogen/generated/android/NitroIap+autolinking.gradle')
|
|
53
86
|
if (nitroAutolinkingFile.exists()) {
|
|
@@ -63,25 +96,61 @@ apply from: "./fix-prefab.gradle"
|
|
|
63
96
|
// }
|
|
64
97
|
|
|
65
98
|
def getExtOrDefault(name) {
|
|
66
|
-
|
|
99
|
+
def value = rootProject.ext.has(name) ? rootProject.ext.get(name) : project.properties["NitroIap_" + name]
|
|
100
|
+
if (value == null || value.toString().trim().isEmpty()) {
|
|
101
|
+
throw new GradleException("react-native-iap: missing NitroIap_${name} in android/gradle.properties")
|
|
102
|
+
}
|
|
103
|
+
return value
|
|
67
104
|
}
|
|
68
105
|
|
|
69
106
|
def getExtOrIntegerDefault(name) {
|
|
70
|
-
return
|
|
107
|
+
return getExtOrDefault(name).toString().toInteger()
|
|
71
108
|
}
|
|
72
109
|
|
|
73
110
|
// Read horizonEnabled from gradle.properties, default to false (play)
|
|
74
111
|
def horizonEnabled = project.findProperty('horizonEnabled')?.toBoolean() ?: false
|
|
75
112
|
|
|
113
|
+
def resolveOpenIapGoogleBuildFile() {
|
|
114
|
+
def candidates = [
|
|
115
|
+
new File(projectDir, '../../../packages/google/openiap/build.gradle.kts'),
|
|
116
|
+
new File(rootDir, '../../../packages/google/openiap/build.gradle.kts'),
|
|
117
|
+
new File(rootProject.projectDir, '../../../packages/google/openiap/build.gradle.kts')
|
|
118
|
+
]
|
|
119
|
+
return candidates.find { it.exists() }
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
def readOpenIapGoogleVariable(File buildFile, String variableName) {
|
|
123
|
+
if (buildFile == null) {
|
|
124
|
+
return null
|
|
125
|
+
}
|
|
126
|
+
def matcher = buildFile.text =~ /val\s+${variableName}\s*=\s*"([^"]+)"/
|
|
127
|
+
return matcher.find() ? matcher.group(1) : null
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
def readOpenIapGoogleDependencyVersion(File buildFile, String coordinate) {
|
|
131
|
+
if (buildFile == null) {
|
|
132
|
+
return null
|
|
133
|
+
}
|
|
134
|
+
def matcher = buildFile.text =~ /${java.util.regex.Pattern.quote(coordinate)}:([^"$)]+)/
|
|
135
|
+
return matcher.find() ? matcher.group(1) : null
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
def googleOpenIapBuildFile = resolveOpenIapGoogleBuildFile()
|
|
139
|
+
def coroutinesVersion = readOpenIapGoogleVariable(googleOpenIapBuildFile, 'coroutinesVersion')
|
|
140
|
+
?: getExtOrDefault("coroutinesVersion")
|
|
141
|
+
def playServicesBaseVersion = getExtOrDefault("playServicesBaseVersion")
|
|
142
|
+
def junitVersion = readOpenIapGoogleDependencyVersion(googleOpenIapBuildFile, 'junit:junit')
|
|
143
|
+
?: getExtOrDefault("junitVersion")
|
|
144
|
+
|
|
76
145
|
android {
|
|
77
|
-
namespace "com.margelo.nitro.iap"
|
|
146
|
+
namespace = "com.margelo.nitro.iap"
|
|
78
147
|
|
|
79
|
-
ndkVersion getExtOrDefault("ndkVersion")
|
|
148
|
+
ndkVersion = getExtOrDefault("ndkVersion")
|
|
80
149
|
compileSdkVersion getExtOrIntegerDefault("compileSdkVersion")
|
|
81
150
|
|
|
82
151
|
defaultConfig {
|
|
83
|
-
minSdkVersion getExtOrIntegerDefault("minSdkVersion")
|
|
84
|
-
targetSdkVersion getExtOrIntegerDefault("targetSdkVersion")
|
|
152
|
+
minSdkVersion = getExtOrIntegerDefault("minSdkVersion")
|
|
153
|
+
targetSdkVersion = getExtOrIntegerDefault("targetSdkVersion")
|
|
85
154
|
buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString()
|
|
86
155
|
// Ship consumer keep rules so Nitro HybridObjects aren't stripped in app release builds
|
|
87
156
|
consumerProguardFiles 'consumer-rules.pro'
|
|
@@ -136,13 +205,13 @@ android {
|
|
|
136
205
|
}
|
|
137
206
|
|
|
138
207
|
buildFeatures {
|
|
139
|
-
buildConfig true
|
|
140
|
-
prefab true
|
|
208
|
+
buildConfig = true
|
|
209
|
+
prefab = true
|
|
141
210
|
}
|
|
142
211
|
|
|
143
212
|
buildTypes {
|
|
144
213
|
release {
|
|
145
|
-
minifyEnabled false
|
|
214
|
+
minifyEnabled = false
|
|
146
215
|
}
|
|
147
216
|
}
|
|
148
217
|
|
|
@@ -151,11 +220,6 @@ android {
|
|
|
151
220
|
targetCompatibility JavaVersion.VERSION_17
|
|
152
221
|
}
|
|
153
222
|
|
|
154
|
-
// Configure Kotlin compiler to match Java compatibility
|
|
155
|
-
kotlinOptions {
|
|
156
|
-
jvmTarget = "17"
|
|
157
|
-
}
|
|
158
|
-
|
|
159
223
|
lintOptions {
|
|
160
224
|
disable "GradleCompatible"
|
|
161
225
|
}
|
|
@@ -163,6 +227,12 @@ android {
|
|
|
163
227
|
// Removed sourceSets configuration for codegen as it's not needed for library modules
|
|
164
228
|
}
|
|
165
229
|
|
|
230
|
+
kotlin {
|
|
231
|
+
compilerOptions {
|
|
232
|
+
jvmTarget.set(JvmTarget.JVM_17)
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
166
236
|
repositories {
|
|
167
237
|
mavenCentral()
|
|
168
238
|
google()
|
|
@@ -181,10 +251,10 @@ dependencies {
|
|
|
181
251
|
}
|
|
182
252
|
|
|
183
253
|
// Google Play Services
|
|
184
|
-
implementation
|
|
254
|
+
implementation "com.google.android.gms:play-services-base:$playServicesBaseVersion"
|
|
185
255
|
|
|
186
256
|
// Kotlin coroutines
|
|
187
|
-
implementation
|
|
257
|
+
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutinesVersion"
|
|
188
258
|
|
|
189
259
|
// Determine which OpenIAP dependency to use
|
|
190
260
|
// In monorepo: use local packages/google source if available
|
|
@@ -198,7 +268,7 @@ dependencies {
|
|
|
198
268
|
}
|
|
199
269
|
|
|
200
270
|
// Test dependencies
|
|
201
|
-
testImplementation
|
|
271
|
+
testImplementation "junit:junit:$junitVersion"
|
|
202
272
|
testImplementation 'org.jetbrains.kotlin:kotlin-test'
|
|
203
273
|
testImplementation 'org.jetbrains.kotlin:kotlin-test-junit'
|
|
204
274
|
}
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
NitroIap_kotlinVersion=2.
|
|
1
|
+
NitroIap_kotlinVersion=2.2.0
|
|
2
|
+
NitroIap_androidGradlePluginVersion=8.13.2
|
|
3
|
+
NitroIap_coroutinesVersion=1.9.0
|
|
4
|
+
NitroIap_playServicesBaseVersion=18.5.0
|
|
5
|
+
NitroIap_junitVersion=4.13.2
|
|
2
6
|
NitroIap_minSdkVersion=23
|
|
3
7
|
NitroIap_targetSdkVersion=36
|
|
4
8
|
NitroIap_compileSdkVersion=36
|
|
@@ -793,7 +793,7 @@ class HybridRnIap : HybridRnIapSpec() {
|
|
|
793
793
|
// Event listener methods
|
|
794
794
|
override fun addPurchaseUpdatedListener(
|
|
795
795
|
listener: (purchase: NitroPurchase) -> Unit,
|
|
796
|
-
options:
|
|
796
|
+
options: PurchaseUpdatedListenerOptions?
|
|
797
797
|
): Double {
|
|
798
798
|
return synchronized(purchaseUpdatedListeners) {
|
|
799
799
|
val token = nextPurchaseUpdatedListenerToken
|
package/ios/HybridRnIap.swift
CHANGED
|
@@ -388,7 +388,10 @@ class HybridRnIap: HybridRnIapSpec {
|
|
|
388
388
|
|
|
389
389
|
RnIapLog.payload("validateReceiptIOS", ["sku": sku])
|
|
390
390
|
let props = try OpenIapSerialization.verifyPurchaseProps(from: ["apple": ["sku": sku]])
|
|
391
|
-
let
|
|
391
|
+
let verifyResult = try await OpenIapModule.shared.verifyPurchase(props)
|
|
392
|
+
guard case let .verifyPurchaseResultIos(result) = verifyResult else {
|
|
393
|
+
throw OpenIapException.make(code: .featureNotSupported, message: "Expected iOS validation result")
|
|
394
|
+
}
|
|
392
395
|
var encoded = RnIapHelper.sanitizeDictionary(OpenIapSerialization.encode(result))
|
|
393
396
|
if encoded["receiptData"] != nil {
|
|
394
397
|
encoded["receiptData"] = "<receipt>"
|
|
@@ -488,7 +491,7 @@ class HybridRnIap: HybridRnIapSpec {
|
|
|
488
491
|
return Promise.async {
|
|
489
492
|
do {
|
|
490
493
|
RnIapLog.payload("getStorefront", nil)
|
|
491
|
-
let storefront = try await OpenIapModule.shared.
|
|
494
|
+
let storefront = try await OpenIapModule.shared.getStorefront()
|
|
492
495
|
RnIapLog.result("getStorefront", storefront)
|
|
493
496
|
return storefront
|
|
494
497
|
} catch let purchaseError as PurchaseError {
|
|
@@ -578,9 +581,12 @@ class HybridRnIap: HybridRnIapSpec {
|
|
|
578
581
|
RnIapLog.payload("buyPromotedProductIOS", nil)
|
|
579
582
|
let ok = try await OpenIapModule.shared.requestPurchaseOnPromotedProductIOS()
|
|
580
583
|
RnIapLog.result("buyPromotedProductIOS", ok)
|
|
584
|
+
} catch let purchaseError as PurchaseError {
|
|
585
|
+
RnIapLog.failure("buyPromotedProductIOS", error: purchaseError)
|
|
586
|
+
throw OpenIapException.from(purchaseError)
|
|
581
587
|
} catch {
|
|
582
|
-
// Event-only: OpenIAP will emit purchaseError for this flow. Avoid Promise rejection.
|
|
583
588
|
RnIapLog.failure("buyPromotedProductIOS", error: error)
|
|
589
|
+
throw OpenIapException.make(code: .featureNotSupported, message: error.localizedDescription)
|
|
584
590
|
}
|
|
585
591
|
}
|
|
586
592
|
}
|
|
@@ -954,7 +960,7 @@ class HybridRnIap: HybridRnIapSpec {
|
|
|
954
960
|
|
|
955
961
|
func addPurchaseUpdatedListener(
|
|
956
962
|
listener: @escaping (NitroPurchase) -> Void,
|
|
957
|
-
options:
|
|
963
|
+
options: PurchaseUpdatedListenerOptions?
|
|
958
964
|
) throws -> Double {
|
|
959
965
|
let dedupeTransactionIOS = purchaseUpdatedDedupeTransactionIOS(from: options)
|
|
960
966
|
let receiveDuplicateTransactionUpdatesIOS = !dedupeTransactionIOS
|
|
@@ -998,7 +1004,7 @@ class HybridRnIap: HybridRnIapSpec {
|
|
|
998
1004
|
}
|
|
999
1005
|
|
|
1000
1006
|
private func purchaseUpdatedDedupeTransactionIOS(
|
|
1001
|
-
from options:
|
|
1007
|
+
from options: PurchaseUpdatedListenerOptions?
|
|
1002
1008
|
) -> Bool {
|
|
1003
1009
|
guard let dedupeTransactionIOS = options?.dedupeTransactionIOS else {
|
|
1004
1010
|
return true
|
|
@@ -1147,7 +1153,7 @@ class HybridRnIap: HybridRnIapSpec {
|
|
|
1147
1153
|
return
|
|
1148
1154
|
}
|
|
1149
1155
|
RnIapLog.payload("purchaseUpdatedListener.register.duplicates", nil)
|
|
1150
|
-
let options = PurchaseUpdatedListenerOptions(
|
|
1156
|
+
let options = OpenIAP.PurchaseUpdatedListenerOptions(
|
|
1151
1157
|
dedupeTransactionIOS: false
|
|
1152
1158
|
)
|
|
1153
1159
|
purchaseUpdatedDuplicateSub = OpenIapModule.shared.purchaseUpdatedListener({ [weak self] openIapPurchase in
|