Generate native iOS project for self-hosted build workflow#3
Generate native iOS project for self-hosted build workflow#3
Conversation
- Run `expo prebuild` to generate ios/ directory - Create placeholder app icon and splash screen assets - Add NATIVE_SETUP.md documentation - Update README with native project setup instructions This fixes the self-hosted iOS build workflow that was failing because there was no native iOS project in the repository. Co-authored-by: astickleyid <201894828+astickleyid@users.noreply.github.com>
- Remove unused imports (THREE, useThree, useEffect) - Remove unused variables (addPower, power, selectBuildingType, etc.) - Fix ESLint config to ignore Three.js/react-three-fiber props - Comment out unused pathfinder code temporarily - All TypeScript checks now pass - Only 2 warnings remain (complexity and non-null assertion) Co-authored-by: astickleyid <201894828+astickleyid@users.noreply.github.com>
Added WORKFLOW_FIX_SUMMARY.md explaining: - Root cause of workflow failures - What was missing (native iOS project) - Complete solution implemented - Verification that the app DOES exist and is complete Co-authored-by: astickleyid <201894828+astickleyid@users.noreply.github.com>
- Convert unused useState to const declarations in UpdatedUnit - Add detailed TODO comments for pathfinding feature flag - Remove unused variables (targetPath, pathIndex, delta) - All TypeScript and ESLint checks now pass cleanly Co-authored-by: astickleyid <201894828+astickleyid@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR generates a native iOS project via expo prebuild to resolve a failing self-hosted iOS build workflow that expected a bare Expo workflow with a committed ios/ directory. It also cleans up unused imports and variables from TypeScript source files that were causing ESLint/type-check failures.
Changes:
- Added the full native iOS project (
ios/directory) including Xcode project, Podfile, AppDelegate, assets, and plists - Cleaned up unused imports in
src/App.tsxandsrc/components/UpdatedUnit.tsx, commented out unimplemented pathfinding code - Updated
package.jsonscripts for bare workflow (expo run:ios/android), updated ESLint config to ignore Three.js/R3F JSX properties, and added documentation files
Reviewed changes
Copilot reviewed 23 out of 30 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
src/components/UpdatedUnit.tsx |
Removed unused imports and state; pathfinding code commented out as Phase 2 TODO |
src/App.tsx |
Removed unused useThree, THREE, addPower, and selectBuildingType imports/destructures |
package.json |
Updated ios/android scripts from expo start to expo run for bare workflow |
package-lock.json |
Mass change of devOptional → dev for Expo-related packages (generated by prebuild) |
ios/Podfile |
New CocoaPods config for bare workflow with Expo autolinking |
ios/Podfile.properties.json |
Expo Hermes/JS engine and network inspector config |
ios/IronCommand/Info.plist |
iOS app metadata, orientation, and transport security settings |
ios/IronCommand/AppDelegate.swift |
Standard Expo React Native app delegate |
ios/IronCommand.xcodeproj/project.pbxproj |
Xcode project structure and build settings |
ios/IronCommand.xcodeproj/...IronCommand.xcscheme |
Xcode build/run/test scheme |
ios/.xcode.env, ios/.gitignore |
Xcode environment config and iOS-specific gitignore |
ios/IronCommand/Images.xcassets/* |
App icon and splash screen asset catalogs |
ios/IronCommand/Supporting/Expo.plist, entitlements, bridging header |
Supporting iOS project files |
ios/IronCommand/SplashScreen.storyboard |
Splash screen UI definition |
assets/icon.png, assets/splash.png |
Placeholder app icon and splash screen |
.eslintrc.js |
Added Three.js/R3F JSX property allowlist to react/no-unknown-property rule |
README.md |
Added CocoaPods prerequisite and native setup steps |
NATIVE_SETUP.md |
New documentation explaining native project setup |
WORKFLOW_FIX_SUMMARY.md |
Analysis document explaining the workflow failure and fix |
| const [targetPath, setTargetPath] = useState<THREE.Vector3[]>([]); | ||
| const [pathIndex, setPathIndex] = useState(0); | ||
| // Current implementation uses static positioning - pathfinding will be added in Phase 2 | ||
| const currentPos = new THREE.Vector3(...position); |
There was a problem hiding this comment.
A new THREE.Vector3 object is instantiated on every render cycle because currentPos is declared as a plain const inside the component function body. Previously this value was stored in useState, which meant it persisted across renders. Now it's recreated from scratch on each render, allocating a new object on every frame tick. This causes unnecessary garbage-collection pressure — a concern for the 60 FPS target on iOS (iPhone 12+) specified in the project guidelines.
Since pathfinding is disabled and currentPos is only used to set the initial group position, consider converting it to a useMemo (or useRef) that derives from the position prop, so that the Vector3 object is only re-created when position actually changes.
| @@ -0,0 +1,4 @@ | |||
| { | |||
| "expo.jsEngine": "hermes", | |||
| "EX_DEV_CLIENT_NETWORK_INSPECTOR": "true" | |||
There was a problem hiding this comment.
The EX_DEV_CLIENT_NETWORK_INSPECTOR is set to "true" in Podfile.properties.json, which is a versioned file. This flag enables the Expo Dev Client network inspector, which is a development-only debugging tool. Having it permanently enabled in a committed configuration file means it will also be active in staging or production builds that use this Podfile. This could expose unintended network traffic inspection capabilities in non-debug builds. Consider setting this to "false" or removing it from the committed configuration, instead enabling it only locally via .xcode.env.local or a developer-specific override.
| "EX_DEV_CLIENT_NETWORK_INSPECTOR": "true" | |
| "EX_DEV_CLIENT_NETWORK_INSPECTOR": "false" |
| <key>LSMinimumSystemVersion</key> | ||
| <string>12.0</string> |
There was a problem hiding this comment.
The key LSMinimumSystemVersion is a macOS key used in Mac app bundles (it specifies the minimum macOS version). It is not the correct key for setting the minimum iOS version in an iOS app's Info.plist. The correct key for iOS is MinimumOSVersion. Additionally, 12.0 is inconsistent with the IPHONEOS_DEPLOYMENT_TARGET = 15.1 set in the Xcode project build settings and the Podfile deployment target (15.1). This stale/wrong key will be ignored by iOS at runtime but represents confusing dead metadata. It should be removed or replaced with the appropriate MinimumOSVersion key matching the configured deployment target of 15.1.
| <key>LSMinimumSystemVersion</key> | |
| <string>12.0</string> | |
| <key>MinimumOSVersion</key> | |
| <string>15.1</string> |
|
|
||
| ## Important Notes | ||
| - The `ios/Pods/` directory is **NOT** committed (ignored by .gitignore) | ||
| - The `ios/Podfile.lock` is **NOT** committed (ignored by .gitignore) |
There was a problem hiding this comment.
NATIVE_SETUP.md states "The ios/Podfile.lock is NOT committed (ignored by .gitignore)" — this is accurate per the root .gitignore. However, it is standard CocoaPods practice to commit Podfile.lock for reproducible builds (analogous to package-lock.json). Since Podfile.lock is intentionally excluded here, the documentation should explain the trade-off: without a committed Podfile.lock, pod versions may drift between developer machines and the CI runner, potentially causing silent version mismatches and hard-to-reproduce build failures. Consider either committing Podfile.lock or updating this note to warn about the reproducibility risk.
| - The `ios/Podfile.lock` is **NOT** committed (ignored by .gitignore) | |
| - The `ios/Podfile.lock` is **NOT** committed (ignored by .gitignore). This means CocoaPods will resolve dependencies on each `pod install`, which can cause pod versions to drift between developer machines and CI over time. If you require fully reproducible native builds, consider committing `ios/Podfile.lock` to version control so that all environments use the exact same pod versions. |
| ENV['EX_DEV_CLIENT_NETWORK_INSPECTOR'] ||= podfile_properties['EX_DEV_CLIENT_NETWORK_INSPECTOR'] | ||
| ENV['RCT_USE_RN_DEP'] ||= '1' if podfile_properties['ios.buildReactNativeFromSource'] != 'true' && podfile_properties['newArchEnabled'] != 'false' | ||
| ENV['RCT_USE_PREBUILT_RNCORE'] ||= '1' if podfile_properties['ios.buildReactNativeFromSource'] != 'true' && podfile_properties['newArchEnabled'] != 'false' | ||
| platform :ios, podfile_properties['ios.deploymentTarget'] || '15.1' |
There was a problem hiding this comment.
The app.json defines "deploymentTarget": "13.4" for the iOS target (line 21 of app.json), but expo prebuild generated native project files with IPHONEOS_DEPLOYMENT_TARGET = 15.1 in project.pbxproj and platform :ios, '15.1' in the Podfile. There is a discrepancy between the Expo configuration (13.4) and the generated native project (15.1). This means the native project cannot be reliably regenerated from app.json via expo prebuild without ending up with different deployment targets. The correct deployment target should be aligned in both the app.json and the generated native project for consistency.
📝 Description
Self-hosted iOS build workflow fails because repository lacks native iOS project. Workflow expects bare workflow with committed
ios/directory; project uses Expo managed workflow. Generated native infrastructure viaexpo prebuild.🎮 Type of Change
🎯 Game Mode Impact
🔍 What Changed?
Added
ios/directory) with Xcode project and Podfileassets/)NATIVE_SETUP.mddocumenting iOS build setupWORKFLOW_FIX_SUMMARY.mdanalyzing workflow failure root causeChanged
README.mdwith CocoaPods prerequisite and native setup stepspackage.jsonandpackage-lock.json(Expo prebuild modifications)Fixed
THREE,useThree,useState) causing TypeScript errorsUpdatedUnitRemoved
📸 Screenshots/Videos
N/A - Infrastructure changes only
🧪 Testing
How Has This Been Tested?
Test Configuration
✅ Checklist
🎯 Performance Impact
📋 Related Issues
Workflow run: https://github.com/astickleyid/iron-command-ios/actions/runs/21132465283
📝 Additional Notes
Workflow still requires self-hosted macOS runner with Xcode and CocoaPods installed. Alternative: migrate to EAS Build for cloud-based iOS builds.
Placeholder assets created programmatically - replace with proper branded assets before release.
iOS Podfile generated but pods not installed -
pod installrequires macOS environment. Self-hosted runner must run this during workflow.🎖️ Deployment Notes
After merge:
pod installautomatically.xcworkspaceto repository after first pod install for faster subsequent buildsBy submitting this PR, I confirm that:
Warning
Firewall rules blocked me from connecting to one or more addresses (expand for details)
I tried to connect to the following addresses, but was blocked by firewall rules:
cdp.expo.dev/usr/local/bin/node /usr/local/bin/node /home/REDACTED/work/iron-command-ios/iron-command-ios/node_modules/expo/node_modules/@expo/cli/build/src/utils/telemetry/clients/flushFetchDetached.js /tmp/bf74ee4441d6ca53d8a9cb285cf42dec/expo-telemetry.json(dns block)If you need me to access, download, or install something from one of these locations, you can either:
Original prompt
💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.