Created
May 13, 2025 03:56
-
-
Save kumeS/04193157125aa2fa02a60a8f4b4ed0b6 to your computer and use it in GitHub Desktop.
A bash script automating iOS app setup via CLI: creates project folders, SwiftUI entrypoint & API key file, generates .xcodeproj with XcodeGen, builds, launches on simulator, and scaffolds config/docs.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env bash | |
| set -euo pipefail | |
| #=================================================== | |
| # init_ios_project.sh | |
| # - Takes a project name as argument and automates: | |
| # 1. Directory structure & Sources/Config, Resources, Tests creation | |
| # 2. Generating APIKeys.swift & SwiftUI entry point | |
| # 3. project.yml + XcodeGen to produce .xcodeproj | |
| # 4. Build → install → launch on simulator | |
| # 5. Generating .env.example, .gitignore, .swiftlint.yml, .swiftformat, | |
| # Tests/*Tests.swift, .cursor/rules, README.md, Makefile, AGENT_GUIDE.md | |
| #=================================================== | |
| if [ $# -lt 1 ]; then | |
| echo "Usage: $0 <ProjectName>" | |
| exit 1 | |
| fi | |
| PROJECT="$1" | |
| BUNDLE_ID="com.example.${PROJECT}" | |
| # 1) Detect available iPhone simulator | |
| SIM_NAME=$( | |
| xcrun simctl list devices available \ | |
| | grep -E "iPhone [0-9]+" \ | |
| | head -n1 \ | |
| | sed -E 's/.*(iPhone [0-9A-Za-z \-]+) \(.*/\1/' | |
| ) | |
| if [ -z "$SIM_NAME" ]; then | |
| echo "⚠️ No iPhone simulator found, falling back to generic" | |
| DEST="generic/platform=iOS Simulator" | |
| else | |
| echo "▶ Detected simulator: ${SIM_NAME}" | |
| DEST="platform=iOS Simulator,name=${SIM_NAME}" | |
| fi | |
| echo "▶ Destination: ${DEST}" | |
| # 2) Create directories and initial files | |
| mkdir -p "${PROJECT}"/{Sources,Resources,Tests,Sources/Config} | |
| cd "${PROJECT}" | |
| # 2.1) APIKeys.swift | |
| cat <<'EOF' > Sources/Config/APIKeys.swift | |
| /** | |
| * API Keys configuration file | |
| * | |
| * Usage: | |
| * 1. Copy this file to `APIKeys.swift` | |
| * 2. Replace placeholder values with actual API keys | |
| * 3. Confirm it is excluded by .gitignore | |
| */ | |
| enum APIKeys { | |
| /// OpenAI API Key | |
| /// Requires appropriate access to GPT-4 Vision | |
| /// Get yours at https://platform.openai.com/ | |
| static let openAI = "YOUR_OPENAI_API_KEY_HERE" | |
| } | |
| EOF | |
| # 2.2) SwiftUI entry point | |
| cat <<EOF > Sources/${PROJECT}App.swift | |
| import SwiftUI | |
| @main | |
| struct ${PROJECT}App: App { | |
| var body: some Scene { | |
| WindowGroup { | |
| ContentView() | |
| } | |
| } | |
| } | |
| struct ContentView: View { | |
| var body: some View { | |
| Text("Hello, ${PROJECT}!") | |
| .padding() | |
| } | |
| } | |
| EOF | |
| # 3) Generate project.yml for XcodeGen | |
| cat <<EOF > project.yml | |
| name: ${PROJECT} | |
| options: | |
| bundleIdPrefix: com.example | |
| settings: | |
| SWIFT_VERSION: 5.9 | |
| configs: | |
| Debug: debug | |
| Release: release | |
| targets: | |
| ${PROJECT}: | |
| type: application | |
| platform: iOS | |
| deploymentTarget: "17.0" | |
| sources: [Sources] | |
| settings: | |
| PRODUCT_BUNDLE_IDENTIFIER: ${BUNDLE_ID} | |
| GENERATE_INFOPLIST_FILE: YES | |
| EOF | |
| # 4) Run XcodeGen to create the Xcode project | |
| echo "▶ Running xcodegen..." | |
| xcodegen generate | |
| # 5) Build, install, and launch on simulator | |
| DERIVED_DATA="build" | |
| echo "▶ Building project..." | |
| xcodebuild \ | |
| -scheme "${PROJECT}" \ | |
| -destination "${DEST}" \ | |
| -derivedDataPath "${DERIVED_DATA}" \ | |
| build | |
| if [[ "${DEST}" != generic* ]]; then | |
| echo "▶ Booting simulator..." | |
| xcrun simctl boot "${SIM_NAME}" || true | |
| APP_PATH="${DERIVED_DATA}/Build/Products/Debug-iphonesimulator/${PROJECT}.app" | |
| echo "▶ Installing app..." | |
| xcrun simctl install booted "${APP_PATH}" | |
| echo "▶ Launching app..." | |
| xcrun simctl launch booted "${BUNDLE_ID}" | |
| else | |
| echo "▶ Generic simulator: skipping install & launch" | |
| fi | |
| # 6) Create supporting configuration and guide files | |
| # .env.example | |
| cat <<EOF > .env.example | |
| # Example environment variables | |
| OPENAI_API_KEY=your_openai_api_key_here | |
| EOF | |
| # .gitignore | |
| cat <<EOF > .gitignore | |
| # Exclude API keys file | |
| Sources/Config/APIKeys.swift | |
| # Environment files | |
| .env | |
| # Build artifacts | |
| build/ | |
| DerivedData/ | |
| # SwiftLint cache | |
| .swiftlint.yml | |
| EOF | |
| # SwiftLint configuration | |
| cat <<EOF > .swiftlint.yml | |
| disabled_rules: | |
| - trailing_whitespace | |
| - line_length | |
| EOF | |
| # SwiftFormat configuration | |
| cat <<EOF > .swiftformat | |
| --indent 4 | |
| --line-length 100 | |
| EOF | |
| # Basic unit test template | |
| cat <<EOF > Tests/${PROJECT}Tests.swift | |
| import XCTest | |
| @testable import ${PROJECT} | |
| final class ${PROJECT}Tests: XCTestCase { | |
| func testExample() throws { | |
| XCTAssertTrue(true) | |
| } | |
| } | |
| EOF | |
| # .cursor/rules | |
| mkdir -p .cursor | |
| cat << 'EOF' > .cursor/rules | |
| style: | |
| - Use Swift 5.9, SwiftUI 3, async/await only | |
| folders: | |
| - Sources: src code | |
| - Sources/Config: config code | |
| - Resources: assets & plist | |
| - Tests: unit tests | |
| restrictions: | |
| - Do NOT import UIKit unless explicitly asked | |
| - Keep imports alphabetically sorted | |
| - Log with os_log only | |
| testing: | |
| - Always add failing unit test before bug-fix | |
| file_safety: | |
| protect: | |
| - "*.xcodeproj" | |
| - "*.xcworkspace" | |
| - "init_ios_project.sh" | |
| - "Makefile" | |
| - ".cursor/rules" | |
| - "README.md" | |
| - "AGENT_GUIDE.md" | |
| - "Sources/Config/APIKeys.swift" | |
| delete: | |
| allow_patterns: | |
| - "DerivedData/**" | |
| - "build/**" | |
| forbid_patterns: | |
| - "Sources/**" | |
| - "Resources/**" | |
| - "Tests/**" | |
| tests: | |
| enforce_location: "Tests/" | |
| naming_pattern: "*Tests.swift" | |
| max_per_feature: 3 | |
| EOF | |
| # README.md | |
| cat << EOF > README.md | |
| # ${PROJECT} | |
| ## Overview | |
| **Description:** (Brief app description) | |
| **Target:** iOS 17 / Swift 5.9 | |
| **Bundle ID:** ${BUNDLE_ID} | |
| ## Features | |
| 1. Feature A | |
| 2. Feature B | |
| 3. Feature C | |
| ## Usage | |
| \`\`\`bash | |
| make run | |
| \`\`\` | |
| EOF | |
| # Makefile | |
| cat << 'EOF' > Makefile | |
| SCHEME = ${PROJECT} | |
| DEST = ${DEST} | |
| build: | |
| xcodebuild -scheme $(SCHEME) -destination $(DEST) -derivedDataPath build build | |
| run: build | |
| @[ "\$(echo \$(DEST) | grep -q '^platform'; echo \$?)" -eq 0 ] && \ | |
| xcrun simctl boot "${SIM_NAME}" && \ | |
| xcrun simctl install booted build/Build/Products/Debug-iphonesimulator/\$(SCHEME).app && \ | |
| xcrun simctl launch booted com.example.\$(SCHEME) || \ | |
| echo "⚠️ generic simulator; skipping install & launch" | |
| test: | |
| xcodebuild test -scheme $(SCHEME) -destination $(DEST) -derivedDataPath build | |
| format: | |
| swift format . | |
| clean: | |
| rm -rf build | |
| xcodebuild clean -scheme $(SCHEME) | |
| EOF | |
| # AGENT_GUIDE.md | |
| cat << 'EOF' > AGENT_GUIDE.md | |
| # Agent Interaction Guide | |
| ## Getting Started | |
| 1. Open the project folder in Cursor Editor: \`cd ${PROJECT}\` | |
| 2. From the gear icon, select **Index Workspace** | |
| ## Sample Agent Prompts | |
| - 🛠 Create a new SwiftUI view "QuizListView" under Sources/QuizListView.swift with Preview. | |
| - 🐛 Fix import errors by adding \`import Vision\` and \`import OpenAI\` to Sources/OCRService.swift, then rebuild. | |
| - 🎨 Change ContentView text from "Hello, ${PROJECT}!" to "Welcome!", preview, and run on simulator. | |
| ## One-Liner Build & Run | |
| \`\`\`bash | |
| make run | |
| \`\`\` | |
| ## Troubleshooting Templates | |
| - 🚑 Paste simctl logs and ask: “What’s causing this simulator error and how to fix it?” | |
| - 🔍 Paste full build logs and ask: “Identify the build error and provide a patch.” | |
| EOF | |
| echo "✅ Initialization complete! cd ${PROJECT} → open in Cursor Editor and index the workspace." |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment