Skip to content

Commit 498680c

Browse files
hyochanclaude
andcommitted
fix(ios): use subspec for conditional OnsideKit dependency
- Add ExpoIap/Onside subspec with default_subspecs = [] so OnsideKit is only included when explicitly enabled - Rename ensureOnsidePod to ensureOnsidePodIOS per naming convention - Keep call site conditional: only called when enableOnside is true - Add ensureOnsidePodIOS tests covering onside true/false scenarios Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 6b49a29 commit 498680c

File tree

3 files changed

+113
-24
lines changed

3 files changed

+113
-24
lines changed

ios/ExpoIap.podspec

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,13 @@ Pod::Spec.new do |s|
3030
ss.dependency 'OnsideKit'
3131
end
3232

33+
s.default_subspecs = []
34+
3335
# Swift/Objective-C compatibility
3436
s.pod_target_xcconfig = {
3537
'DEFINES_MODULE' => 'YES',
3638
'SWIFT_COMPILATION_MODE' => 'wholemodule'
3739
}
3840

3941
s.source_files = "**/*.{h,m,swift}"
40-
s.default_subspecs = []
4142
end

plugin/__tests__/withIAP.test.ts

Lines changed: 94 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import type {ExpoConfig} from '@expo/config-types';
22
import {
33
computeAutolinkModules,
4+
ensureOnsidePodIOS,
45
modifyAppBuildGradle,
56
resolveModuleSelection,
67
} from '../src/withIAP';
@@ -28,7 +29,7 @@ jest.mock('expo/config-plugins', () => {
2829

2930
return {
3031
...plugins,
31-
WarningAggregator: {addWarningAndroid: jest.fn()},
32+
WarningAggregator: {addWarningAndroid: jest.fn(), addWarningIOS: jest.fn()},
3233
};
3334
});
3435

@@ -183,3 +184,95 @@ describe('ios module selection', () => {
183184
});
184185
});
185186
});
187+
188+
describe('ensureOnsidePodIOS', () => {
189+
const basePodfile = [
190+
"source 'https://cdn.cocoapods.org/'",
191+
'',
192+
"target 'MyApp' do",
193+
" pod 'ExpoModulesCore'",
194+
'end',
195+
'',
196+
].join('\n');
197+
198+
it('adds both OnsideKit and ExpoIap/Onside pods', () => {
199+
const result = ensureOnsidePodIOS(basePodfile);
200+
expect(result).toContain("pod 'OnsideKit'");
201+
expect(result).toContain("pod 'ExpoIap/Onside'");
202+
});
203+
204+
it('inserts pods inside the target block', () => {
205+
const result = ensureOnsidePodIOS(basePodfile);
206+
const targetIndex = result.indexOf("target 'MyApp' do");
207+
const onsideKitIndex = result.indexOf("pod 'OnsideKit'");
208+
const endIndex = result.indexOf('end');
209+
expect(onsideKitIndex).toBeGreaterThan(targetIndex);
210+
expect(onsideKitIndex).toBeLessThan(endIndex);
211+
});
212+
213+
it('skips if both pods already exist', () => {
214+
const podfileWithBoth = [
215+
"target 'MyApp' do",
216+
" pod 'OnsideKit', :podspec => 'https://example.com'",
217+
" pod 'ExpoIap/Onside', :path => '../node_modules/expo-iap/ios'",
218+
'end',
219+
].join('\n');
220+
const result = ensureOnsidePodIOS(podfileWithBoth);
221+
expect(result).toBe(podfileWithBoth);
222+
});
223+
224+
it('adds missing ExpoIap/Onside when OnsideKit already exists', () => {
225+
const podfileWithOnsideKit = [
226+
"target 'MyApp' do",
227+
" pod 'OnsideKit', :podspec => 'https://example.com'",
228+
'end',
229+
].join('\n');
230+
const result = ensureOnsidePodIOS(podfileWithOnsideKit);
231+
expect(result).toContain("pod 'ExpoIap/Onside'");
232+
expect(result).not.toContain('raw.githubusercontent');
233+
});
234+
235+
it('adds missing OnsideKit when ExpoIap/Onside already exists', () => {
236+
const podfileWithSubspec = [
237+
"target 'MyApp' do",
238+
" pod 'ExpoIap/Onside', :path => '../node_modules/expo-iap/ios'",
239+
'end',
240+
].join('\n');
241+
const result = ensureOnsidePodIOS(podfileWithSubspec);
242+
expect(result).toContain("pod 'OnsideKit'");
243+
const subspecCount = (result.match(/pod 'ExpoIap\/Onside'/g) ?? []).length;
244+
expect(subspecCount).toBe(1);
245+
});
246+
247+
it('returns unchanged content when no target block found', () => {
248+
const noPodfile = '# empty';
249+
const result = ensureOnsidePodIOS(noPodfile);
250+
expect(result).toBe(noPodfile);
251+
});
252+
253+
it('does not modify Podfile when onside is disabled (not called)', () => {
254+
const enableOnside = false;
255+
let content = basePodfile;
256+
257+
if (enableOnside) {
258+
content = ensureOnsidePodIOS(content);
259+
}
260+
261+
expect(content).toBe(basePodfile);
262+
expect(content).not.toContain("pod 'OnsideKit'");
263+
expect(content).not.toContain("pod 'ExpoIap/Onside'");
264+
});
265+
266+
it('modifies Podfile when onside is enabled', () => {
267+
const enableOnside = true;
268+
let content = basePodfile;
269+
270+
if (enableOnside) {
271+
content = ensureOnsidePodIOS(content);
272+
}
273+
274+
expect(content).not.toBe(basePodfile);
275+
expect(content).toContain("pod 'OnsideKit'");
276+
expect(content).toContain("pod 'ExpoIap/Onside'");
277+
});
278+
});

plugin/src/withIAP.ts

Lines changed: 17 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import {
77
withGradleProperties,
88
withInfoPlist,
99
withPodfile,
10-
withAppDelegate,
1110
} from 'expo/config-plugins';
1211
import type {ExpoConfig} from '@expo/config-types';
1312
import * as fs from 'fs';
@@ -268,21 +267,13 @@ const ONSIDEKIT_PODSPEC_URL =
268267

269268
const EXPO_IAP_IOS_PATH = '../node_modules/expo-iap/ios';
270269

271-
const ensureOnsidePod = (content: string, onside: boolean): string => {
272-
const alreadyHasOnsideKit = /^\s*pod\s+['"]OnsideKit['"]\b.*$/m.test(content);
270+
export const ensureOnsidePodIOS = (content: string): string => {
271+
const alreadyHasOnsideKit = /^\s*pod\s+['"]OnsideKit['"].*$/m.test(content);
273272
const alreadyHasExpoIapOnside = /^\s*pod\s+['"]ExpoIap\/Onside['"].*$/m.test(
274273
content,
275274
);
276275

277-
let podLines = '';
278-
if (!alreadyHasOnsideKit) {
279-
podLines += ` pod 'OnsideKit', :podspec => '${ONSIDEKIT_PODSPEC_URL}'\n`;
280-
}
281-
if (onside && !alreadyHasExpoIapOnside) {
282-
podLines += ` pod 'ExpoIap/Onside', :path => '${EXPO_IAP_IOS_PATH}'`;
283-
}
284-
285-
if (!podLines) {
276+
if (alreadyHasOnsideKit && alreadyHasExpoIapOnside) {
286277
return content;
287278
}
288279

@@ -295,19 +286,21 @@ const ensureOnsidePod = (content: string, onside: boolean): string => {
295286
return content;
296287
}
297288

289+
let podLines = '';
290+
if (!alreadyHasOnsideKit) {
291+
podLines += ` pod 'OnsideKit', :podspec => '${ONSIDEKIT_PODSPEC_URL}'\n`;
292+
}
293+
if (!alreadyHasExpoIapOnside) {
294+
podLines += ` pod 'ExpoIap/Onside', :path => '${EXPO_IAP_IOS_PATH}'\n`;
295+
}
296+
298297
const insertIndex = targetMatch.index! + targetMatch[0].length;
299298
const before = content.slice(0, insertIndex);
300299
const after = content.slice(insertIndex);
301300

302-
if (onside && !alreadyHasExpoIapOnside) {
303-
logOnce(
304-
'📦 expo-iap: Added ExpoIap/Onside subspec (and OnsideKit for resolution) to Podfile',
305-
);
306-
} else if (!alreadyHasOnsideKit) {
307-
logOnce('📦 expo-iap: Added OnsideKit to Podfile');
308-
}
301+
logOnce('📦 expo-iap: Added ExpoIap/Onside subspec to Podfile');
309302

310-
return `${before}${podLines}\n${after}`;
303+
return `${before}${podLines}${after}`;
311304
};
312305

313306
export type AutolinkState = {expoIap: boolean; onside: boolean};
@@ -511,8 +504,10 @@ const withIapIOS: ConfigPlugin<WithIapIosOptions | undefined> = (
511504
logOnce('🧹 expo-iap: Removed local OpenIAP pod from Podfile');
512505
}
513506

514-
// 3) Always add OnsideKit; add ExpoIap/Onside only when onside is enabled
515-
content = ensureOnsidePod(content, options?.enableOnside ?? false);
507+
// 3) Optionally install OnsideKit when enabled in config
508+
if (options?.enableOnside) {
509+
content = ensureOnsidePodIOS(content);
510+
}
516511

517512
config.modResults.contents = content;
518513
return config;

0 commit comments

Comments
 (0)