Skip to content

fix(ios): Add OnsideKit as a default dependency in ExpoIap.podspec#321

Open
retweakr wants to merge 6 commits intohyochan:mainfrom
retweakr:fix/onside-kit-podspec
Open

fix(ios): Add OnsideKit as a default dependency in ExpoIap.podspec#321
retweakr wants to merge 6 commits intohyochan:mainfrom
retweakr:fix/onside-kit-podspec

Conversation

@retweakr
Copy link
Contributor

@retweakr retweakr commented Mar 16, 2026

Summary by CodeRabbit

  • New Features

    • Onside is available as an optional subspec and can be enabled via the Expo plugin; OnsideKit integration supported for enabled setups.
    • Default subspecs disabled to require explicit opt-in.
  • Chores

    • Pod insertion flow refined to avoid duplicate entries and improve installer messaging/behavior.
  • Tests

    • Added tests validating Podfile modifications, idempotency, target handling, and warning behavior.

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request addresses a dependency issue by explicitly adding OnsideKit as a required dependency in the ExpoIap.podspec. This ensures that OnsideKit is always included, resolving potential build or runtime problems that could arise from its previous optional status.

Highlights

  • Dependency Management: Changed OnsideKit from an optional dependency to a required dependency in ExpoIap.podspec.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Changelog
  • ios/ExpoIap.podspec
    • Updated the OnsideKit dependency status from optional to required.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@coderabbitai
Copy link

coderabbitai bot commented Mar 16, 2026

📝 Walkthrough

Walkthrough

Adds an iOS Onside subspec to ios/ExpoIap.podspec and refactors the plugin to insert ExpoIap/Onside (and detect existing Onside pods) into Podfiles via a new iOS-specific function ensureOnsidePodIOS(content: string).

Changes

Cohort / File(s) Summary
iOS Podspec
ios/ExpoIap.podspec
Adds Onside subspec depending on OnsideKit and sets s.default_subspecs = [].
Plugin: Podfile manipulation
plugin/src/withIAP.ts
Adds EXPO_IAP_IOS_PATH, replaces generic pod insertion with ensureOnsidePodIOS(content: string): string; inserts ExpoIap/Onside and avoids duplicates by detecting existing OnsideKit/ExpoIap/Onside; updates logs and warning flows.
Tests
plugin/__tests__/withIAP.test.ts
Exports/imports updated to include ensureOnsidePodIOS; test mocks extended (adds addWarningIOS); adds tests covering insertion, idempotency, target/no-target scenarios, and enabled/disabled states.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant Plugin as Config Plugin
  participant Podfile as Podfile (file)
  participant Podspecs as CocoaPods/Podspecs
  participant WA as WarningAggregator

  Plugin->>Podfile: read Podfile content
  Plugin->>Plugin: ensureOnsidePodIOS(content)
  alt Onside subspec or OnsideKit missing
    Plugin->>Podspecs: check for existing `OnsideKit` / `ExpoIap/Onside`
    Podspecs-->>Plugin: discovery result
    Plugin->>Podfile: insert `pod 'ExpoIap/Onside', :path => EXPO_IAP_IOS_PATH` (and/or OnsideKit pod line)
    Podfile-->>Plugin: updated content
    Plugin->>WA: addWarningIOS(target-block insertion warning)
  else Already present
    Plugin-->>Podfile: no-op (idempotent)
  end
  Plugin->>Podfile: write updated Podfile
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested labels

፦ refactor

Poem

🐰 I hopped through pods beneath the moon,
Found subspecs sprouting—added soon.
I nudged the Podfile, checked with care,
No duplicates left — tidy and fair.
A joyful hop, a tiny cheer! 🥕✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title references adding OnsideKit as a dependency in ExpoIap.podspec, which aligns with the primary changes of adding an Onside subspec and setting default_subspecs in the podspec file.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
📝 Coding Plan
  • Generate coding plan for human review comments

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request makes OnsideKit a direct dependency in the podspec. However, this creates a conflict with the existing config plugin logic in plugin/src/withIAP.ts, which still tries to inject the same dependency into the user's Podfile. This redundancy can lead to build failures and versioning issues. I recommend that the logic in the config plugin be removed if this change is to proceed. Furthermore, making this a mandatory dependency for all users might not be ideal, as it could increase app size for those not using the Onside feature.

s.dependency 'openiap', "#{versions['apple']}"

# OnsideKit is optional; added via ensureOnsidePod() in Podfile when modules.onside is enabled
s.dependency 'OnsideKit'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Making OnsideKit a direct dependency here conflicts with the existing logic in plugin/src/withIAP.ts. The ensureOnsidePod function in that file still injects OnsideKit into the user's Podfile when modules.onside is enabled. This can cause two problems:

  1. A potential CocoaPods conflict if OnsideKit is defined both here and in the main Podfile.
  2. The plugin injects a specific version from a URL (:podspec => '...'), while this dependency is unversioned, which could lead to version mismatches.

If the goal is to make OnsideKit a direct dependency, the corresponding injection logic in withIAP.ts should be removed in the same pull request to avoid breaking user builds. Since that file isn't modified here, I suggest reverting this change and creating a new PR that addresses both files together.

  # OnsideKit is optional; added via ensureOnsidePod() in Podfile when modules.onside is enabled

@codecov
Copy link

codecov bot commented Mar 16, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 92.05%. Comparing base (b60cc36) to head (0057e54).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files

Impacted file tree graph

@@           Coverage Diff           @@
##             main     #321   +/-   ##
=======================================
  Coverage   92.05%   92.05%           
=======================================
  Files           7        7           
  Lines         642      642           
  Branches      202      202           
=======================================
  Hits          591      591           
  Misses         47       47           
  Partials        4        4           
Flag Coverage Δ
root 92.05% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.


Continue to review full report in Codecov by Sentry.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update bd2fd85...0057e54. Read the comment docs.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@hyochan
Copy link
Owner

hyochan commented Mar 16, 2026

Thanks for catching this, Artyom! I appreciate you staying up to work through it.

You're right that the current ensureOnsidePod() approach (adding OnsideKit to the app's Podfile) doesn't work — CocoaPods scopes dependencies per pod, so ExpoIap can't see OnsideKit even when it's installed in the app target.

However, adding s.dependency 'OnsideKit' unconditionally would force all users to download OnsideKit, even those who don't use Onside. We'd like to avoid that.

Proposed approach: subspec

Instead, we can use an optional subspec:

s.subspec 'Onside' do |ss|
  ss.dependency 'OnsideKit'
end

The Swift source files already use #if canImport(OnsideKit), so no source file splitting is needed. Then we update the plugin's ensureOnsidePod() to add pod 'ExpoIap/Onside' instead of pod 'OnsideKit' — this way OnsideKit becomes part of ExpoIap's dependency tree and Xcode can see it.

Release plan

Since this doesn't cause side effects for non-Onside users (the #if canImport guard compiles cleanly without OnsideKit), we'll keep the current version as-is and ship the fix in the next patch release with updated docs.

@retweakr retweakr force-pushed the fix/onside-kit-podspec branch 2 times, most recently from c2518bb to 34c8e6a Compare March 16, 2026 16:04
@retweakr retweakr force-pushed the fix/onside-kit-podspec branch from bdbdbf4 to 6b49a29 Compare March 17, 2026 11:10
@retweakr retweakr marked this pull request as ready for review March 17, 2026 14:33
Copy link
Owner

@hyochan hyochan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the subspec approach, Artyom! The podspec changes look good — s.subspec 'Onside' with s.default_subspecs = [] is exactly the right pattern.

However, there's an issue in the plugin logic. In withIAP.ts:

// 3) Always add OnsideKit; add ExpoIap/Onside only when onside is enabled
content = ensureOnsidePod(content, options?.enableOnside ?? false);

Inside ensureOnsidePod, pod 'OnsideKit' is added unconditionally — even when onside: false. This means all users (including those who don't use Onside) will have OnsideKit installed in their Podfile, which is what we want to avoid.

Both lines should only be added when onside: true:

  1. pod 'OnsideKit', :podspec => '...' — needed so CocoaPods knows the source URL
  2. pod 'ExpoIap/Onside', :path => '...' — needed so ExpoIap can see OnsideKit

When onside: false, neither should be added. The call site should stay conditional:

if (options?.enableOnside) {
  content = ensureOnsidePod(content);
}

Or keep the boolean parameter but guard both pod lines behind it inside the function.

The podspec side is good to go 👍

Copy link
Owner

@hyochan hyochan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The podspec subspec approach is correct (s.subspec 'Onside' + s.default_subspecs = []), but the plugin logic needs a fix.

In ensureOnsidePod, pod 'OnsideKit' is added unconditionally regardless of the onside flag. This causes all users to install OnsideKit even when they don't use Onside.

Both pod lines should only be added when onside: true:

  1. pod 'OnsideKit', :podspec => '...' — for CocoaPods source resolution
  2. pod 'ExpoIap/Onside', :path => '...' — so ExpoIap can import OnsideKit

See my previous comment for details.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
plugin/src/withIAP.ts (1)

271-271: Rename iOS-only helper with IOS suffix.

ensureOnsidePod is iOS-specific Podfile logic; consider ensureOnsidePodIOS to align naming with repository conventions.

As per coding guidelines **/*.{ts,tsx,js,jsx}: Functions that only operate on one platform must carry the suffix: nameIOS or nameAndroid.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@plugin/src/withIAP.ts` at line 271, The function ensureOnsidePod is
iOS-specific and should be renamed to ensureOnsidePodIOS to follow the
platform-suffix convention; update the function declaration name and all
references/usages (imports, exports, calls) to ensureOnsidePodIOS and adjust any
TypeScript types or JSDoc that reference the old name so compilation and tooling
continue to work.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@plugin/src/withIAP.ts`:
- Around line 277-283: The current code unconditionally injects pod 'OnsideKit'
regardless of the onside flag and uses the function name ensureOnsidePod which
must be platform-specific; modify the pod injection block so pod 'OnsideKit' is
only added when onside is true (use the existing onside boolean and
alreadyHasOnsideKit guard) and rename the function ensureOnsidePod to
ensureOnsidePodIOS (update its definition and all call sites, e.g., where
ensureOnsidePod is invoked) so the iOS-specific helper follows the naming
convention; ensure the podLines concatenation for OnsideKit and ExpoIap/Onside
remains correct under the new gating and that references to alreadyHasOnsideKit
and alreadyHasExpoIapOnside are preserved.

---

Nitpick comments:
In `@plugin/src/withIAP.ts`:
- Line 271: The function ensureOnsidePod is iOS-specific and should be renamed
to ensureOnsidePodIOS to follow the platform-suffix convention; update the
function declaration name and all references/usages (imports, exports, calls) to
ensureOnsidePodIOS and adjust any TypeScript types or JSDoc that reference the
old name so compilation and tooling continue to work.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 304933d7-3dc0-4d87-8965-1fb472746081

📥 Commits

Reviewing files that changed from the base of the PR and between bd2fd85 and 6b49a29.

📒 Files selected for processing (2)
  • ios/ExpoIap.podspec
  • plugin/src/withIAP.ts

- 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>
@hyochan
Copy link
Owner

hyochan commented Mar 17, 2026

@retweakr I pushed a commit on top of your branch with the fix. Here's what changed:

Key changes:

  • ensureOnsidePodIOS (renamed per iOS naming convention) is only called when enableOnside is true — so non-Onside users get zero OnsideKit-related changes in their Podfile
  • When called, it adds both pod 'OnsideKit' (for CocoaPods source resolution) and pod 'ExpoIap/Onside' (so ExpoIap module can import OnsideKit)
  • Added 8 tests covering onside true/false, idempotency, and edge cases — all 240 tests pass

Could you test this with your setup (onside: true) and confirm it works? Feel free to revert or modify if needed 🙏

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
plugin/__tests__/withIAP.test.ts (1)

247-251: Consider asserting the warning call for completeness.

The test correctly verifies content is unchanged, but could be strengthened by asserting that WarningAggregator.addWarningIOS was called when no target block is found.

💡 Optional enhancement
+import {WarningAggregator} from 'expo/config-plugins';
+
 it('returns unchanged content when no target block found', () => {
   const noPodfile = '# empty';
   const result = ensureOnsidePodIOS(noPodfile);
   expect(result).toBe(noPodfile);
+  expect(WarningAggregator.addWarningIOS).toHaveBeenCalledWith(
+    'expo-iap',
+    expect.stringContaining('Could not find a target block'),
+  );
 });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@plugin/__tests__/withIAP.test.ts` around lines 247 - 251, The test for
ensureOnsidePodIOS should also assert that WarningAggregator.addWarningIOS was
invoked when no target block exists; update the test case (the it('returns
unchanged content when no target block found') block) to mock or spy on
WarningAggregator.addWarningIOS and add an expectation that it was called (e.g.,
toHaveBeenCalled or toHaveBeenCalledWith appropriate args) after calling
ensureOnsidePodIOS(noPodfile), while keeping the existing
expect(result).toBe(noPodfile).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@plugin/__tests__/withIAP.test.ts`:
- Around line 247-251: The test for ensureOnsidePodIOS should also assert that
WarningAggregator.addWarningIOS was invoked when no target block exists; update
the test case (the it('returns unchanged content when no target block found')
block) to mock or spy on WarningAggregator.addWarningIOS and add an expectation
that it was called (e.g., toHaveBeenCalled or toHaveBeenCalledWith appropriate
args) after calling ensureOnsidePodIOS(noPodfile), while keeping the existing
expect(result).toBe(noPodfile).

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 63de7f5b-47ce-4bea-901e-57bfef1ce46a

📥 Commits

Reviewing files that changed from the base of the PR and between 6b49a29 and 498680c.

📒 Files selected for processing (3)
  • ios/ExpoIap.podspec
  • plugin/__tests__/withIAP.test.ts
  • plugin/src/withIAP.ts

@hyochan
Copy link
Owner

hyochan commented Mar 17, 2026

@retweakr Pushed a new approach — the subspec doesn't work because OnsideKit isn't on CocoaPods CDN yet (confirmed by Alex).

New approach: post_install hook

Instead of a subspec dependency, the plugin now:

  1. Adds pod 'OnsideKit', :podspec => '...' to the Podfile (same as before)
  2. Adds a post_install hook that injects OnsideKit's build directory into ExpoIap's SWIFT_INCLUDE_PATHS

This makes #if canImport(OnsideKit) work without needing OnsideKit in ExpoIap's podspec dependencies. The podspec itself has no OnsideKit reference at all — clean for non-Onside users.

Once OnsideKit is published to CocoaPods CDN (Alex mentioned at 1.0), we can simplify this to a subspec.

Could you test both cases?

  • ["expo-iap"] — should build with no OnsideKit at all
  • ["expo-iap", { modules: { onside: true } }] — should resolve OnsideKit and canImport should work

Feel free to revert or modify if needed 🙏

…ubspec

OnsideKit is not on CocoaPods CDN yet, so subspec dependency fails to
resolve. Instead, inject a post_install hook that adds OnsideKit's build
dir to ExpoIap's SWIFT_INCLUDE_PATHS, making #if canImport(OnsideKit)
work without requiring a podspec dependency.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@hyochan hyochan force-pushed the fix/onside-kit-podspec branch from 17b20d1 to 15fa2b5 Compare March 17, 2026 15:08
Replace post_install hook workaround with a clean subspec dependency.
The plugin adds `pod 'ExpoIap/Onside'` to Podfile only when onside is
enabled. Requires OnsideKit to be published on CocoaPods CDN.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@hyochan
Copy link
Owner

hyochan commented Mar 17, 2026

@retweakr Simplified the approach — removed the post_install hook workaround (it didn't work for canImport anyway).

Now it's a clean subspec approach:

Podspec:

s.subspec 'Onside' do |ss|
  ss.dependency 'OnsideKit'
end
s.default_subspecs = []

Plugin: When onside: true, adds just one line to Podfile:

pod 'ExpoIap/Onside', :path => '../node_modules/expo-iap/ios'

This requires OnsideKit to be on CocoaPods CDN — which is why I asked about publishing it. Once Alex publishes it (even a pre-release), this should just work.

Could you check with Alex on the CDN publishing timeline? That's the blocker — once it's there, this PR is ready to merge.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@plugin/src/withIAP.ts`:
- Around line 267-287: ensureOnsidePodIOS currently injects "pod
'ExpoIap/Onside'" unconditionally which breaks pod install because the OnsideKit
dependency isn't on the public CocoaPods CDN; update ensureOnsidePodIOS to
either (A) inject the required CocoaPods source/repo entry before inserting the
podLine (so the resolver can find OnsideKit) or (B) avoid adding the subspec and
instead emit a clear WarningAggregator.addWarningIOS message instructing the
user how to add the private source or enable Onside manually; locate the logic
in ensureOnsidePodIOS (look for EXPO_IAP_IOS_PATH, podLine, targetMatch) and
implement one of these fixes so pod install can resolve OnsideKit.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 1c944b6a-470c-41e3-8645-97441158b101

📥 Commits

Reviewing files that changed from the base of the PR and between 498680c and 0057e54.

📒 Files selected for processing (3)
  • ios/ExpoIap.podspec
  • plugin/__tests__/withIAP.test.ts
  • plugin/src/withIAP.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • plugin/tests/withIAP.test.ts

Comment on lines +267 to 287
export const ensureOnsidePodIOS = (content: string): string => {
if (/^\s*pod\s+['"]ExpoIap\/Onside['"].*$/m.test(content)) {
return content;
}

const targetMatch = content.match(/target\s+'[^']+'\s+do\s*\n/);
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);
};
Copy link

@coderabbitai coderabbitai bot Mar 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Checking CocoaPods availability for OnsideKit..."
status=$(curl -s -o /tmp/onsidekit.html -w "%{http_code}" https://cocoapods.org/pods/OnsideKit || true)
echo "HTTP status (https://cocoapods.org/pods/OnsideKit): $status"

echo
echo "Checking current plugin pod injection logic..."
rg -n "ensureOnsidePodIOS|ExpoIap/Onside|OnsideKit" plugin/src/withIAP.ts

echo
echo "Expected verification outcome:"
echo "- If status is not 200 and plugin does not inject a direct OnsideKit podspec fallback,"
echo "  Onside-enabled Pod install can fail on dependency resolution."

Repository: hyochan/expo-iap

Length of output: 838


🏁 Script executed:

cat -n ios/ExpoIap.podspec

Repository: hyochan/expo-iap

Length of output: 2087


🏁 Script executed:

rg -A 10 "subspec.*[Oo]nside" ios/ExpoIap.podspec

Repository: hyochan/expo-iap

Length of output: 297


🏁 Script executed:

find . -name "*.podspec" -o -name "*.md" | xargs rg -l "OnsideKit|Onside" 2>/dev/null | head -20

Repository: hyochan/expo-iap

Length of output: 362


🏁 Script executed:

head -100 docs/docs/guides/onside-integration.md

Repository: hyochan/expo-iap

Length of output: 3759


🏁 Script executed:

head -100 docs/blog/2026-03-15-3.4.10-onside-integration.md

Repository: hyochan/expo-iap

Length of output: 3131


🏁 Script executed:

rg -n "OnsideKit|podspec|source|private" plugin/src/withIAP.ts | head -30

Repository: hyochan/expo-iap

Length of output: 330


🏁 Script executed:

rg -B 5 -A 5 "ensureOnsidePodIOS" plugin/src/withIAP.ts | head -50

Repository: hyochan/expo-iap

Length of output: 653


🏁 Script executed:

rg -n "OnsideKit" README.md docs/

Repository: hyochan/expo-iap

Length of output: 42


🏁 Script executed:

grep -r "OnsideKit" . --include="*.json" --include="*.ts" --include="*.tsx" 2>/dev/null | grep -v node_modules

Repository: hyochan/expo-iap

Length of output: 145


🏁 Script executed:

grep -r "OnsideKit\|onside-kit\|onside_kit" . --include="*.md" --include="*.json" 2>/dev/null | grep -v node_modules | grep -v ".next"

Repository: hyochan/expo-iap

Length of output: 42


🏁 Script executed:

cat plugin/src/withIAP.ts | sed -n '475,510p'

Repository: hyochan/expo-iap

Length of output: 1255


ExpoIap/Onside injection will break pod install for Onside-enabled users due to unresolvable OnsideKit dependency.

The Onside subspec (ios/ExpoIap.podspec:32) declares ss.dependency 'OnsideKit', but OnsideKit is not available on the public CocoaPods CDN (HTTP 404). When users enable Onside via the plugin, pod install fails during dependency resolution. The plugin must either inject a CocoaPods source for OnsideKit or implement an alternative dependency resolution strategy. Currently, documentation presents Onside as ready to use with "Easy Setup," but enabling it produces a broken build.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@plugin/src/withIAP.ts` around lines 267 - 287, ensureOnsidePodIOS currently
injects "pod 'ExpoIap/Onside'" unconditionally which breaks pod install because
the OnsideKit dependency isn't on the public CocoaPods CDN; update
ensureOnsidePodIOS to either (A) inject the required CocoaPods source/repo entry
before inserting the podLine (so the resolver can find OnsideKit) or (B) avoid
adding the subspec and instead emit a clear WarningAggregator.addWarningIOS
message instructing the user how to add the private source or enable Onside
manually; locate the logic in ensureOnsidePodIOS (look for EXPO_IAP_IOS_PATH,
podLine, targetMatch) and implement one of these fixes so pod install can
resolve OnsideKit.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Acknowledged — this is a known blocker. OnsideKit is not on CocoaPods CDN yet (confirmed by the OnsideKit team). We've asked them to publish it. Once it's on CDN, this subspec approach works as-is with no code changes needed. This PR is intentionally written for that scenario.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@hyochan, understood — thanks for the context. Since this approach is intentionally forward-looking for when OnsideKit lands on the CDN, that makes sense.

One optional suggestion: it may be worth adding a temporary WarningAggregator.addWarningIOS note inside ensureOnsidePodIOS (or in the docs) to surface a clear message to users who enable Onside before OnsideKit is published — so they get an actionable error rather than a cryptic pod install failure. This can be removed once CDN availability is confirmed.

That said, if you prefer to keep it minimal until the CDN publish is done, that's reasonable too.


✏️ Learnings added
Learnt from: hyochan
Repo: hyochan/expo-iap PR: 321
File: plugin/src/withIAP.ts:267-287
Timestamp: 2026-03-17T16:08:04.425Z
Learning: In `expo-iap`, the `ExpoIap/Onside` subspec in `ios/ExpoIap.podspec` declares `ss.dependency 'OnsideKit'`, but OnsideKit is NOT yet published to the public CocoaPods CDN (as of March 2026). The PR using this subspec approach is intentionally written for when OnsideKit becomes available on CDN — at that point no code changes are needed. The OnsideKit team has been contacted to publish it.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.


🧠 Learnings used
Learnt from: CR
Repo: hyochan/expo-iap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-16T23:18:39.882Z
Learning: Applies to ios/ExpoIap.podspec : Never modify the iOS platform version in `ios/ExpoIap.podspec` - it MUST remain at `13.4` due to Expo SDK compatibility, even though code requires iOS 15.0+

Learnt from: CR
Repo: hyochan/expo-iap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-16T23:18:39.882Z
Learning: Applies to ios/ExpoIap.podspec : Ensure tvOS platform version in `ios/ExpoIap.podspec` is set to `16.0` (not `13.4`) because the `openiap` CocoaPods dependency requires tvOS 16.0 minimum

Learnt from: CR
Repo: hyochan/expo-iap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-16T23:18:39.882Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Functions that only operate on one platform must carry the suffix: `nameIOS` or `nameAndroid` (e.g., `getStorefrontIOS`, `deepLinkToSubscriptionsAndroid`)

Learnt from: CR
Repo: hyochan/expo-iap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-16T23:18:39.882Z
Learning: Applies to **/*.{ts,tsx} : Inside the `useIAP` hook, most methods return `Promise<void>` and update internal state. Do not design examples or implementations that expect data from methods like `fetchProducts`, `requestPurchase`, `getAvailablePurchases`, `getActiveSubscriptions`. Consume state from hook instead

Learnt from: hyochan
Repo: hyochan/expo-iap PR: 198
File: android/src/main/java/expo/modules/iap/ExpoIapModule.kt:39-49
Timestamp: 2025-09-12T03:46:34.343Z
Learning: In expo-iap codebase, maintainer hyochan prefers simpler implementations over complex safety measures when the additional complexity isn't justified by the specific use case requirements.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants