From ef1d9cf2f977d1e74dae6e4b7bbc5cd2311cf77b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Mi=C5=82kowski?= Date: Mon, 16 Feb 2026 17:38:48 +0100 Subject: [PATCH 1/8] feat: add rn-new-architecture-migration skill --- skills/rn-new-architecture-migration/SKILL.md | 41 +++ .../references/xcframework-distribution.md | 329 ++++++++++++++++++ 2 files changed, 370 insertions(+) create mode 100644 skills/rn-new-architecture-migration/SKILL.md create mode 100644 skills/rn-new-architecture-migration/references/xcframework-distribution.md diff --git a/skills/rn-new-architecture-migration/SKILL.md b/skills/rn-new-architecture-migration/SKILL.md new file mode 100644 index 0000000..6d389c7 --- /dev/null +++ b/skills/rn-new-architecture-migration/SKILL.md @@ -0,0 +1,41 @@ +--- +name: rn-new-architecture-migration +description: Guides React Native New Architecture migration, focusing on XCFramework distribution for brownfield iOS apps. Use when packaging React Native as a reusable XCFramework, integrating RN into existing iOS apps, or migrating to the New Architecture. +license: MIT +metadata: + author: Callstack + tags: react-native, new-architecture, xcframework, brownfield, ios, swift-package +--- + +# React Native New Architecture Migration + +## Overview + +Covers packaging and distributing React Native as an XCFramework for brownfield iOS integration, including bridge initialization, Hermes embedding, and Swift Package distribution. + +## When to Apply + +Reference these guidelines when: +- Packaging React Native as a reusable XCFramework for existing iOS apps +- Integrating React Native into a brownfield iOS project +- Setting up RN bridge initialization for old architecture (<0.78) +- Using RNViewFactory or ReactNativeFactory patterns +- Generating universal XCFramework binaries +- Distributing React Native via Swift Package Manager + +## Quick Reference + +| File | Description | +|------|-------------| +| [xcframework-distribution.md][xcframework-distribution] | Package and distribute RN as XCFramework for brownfield iOS | + +## Problem → Skill Mapping + +| Problem | Start With | +|---------|------------| +| Need to embed RN in existing iOS app | [xcframework-distribution.md][xcframework-distribution] | +| Building XCFramework from RN project | [xcframework-distribution.md][xcframework-distribution] | +| Bridge initialization for old arch | [xcframework-distribution.md][xcframework-distribution] | +| Hermes embedding in XCFramework | [xcframework-distribution.md][xcframework-distribution] | + +[xcframework-distribution]: references/xcframework-distribution.md diff --git a/skills/rn-new-architecture-migration/references/xcframework-distribution.md b/skills/rn-new-architecture-migration/references/xcframework-distribution.md new file mode 100644 index 0000000..823be3c --- /dev/null +++ b/skills/rn-new-architecture-migration/references/xcframework-distribution.md @@ -0,0 +1,329 @@ +--- +title: XCFramework Distribution +impact: HIGH +tags: xcframework, brownfield, ios, swift-package, hermes, bridge, new-architecture +--- + +# Skill: XCFramework Distribution + +Package React Native as a reusable XCFramework for brownfield iOS app integration. + +## Quick Reference + +| Step | Action | +|------|--------| +| 1 | Create RN app with `npx react-native init` | +| 2 | Add Swift Framework target in Xcode | +| 3 | Configure Build Settings | +| 4 | Add Run Script Phase for Metro bundle | +| 5 | Set up Podfile integration | +| 6 | Initialize RN bridge (old arch) or use ReactNativeFactory (0.78+) | +| 7 | Generate XCFramework with `xcodebuild` | + +## When to Use + +- Embedding React Native into an existing native iOS app +- Distributing RN-based features as a prebuilt binary +- Building a reusable SDK powered by React Native +- Brownfield integration requiring framework-level packaging + +## Prerequisites + +- Xcode 15+ +- React Native 0.73+ (0.78+ recommended for ReactNativeFactory) +- CocoaPods installed +- Familiarity with Xcode build settings and targets + +## Step-by-Step Instructions + +### 1. Create React Native App + +```bash +npx @react-native-community/cli@latest init MyRNApp +cd MyRNApp +``` + +This serves as the source project from which the framework is built. + +### 2. Add Swift Framework Target + +In Xcode: +1. File → New → Target → Framework +2. Select Swift as the language +3. Set "Embed in Application" to **None** +4. Name it (e.g., `MyRNFramework`) +5. Set deployment target to match the RN app + +### 3. Configure Build Settings + +Set these on the framework target: + +| Setting | Value | Why | +|---------|-------|-----| +| `User Script Sandboxing` | `NO` | Allows Run Script phases to access Metro bundle | +| `Skip Install` | `NO` | Ensures the framework is included in archives | +| `Build Libraries for Distribution` | `YES` | Required for XCFramework generation | +| `DEFINES_MODULE` | `YES` | Generates module map for Swift imports | + +### 4. Add Run Script Phase + +Add a Run Script build phase to the framework target that bundles JS via Metro: + +```bash +set -e + +WITH_ENVIRONMENT="$REACT_NATIVE_PATH/scripts/xcode/with-environment.sh" +REACT_NATIVE_XCODE="$REACT_NATIVE_PATH/scripts/react-native-xcode.sh" + +/bin/sh -c "$WITH_ENVIRONMENT $REACT_NATIVE_XCODE" +``` + +This embeds the JS bundle into the framework during build. + +### 5. Podfile Integration + +Nest the framework target inside the app target in the Podfile with `inherit! :complete`: + +```ruby +target 'MyRNApp' do + config = use_native_modules! + + use_react_native!( + :path => config[:reactNativePath], + :app_path => "#{Pod::Config.instance.installation_root}/.." + ) + + # Nest framework target to inherit all RN pods + target 'MyRNFramework' do + inherit! :complete + end +end +``` + +Then install: + +```bash +npx pod-install ios +``` + +### 6. Bridge Initialization + +#### React Native 0.78+ (ReactNativeFactory) + +```swift +import React +import ReactNativeFactory + +public class MyRNView { + private var factory: ReactNativeFactory? + + public func createView() -> UIView { + factory = ReactNativeFactory() + return factory!.createRootView( + moduleName: "MyRNApp", + initialProperties: nil + ) + } +} +``` + +#### React Native <0.78 (Old Architecture) + +Use a singleton bridge manager with `@_implementationOnly import` to hide React headers from consumers: + +```swift +import UIKit +@_implementationOnly import React + +public class RNBridgeManager { + public static let shared = RNBridgeManager() + + private var bridge: RCTBridge? + + public func initialize(launchOptions: [UIApplication.LaunchOptionsKey: Any]?) { + bridge = RCTBridge(delegate: RNBridgeDelegate(), launchOptions: launchOptions) + } + + func getBridge() -> RCTBridge { + guard let bridge = bridge else { + fatalError("RN bridge must be initialized before creating a RN view!") + } + return bridge + } +} + +private class RNBridgeDelegate: NSObject, RCTBridgeDelegate { + func sourceURL(for _: RCTBridge) -> URL? { + #if DEBUG + return RCTBundleURLProvider.sharedSettings().jsBundleURL(forBundleRoot: "index") + #else + return Bundle(for: Self.self).url(forResource: "main", withExtension: "jsbundle") + #endif + } +} +``` + +### 7. RNViewFactory Pattern + +Expose a factory with typed module names for consuming apps: + +```swift +import UIKit +@_implementationOnly import React + +public struct RNViewFactory { + public static func createView( + moduleName: RNModule, + initialProperties: [String: Any]? = nil + ) -> UIView { + let bridge = RNBridgeManager.shared.getBridge() + return RCTRootView( + bridge: bridge, + moduleName: moduleName.rawValue, + initialProperties: initialProperties + ) + } +} + +public enum RNModule: String { + case myFeature = "MyFeature" +} +``` + +The consuming app calls `RNViewFactory.createView(moduleName: .myFeature)` without needing React Native knowledge. + +### 8. Hermes Embedding + +Hermes is the recommended JS engine but complicates XCFramework distribution: + +- **Recommended**: Treat Hermes as a peer dependency — require the consuming app to include `hermes-engine` via CocoaPods +- **Not recommended**: Embedding `Hermes.xcframework` directly into the output framework (causes symbol duplication issues) + +#### dSYM Fix for React Native <0.76 + +Builds may fail due to a `DebugSymbolsPath` bug in `hermes.xcframework/Info.plist` (fixed in RN 0.76). Remove the problematic entries in Podfile post-install using PlistBuddy: + +```ruby +post_install do |installer| + react_native_post_install( + installer, + config[:reactNativePath], + :mac_catalyst_enabled => false, + ) + + # Remove broken DebugSymbolsPath from hermes.xcframework + PLIST_BUDDY_PATH = '/usr/libexec/PlistBuddy' + installer.pods_project.targets.each do |target| + next unless target.name == "hermes-engine" + installer.pods_project.files.each do |fileref| + next unless fileref.path.end_with?("hermes.xcframework") + plist_file = "#{fileref.real_path}/Info.plist" + stdout, _stderr, _status = Open3.capture3( + "#{PLIST_BUDDY_PATH} -c 'Print :AvailableLibraries' #{plist_file}" + ) + stdout.scan(/Dict/).count.times do |i| + Open3.capture3( + "#{PLIST_BUDDY_PATH} -c 'Delete :AvailableLibraries:#{i}:DebugSymbolsPath' #{plist_file}" + ) + end + end + end +end +``` + +### 9. Generate XCFramework + +Build for both simulator and device, then combine: + +```bash +#!/bin/bash + +WORKSPACE=${WORKSPACE:-MyRNApp} +SCHEME=${SCHEME:-MyRNFramework} +CONFIGURATION=${BUILD_TYPE:-Release} +ARCHIVE_DIR="archives" + +cd ios + +# Build for iOS Simulator +xcodebuild archive \ + -workspace $WORKSPACE.xcworkspace \ + -scheme $SCHEME \ + -destination "generic/platform=iOS Simulator" \ + -configuration $CONFIGURATION \ + -archivePath $ARCHIVE_DIR/${SCHEME}-iOS_Simulator.xcarchive \ + -quiet || exit 1 + +# Build for iOS device +xcodebuild archive \ + -workspace $WORKSPACE.xcworkspace \ + -scheme $SCHEME \ + -destination "generic/platform=iOS" \ + -configuration $CONFIGURATION \ + -archivePath $ARCHIVE_DIR/${SCHEME}-iOS.xcarchive \ + -quiet || exit 1 + +# Remove previous output +rm -rf $ARCHIVE_DIR/$SCHEME.xcframework + +# Create XCFramework +xcodebuild -create-xcframework \ + -archive $ARCHIVE_DIR/${SCHEME}-iOS_Simulator.xcarchive -framework $SCHEME.framework \ + -archive $ARCHIVE_DIR/${SCHEME}-iOS.xcarchive -framework $SCHEME.framework \ + -output $ARCHIVE_DIR/$SCHEME.xcframework + +cd - +``` + +### 10. Distribution via Swift Package (Future) + +Swift Package Manager distribution requires: +- Hosting the XCFramework as a binary target (zip + checksum) +- Creating a `Package.swift` with `.binaryTarget` + +```swift +// Package.swift (example structure) +let package = Package( + name: "MyRNFramework", + platforms: [.iOS(.v15)], + products: [ + .library(name: "MyRNFramework", targets: ["MyRNFramework"]), + ], + targets: [ + .binaryTarget( + name: "MyRNFramework", + url: "https://example.com/MyRNFramework.xcframework.zip", + checksum: "" + ), + ] +) +``` + +## FAQ + +### Does this support both old and new architecture? +The bridge-based approach (steps 6-7) only supports the old architecture. On RN 0.78+, use `ReactNativeFactory` (see [PR #46298](https://github.com/facebook/react-native/pull/46298)) which supports both architectures. + +### What architectures are supported? +XCFramework supports arm64 (device) and arm64 + x86_64 (simulator). Use `lipo -info` to verify slices. + +### Can Hermes be bundled inside the XCFramework? +No — there is no support for including an XCFramework inside another XCFramework. Include `hermes.xcframework` directly in the brownfield app as a "peer dependency." + +### pod install fails on Xcode 16? +RN 0.76 doesn't have proper Xcode 16 support. Update CocoaPods: +```bash +gem install cocoapods --pre +``` + +## Common Pitfalls + +- **User Script Sandboxing enabled**: Metro bundling fails silently. Always set to `NO`. +- **Skip Install = YES**: The framework won't appear in the archive. Set to `NO`. +- **Embedding Hermes directly**: Causes duplicate symbol errors in consuming apps. +- **Missing JS bundle**: Ensure the Run Script phase runs before the framework's Compile Sources phase. +- **Architecture mismatch**: Always build both arm64 and x86_64 simulator slices. + +## Related Skills + +- [rn-native-ios-tooling](../../rn-native-ios-tooling/SKILL.md) — iOS dependency managers and tooling From cff97823fd1f0d624328aad9fca4fcf825a54961 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Mi=C5=82kowski?= Date: Mon, 16 Feb 2026 17:46:47 +0100 Subject: [PATCH 2/8] feat: add rn-testing-and-debugging skill --- skills/rn-testing-and-debugging/SKILL.md | 43 ++++ .../references/api-failure-simulation.md | 197 ++++++++++++++++++ .../references/detox-vs-maestro.md | 144 +++++++++++++ 3 files changed, 384 insertions(+) create mode 100644 skills/rn-testing-and-debugging/SKILL.md create mode 100644 skills/rn-testing-and-debugging/references/api-failure-simulation.md create mode 100644 skills/rn-testing-and-debugging/references/detox-vs-maestro.md diff --git a/skills/rn-testing-and-debugging/SKILL.md b/skills/rn-testing-and-debugging/SKILL.md new file mode 100644 index 0000000..a60b8c7 --- /dev/null +++ b/skills/rn-testing-and-debugging/SKILL.md @@ -0,0 +1,43 @@ +--- +name: rn-testing-and-debugging +description: Covers E2E testing framework comparison (Detox vs Maestro) and API failure simulation using MITMProxy for React Native and web apps. Use when choosing an E2E testing framework, setting up Maestro on CI, or simulating API failures during development. +license: MIT +metadata: + author: Callstack + tags: react-native, testing, e2e, detox, maestro, mitmproxy, debugging, api, ci +--- + +# React Native Testing & Debugging + +## Overview + +Practical guidance for E2E testing framework selection and API failure simulation. Based on real-world project experience with Detox and Maestro, plus a MITMProxy-based solution for testing API error resilience. + +## When to Apply + +Reference these guidelines when: +- Choosing between Detox and Maestro for E2E testing +- Setting up Maestro tests on CI (GitHub Actions) +- Simulating API failures or error responses during development +- Debugging API error handling in React Native or web apps +- Evaluating E2E testing costs for OSS or budget-constrained projects + +## Quick Reference + +| File | Description | +|------|-------------| +| [detox-vs-maestro.md][detox-vs-maestro] | Real-world Detox vs Maestro comparison with CI setup | +| [api-failure-simulation.md][api-failure-simulation] | MITMProxy + Redis setup for API response overriding | + +## Problem → Skill Mapping + +| Problem | Start With | +|---------|------------| +| Choosing E2E testing framework | [detox-vs-maestro.md][detox-vs-maestro] | +| Detox flaky on CI | [detox-vs-maestro.md][detox-vs-maestro] | +| Setting up Maestro on GitHub Actions | [detox-vs-maestro.md][detox-vs-maestro] | +| Need to simulate API errors | [api-failure-simulation.md][api-failure-simulation] | +| Test error handling without backend changes | [api-failure-simulation.md][api-failure-simulation] | + +[detox-vs-maestro]: references/detox-vs-maestro.md +[api-failure-simulation]: references/api-failure-simulation.md diff --git a/skills/rn-testing-and-debugging/references/api-failure-simulation.md b/skills/rn-testing-and-debugging/references/api-failure-simulation.md new file mode 100644 index 0000000..be09956 --- /dev/null +++ b/skills/rn-testing-and-debugging/references/api-failure-simulation.md @@ -0,0 +1,197 @@ +--- +title: API Failure Simulation +impact: MEDIUM +tags: mitmproxy, redis, api, debugging, testing, proxy, error-simulation +--- + +# Skill: API Failure Simulation + +Simulate API failures and override responses using MITMProxy + Redis + a companion Next.js UI, without modifying the backend. + +## Quick Command + +```bash +# Install dependencies +brew install mitmproxy redis + +# Start Redis +brew services start redis + +# Run MITMProxy with response override addon +mitmweb --listen-port 8080 -s ./filter.py +``` + +## When to Use + +- Testing app behavior when APIs return errors (500, 404, 403) +- Verifying error handling UI without backend changes +- Simulating network failures for specific endpoints +- QA needs to reproduce API-related bugs on demand +- Testing API error resilience in React Native or web apps + +## Prerequisites + +- macOS with Homebrew +- MITMProxy (`brew install mitmproxy`) +- Redis (`brew install redis`) +- Node.js for the companion Next.js UI +- FoxyProxy browser extension (for web app testing) + +## Step-by-Step Instructions + +### 1. Install and Configure MITMProxy + +```bash +brew install mitmproxy redis +brew services start redis +``` + +Run once to generate CA certificate: +```bash +mitmweb --listen-port 8080 +# Close after startup +``` + +Install the CA cert for HTTPS interception: +```bash +sudo security add-trusted-cert -d -p ssl -p basic \ + -k /Library/Keychains/System.keychain \ + ~/.mitmproxy/mitmproxy-ca-cert.pem +``` + +### 2. Install Redis for MITMProxy's Python + +MITMProxy uses its own Homebrew-managed Python. Install the Redis client into it: + +```bash +# Find MITMProxy's Python path +brew info mitmproxy +# Look for the Cellar path, e.g., /opt/homebrew/Cellar/mitmproxy/10.0.0 + +cd /opt/homebrew/Cellar/mitmproxy/10.0.0/libexec/bin +ls -la # Find the python symlink + +# Navigate to the actual Python installation +# Follow the symlink to find pip3 +cd ../../../../../opt/python@3.12/Frameworks/Python.framework/Versions/3.12/bin + +# Install redis package +./pip3 install redis --break-system-packages +``` + +### 3. Create the Filter Addon + +Create `filter.py` — the MITMProxy addon that reads override rules from Redis: + +```python +import redis + +class MyAddon: + def __init__(self): + self.r = redis.Redis(host='localhost', port=6379, db=0) + + def response(self, flow): + urls = [url.decode('utf-8') + for url in self.r.lrange('override:urls', 0, -1)] + data = [self.r.hgetall(f'override:{url}') for url in urls] + + match = None + for node in data: + if (b'enabled' in node + and node[b'enabled'] == b'true' + and node[b'urlMatch'].decode('utf-8') + in flow.request.url): + match = node + break + + if (match is not None + and flow.request.method != 'OPTIONS' + and (b'method' not in match + or match[b'method'].decode('utf-8') + == flow.request.method)): + flow.response.status_code = int(match[b'statusCode']) + if b'body' in match: + flow.response.content = match[b'body'] + +addons = [MyAddon()] +``` + +**How it works:** +1. On each intercepted response, check if any Redis-stored `urlMatch` pattern matches the request URL (partial match) +2. If a match is found and the rule is enabled, override the response status code and body +3. Skips OPTIONS requests (CORS preflight) +4. Optionally filters by HTTP method + +### 4. Set Up the Companion UI + +Clone the companion Next.js app for managing override rules: + +```bash +git clone https://github.com/Killavus/request-tester.git +cd request-tester +yarn +yarn dev --port 3002 +``` + +Open `http://localhost:3002` to create, toggle, and manage override rules via a web UI. + +### 5. Configure Browser Proxy (Web Apps) + +Install FoxyProxy extension for Chrome or Firefox: +1. Add proxy configuration pointing to `localhost:8080` +2. Enable the proxy when testing +3. Create override rules in the companion UI +4. Toggle rules on/off as needed + +### 6. Run the Full Stack + +```bash +# Terminal 1: Redis (if not already running as service) +brew services start redis + +# Terminal 2: MITMProxy with addon +mitmweb --listen-port 8080 -s ./filter.py + +# Terminal 3: Companion UI +cd request-tester && yarn dev --port 3002 +``` + +For self-signed certificate APIs, enable "Ignore server certificates" in MITMProxy web UI options. + +## Server-Side Interception + +For Next.js or Node-based server-side requests, use `node-fetch` with `https-proxy-agent`: + +```bash +npm install node-fetch https-proxy-agent +``` + +```javascript +import fetch from 'node-fetch'; +import { HttpsProxyAgent } from 'https-proxy-agent'; + +const agent = new HttpsProxyAgent('http://localhost:8080'); + +const response = await fetch('https://api.example.com/data', { + agent, +}); +``` + +This routes server-side requests through MITMProxy, enabling the same override rules. + +## Important Caveats + +- **Side effects still execute**: Overriding a DELETE endpoint's response to 500 still deletes the resource server-side. Only the *response* is modified. +- **HTTPS requires CA cert**: Without the CA cert installed, HTTPS interception fails silently. +- **Redis must be running**: The addon crashes if Redis is unavailable. + +## Common Pitfalls + +- **Forgetting to install Redis in MITMProxy's Python**: The addon imports `redis` from MITMProxy's bundled Python, not system Python +- **Not installing CA certificate**: HTTPS interception won't work without it +- **Expecting request blocking**: This tool overrides *responses*, not requests — the original request still reaches the server +- **FoxyProxy not active**: Ensure the proxy is enabled in the browser extension before testing + +## Related Skills + +- [detox-vs-maestro.md](./detox-vs-maestro.md) — E2E testing framework comparison diff --git a/skills/rn-testing-and-debugging/references/detox-vs-maestro.md b/skills/rn-testing-and-debugging/references/detox-vs-maestro.md new file mode 100644 index 0000000..dff0ffb --- /dev/null +++ b/skills/rn-testing-and-debugging/references/detox-vs-maestro.md @@ -0,0 +1,144 @@ +--- +title: Detox vs Maestro +impact: HIGH +tags: e2e, testing, detox, maestro, ci, github-actions, yaml, mobile-testing +--- + +# Skill: Detox vs Maestro + +Real-world comparison of Detox and Maestro for React Native E2E testing, based on production project experience. + +## Quick Reference + +| Aspect | Detox | Maestro | +|--------|-------|---------| +| Test format | JavaScript/TypeScript | YAML | +| CI reliability | Flaky, often disabled | Stable with proper setup | +| Test authoring | Developers only | Manual testers can contribute | +| Mocking support | Built-in network mocking | None (young ecosystem) | +| Setup complexity | High (native build deps) | Low (standalone binary) | +| Maintenance | High | Low (YAML tests are simple) | + +## When to Use + +- Evaluating E2E testing frameworks for a React Native project +- Experiencing CI flakiness with Detox +- Need non-developers to write E2E tests +- Considering Maestro for an open-source project + +## The Case for Maestro + +### Detox Pain Points (Real-World) + +On a production project, Detox tests were: +- **Disabled on CI** due to persistent unreliability +- Flaky across different CI environments +- Difficult to debug when failures occurred +- Required developer involvement for every test change + +### Maestro Advantages + +**YAML-based tests** — Non-developers can author tests: + +```yaml +appId: com.example.myapp +--- +- launchApp +- tapOn: "Login" +- inputText: + id: "email-input" + text: "test@example.com" +- inputText: + id: "password-input" + text: "password123" +- tapOn: "Submit" +- assertVisible: "Welcome" +``` + +**Maestro Studio** — Visual test recorder: +```bash +maestro studio +``` + +Opens a browser UI for recording interactions and generating YAML tests. + +**Scale**: On one project a manual tester wrote 100+ YAML tests without developer assistance. + +### CI Setup with GitHub Actions + +No official Maestro CI guide exists. Use a self-hosted approach based on Stripe's GitHub Actions setup: + +```yaml +name: E2E Tests +on: [pull_request] + +jobs: + maestro-tests: + runs-on: macos-latest + steps: + - uses: actions/checkout@v4 + + - name: Install Maestro + run: | + curl -Ls "https://get.maestro.mobile.dev" | bash + echo "$HOME/.maestro/bin" >> $GITHUB_PATH + + - name: Build app + run: | + # Build the iOS app for simulator + npx react-native build-ios --mode Release --simulator "iPhone 16" + + - name: Boot simulator + run: | + xcrun simctl boot "iPhone 16" + + - name: Install app + run: | + xcrun simctl install booted build/Build/Products/Release-iphonesimulator/MyApp.app + + - name: Run Maestro tests + run: | + maestro test .maestro/ +``` + +### Cost Considerations + +- **Maestro Cloud**: Pricing too high for OSS / budget-constrained projects +- **Self-hosted GitHub Actions**: Free for public repos, cost-effective for private +- **Local development**: Maestro CLI is free and open-source + +## Maestro Limitations + +- **No mocking**: Cannot mock network requests or native modules natively +- **Young ecosystem**: Fewer community resources and plugins than Detox +- **Limited assertions**: Assertion API is simpler than Detox's +- **Platform gaps**: Some platform-specific interactions may not be supported + +### Workarounds for Missing Mocking + +- Use environment variables to switch API endpoints in the app +- Set up a mock API server (MSW, json-server) running alongside tests +- Use build flavors/schemes to inject test configurations + +## Decision Matrix + +| Scenario | Recommendation | +|----------|---------------| +| Non-developers write tests | Maestro | +| Need network mocking | Detox | +| CI reliability is critical | Maestro | +| Large test suite (100+ tests) | Maestro (easier maintenance) | +| Deep native interaction testing | Detox | +| OSS project (budget-sensitive) | Maestro (self-hosted) | +| Existing Detox suite working well | Keep Detox | + +## Common Pitfalls + +- **Assuming Maestro Cloud is required**: Self-hosted runners work well and are cost-effective +- **Missing CI setup docs**: No official guide exists — use community examples (Stripe's GH Actions) +- **Expecting Detox-level mocking**: Plan alternative mocking strategies when using Maestro +- **Not using Maestro Studio**: Dramatically speeds up test creation for non-developers + +## Related Skills + +- [api-failure-simulation.md](./api-failure-simulation.md) — Simulate API failures for testing error handling From 50d117cace972fbb9205247228ab239d07f2c42a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Mi=C5=82kowski?= Date: Mon, 16 Feb 2026 17:47:07 +0100 Subject: [PATCH 3/8] feat: add rn-native-ios-tooling skill --- skills/rn-native-ios-tooling/SKILL.md | 46 ++++ .../references/ios-dependency-managers.md | 119 +++++++++++ .../references/objc-to-swift-migration.md | 197 ++++++++++++++++++ .../references/oss-licensing-tools.md | 171 +++++++++++++++ 4 files changed, 533 insertions(+) create mode 100644 skills/rn-native-ios-tooling/SKILL.md create mode 100644 skills/rn-native-ios-tooling/references/ios-dependency-managers.md create mode 100644 skills/rn-native-ios-tooling/references/objc-to-swift-migration.md create mode 100644 skills/rn-native-ios-tooling/references/oss-licensing-tools.md diff --git a/skills/rn-native-ios-tooling/SKILL.md b/skills/rn-native-ios-tooling/SKILL.md new file mode 100644 index 0000000..0b9eb80 --- /dev/null +++ b/skills/rn-native-ios-tooling/SKILL.md @@ -0,0 +1,46 @@ +--- +name: rn-native-ios-tooling +description: Covers iOS dependency manager comparison (SPM vs Carthage vs CocoaPods), OSS licensing tools for mobile apps, and Objective-C to Swift migration strategies. Use when evaluating iOS dependency managers, setting up license compliance, or planning an ObjC to Swift migration. +license: MIT +metadata: + author: Callstack + tags: react-native, ios, spm, cocoapods, carthage, licensing, objc, swift, migration +--- + +# React Native Native iOS Tooling + +## Overview + +Practical guidance for iOS dependency management, open-source license compliance, and Objective-C to Swift migration in React Native projects. + +## When to Apply + +Reference these guidelines when: +- Choosing or switching iOS dependency managers (SPM, Carthage, CocoaPods) +- Setting up OSS license compliance for iOS/Android apps +- Planning a migration from Objective-C to Swift +- Evaluating the cost of switching away from CocoaPods +- Need cross-platform license notice generation + +## Quick Reference + +| File | Description | +|------|-------------| +| [ios-dependency-managers.md][ios-dependency-managers] | SPM vs Carthage vs CocoaPods comparison | +| [oss-licensing-tools.md][oss-licensing-tools] | OSS license compliance tools for mobile | +| [objc-to-swift-migration.md][objc-to-swift-migration] | ObjC → Swift migration checklist | + +## Problem → Skill Mapping + +| Problem | Start With | +|---------|------------| +| Choosing iOS dependency manager | [ios-dependency-managers.md][ios-dependency-managers] | +| Migrating away from CocoaPods | [ios-dependency-managers.md][ios-dependency-managers] | +| Setting up license notices in app | [oss-licensing-tools.md][oss-licensing-tools] | +| Cross-platform license generation | [oss-licensing-tools.md][oss-licensing-tools] | +| Planning ObjC to Swift migration | [objc-to-swift-migration.md][objc-to-swift-migration] | +| Migrating native module to Swift | [objc-to-swift-migration.md][objc-to-swift-migration] | + +[ios-dependency-managers]: references/ios-dependency-managers.md +[oss-licensing-tools]: references/oss-licensing-tools.md +[objc-to-swift-migration]: references/objc-to-swift-migration.md diff --git a/skills/rn-native-ios-tooling/references/ios-dependency-managers.md b/skills/rn-native-ios-tooling/references/ios-dependency-managers.md new file mode 100644 index 0000000..807b61f --- /dev/null +++ b/skills/rn-native-ios-tooling/references/ios-dependency-managers.md @@ -0,0 +1,119 @@ +--- +title: iOS Dependency Managers +impact: HIGH +tags: spm, cocoapods, carthage, ios, dependency-management, xcode +--- + +# Skill: iOS Dependency Managers + +Compare and choose between SPM, Carthage, and CocoaPods for iOS dependency management. + +## Quick Reference + +**Recommended ranking**: SPM > Carthage > CocoaPods + +| Feature | SPM | Carthage | CocoaPods | +|---------|-----|----------|-----------| +| Swift support | Full (native) | Full | Full | +| ObjC support | Limited | Full | Full | +| Installation | Built into Xcode | `brew install carthage` | `gem install cocoapods` | +| Project impact | **None** | Almost none | **Heavy** (wraps into workspace, modifies xcodeproj) | +| Removal complexity | Trivial | Easy | Very complex | +| Build speed | Fast (Apple's caching) | Slow initial (prebuilds once) | Rebuilds deps every time | +| Market share | ~46% | ~11% | ~61% | +| Apple maintained | Yes | Community | Community | +| Binary distribution | Supported (XCFramework) | Supported | Limited | + +## When to Use + +- Starting a new iOS/React Native project and choosing a dependency manager +- Evaluating whether to migrate away from CocoaPods +- Need to understand trade-offs between available options + +## Comparison Details + +### Swift Package Manager (SPM) + +**Strengths:** +- Built into Xcode — no external tools needed +- Minimal project file changes +- Fast dependency resolution with caching +- Apple-maintained, long-term investment +- Easy to add/remove packages +- First-class binary target (XCFramework) support + +**Weaknesses:** +- Limited Objective-C library support +- Some RN dependencies still require CocoaPods +- Resource bundle handling can be tricky +- Cannot mix with CocoaPods for the same target easily + +**Best for**: New Swift-first projects, libraries with SPM support. + +### Carthage + +**Strengths:** +- Decentralized — no central spec repo +- Prebuilds frameworks (faster CI if cached) +- Minimal project file intrusion +- Easy to remove +- Good ObjC and Swift support + +**Weaknesses:** +- Slow initial build (compiles all dependencies from source) +- Requires manual framework linking +- Smaller ecosystem than CocoaPods +- Some libraries don't support Carthage + +**Best for**: Projects wanting prebuilt binaries without project file modification. + +### CocoaPods + +**Strengths:** +- Largest library ecosystem +- Excellent Objective-C support +- React Native's default dependency manager +- Well-documented integration +- Handles complex dependency graphs + +**Weaknesses:** +- **Extremely hard to switch away from** — modifies xcodeproj, creates workspace, adds build phases +- Slow `pod install` on large projects +- Ruby dependency management adds complexity +- Central spec repo can be slow +- Xcode 16 compatibility issues (frequently) + +**Best for**: React Native projects (required by most RN libraries), large ObjC codebases. + +## Key Insight: CocoaPods Lock-In + +CocoaPods is extremely hard to switch away from because it: +1. Creates and manages a `.xcworkspace` +2. Modifies the `.xcodeproj` with custom build phases +3. Manages header search paths and framework search paths +4. Many React Native libraries only provide Podspecs + +**Migration effort from CocoaPods**: Weeks to months for a medium-sized RN project. Requires rewriting build configuration and potentially forking libraries. + +## Decision Matrix + +| Scenario | Recommendation | +|----------|---------------| +| New RN project | CocoaPods (required by RN ecosystem) | +| Pure Swift project, no RN | SPM | +| Need easy dependency removal | SPM or Carthage | +| Large ObjC codebase | CocoaPods | +| Want prebuilt frameworks | Carthage or SPM (binary targets) | +| Evaluating migration from CocoaPods | Only if strong business case justifies the effort | + +## Common Pitfalls + +- **Attempting to remove CocoaPods casually**: Understand the full scope of project file changes before starting +- **Mixing SPM and CocoaPods for same dependency**: Can cause duplicate symbol errors +- **Not caching Carthage builds**: Initial builds are slow; cache `Carthage/Build` in CI +- **Assuming all RN libraries support SPM**: Most still require CocoaPods + +## Related Skills + +- [oss-licensing-tools.md](./oss-licensing-tools.md) — License compliance for dependencies +- [objc-to-swift-migration.md](./objc-to-swift-migration.md) — ObjC → Swift migration strategies diff --git a/skills/rn-native-ios-tooling/references/objc-to-swift-migration.md b/skills/rn-native-ios-tooling/references/objc-to-swift-migration.md new file mode 100644 index 0000000..835666f --- /dev/null +++ b/skills/rn-native-ios-tooling/references/objc-to-swift-migration.md @@ -0,0 +1,197 @@ +--- +title: Objective-C to Swift Migration +impact: HIGH +tags: objc, swift, migration, ios, bridging-header, refactoring, native +--- + +# Skill: Objective-C to Swift Migration + +Plan and execute an Objective-C to Swift migration for iOS native code in React Native projects. + +## Quick Reference + +| Phase | Key Actions | +|-------|------------| +| Before | Investigate code, understand flows, simplify ObjC first | +| During | Migrate by module, use bridging headers, rewrite when needed | +| After | Migrate unit tests, update docs, apply SOLID principles | + +## When to Use + +- Planning migration of native iOS modules from ObjC to Swift +- React Native native module needs Swift rewrite +- Brownfield app has legacy ObjC code +- Team wants to leverage Swift-only features (async/await, structured concurrency) + +## Prerequisites + +- Xcode 15+ with Swift 5.9+ +- Understanding of both Objective-C and Swift +- Existing unit test coverage (or willingness to add it) +- Bridging header knowledge + +## Before Migration + +### 1. Investigate the Code + +- Map all ObjC files and their dependencies +- Identify interconnected modules and isolated components +- Document threading model, queuing, and dispatch patterns +- Note any C/C++ interop (Swift's C interop is more limited) + +### 2. Understand Flows and Threading + +- Trace execution paths through ObjC code +- Document GCD/NSOperationQueue usage patterns +- Identify main thread vs background thread boundaries +- Note any `@synchronized` blocks or locking mechanisms + +### 3. Simplify First + +Before migrating, clean up the ObjC: +- Remove dead code +- Break large classes into smaller ones +- Reduce coupling between modules +- Fix existing bugs (don't carry them into Swift) + +### 4. Plan the Migration Order + +Start with the **smallest-impact, most-isolated** module: +- Utility classes with no dependencies +- Data models / value objects +- Standalone helpers + +Work outward toward more connected code. + +## During Migration + +### 5. Migrate Module by Module + +**Do not attempt a "big bang" rewrite.** Migrate one module at a time: + +1. Create Swift file(s) for the module +2. Set up bridging header for ObjC → Swift interop +3. Migrate the implementation +4. Update callers to use the Swift version +5. Remove old ObjC files +6. Verify tests pass + +### 6. Use Bridging Headers + +**ObjC calling Swift:** +```objc +// Import the auto-generated Swift header +#import "MyApp-Swift.h" + +// Use Swift class +MySwiftClass *obj = [[MySwiftClass alloc] init]; +``` + +**Swift calling ObjC:** +```swift +// In MyApp-Bridging-Header.h, add: +// #import "MyObjCClass.h" + +// Then use directly in Swift +let obj = MyObjCClass() +``` + +**Tip**: Expose only what's needed via `@objc` and `@objcMembers`. Don't make everything visible. + +### 7. Don't Hesitate to Rewrite + +- Translating ObjC patterns 1:1 into Swift often produces poor Swift code +- Use Swift idioms: optionals instead of nil checks, enums with associated values, structs for value types +- Rewrite delegate patterns as closures where appropriate +- Replace NSNotificationCenter with Combine or async/await where practical + +### 8. Leverage Swift Features + +| ObjC Pattern | Swift Replacement | +|-------------|-------------------| +| Delegate + protocol | Closure / async-await | +| NSError** | throws / Result type | +| GCD dispatch_async | Task { } / structured concurrency | +| KVO | @Published + Combine | +| NSMutableArray | [Element] (value type) | +| Category | Extension | +| typedef enum | enum with raw values | + +### 9. Migrate Unit Tests Early + +- Migrate tests for a module **alongside** the module itself +- Swift tests can call both ObjC and Swift code +- Use XCTest's Swift API directly +- Don't leave test migration for "later" — it rarely happens + +### 10. Apply SOLID Principles + +Migration is an opportunity to improve architecture: +- **Single Responsibility**: Split classes that do too much +- **Open/Closed**: Use protocols for extensibility +- **Liskov Substitution**: Ensure protocol conformances are correct +- **Interface Segregation**: Prefer small, focused protocols +- **Dependency Inversion**: Inject dependencies rather than hard-coding + +## Documentation + +Keep documentation updated throughout: +- Update API docs as interfaces change +- Document any behavior changes (even if intentional improvements) +- Note breaking changes for consumers of the migrated code +- Update README with new Swift requirements + +## React Native Specific Considerations + +### Native Modules + +When migrating a RN native module from ObjC to Swift: + +```swift +import React + +@objc(MyModule) +class MyModule: NSObject { + @objc static func requiresMainQueueSetup() -> Bool { + return false + } + + @objc func doSomething( + _ resolve: @escaping RCTPromiseResolveBlock, + reject: @escaping RCTPromiseRejectBlock + ) { + resolve(["result": "success"]) + } +} +``` + +The `RCT_EXTERN_MODULE` macro still requires an ObjC file: + +```objc +// MyModule.m +#import + +@interface RCT_EXTERN_MODULE(MyModule, NSObject) +RCT_EXTERN_METHOD(doSomething: + (RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject) +@end +``` + +### Turbo Modules + +For New Architecture Turbo Modules, prefer Swift with `@objc` annotations. The codegen bridge handles the interop layer. + +## Common Pitfalls + +- **"Big bang" migration**: Migrating everything at once introduces too many bugs simultaneously +- **1:1 translation**: Produces un-idiomatic Swift code. Rewrite to use Swift patterns. +- **Ignoring threading differences**: Swift concurrency model differs from GCD patterns +- **Skipping test migration**: Leads to untested Swift code +- **Making everything @objcMembers**: Only expose what ObjC callers actually need +- **Not simplifying ObjC first**: Migrating messy ObjC produces messy Swift + +## Related Skills + +- [ios-dependency-managers.md](./ios-dependency-managers.md) — Dependencies may change during migration +- [oss-licensing-tools.md](./oss-licensing-tools.md) — Verify license compliance after dependency changes diff --git a/skills/rn-native-ios-tooling/references/oss-licensing-tools.md b/skills/rn-native-ios-tooling/references/oss-licensing-tools.md new file mode 100644 index 0000000..02991b2 --- /dev/null +++ b/skills/rn-native-ios-tooling/references/oss-licensing-tools.md @@ -0,0 +1,171 @@ +--- +title: OSS Licensing Tools +impact: MEDIUM +tags: licensing, oss, compliance, android, ios, react-native, legal +--- + +# Skill: OSS Licensing Tools + +Set up open-source license compliance and notice generation for mobile apps. + +## Quick Reference + +| Tool | Platform | Type | +|------|----------|------| +| AboutLibraries | Android | Native Gradle plugin | +| LicensePlist | iOS | CocoaPods/SPM integration | +| Google OSS Licenses Plugin | Android | Gradle plugin | +| `with-react-native-oss-notice` | Cross-platform | Expo config plugin (Callstack, internal) | +| ORT (OSS Review Toolkit) | Cross-platform | Full compliance pipeline | +| FOSSology | Cross-platform | Compliance scanning | + +## When to Use + +- App store submission requires license attribution +- Legal/compliance review of third-party dependencies +- Need to generate a "licenses" or "acknowledgements" screen in the app +- Auditing OSS license compatibility + +## Platform-Specific Tools + +### Android: AboutLibraries + +Gradle plugin that automatically collects license info from dependencies: + +```groovy +// build.gradle +plugins { + id "com.mikepenz.aboutlibraries.plugin" version "10.10.0" +} +``` + +```kotlin +// In-app usage +AboutLibraries.Builder() + .withAutoDetect(true) + .start(context) +``` + +**Strengths**: Automatic detection, UI component included, widely used. Can use the built-in UI or extract generated metadata for custom display. + +### Android: Google OSS Licenses Plugin + +```groovy +// build.gradle +plugins { + id 'com.google.android.gms.oss-licenses-plugin' +} + +dependencies { + implementation 'com.google.android.gms:play-services-oss-licenses:17.0.1' +} +``` + +```kotlin +startActivity(Intent(this, OssLicensesMenuActivity::class.java)) +``` + +**Strengths**: Google-maintained, simple integration. +**Weaknesses**: Only detects Google Play Services and Gradle dependencies. + +### iOS: LicensePlist + +Generates a Settings.bundle plist from CocoaPods/Carthage/SPM dependencies: + +```bash +# Install +brew install licenseplist + +# Generate +license-plist --output-path Settings.bundle +``` + +Or via SPM/CocoaPods integration as a build phase: + +```bash +# Xcode Run Script Phase +if which license-plist > /dev/null; then + license-plist --output-path $SRCROOT/Settings.bundle \ + --github-token $LICENSE_PLIST_GITHUB_TOKEN +fi +``` + +Licenses appear in iOS Settings app under the app's entry. + +**Strengths**: Automatic, integrates with iOS Settings. +**Weaknesses**: iOS only, Settings.bundle approach may not match desired UX. + +## Cross-Platform Tools + +### with-react-native-oss-notice (Callstack) + +Expo config plugin for generating license notices on both platforms: + +```bash +npx expo install with-react-native-oss-notice +``` + +```json +// app.json +{ + "expo": { + "plugins": ["with-react-native-oss-notice"] + } +} +``` + +Generates platform-appropriate license files during the build process. Combines platform-specific tools (AboutLibraries + LicensePlist) under one config plugin. + +> **Note**: This is a Callstack internal library, not yet publicly released. + +### ORT (OSS Review Toolkit) + +Full compliance pipeline: analyze → scan → evaluate → report. + +```bash +# Analyze project dependencies +ort analyze -i /path/to/project -o /path/to/output + +# Scan for license texts +ort scan -i /path/to/output/analyzer-result.yml -o /path/to/output + +# Generate report +ort report -i /path/to/output/scan-result.yml -o /path/to/output \ + -f NoticeTemplate +``` + +**Best for**: Enterprise compliance requirements, large projects needing full audit trail. + +### FOSSology + +Open-source compliance scanning platform: +- Server-based scanning +- License identification from source code +- Bulk scanning of dependencies +- Compliance workflow management + +**Caveat**: Very generic scanner — does not specifically scan for licenses in third-party libraries. Better as a supplement to platform-specific tools. + +**Best for**: Organizations needing ongoing compliance scanning infrastructure. + +## Decision Matrix + +| Scenario | Recommendation | +|----------|---------------| +| Android-only app | AboutLibraries | +| iOS-only app | LicensePlist | +| React Native / Expo app | `with-react-native-oss-notice` | +| Enterprise compliance | ORT + FOSSology | +| Quick "licenses" screen | AboutLibraries (Android) + LicensePlist (iOS) | + +## Common Pitfalls + +- **Relying only on automatic detection**: Some transitive dependencies may be missed — verify manually +- **Ignoring license compatibility**: MIT + GPL in same app can create legal issues +- **Not updating before release**: Run license generation as part of release process +- **Missing native dependency licenses**: JS-only tools miss CocoaPods/Gradle-only dependencies + +## Related Skills + +- [ios-dependency-managers.md](./ios-dependency-managers.md) — Understanding dependency sources +- [objc-to-swift-migration.md](./objc-to-swift-migration.md) — Migration may change dependency licensing From 3e84fd3f1af05d57162dd36824dbc175ea6d3ecd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Mi=C5=82kowski?= Date: Mon, 16 Feb 2026 17:49:06 +0100 Subject: [PATCH 4/8] chore: update marketplace configuration --- .claude-plugin/marketplace.json | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index f09160e..c16addb 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -27,6 +27,24 @@ "description": "React Native upgrade workflow covering updated templates, dependencies, and common pitfalls. Use when migrating a React Native app to a newer release.", "source": "./", "skills": ["./skills/upgrading-react-native"] + }, + { + "name": "rn-new-architecture-migration", + "description": "React Native New Architecture migration guide focusing on XCFramework distribution for brownfield iOS apps. Covers bridge initialization, Hermes embedding, and Swift Package distribution.", + "source": "./", + "skills": ["./skills/rn-new-architecture-migration"] + }, + { + "name": "rn-testing-and-debugging", + "description": "E2E testing framework comparison (Detox vs Maestro) and API failure simulation using MITMProxy. Covers CI setup, test authoring, and response overriding.", + "source": "./", + "skills": ["./skills/rn-testing-and-debugging"] + }, + { + "name": "rn-native-ios-tooling", + "description": "iOS dependency manager comparison (SPM vs Carthage vs CocoaPods), OSS licensing tools for mobile apps, and Objective-C to Swift migration strategies.", + "source": "./", + "skills": ["./skills/rn-native-ios-tooling"] } ] } From dcd38bec6cb82fd06509232a990bff10359c1749 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Mi=C5=82kowski?= Date: Tue, 17 Feb 2026 15:17:28 +0100 Subject: [PATCH 5/8] fix: remove rn-new-architecture-migration skill --- .claude-plugin/marketplace.json | 6 - skills/rn-new-architecture-migration/SKILL.md | 41 --- .../references/xcframework-distribution.md | 329 ------------------ 3 files changed, 376 deletions(-) delete mode 100644 skills/rn-new-architecture-migration/SKILL.md delete mode 100644 skills/rn-new-architecture-migration/references/xcframework-distribution.md diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index c16addb..d49ea86 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -28,12 +28,6 @@ "source": "./", "skills": ["./skills/upgrading-react-native"] }, - { - "name": "rn-new-architecture-migration", - "description": "React Native New Architecture migration guide focusing on XCFramework distribution for brownfield iOS apps. Covers bridge initialization, Hermes embedding, and Swift Package distribution.", - "source": "./", - "skills": ["./skills/rn-new-architecture-migration"] - }, { "name": "rn-testing-and-debugging", "description": "E2E testing framework comparison (Detox vs Maestro) and API failure simulation using MITMProxy. Covers CI setup, test authoring, and response overriding.", diff --git a/skills/rn-new-architecture-migration/SKILL.md b/skills/rn-new-architecture-migration/SKILL.md deleted file mode 100644 index 6d389c7..0000000 --- a/skills/rn-new-architecture-migration/SKILL.md +++ /dev/null @@ -1,41 +0,0 @@ ---- -name: rn-new-architecture-migration -description: Guides React Native New Architecture migration, focusing on XCFramework distribution for brownfield iOS apps. Use when packaging React Native as a reusable XCFramework, integrating RN into existing iOS apps, or migrating to the New Architecture. -license: MIT -metadata: - author: Callstack - tags: react-native, new-architecture, xcframework, brownfield, ios, swift-package ---- - -# React Native New Architecture Migration - -## Overview - -Covers packaging and distributing React Native as an XCFramework for brownfield iOS integration, including bridge initialization, Hermes embedding, and Swift Package distribution. - -## When to Apply - -Reference these guidelines when: -- Packaging React Native as a reusable XCFramework for existing iOS apps -- Integrating React Native into a brownfield iOS project -- Setting up RN bridge initialization for old architecture (<0.78) -- Using RNViewFactory or ReactNativeFactory patterns -- Generating universal XCFramework binaries -- Distributing React Native via Swift Package Manager - -## Quick Reference - -| File | Description | -|------|-------------| -| [xcframework-distribution.md][xcframework-distribution] | Package and distribute RN as XCFramework for brownfield iOS | - -## Problem → Skill Mapping - -| Problem | Start With | -|---------|------------| -| Need to embed RN in existing iOS app | [xcframework-distribution.md][xcframework-distribution] | -| Building XCFramework from RN project | [xcframework-distribution.md][xcframework-distribution] | -| Bridge initialization for old arch | [xcframework-distribution.md][xcframework-distribution] | -| Hermes embedding in XCFramework | [xcframework-distribution.md][xcframework-distribution] | - -[xcframework-distribution]: references/xcframework-distribution.md diff --git a/skills/rn-new-architecture-migration/references/xcframework-distribution.md b/skills/rn-new-architecture-migration/references/xcframework-distribution.md deleted file mode 100644 index 823be3c..0000000 --- a/skills/rn-new-architecture-migration/references/xcframework-distribution.md +++ /dev/null @@ -1,329 +0,0 @@ ---- -title: XCFramework Distribution -impact: HIGH -tags: xcframework, brownfield, ios, swift-package, hermes, bridge, new-architecture ---- - -# Skill: XCFramework Distribution - -Package React Native as a reusable XCFramework for brownfield iOS app integration. - -## Quick Reference - -| Step | Action | -|------|--------| -| 1 | Create RN app with `npx react-native init` | -| 2 | Add Swift Framework target in Xcode | -| 3 | Configure Build Settings | -| 4 | Add Run Script Phase for Metro bundle | -| 5 | Set up Podfile integration | -| 6 | Initialize RN bridge (old arch) or use ReactNativeFactory (0.78+) | -| 7 | Generate XCFramework with `xcodebuild` | - -## When to Use - -- Embedding React Native into an existing native iOS app -- Distributing RN-based features as a prebuilt binary -- Building a reusable SDK powered by React Native -- Brownfield integration requiring framework-level packaging - -## Prerequisites - -- Xcode 15+ -- React Native 0.73+ (0.78+ recommended for ReactNativeFactory) -- CocoaPods installed -- Familiarity with Xcode build settings and targets - -## Step-by-Step Instructions - -### 1. Create React Native App - -```bash -npx @react-native-community/cli@latest init MyRNApp -cd MyRNApp -``` - -This serves as the source project from which the framework is built. - -### 2. Add Swift Framework Target - -In Xcode: -1. File → New → Target → Framework -2. Select Swift as the language -3. Set "Embed in Application" to **None** -4. Name it (e.g., `MyRNFramework`) -5. Set deployment target to match the RN app - -### 3. Configure Build Settings - -Set these on the framework target: - -| Setting | Value | Why | -|---------|-------|-----| -| `User Script Sandboxing` | `NO` | Allows Run Script phases to access Metro bundle | -| `Skip Install` | `NO` | Ensures the framework is included in archives | -| `Build Libraries for Distribution` | `YES` | Required for XCFramework generation | -| `DEFINES_MODULE` | `YES` | Generates module map for Swift imports | - -### 4. Add Run Script Phase - -Add a Run Script build phase to the framework target that bundles JS via Metro: - -```bash -set -e - -WITH_ENVIRONMENT="$REACT_NATIVE_PATH/scripts/xcode/with-environment.sh" -REACT_NATIVE_XCODE="$REACT_NATIVE_PATH/scripts/react-native-xcode.sh" - -/bin/sh -c "$WITH_ENVIRONMENT $REACT_NATIVE_XCODE" -``` - -This embeds the JS bundle into the framework during build. - -### 5. Podfile Integration - -Nest the framework target inside the app target in the Podfile with `inherit! :complete`: - -```ruby -target 'MyRNApp' do - config = use_native_modules! - - use_react_native!( - :path => config[:reactNativePath], - :app_path => "#{Pod::Config.instance.installation_root}/.." - ) - - # Nest framework target to inherit all RN pods - target 'MyRNFramework' do - inherit! :complete - end -end -``` - -Then install: - -```bash -npx pod-install ios -``` - -### 6. Bridge Initialization - -#### React Native 0.78+ (ReactNativeFactory) - -```swift -import React -import ReactNativeFactory - -public class MyRNView { - private var factory: ReactNativeFactory? - - public func createView() -> UIView { - factory = ReactNativeFactory() - return factory!.createRootView( - moduleName: "MyRNApp", - initialProperties: nil - ) - } -} -``` - -#### React Native <0.78 (Old Architecture) - -Use a singleton bridge manager with `@_implementationOnly import` to hide React headers from consumers: - -```swift -import UIKit -@_implementationOnly import React - -public class RNBridgeManager { - public static let shared = RNBridgeManager() - - private var bridge: RCTBridge? - - public func initialize(launchOptions: [UIApplication.LaunchOptionsKey: Any]?) { - bridge = RCTBridge(delegate: RNBridgeDelegate(), launchOptions: launchOptions) - } - - func getBridge() -> RCTBridge { - guard let bridge = bridge else { - fatalError("RN bridge must be initialized before creating a RN view!") - } - return bridge - } -} - -private class RNBridgeDelegate: NSObject, RCTBridgeDelegate { - func sourceURL(for _: RCTBridge) -> URL? { - #if DEBUG - return RCTBundleURLProvider.sharedSettings().jsBundleURL(forBundleRoot: "index") - #else - return Bundle(for: Self.self).url(forResource: "main", withExtension: "jsbundle") - #endif - } -} -``` - -### 7. RNViewFactory Pattern - -Expose a factory with typed module names for consuming apps: - -```swift -import UIKit -@_implementationOnly import React - -public struct RNViewFactory { - public static func createView( - moduleName: RNModule, - initialProperties: [String: Any]? = nil - ) -> UIView { - let bridge = RNBridgeManager.shared.getBridge() - return RCTRootView( - bridge: bridge, - moduleName: moduleName.rawValue, - initialProperties: initialProperties - ) - } -} - -public enum RNModule: String { - case myFeature = "MyFeature" -} -``` - -The consuming app calls `RNViewFactory.createView(moduleName: .myFeature)` without needing React Native knowledge. - -### 8. Hermes Embedding - -Hermes is the recommended JS engine but complicates XCFramework distribution: - -- **Recommended**: Treat Hermes as a peer dependency — require the consuming app to include `hermes-engine` via CocoaPods -- **Not recommended**: Embedding `Hermes.xcframework` directly into the output framework (causes symbol duplication issues) - -#### dSYM Fix for React Native <0.76 - -Builds may fail due to a `DebugSymbolsPath` bug in `hermes.xcframework/Info.plist` (fixed in RN 0.76). Remove the problematic entries in Podfile post-install using PlistBuddy: - -```ruby -post_install do |installer| - react_native_post_install( - installer, - config[:reactNativePath], - :mac_catalyst_enabled => false, - ) - - # Remove broken DebugSymbolsPath from hermes.xcframework - PLIST_BUDDY_PATH = '/usr/libexec/PlistBuddy' - installer.pods_project.targets.each do |target| - next unless target.name == "hermes-engine" - installer.pods_project.files.each do |fileref| - next unless fileref.path.end_with?("hermes.xcframework") - plist_file = "#{fileref.real_path}/Info.plist" - stdout, _stderr, _status = Open3.capture3( - "#{PLIST_BUDDY_PATH} -c 'Print :AvailableLibraries' #{plist_file}" - ) - stdout.scan(/Dict/).count.times do |i| - Open3.capture3( - "#{PLIST_BUDDY_PATH} -c 'Delete :AvailableLibraries:#{i}:DebugSymbolsPath' #{plist_file}" - ) - end - end - end -end -``` - -### 9. Generate XCFramework - -Build for both simulator and device, then combine: - -```bash -#!/bin/bash - -WORKSPACE=${WORKSPACE:-MyRNApp} -SCHEME=${SCHEME:-MyRNFramework} -CONFIGURATION=${BUILD_TYPE:-Release} -ARCHIVE_DIR="archives" - -cd ios - -# Build for iOS Simulator -xcodebuild archive \ - -workspace $WORKSPACE.xcworkspace \ - -scheme $SCHEME \ - -destination "generic/platform=iOS Simulator" \ - -configuration $CONFIGURATION \ - -archivePath $ARCHIVE_DIR/${SCHEME}-iOS_Simulator.xcarchive \ - -quiet || exit 1 - -# Build for iOS device -xcodebuild archive \ - -workspace $WORKSPACE.xcworkspace \ - -scheme $SCHEME \ - -destination "generic/platform=iOS" \ - -configuration $CONFIGURATION \ - -archivePath $ARCHIVE_DIR/${SCHEME}-iOS.xcarchive \ - -quiet || exit 1 - -# Remove previous output -rm -rf $ARCHIVE_DIR/$SCHEME.xcframework - -# Create XCFramework -xcodebuild -create-xcframework \ - -archive $ARCHIVE_DIR/${SCHEME}-iOS_Simulator.xcarchive -framework $SCHEME.framework \ - -archive $ARCHIVE_DIR/${SCHEME}-iOS.xcarchive -framework $SCHEME.framework \ - -output $ARCHIVE_DIR/$SCHEME.xcframework - -cd - -``` - -### 10. Distribution via Swift Package (Future) - -Swift Package Manager distribution requires: -- Hosting the XCFramework as a binary target (zip + checksum) -- Creating a `Package.swift` with `.binaryTarget` - -```swift -// Package.swift (example structure) -let package = Package( - name: "MyRNFramework", - platforms: [.iOS(.v15)], - products: [ - .library(name: "MyRNFramework", targets: ["MyRNFramework"]), - ], - targets: [ - .binaryTarget( - name: "MyRNFramework", - url: "https://example.com/MyRNFramework.xcframework.zip", - checksum: "" - ), - ] -) -``` - -## FAQ - -### Does this support both old and new architecture? -The bridge-based approach (steps 6-7) only supports the old architecture. On RN 0.78+, use `ReactNativeFactory` (see [PR #46298](https://github.com/facebook/react-native/pull/46298)) which supports both architectures. - -### What architectures are supported? -XCFramework supports arm64 (device) and arm64 + x86_64 (simulator). Use `lipo -info` to verify slices. - -### Can Hermes be bundled inside the XCFramework? -No — there is no support for including an XCFramework inside another XCFramework. Include `hermes.xcframework` directly in the brownfield app as a "peer dependency." - -### pod install fails on Xcode 16? -RN 0.76 doesn't have proper Xcode 16 support. Update CocoaPods: -```bash -gem install cocoapods --pre -``` - -## Common Pitfalls - -- **User Script Sandboxing enabled**: Metro bundling fails silently. Always set to `NO`. -- **Skip Install = YES**: The framework won't appear in the archive. Set to `NO`. -- **Embedding Hermes directly**: Causes duplicate symbol errors in consuming apps. -- **Missing JS bundle**: Ensure the Run Script phase runs before the framework's Compile Sources phase. -- **Architecture mismatch**: Always build both arm64 and x86_64 simulator slices. - -## Related Skills - -- [rn-native-ios-tooling](../../rn-native-ios-tooling/SKILL.md) — iOS dependency managers and tooling From 7e48f8930c00d2c8a8a4da92b05ae44a05b191f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Mi=C5=82kowski?= Date: Tue, 17 Feb 2026 15:23:37 +0100 Subject: [PATCH 6/8] fix: remove detox-vs-maestro reference --- skills/rn-testing-and-debugging/SKILL.md | 14 +- .../references/detox-vs-maestro.md | 144 ------------------ 2 files changed, 3 insertions(+), 155 deletions(-) delete mode 100644 skills/rn-testing-and-debugging/references/detox-vs-maestro.md diff --git a/skills/rn-testing-and-debugging/SKILL.md b/skills/rn-testing-and-debugging/SKILL.md index a60b8c7..ccc6313 100644 --- a/skills/rn-testing-and-debugging/SKILL.md +++ b/skills/rn-testing-and-debugging/SKILL.md @@ -1,43 +1,35 @@ --- name: rn-testing-and-debugging -description: Covers E2E testing framework comparison (Detox vs Maestro) and API failure simulation using MITMProxy for React Native and web apps. Use when choosing an E2E testing framework, setting up Maestro on CI, or simulating API failures during development. +description: Covers API failure simulation using MITMProxy for React Native and web apps. Use when simulating API failures during development. license: MIT metadata: author: Callstack - tags: react-native, testing, e2e, detox, maestro, mitmproxy, debugging, api, ci + tags: react-native, testing, mitmproxy, debugging, api --- # React Native Testing & Debugging ## Overview -Practical guidance for E2E testing framework selection and API failure simulation. Based on real-world project experience with Detox and Maestro, plus a MITMProxy-based solution for testing API error resilience. +Practical guidance for API failure simulation. A MITMProxy-based solution for testing API error resilience. ## When to Apply Reference these guidelines when: -- Choosing between Detox and Maestro for E2E testing -- Setting up Maestro tests on CI (GitHub Actions) - Simulating API failures or error responses during development - Debugging API error handling in React Native or web apps -- Evaluating E2E testing costs for OSS or budget-constrained projects ## Quick Reference | File | Description | |------|-------------| -| [detox-vs-maestro.md][detox-vs-maestro] | Real-world Detox vs Maestro comparison with CI setup | | [api-failure-simulation.md][api-failure-simulation] | MITMProxy + Redis setup for API response overriding | ## Problem → Skill Mapping | Problem | Start With | |---------|------------| -| Choosing E2E testing framework | [detox-vs-maestro.md][detox-vs-maestro] | -| Detox flaky on CI | [detox-vs-maestro.md][detox-vs-maestro] | -| Setting up Maestro on GitHub Actions | [detox-vs-maestro.md][detox-vs-maestro] | | Need to simulate API errors | [api-failure-simulation.md][api-failure-simulation] | | Test error handling without backend changes | [api-failure-simulation.md][api-failure-simulation] | -[detox-vs-maestro]: references/detox-vs-maestro.md [api-failure-simulation]: references/api-failure-simulation.md diff --git a/skills/rn-testing-and-debugging/references/detox-vs-maestro.md b/skills/rn-testing-and-debugging/references/detox-vs-maestro.md deleted file mode 100644 index dff0ffb..0000000 --- a/skills/rn-testing-and-debugging/references/detox-vs-maestro.md +++ /dev/null @@ -1,144 +0,0 @@ ---- -title: Detox vs Maestro -impact: HIGH -tags: e2e, testing, detox, maestro, ci, github-actions, yaml, mobile-testing ---- - -# Skill: Detox vs Maestro - -Real-world comparison of Detox and Maestro for React Native E2E testing, based on production project experience. - -## Quick Reference - -| Aspect | Detox | Maestro | -|--------|-------|---------| -| Test format | JavaScript/TypeScript | YAML | -| CI reliability | Flaky, often disabled | Stable with proper setup | -| Test authoring | Developers only | Manual testers can contribute | -| Mocking support | Built-in network mocking | None (young ecosystem) | -| Setup complexity | High (native build deps) | Low (standalone binary) | -| Maintenance | High | Low (YAML tests are simple) | - -## When to Use - -- Evaluating E2E testing frameworks for a React Native project -- Experiencing CI flakiness with Detox -- Need non-developers to write E2E tests -- Considering Maestro for an open-source project - -## The Case for Maestro - -### Detox Pain Points (Real-World) - -On a production project, Detox tests were: -- **Disabled on CI** due to persistent unreliability -- Flaky across different CI environments -- Difficult to debug when failures occurred -- Required developer involvement for every test change - -### Maestro Advantages - -**YAML-based tests** — Non-developers can author tests: - -```yaml -appId: com.example.myapp ---- -- launchApp -- tapOn: "Login" -- inputText: - id: "email-input" - text: "test@example.com" -- inputText: - id: "password-input" - text: "password123" -- tapOn: "Submit" -- assertVisible: "Welcome" -``` - -**Maestro Studio** — Visual test recorder: -```bash -maestro studio -``` - -Opens a browser UI for recording interactions and generating YAML tests. - -**Scale**: On one project a manual tester wrote 100+ YAML tests without developer assistance. - -### CI Setup with GitHub Actions - -No official Maestro CI guide exists. Use a self-hosted approach based on Stripe's GitHub Actions setup: - -```yaml -name: E2E Tests -on: [pull_request] - -jobs: - maestro-tests: - runs-on: macos-latest - steps: - - uses: actions/checkout@v4 - - - name: Install Maestro - run: | - curl -Ls "https://get.maestro.mobile.dev" | bash - echo "$HOME/.maestro/bin" >> $GITHUB_PATH - - - name: Build app - run: | - # Build the iOS app for simulator - npx react-native build-ios --mode Release --simulator "iPhone 16" - - - name: Boot simulator - run: | - xcrun simctl boot "iPhone 16" - - - name: Install app - run: | - xcrun simctl install booted build/Build/Products/Release-iphonesimulator/MyApp.app - - - name: Run Maestro tests - run: | - maestro test .maestro/ -``` - -### Cost Considerations - -- **Maestro Cloud**: Pricing too high for OSS / budget-constrained projects -- **Self-hosted GitHub Actions**: Free for public repos, cost-effective for private -- **Local development**: Maestro CLI is free and open-source - -## Maestro Limitations - -- **No mocking**: Cannot mock network requests or native modules natively -- **Young ecosystem**: Fewer community resources and plugins than Detox -- **Limited assertions**: Assertion API is simpler than Detox's -- **Platform gaps**: Some platform-specific interactions may not be supported - -### Workarounds for Missing Mocking - -- Use environment variables to switch API endpoints in the app -- Set up a mock API server (MSW, json-server) running alongside tests -- Use build flavors/schemes to inject test configurations - -## Decision Matrix - -| Scenario | Recommendation | -|----------|---------------| -| Non-developers write tests | Maestro | -| Need network mocking | Detox | -| CI reliability is critical | Maestro | -| Large test suite (100+ tests) | Maestro (easier maintenance) | -| Deep native interaction testing | Detox | -| OSS project (budget-sensitive) | Maestro (self-hosted) | -| Existing Detox suite working well | Keep Detox | - -## Common Pitfalls - -- **Assuming Maestro Cloud is required**: Self-hosted runners work well and are cost-effective -- **Missing CI setup docs**: No official guide exists — use community examples (Stripe's GH Actions) -- **Expecting Detox-level mocking**: Plan alternative mocking strategies when using Maestro -- **Not using Maestro Studio**: Dramatically speeds up test creation for non-developers - -## Related Skills - -- [api-failure-simulation.md](./api-failure-simulation.md) — Simulate API failures for testing error handling From 79c07e62ef50174020086986632371d4874e0615 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Mi=C5=82kowski?= Date: Tue, 17 Feb 2026 15:28:30 +0100 Subject: [PATCH 7/8] fix: remove oss-licensing-tools reference --- skills/rn-native-ios-tooling/SKILL.md | 12 +- .../references/oss-licensing-tools.md | 171 ------------------ 2 files changed, 3 insertions(+), 180 deletions(-) delete mode 100644 skills/rn-native-ios-tooling/references/oss-licensing-tools.md diff --git a/skills/rn-native-ios-tooling/SKILL.md b/skills/rn-native-ios-tooling/SKILL.md index 0b9eb80..e1e5a7e 100644 --- a/skills/rn-native-ios-tooling/SKILL.md +++ b/skills/rn-native-ios-tooling/SKILL.md @@ -1,33 +1,30 @@ --- name: rn-native-ios-tooling -description: Covers iOS dependency manager comparison (SPM vs Carthage vs CocoaPods), OSS licensing tools for mobile apps, and Objective-C to Swift migration strategies. Use when evaluating iOS dependency managers, setting up license compliance, or planning an ObjC to Swift migration. +description: Covers iOS dependency manager comparison (SPM vs Carthage vs CocoaPods) and Objective-C to Swift migration strategies. Use when evaluating iOS dependency managers or planning an ObjC to Swift migration. license: MIT metadata: author: Callstack - tags: react-native, ios, spm, cocoapods, carthage, licensing, objc, swift, migration + tags: react-native, ios, spm, cocoapods, carthage, objc, swift, migration --- # React Native Native iOS Tooling ## Overview -Practical guidance for iOS dependency management, open-source license compliance, and Objective-C to Swift migration in React Native projects. +Practical guidance for iOS dependency management and Objective-C to Swift migration in React Native projects. ## When to Apply Reference these guidelines when: - Choosing or switching iOS dependency managers (SPM, Carthage, CocoaPods) -- Setting up OSS license compliance for iOS/Android apps - Planning a migration from Objective-C to Swift - Evaluating the cost of switching away from CocoaPods -- Need cross-platform license notice generation ## Quick Reference | File | Description | |------|-------------| | [ios-dependency-managers.md][ios-dependency-managers] | SPM vs Carthage vs CocoaPods comparison | -| [oss-licensing-tools.md][oss-licensing-tools] | OSS license compliance tools for mobile | | [objc-to-swift-migration.md][objc-to-swift-migration] | ObjC → Swift migration checklist | ## Problem → Skill Mapping @@ -36,11 +33,8 @@ Reference these guidelines when: |---------|------------| | Choosing iOS dependency manager | [ios-dependency-managers.md][ios-dependency-managers] | | Migrating away from CocoaPods | [ios-dependency-managers.md][ios-dependency-managers] | -| Setting up license notices in app | [oss-licensing-tools.md][oss-licensing-tools] | -| Cross-platform license generation | [oss-licensing-tools.md][oss-licensing-tools] | | Planning ObjC to Swift migration | [objc-to-swift-migration.md][objc-to-swift-migration] | | Migrating native module to Swift | [objc-to-swift-migration.md][objc-to-swift-migration] | [ios-dependency-managers]: references/ios-dependency-managers.md -[oss-licensing-tools]: references/oss-licensing-tools.md [objc-to-swift-migration]: references/objc-to-swift-migration.md diff --git a/skills/rn-native-ios-tooling/references/oss-licensing-tools.md b/skills/rn-native-ios-tooling/references/oss-licensing-tools.md deleted file mode 100644 index 02991b2..0000000 --- a/skills/rn-native-ios-tooling/references/oss-licensing-tools.md +++ /dev/null @@ -1,171 +0,0 @@ ---- -title: OSS Licensing Tools -impact: MEDIUM -tags: licensing, oss, compliance, android, ios, react-native, legal ---- - -# Skill: OSS Licensing Tools - -Set up open-source license compliance and notice generation for mobile apps. - -## Quick Reference - -| Tool | Platform | Type | -|------|----------|------| -| AboutLibraries | Android | Native Gradle plugin | -| LicensePlist | iOS | CocoaPods/SPM integration | -| Google OSS Licenses Plugin | Android | Gradle plugin | -| `with-react-native-oss-notice` | Cross-platform | Expo config plugin (Callstack, internal) | -| ORT (OSS Review Toolkit) | Cross-platform | Full compliance pipeline | -| FOSSology | Cross-platform | Compliance scanning | - -## When to Use - -- App store submission requires license attribution -- Legal/compliance review of third-party dependencies -- Need to generate a "licenses" or "acknowledgements" screen in the app -- Auditing OSS license compatibility - -## Platform-Specific Tools - -### Android: AboutLibraries - -Gradle plugin that automatically collects license info from dependencies: - -```groovy -// build.gradle -plugins { - id "com.mikepenz.aboutlibraries.plugin" version "10.10.0" -} -``` - -```kotlin -// In-app usage -AboutLibraries.Builder() - .withAutoDetect(true) - .start(context) -``` - -**Strengths**: Automatic detection, UI component included, widely used. Can use the built-in UI or extract generated metadata for custom display. - -### Android: Google OSS Licenses Plugin - -```groovy -// build.gradle -plugins { - id 'com.google.android.gms.oss-licenses-plugin' -} - -dependencies { - implementation 'com.google.android.gms:play-services-oss-licenses:17.0.1' -} -``` - -```kotlin -startActivity(Intent(this, OssLicensesMenuActivity::class.java)) -``` - -**Strengths**: Google-maintained, simple integration. -**Weaknesses**: Only detects Google Play Services and Gradle dependencies. - -### iOS: LicensePlist - -Generates a Settings.bundle plist from CocoaPods/Carthage/SPM dependencies: - -```bash -# Install -brew install licenseplist - -# Generate -license-plist --output-path Settings.bundle -``` - -Or via SPM/CocoaPods integration as a build phase: - -```bash -# Xcode Run Script Phase -if which license-plist > /dev/null; then - license-plist --output-path $SRCROOT/Settings.bundle \ - --github-token $LICENSE_PLIST_GITHUB_TOKEN -fi -``` - -Licenses appear in iOS Settings app under the app's entry. - -**Strengths**: Automatic, integrates with iOS Settings. -**Weaknesses**: iOS only, Settings.bundle approach may not match desired UX. - -## Cross-Platform Tools - -### with-react-native-oss-notice (Callstack) - -Expo config plugin for generating license notices on both platforms: - -```bash -npx expo install with-react-native-oss-notice -``` - -```json -// app.json -{ - "expo": { - "plugins": ["with-react-native-oss-notice"] - } -} -``` - -Generates platform-appropriate license files during the build process. Combines platform-specific tools (AboutLibraries + LicensePlist) under one config plugin. - -> **Note**: This is a Callstack internal library, not yet publicly released. - -### ORT (OSS Review Toolkit) - -Full compliance pipeline: analyze → scan → evaluate → report. - -```bash -# Analyze project dependencies -ort analyze -i /path/to/project -o /path/to/output - -# Scan for license texts -ort scan -i /path/to/output/analyzer-result.yml -o /path/to/output - -# Generate report -ort report -i /path/to/output/scan-result.yml -o /path/to/output \ - -f NoticeTemplate -``` - -**Best for**: Enterprise compliance requirements, large projects needing full audit trail. - -### FOSSology - -Open-source compliance scanning platform: -- Server-based scanning -- License identification from source code -- Bulk scanning of dependencies -- Compliance workflow management - -**Caveat**: Very generic scanner — does not specifically scan for licenses in third-party libraries. Better as a supplement to platform-specific tools. - -**Best for**: Organizations needing ongoing compliance scanning infrastructure. - -## Decision Matrix - -| Scenario | Recommendation | -|----------|---------------| -| Android-only app | AboutLibraries | -| iOS-only app | LicensePlist | -| React Native / Expo app | `with-react-native-oss-notice` | -| Enterprise compliance | ORT + FOSSology | -| Quick "licenses" screen | AboutLibraries (Android) + LicensePlist (iOS) | - -## Common Pitfalls - -- **Relying only on automatic detection**: Some transitive dependencies may be missed — verify manually -- **Ignoring license compatibility**: MIT + GPL in same app can create legal issues -- **Not updating before release**: Run license generation as part of release process -- **Missing native dependency licenses**: JS-only tools miss CocoaPods/Gradle-only dependencies - -## Related Skills - -- [ios-dependency-managers.md](./ios-dependency-managers.md) — Understanding dependency sources -- [objc-to-swift-migration.md](./objc-to-swift-migration.md) — Migration may change dependency licensing From 5dfabdaa70941fde575e572c1dce8d48b89fdcaf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Mi=C5=82kowski?= Date: Tue, 17 Feb 2026 15:30:41 +0100 Subject: [PATCH 8/8] fix: remove iso-dependency-managers reference --- skills/rn-native-ios-tooling/SKILL.md | 12 +- .../references/ios-dependency-managers.md | 119 ------------------ 2 files changed, 3 insertions(+), 128 deletions(-) delete mode 100644 skills/rn-native-ios-tooling/references/ios-dependency-managers.md diff --git a/skills/rn-native-ios-tooling/SKILL.md b/skills/rn-native-ios-tooling/SKILL.md index e1e5a7e..1636b98 100644 --- a/skills/rn-native-ios-tooling/SKILL.md +++ b/skills/rn-native-ios-tooling/SKILL.md @@ -1,40 +1,34 @@ --- name: rn-native-ios-tooling -description: Covers iOS dependency manager comparison (SPM vs Carthage vs CocoaPods) and Objective-C to Swift migration strategies. Use when evaluating iOS dependency managers or planning an ObjC to Swift migration. +description: Covers Objective-C to Swift migration strategies. Use when planning an ObjC to Swift migration. license: MIT metadata: author: Callstack - tags: react-native, ios, spm, cocoapods, carthage, objc, swift, migration + tags: react-native, ios, objc, swift, migration --- # React Native Native iOS Tooling ## Overview -Practical guidance for iOS dependency management and Objective-C to Swift migration in React Native projects. +Practical guidance for Objective-C to Swift migration in React Native projects. ## When to Apply Reference these guidelines when: -- Choosing or switching iOS dependency managers (SPM, Carthage, CocoaPods) - Planning a migration from Objective-C to Swift -- Evaluating the cost of switching away from CocoaPods ## Quick Reference | File | Description | |------|-------------| -| [ios-dependency-managers.md][ios-dependency-managers] | SPM vs Carthage vs CocoaPods comparison | | [objc-to-swift-migration.md][objc-to-swift-migration] | ObjC → Swift migration checklist | ## Problem → Skill Mapping | Problem | Start With | |---------|------------| -| Choosing iOS dependency manager | [ios-dependency-managers.md][ios-dependency-managers] | -| Migrating away from CocoaPods | [ios-dependency-managers.md][ios-dependency-managers] | | Planning ObjC to Swift migration | [objc-to-swift-migration.md][objc-to-swift-migration] | | Migrating native module to Swift | [objc-to-swift-migration.md][objc-to-swift-migration] | -[ios-dependency-managers]: references/ios-dependency-managers.md [objc-to-swift-migration]: references/objc-to-swift-migration.md diff --git a/skills/rn-native-ios-tooling/references/ios-dependency-managers.md b/skills/rn-native-ios-tooling/references/ios-dependency-managers.md deleted file mode 100644 index 807b61f..0000000 --- a/skills/rn-native-ios-tooling/references/ios-dependency-managers.md +++ /dev/null @@ -1,119 +0,0 @@ ---- -title: iOS Dependency Managers -impact: HIGH -tags: spm, cocoapods, carthage, ios, dependency-management, xcode ---- - -# Skill: iOS Dependency Managers - -Compare and choose between SPM, Carthage, and CocoaPods for iOS dependency management. - -## Quick Reference - -**Recommended ranking**: SPM > Carthage > CocoaPods - -| Feature | SPM | Carthage | CocoaPods | -|---------|-----|----------|-----------| -| Swift support | Full (native) | Full | Full | -| ObjC support | Limited | Full | Full | -| Installation | Built into Xcode | `brew install carthage` | `gem install cocoapods` | -| Project impact | **None** | Almost none | **Heavy** (wraps into workspace, modifies xcodeproj) | -| Removal complexity | Trivial | Easy | Very complex | -| Build speed | Fast (Apple's caching) | Slow initial (prebuilds once) | Rebuilds deps every time | -| Market share | ~46% | ~11% | ~61% | -| Apple maintained | Yes | Community | Community | -| Binary distribution | Supported (XCFramework) | Supported | Limited | - -## When to Use - -- Starting a new iOS/React Native project and choosing a dependency manager -- Evaluating whether to migrate away from CocoaPods -- Need to understand trade-offs between available options - -## Comparison Details - -### Swift Package Manager (SPM) - -**Strengths:** -- Built into Xcode — no external tools needed -- Minimal project file changes -- Fast dependency resolution with caching -- Apple-maintained, long-term investment -- Easy to add/remove packages -- First-class binary target (XCFramework) support - -**Weaknesses:** -- Limited Objective-C library support -- Some RN dependencies still require CocoaPods -- Resource bundle handling can be tricky -- Cannot mix with CocoaPods for the same target easily - -**Best for**: New Swift-first projects, libraries with SPM support. - -### Carthage - -**Strengths:** -- Decentralized — no central spec repo -- Prebuilds frameworks (faster CI if cached) -- Minimal project file intrusion -- Easy to remove -- Good ObjC and Swift support - -**Weaknesses:** -- Slow initial build (compiles all dependencies from source) -- Requires manual framework linking -- Smaller ecosystem than CocoaPods -- Some libraries don't support Carthage - -**Best for**: Projects wanting prebuilt binaries without project file modification. - -### CocoaPods - -**Strengths:** -- Largest library ecosystem -- Excellent Objective-C support -- React Native's default dependency manager -- Well-documented integration -- Handles complex dependency graphs - -**Weaknesses:** -- **Extremely hard to switch away from** — modifies xcodeproj, creates workspace, adds build phases -- Slow `pod install` on large projects -- Ruby dependency management adds complexity -- Central spec repo can be slow -- Xcode 16 compatibility issues (frequently) - -**Best for**: React Native projects (required by most RN libraries), large ObjC codebases. - -## Key Insight: CocoaPods Lock-In - -CocoaPods is extremely hard to switch away from because it: -1. Creates and manages a `.xcworkspace` -2. Modifies the `.xcodeproj` with custom build phases -3. Manages header search paths and framework search paths -4. Many React Native libraries only provide Podspecs - -**Migration effort from CocoaPods**: Weeks to months for a medium-sized RN project. Requires rewriting build configuration and potentially forking libraries. - -## Decision Matrix - -| Scenario | Recommendation | -|----------|---------------| -| New RN project | CocoaPods (required by RN ecosystem) | -| Pure Swift project, no RN | SPM | -| Need easy dependency removal | SPM or Carthage | -| Large ObjC codebase | CocoaPods | -| Want prebuilt frameworks | Carthage or SPM (binary targets) | -| Evaluating migration from CocoaPods | Only if strong business case justifies the effort | - -## Common Pitfalls - -- **Attempting to remove CocoaPods casually**: Understand the full scope of project file changes before starting -- **Mixing SPM and CocoaPods for same dependency**: Can cause duplicate symbol errors -- **Not caching Carthage builds**: Initial builds are slow; cache `Carthage/Build` in CI -- **Assuming all RN libraries support SPM**: Most still require CocoaPods - -## Related Skills - -- [oss-licensing-tools.md](./oss-licensing-tools.md) — License compliance for dependencies -- [objc-to-swift-migration.md](./objc-to-swift-migration.md) — ObjC → Swift migration strategies