expo-iap 3.1.17 → 3.1.19

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.
@@ -6,7 +6,10 @@ import {
6
6
  } from 'expo/config-plugins';
7
7
  import * as fs from 'fs';
8
8
  import * as path from 'path';
9
- import type {IOSAlternativeBillingConfig} from './withIAP';
9
+ import {
10
+ withIosAlternativeBilling,
11
+ type IOSAlternativeBillingConfig,
12
+ } from './withIosAlternativeBilling';
10
13
 
11
14
  /**
12
15
  * Plugin to add local OpenIAP pod dependency for development
@@ -14,17 +17,28 @@ import type {IOSAlternativeBillingConfig} from './withIAP';
14
17
  */
15
18
  type LocalPathOption = string | {ios?: string; android?: string};
16
19
 
20
+ // Log a message only once per Node process
21
+ const logOnce = (() => {
22
+ const printed = new Set<string>();
23
+ return (msg: string) => {
24
+ if (!printed.has(msg)) {
25
+ console.log(msg);
26
+ printed.add(msg);
27
+ }
28
+ };
29
+ })();
30
+
17
31
  const withLocalOpenIAP: ConfigPlugin<
18
32
  {
19
33
  localPath?: LocalPathOption;
20
34
  iosAlternativeBilling?: IOSAlternativeBillingConfig;
35
+ horizonAppId?: string;
36
+ /** Resolved from modules.horizon by withIAP */
37
+ isHorizonEnabled?: boolean;
21
38
  } | void
22
39
  > = (config, props) => {
23
40
  // Import and apply iOS alternative billing configuration if provided
24
41
  if (props?.iosAlternativeBilling) {
25
- // Import withIosAlternativeBilling from withIAP module
26
- // eslint-disable-next-line @typescript-eslint/no-require-imports
27
- const {withIosAlternativeBilling} = require('./withIAP');
28
42
  config = withIosAlternativeBilling(config, props.iosAlternativeBilling);
29
43
  }
30
44
  // Helper to resolve Android module path
@@ -71,7 +85,7 @@ const withLocalOpenIAP: ConfigPlugin<
71
85
  let podfileContent = fs.readFileSync(podfilePath, 'utf8');
72
86
 
73
87
  if (podfileContent.includes("pod 'openiap',")) {
74
- console.log('✅ Local OpenIAP pod already configured');
88
+ logOnce('✅ Local OpenIAP pod already configured');
75
89
  return config;
76
90
  }
77
91
 
@@ -86,7 +100,7 @@ const withLocalOpenIAP: ConfigPlugin<
86
100
  pod 'openiap', :path => '${iosPath}'`;
87
101
  });
88
102
  fs.writeFileSync(podfilePath, podfileContent);
89
- console.log(`✅ Added local OpenIAP pod at: ${iosPath}`);
103
+ logOnce(`✅ Added local OpenIAP pod at: ${iosPath}`);
90
104
  } else {
91
105
  console.warn('⚠️ Could not find target block in Podfile');
92
106
  }
@@ -185,14 +199,14 @@ const withLocalOpenIAP: ConfigPlugin<
185
199
  if (!contents.includes(includeLine)) contents += `\n${includeLine}\n`;
186
200
  if (!contents.includes(projectDirLine)) contents += `${projectDirLine}\n`;
187
201
  settings.contents = contents;
188
- console.log(`✅ Linked local Android module at: ${androidModulePath}`);
202
+ logOnce(`✅ Linked local Android module at: ${androidModulePath}`);
189
203
  return config;
190
204
  });
191
205
 
192
206
  // 2) app/build.gradle: add implementation project(':openiap-google')
193
207
  config = withAppBuildGradle(config, (config) => {
194
- const raw = props?.localPath;
195
208
  const projectRoot = (config.modRequest as any).projectRoot as string;
209
+ const raw = props?.localPath;
196
210
  const androidInput = typeof raw === 'string' ? undefined : raw?.android;
197
211
  const androidModulePath =
198
212
  resolveAndroidModulePath(androidInput) ||
@@ -205,85 +219,84 @@ const withLocalOpenIAP: ConfigPlugin<
205
219
 
206
220
  const gradle = config.modResults;
207
221
  const dependencyLine = ` implementation project(':openiap-google')`;
222
+ const flavor = props?.isHorizonEnabled ? 'horizon' : 'play';
223
+ const strategyLine = ` missingDimensionStrategy "platform", "${flavor}"`;
208
224
 
209
- // Remove any previously added Maven deps for openiap-google to avoid duplicate classes
210
- const removalPatterns = [
211
- // Groovy DSL: implementation "io.github.hyochan.openiap:openiap-google:x.y.z" or api "..."
212
- /^\s*(?:implementation|api)\s+["']io\.github\.hyochan\.openiap:openiap-google:[^"']+["']\s*$/gm,
213
- // Kotlin DSL: implementation("io.github.hyochan.openiap:openiap-google:x.y.z") or api("...")
214
- /^\s*(?:implementation|api)\s*\(\s*["']io\.github\.hyochan\.openiap:openiap-google:[^"']+["']\s*\)\s*$/gm,
215
- ];
216
225
  let contents = gradle.contents;
217
- let removedAny = false;
218
- for (const pattern of removalPatterns) {
219
- if (pattern.test(contents)) {
220
- contents = contents.replace(pattern, '\n');
221
- removedAny = true;
222
- }
226
+
227
+ // Remove Maven deps (avoid duplicate classes with local module)
228
+ const mavenPattern =
229
+ /^\s*(?:implementation|api)\s*\(?\s*["']io\.github\.hyochan\.openiap:openiap-google:[^"']+["']\s*\)?\s*$/gm;
230
+ if (mavenPattern.test(contents)) {
231
+ contents = contents.replace(mavenPattern, '\n');
232
+ logOnce('🧹 Removed Maven openiap-google (using local module)');
223
233
  }
224
- if (removedAny) {
225
- gradle.contents = contents;
226
- console.log(
227
- '🧹 Removed Maven openiap-google to use local :openiap-google',
228
- );
234
+
235
+ // Add missingDimensionStrategy (required for flavored module)
236
+ // Remove any existing platform strategies first to avoid duplicates
237
+ const strategyPattern =
238
+ /^\s*missingDimensionStrategy\s*\(?\s*["']platform["']\s*,\s*["'](play|horizon)["']\s*\)?\s*$/gm;
239
+ if (strategyPattern.test(contents)) {
240
+ contents = contents.replace(strategyPattern, '');
241
+ logOnce('🧹 Removed existing missingDimensionStrategy for platform');
229
242
  }
230
- if (!gradle.contents.includes(dependencyLine)) {
231
- const anchor = /dependencies\s*\{/m;
232
- if (anchor.test(gradle.contents)) {
233
- gradle.contents = gradle.contents.replace(
234
- anchor,
235
- (m) => `${m}\n${dependencyLine}`,
243
+
244
+ if (!contents.includes(strategyLine)) {
245
+ const lines = contents.split('\n');
246
+ const idx = lines.findIndex((line) => line.match(/defaultConfig\s*\{/));
247
+ if (idx !== -1) {
248
+ lines.splice(idx + 1, 0, strategyLine);
249
+ contents = lines.join('\n');
250
+ logOnce(
251
+ `🛠️ expo-iap: Added missingDimensionStrategy for ${flavor} flavor`,
236
252
  );
253
+ }
254
+ }
255
+
256
+ // Add project dependency
257
+ if (!contents.includes(dependencyLine)) {
258
+ const anchor = /dependencies\s*\{/m;
259
+ if (anchor.test(contents)) {
260
+ contents = contents.replace(anchor, (m) => `${m}\n${dependencyLine}`);
237
261
  } else {
238
- gradle.contents += `\n\ndependencies {\n${dependencyLine}\n}\n`;
262
+ contents += `\n\ndependencies {\n${dependencyLine}\n}\n`;
239
263
  }
240
- console.log('🛠️ Added dependency on local :openiap-google project');
264
+ logOnce('🛠️ Added dependency on local :openiap-google project');
241
265
  }
266
+
267
+ gradle.contents = contents;
242
268
  return config;
243
269
  });
244
270
 
245
- // 3) Ensure final cleanup in app/build.gradle after all mods are applied
271
+ // 3) Set horizonEnabled in gradle.properties
246
272
  config = withDangerousMod(config, [
247
273
  'android',
248
274
  async (config) => {
249
- try {
250
- const {platformProjectRoot} = config.modRequest as any;
251
- const appBuildGradle = path.join(
252
- platformProjectRoot,
253
- 'app',
254
- 'build.gradle',
275
+ const {platformProjectRoot} = config.modRequest as any;
276
+ const gradlePropertiesPath = path.join(
277
+ platformProjectRoot,
278
+ 'gradle.properties',
279
+ );
280
+
281
+ if (fs.existsSync(gradlePropertiesPath)) {
282
+ let contents = fs.readFileSync(gradlePropertiesPath, 'utf8');
283
+ const isHorizon = props?.isHorizonEnabled ?? false;
284
+
285
+ // Update horizonEnabled property
286
+ contents = contents.replace(/^horizonEnabled=.*$/gm, '');
287
+ if (!contents.endsWith('\n')) contents += '\n';
288
+ contents += `horizonEnabled=${isHorizon}\n`;
289
+
290
+ fs.writeFileSync(gradlePropertiesPath, contents);
291
+ logOnce(
292
+ `🛠️ expo-iap: Set horizonEnabled=${isHorizon} in gradle.properties`,
255
293
  );
256
- if (fs.existsSync(appBuildGradle)) {
257
- let contents = fs.readFileSync(appBuildGradle, 'utf8');
258
- const patterns = [
259
- // Groovy DSL
260
- /^\s*(?:implementation|api)\s+["']io\.github\.hyochan\.openiap:openiap-google:[^"']+["']\s*$/gm,
261
- // Kotlin DSL
262
- /^\s*(?:implementation|api)\s*\(\s*["']io\.github\.hyochan\.openiap:openiap-google:[^"']+["']\s*\)\s*$/gm,
263
- ];
264
- let changed = false;
265
- for (const p of patterns) {
266
- if (p.test(contents)) {
267
- contents = contents.replace(p, '\n');
268
- changed = true;
269
- }
270
- }
271
- if (changed) {
272
- fs.writeFileSync(appBuildGradle, contents);
273
- console.log(
274
- '🧹 expo-iap: Cleaned Maven openiap-google for local :openiap-google',
275
- );
276
- }
277
- }
278
- } catch (e) {
279
- console.warn('expo-iap: cleanup step failed:', e);
280
294
  }
295
+
281
296
  return config;
282
297
  },
283
298
  ]);
284
299
 
285
- // (removed) Avoid global root build.gradle mutations; included module should manage its plugins
286
-
287
300
  return config;
288
301
  };
289
302
 
@@ -1 +1 @@
1
- {"root":["./src/expoConfig.augmentation.d.ts","./src/withIAP.ts","./src/withLocalOpenIAP.ts"],"version":"5.9.3"}
1
+ {"root":["./src/expoConfig.augmentation.d.ts","./src/withIAP.ts","./src/withIosAlternativeBilling.ts","./src/withLocalOpenIAP.ts"],"version":"5.9.3"}
@@ -42,7 +42,7 @@ function parseArgs() {
42
42
  }
43
43
 
44
44
  function getReleaseUrl(tag) {
45
- return `https://github.com/hyodotdev/openiap-gql/releases/download/${tag}/openiap-typescript.zip`;
45
+ return `https://github.com/hyodotdev/openiap/releases/download/${tag}/openiap-typescript.zip`;
46
46
  }
47
47
 
48
48
  function main() {