expo-iap 3.0.0 → 3.0.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/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # CHANGELOG
2
2
 
3
+ ## 3.0.1 - 2025-09-13
4
+
5
+ - Android: Ensure `openiap-google:1.1.0` is added inside `dependencies {}` and replace/dedupe existing entries. In local dev, remove the Maven line and rely on `project(':openiap-google')`. Library fallback bumped to 1.1.0.
6
+ - iOS: Honor `enableLocalDev: false` even when `localPath` is set. Ensure CocoaPods CDN in Podfile and remove any stale local `pod 'openiap', :path => ...` lines.
7
+ - Misc: Drop legacy Billing/GMS cleanup patterns, simplify prebuild logs, and add a short release blog post.
8
+
3
9
  ## 3.0.0 - 2025-09-13
4
10
 
5
11
  Breaking changes:
package/README.md CHANGED
@@ -16,7 +16,15 @@
16
16
 
17
17
  ## Notice
18
18
 
19
- The `expo-iap` module has been migrated from [react-native-iap](https://github.com/dooboolab/react-native-iap). Moving forward, the `react-native-iap` repository will gradually be deprecated, and `expo-iap` will become the actively maintained module. Please take note of this transition. For more details, refer to the [Future Roadmap and Discussion in react-native-iap](https://github.com/dooboolab-community/react-native-iap/discussions/2754). Additionally, you can check the [Current Project Status comment](https://github.com/dooboolab-community/react-native-iap/discussions/2754#discussioncomment-10510249) to stay updated on the project's progress.
19
+ The `expo-iap` module has been migrated from [react-native-iap](https://github.com/dooboolab/react-native-iap). While we initially considered fully merging everything into `react-native-iap`, we ultimately decided to maintain the two libraries in parallel, each tailored to its own ecosystem.
20
+
21
+ - **`react-native-iap`** → a **Nitro Modules–based** implementation for React Native.
22
+ - **`expo-iap`** → an **Expo Module** with tighter integration and smoother compatibility in the Expo ecosystem.
23
+
24
+ Both libraries will continue to be maintained in parallel going forward.
25
+
26
+ 📖 See the [Future Roadmap and Discussion](https://github.com/dooboolab-community/react-native-iap/discussions/2754) for more details.
27
+ 👉 Stay updated via the [Current Project Status comment](https://github.com/dooboolab-community/react-native-iap/discussions/2754#discussioncomment-10510249).
20
28
 
21
29
  ## Installation
22
30
 
@@ -58,6 +58,6 @@ dependencies {
58
58
  implementation project(":openiap-google")
59
59
  } else {
60
60
  // Fallback to published artifact when local project isn't linked
61
- implementation "io.github.hyochan.openiap:openiap-google:1.0.1"
61
+ implementation "io.github.hyochan.openiap:openiap-google:1.1.0"
62
62
  }
63
63
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "expo-iap",
3
- "version": "3.0.0",
3
+ "version": "3.0.1",
4
4
  "description": "In App Purchase module in Expo",
5
5
  "main": "build/index.js",
6
6
  "types": "build/index.d.ts",
@@ -65,21 +65,26 @@ const addLineToGradle = (content, anchor, lineToAdd, offset = 1) => {
65
65
  };
66
66
  const modifyAppBuildGradle = (gradle, language) => {
67
67
  let modified = gradle;
68
- // Add OpenIAP dependency to app-level build.gradle(.kts)
68
+ // Ensure OpenIAP dependency exists at desired version in app-level build.gradle(.kts)
69
69
  const impl = (ga, v) => language === 'kotlin'
70
70
  ? ` implementation("${ga}:${v}")`
71
71
  : ` implementation "${ga}:${v}"`;
72
72
  // Pin OpenIAP Google library to 1.1.0
73
73
  const openiapDep = impl('io.github.hyochan.openiap:openiap-google', '1.1.0');
74
- const hasGA = (ga) => new RegExp(String.raw `\b(?:implementation|api)\s*\(?["']${ga}:`, 'm').test(modified);
75
- let hasAddedDependency = false;
76
- if (!hasGA('io.github.hyochan.openiap:openiap-google')) {
77
- modified = addLineToGradle(modified, /dependencies\s*{/, openiapDep, 0);
78
- hasAddedDependency = true;
74
+ // Remove any existing openiap-google lines (any version, groovy/kotlin, implementation/api)
75
+ const openiapAnyLine = /^\s*(?:implementation|api)\s*\(?\s*["']io\.github\.hyochan\.openiap:openiap-google:[^"']+["']\s*\)?\s*$/gm;
76
+ const hadExisting = openiapAnyLine.test(modified);
77
+ if (hadExisting) {
78
+ modified = modified.replace(openiapAnyLine, '').replace(/\n{3,}/g, '\n\n');
79
+ }
80
+ // Ensure the desired dependency line is present
81
+ if (!new RegExp(String.raw `io\.github\.hyochan\.openiap:openiap-google:1\.1\.0`).test(modified)) {
82
+ // Insert just after the opening `dependencies {` line
83
+ modified = addLineToGradle(modified, /dependencies\s*{/, openiapDep, 1);
84
+ logOnce(hadExisting
85
+ ? '🛠️ expo-iap: Replaced OpenIAP dependency with 1.1.0'
86
+ : '🛠️ expo-iap: Added OpenIAP dependency (1.1.0) to build.gradle');
79
87
  }
80
- // Log only once and only if we actually added dependencies
81
- if (hasAddedDependency)
82
- logOnce('🛠️ expo-iap: Added OpenIAP dependency to build.gradle');
83
88
  return modified;
84
89
  };
85
90
  const withIapAndroid = (config, props) => {
@@ -141,11 +146,12 @@ const withIapIOS = (config) => {
141
146
  };
142
147
  const withIap = (config, options) => {
143
148
  try {
144
- const isLocalDev = !!(options?.enableLocalDev || options?.localPath);
149
+ // Respect explicit flag; fall back to presence of localPath only when flag is unset
150
+ const isLocalDev = options?.enableLocalDev ?? !!options?.localPath;
145
151
  // Apply Android modifications (skip adding deps when linking local module)
146
152
  let result = withIapAndroid(config, { addDeps: !isLocalDev });
147
153
  // iOS: choose one path to avoid overlap
148
- if (options?.enableLocalDev || options?.localPath) {
154
+ if (isLocalDev) {
149
155
  if (!options?.localPath) {
150
156
  config_plugins_1.WarningAggregator.addWarningIOS('expo-iap', 'enableLocalDev is true but no localPath provided. Skipping local OpenIAP integration.');
151
157
  }
@@ -177,10 +177,12 @@ const withLocalOpenIAP = (config, props) => {
177
177
  }
178
178
  const gradle = config.modResults;
179
179
  const dependencyLine = ` implementation project(':openiap-google')`;
180
- // Remove any previously injected external deps that can conflict with the local module
180
+ // Remove any previously added Maven deps for openiap-google to avoid duplicate classes
181
181
  const removalPatterns = [
182
- /\n\s*implementation\s+"com\.android\.billingclient:billing-ktx:[^"]+"\s*\n/g,
183
- /\n\s*implementation\s+"com\.google\.android\.gms:play-services-base:[^"]+"\s*\n/g,
182
+ // Groovy DSL: implementation "io.github.hyochan.openiap:openiap-google:x.y.z" or api "..."
183
+ /^\s*(?:implementation|api)\s+["']io\.github\.hyochan\.openiap:openiap-google:[^"']+["']\s*$/gm,
184
+ // Kotlin DSL: implementation("io.github.hyochan.openiap:openiap-google:x.y.z") or api("...")
185
+ /^\s*(?:implementation|api)\s*\(\s*["']io\.github\.hyochan\.openiap:openiap-google:[^"']+["']\s*\)\s*$/gm,
184
186
  ];
185
187
  let contents = gradle.contents;
186
188
  let removedAny = false;
@@ -192,7 +194,7 @@ const withLocalOpenIAP = (config, props) => {
192
194
  }
193
195
  if (removedAny) {
194
196
  gradle.contents = contents;
195
- console.log('🧹 Removed external Play Billing/GMS deps to use local :openiap-google');
197
+ console.log('🧹 Removed Maven openiap-google to use local :openiap-google');
196
198
  }
197
199
  if (!gradle.contents.includes(dependencyLine)) {
198
200
  const anchor = /dependencies\s*\{/m;
@@ -216,8 +218,10 @@ const withLocalOpenIAP = (config, props) => {
216
218
  if (fs.existsSync(appBuildGradle)) {
217
219
  let contents = fs.readFileSync(appBuildGradle, 'utf8');
218
220
  const patterns = [
219
- /\n\s*implementation\s+"com\.android\.billingclient:billing-ktx:[^"]+"\s*\n/g,
220
- /\n\s*implementation\s+"com\.google\.android\.gms:play-services-base:[^"]+"\s*\n/g,
221
+ // Groovy DSL
222
+ /^\s*(?:implementation|api)\s+["']io\.github\.hyochan\.openiap:openiap-google:[^"']+["']\s*$/gm,
223
+ // Kotlin DSL
224
+ /^\s*(?:implementation|api)\s*\(\s*["']io\.github\.hyochan\.openiap:openiap-google:[^"']+["']\s*\)\s*$/gm,
221
225
  ];
222
226
  let changed = false;
223
227
  for (const p of patterns) {
@@ -228,7 +232,7 @@ const withLocalOpenIAP = (config, props) => {
228
232
  }
229
233
  if (changed) {
230
234
  fs.writeFileSync(appBuildGradle, contents);
231
- console.log('🧹 expo-iap: Cleaned app/build.gradle billing/gms deps for local :openiap-google');
235
+ console.log('🧹 expo-iap: Cleaned Maven openiap-google for local :openiap-google');
232
236
  }
233
237
  }
234
238
  }
@@ -49,7 +49,7 @@ const modifyAppBuildGradle = (
49
49
  ): string => {
50
50
  let modified = gradle;
51
51
 
52
- // Add OpenIAP dependency to app-level build.gradle(.kts)
52
+ // Ensure OpenIAP dependency exists at desired version in app-level build.gradle(.kts)
53
53
  const impl = (ga: string, v: string) =>
54
54
  language === 'kotlin'
55
55
  ? ` implementation("${ga}:${v}")`
@@ -57,21 +57,28 @@ const modifyAppBuildGradle = (
57
57
  // Pin OpenIAP Google library to 1.1.0
58
58
  const openiapDep = impl('io.github.hyochan.openiap:openiap-google', '1.1.0');
59
59
 
60
- const hasGA = (ga: string) =>
61
- new RegExp(String.raw`\b(?:implementation|api)\s*\(?["']${ga}:`, 'm').test(
62
- modified,
63
- );
64
-
65
- let hasAddedDependency = false;
66
-
67
- if (!hasGA('io.github.hyochan.openiap:openiap-google')) {
68
- modified = addLineToGradle(modified, /dependencies\s*{/, openiapDep, 0);
69
- hasAddedDependency = true;
60
+ // Remove any existing openiap-google lines (any version, groovy/kotlin, implementation/api)
61
+ const openiapAnyLine =
62
+ /^\s*(?:implementation|api)\s*\(?\s*["']io\.github\.hyochan\.openiap:openiap-google:[^"']+["']\s*\)?\s*$/gm;
63
+ const hadExisting = openiapAnyLine.test(modified);
64
+ if (hadExisting) {
65
+ modified = modified.replace(openiapAnyLine, '').replace(/\n{3,}/g, '\n\n');
70
66
  }
71
67
 
72
- // Log only once and only if we actually added dependencies
73
- if (hasAddedDependency)
74
- logOnce('🛠️ expo-iap: Added OpenIAP dependency to build.gradle');
68
+ // Ensure the desired dependency line is present
69
+ if (
70
+ !new RegExp(
71
+ String.raw`io\.github\.hyochan\.openiap:openiap-google:1\.1\.0`,
72
+ ).test(modified)
73
+ ) {
74
+ // Insert just after the opening `dependencies {` line
75
+ modified = addLineToGradle(modified, /dependencies\s*{/, openiapDep, 1);
76
+ logOnce(
77
+ hadExisting
78
+ ? '🛠️ expo-iap: Replaced OpenIAP dependency with 1.1.0'
79
+ : '🛠️ expo-iap: Added OpenIAP dependency (1.1.0) to build.gradle',
80
+ );
81
+ }
75
82
 
76
83
  return modified;
77
84
  };
@@ -173,12 +180,13 @@ const withIap: ConfigPlugin<ExpoIapPluginOptions | void> = (
173
180
  options,
174
181
  ) => {
175
182
  try {
176
- const isLocalDev = !!(options?.enableLocalDev || options?.localPath);
183
+ // Respect explicit flag; fall back to presence of localPath only when flag is unset
184
+ const isLocalDev = options?.enableLocalDev ?? !!options?.localPath;
177
185
  // Apply Android modifications (skip adding deps when linking local module)
178
186
  let result = withIapAndroid(config, {addDeps: !isLocalDev});
179
187
 
180
188
  // iOS: choose one path to avoid overlap
181
- if (options?.enableLocalDev || options?.localPath) {
189
+ if (isLocalDev) {
182
190
  if (!options?.localPath) {
183
191
  WarningAggregator.addWarningIOS(
184
192
  'expo-iap',
@@ -196,10 +196,12 @@ const withLocalOpenIAP: ConfigPlugin<{localPath?: LocalPathOption} | void> = (
196
196
  const gradle = config.modResults;
197
197
  const dependencyLine = ` implementation project(':openiap-google')`;
198
198
 
199
- // Remove any previously injected external deps that can conflict with the local module
199
+ // Remove any previously added Maven deps for openiap-google to avoid duplicate classes
200
200
  const removalPatterns = [
201
- /\n\s*implementation\s+"com\.android\.billingclient:billing-ktx:[^"]+"\s*\n/g,
202
- /\n\s*implementation\s+"com\.google\.android\.gms:play-services-base:[^"]+"\s*\n/g,
201
+ // Groovy DSL: implementation "io.github.hyochan.openiap:openiap-google:x.y.z" or api "..."
202
+ /^\s*(?:implementation|api)\s+["']io\.github\.hyochan\.openiap:openiap-google:[^"']+["']\s*$/gm,
203
+ // Kotlin DSL: implementation("io.github.hyochan.openiap:openiap-google:x.y.z") or api("...")
204
+ /^\s*(?:implementation|api)\s*\(\s*["']io\.github\.hyochan\.openiap:openiap-google:[^"']+["']\s*\)\s*$/gm,
203
205
  ];
204
206
  let contents = gradle.contents;
205
207
  let removedAny = false;
@@ -212,7 +214,7 @@ const withLocalOpenIAP: ConfigPlugin<{localPath?: LocalPathOption} | void> = (
212
214
  if (removedAny) {
213
215
  gradle.contents = contents;
214
216
  console.log(
215
- '🧹 Removed external Play Billing/GMS deps to use local :openiap-google',
217
+ '🧹 Removed Maven openiap-google to use local :openiap-google',
216
218
  );
217
219
  }
218
220
  if (!gradle.contents.includes(dependencyLine)) {
@@ -244,8 +246,10 @@ const withLocalOpenIAP: ConfigPlugin<{localPath?: LocalPathOption} | void> = (
244
246
  if (fs.existsSync(appBuildGradle)) {
245
247
  let contents = fs.readFileSync(appBuildGradle, 'utf8');
246
248
  const patterns = [
247
- /\n\s*implementation\s+"com\.android\.billingclient:billing-ktx:[^"]+"\s*\n/g,
248
- /\n\s*implementation\s+"com\.google\.android\.gms:play-services-base:[^"]+"\s*\n/g,
249
+ // Groovy DSL
250
+ /^\s*(?:implementation|api)\s+["']io\.github\.hyochan\.openiap:openiap-google:[^"']+["']\s*$/gm,
251
+ // Kotlin DSL
252
+ /^\s*(?:implementation|api)\s*\(\s*["']io\.github\.hyochan\.openiap:openiap-google:[^"']+["']\s*\)\s*$/gm,
249
253
  ];
250
254
  let changed = false;
251
255
  for (const p of patterns) {
@@ -257,7 +261,7 @@ const withLocalOpenIAP: ConfigPlugin<{localPath?: LocalPathOption} | void> = (
257
261
  if (changed) {
258
262
  fs.writeFileSync(appBuildGradle, contents);
259
263
  console.log(
260
- '🧹 expo-iap: Cleaned app/build.gradle billing/gms deps for local :openiap-google',
264
+ '🧹 expo-iap: Cleaned Maven openiap-google for local :openiap-google',
261
265
  );
262
266
  }
263
267
  }