diff --git a/ios/ExpoIap.podspec b/ios/ExpoIap.podspec index eb1fb0578..fcf599f54 100644 --- a/ios/ExpoIap.podspec +++ b/ios/ExpoIap.podspec @@ -26,7 +26,14 @@ Pod::Spec.new do |s| s.dependency 'ExpoModulesCore' s.dependency 'openiap', "#{versions['apple']}" - # OnsideKit is optional; added via ensureOnsidePod() in Podfile when modules.onside is enabled + # OnsideKit is optional; only included when modules.onside is enabled via the Expo plugin. + # The plugin adds `pod 'ExpoIap/Onside'` to the Podfile when onside is enabled. + s.subspec 'Onside' do |ss| + ss.dependency 'OnsideKit' + end + + s.default_subspecs = [] + # Swift/Objective-C compatibility s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', diff --git a/plugin/__tests__/withIAP.test.ts b/plugin/__tests__/withIAP.test.ts index 976885164..f903540b0 100644 --- a/plugin/__tests__/withIAP.test.ts +++ b/plugin/__tests__/withIAP.test.ts @@ -1,6 +1,7 @@ import type {ExpoConfig} from '@expo/config-types'; import { computeAutolinkModules, + ensureOnsidePodIOS, modifyAppBuildGradle, resolveModuleSelection, } from '../src/withIAP'; @@ -28,7 +29,7 @@ jest.mock('expo/config-plugins', () => { return { ...plugins, - WarningAggregator: {addWarningAndroid: jest.fn()}, + WarningAggregator: {addWarningAndroid: jest.fn(), addWarningIOS: jest.fn()}, }; }); @@ -183,3 +184,68 @@ describe('ios module selection', () => { }); }); }); + +describe('ensureOnsidePodIOS', () => { + const basePodfile = [ + "source 'https://cdn.cocoapods.org/'", + '', + "target 'MyApp' do", + " pod 'ExpoModulesCore'", + 'end', + '', + ].join('\n'); + + it('adds ExpoIap/Onside subspec pod', () => { + const result = ensureOnsidePodIOS(basePodfile); + expect(result).toContain("pod 'ExpoIap/Onside'"); + }); + + it('inserts pod inside the target block', () => { + const result = ensureOnsidePodIOS(basePodfile); + const targetIndex = result.indexOf("target 'MyApp' do"); + const subspecIndex = result.indexOf("pod 'ExpoIap/Onside'"); + const endIndex = result.indexOf('end'); + expect(subspecIndex).toBeGreaterThan(targetIndex); + expect(subspecIndex).toBeLessThan(endIndex); + }); + + it('skips if ExpoIap/Onside already exists', () => { + const podfileWithSubspec = [ + "target 'MyApp' do", + " pod 'ExpoIap/Onside', :path => '../node_modules/expo-iap/ios'", + 'end', + ].join('\n'); + const result = ensureOnsidePodIOS(podfileWithSubspec); + expect(result).toBe(podfileWithSubspec); + }); + + it('returns unchanged content when no target block found', () => { + const noPodfile = '# empty'; + const result = ensureOnsidePodIOS(noPodfile); + expect(result).toBe(noPodfile); + }); + + it('does not modify Podfile when onside is disabled (not called)', () => { + const enableOnside = false; + let content = basePodfile; + + if (enableOnside) { + content = ensureOnsidePodIOS(content); + } + + expect(content).toBe(basePodfile); + expect(content).not.toContain("pod 'ExpoIap/Onside'"); + }); + + it('modifies Podfile when onside is enabled', () => { + const enableOnside = true; + let content = basePodfile; + + if (enableOnside) { + content = ensureOnsidePodIOS(content); + } + + expect(content).not.toBe(basePodfile); + expect(content).toContain("pod 'ExpoIap/Onside'"); + }); +}); diff --git a/plugin/src/withIAP.ts b/plugin/src/withIAP.ts index c52df44dd..716d280e0 100644 --- a/plugin/src/withIAP.ts +++ b/plugin/src/withIAP.ts @@ -7,7 +7,6 @@ import { withGradleProperties, withInfoPlist, withPodfile, - withAppDelegate, } from 'expo/config-plugins'; import type {ExpoConfig} from '@expo/config-types'; import * as fs from 'fs'; @@ -263,12 +262,10 @@ const withIapAndroid: ConfigPlugin< return config; }; -const ensureOnsidePod = (content: string): string => { - const podLine = - " pod 'OnsideKit', :podspec => 'https://raw.githubusercontent.com/onside-io/OnsideKit-iOS/0.5.0/OnsideKit.podspec'"; - const podRegex = /^\s*pod\s+'OnsideKit'\b.*$/m; +const EXPO_IAP_IOS_PATH = '../node_modules/expo-iap/ios'; - if (podRegex.test(content)) { +export const ensureOnsidePodIOS = (content: string): string => { + if (/^\s*pod\s+['"]ExpoIap\/Onside['"].*$/m.test(content)) { return content; } @@ -276,18 +273,17 @@ const ensureOnsidePod = (content: string): string => { if (!targetMatch) { WarningAggregator.addWarningIOS( 'expo-iap', - 'Could not find a target block in Podfile when adding OnsideKit; skipping installation.', + 'Could not find a target block in Podfile when adding ExpoIap/Onside; skipping installation.', ); return content; } + const podLine = ` pod 'ExpoIap/Onside', :path => '${EXPO_IAP_IOS_PATH}'\n`; const insertIndex = targetMatch.index! + targetMatch[0].length; - const before = content.slice(0, insertIndex); - const after = content.slice(insertIndex); - logOnce('📦 expo-iap: Added OnsideKit pod to Podfile'); + logOnce('📦 expo-iap: Added ExpoIap/Onside subspec to Podfile'); - return `${before}${podLine}\n${after}`; + return content.slice(0, insertIndex) + podLine + content.slice(insertIndex); }; export type AutolinkState = {expoIap: boolean; onside: boolean}; @@ -493,7 +489,7 @@ const withIapIOS: ConfigPlugin = ( // 3) Optionally install OnsideKit when enabled in config if (options?.enableOnside) { - content = ensureOnsidePod(content); + content = ensureOnsidePodIOS(content); } config.modResults.contents = content;