#!/usr/bin/env ruby require 'xcodeproj' require 'fileutils' project_name = ARGV[0] base_dir = '/Users/mattbruce/Documents/Projects/iPhone/OpenClaw' target_dir = File.join(base_dir, project_name) org_id = 'com.mattbruce' bundle_id = "#{org_id}.#{project_name.downcase}" deployment_target = '17.0' if ARGV.empty? puts 'Usage: ruby create_ios_project.rb ' exit 1 end if Dir.exist?(target_dir) puts "Target directory #{target_dir} already exists. Skipping." exit 1 end FileUtils.mkdir_p(target_dir) FileUtils.cd(target_dir) # Create the project xcodeproj_path = File.join(target_dir, "#{project_name}.xcodeproj") proj = Xcodeproj::Project.new(xcodeproj_path) # Main group main_group = proj.main_group app_group = main_group.new_group(project_name) # Create Assets.xcassets assets_group = app_group.new_group('Assets.xcassets') # For basic, create empty AppIcon.appiconset, but skip for minimal, Xcode will complain but ok # Create Preview Assets.xcassets preview_assets_group = app_group.new_group('Preview Assets.xcassets') # Create files content_view_path = File.join(target_dir, 'ContentView.swift') File.open(content_view_path, 'w') do |f| f.write <<~SWIFT import SwiftUI struct ContentView: View { var body: some View { VStack { Image(systemName: "globe") .imageScale(.large) .foregroundStyle(.tint) Text("Hello, world!") } .padding() } } #Preview { ContentView() } SWIFT end app_path = File.join(target_dir, "#{project_name}App.swift") File.open(app_path, 'w') do |f| f.write <<~SWIFT import SwiftUI @main struct #{project_name}App: App { var body: some Scene { WindowGroup { ContentView() } } } SWIFT end info_plist_path = File.join(target_dir, 'Info.plist') File.open(info_plist_path, 'w') do |f| f.write <<~PLIST CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleDisplayName $(PRODUCT_NAME) CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier #{bundle_id} CFBundleInfoDictionaryVersion 6.0 CFBundleName #{project_name} CFBundlePackageType APPL CFBundleShortVersionString 1.0 CFBundleVersion 1 LSRequiresIPhoneOS UIApplicationSceneManifest UIApplicationSupportsMultipleScenes UISceneConfigurations UIWindowSceneSessionRoleApplication UISceneConfigurationName Default Configuration UISceneDelegateClassName $(PRODUCT_MODULE_NAME).SceneDelegate UILaunchStoryboardName UIMainStoryboardFile UIRequiredDeviceCapabilities arm64 UISupportedInterfaceOrientations UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UISupportedInterfaceOrientations~ipad UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight PLIST end # Add files to project content_view_file = app_group.new_reference(content_view_path) app_file = app_group.new_reference(app_path) info_plist_file = app_group.new_reference(info_plist_path) # Create target target = proj.new_target(:application, project_name, :ios) target.product_name = project_name target.product_type = 'com.apple.product-type.application' target.build_phases << Xcodeproj::PBXShellScriptBuildPhase.new(proj, :shell_script => 'true') # Add sources build phase sources_phase = target.new_shell_script_build_phase('Sources') sources_phase.shell_script = '' target.source_build_phase.files << content_view_file target.source_build_phase.files << app_file # Frameworks phase frameworks_phase = target.new_frameworks_build_phase frameworks_phase.files << Xcodeproj::FrameworkProduct.new(proj, 'UIKit.framework', :sdk => :iphoneos) target.resources_build_phase.files << info_plist_file # Build settings target.build_configurations.each do |config| config.build_settings['PRODUCT_NAME'] = project_name config.build_settings['PRODUCT_BUNDLE_IDENTIFIER'] = bundle_id config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = deployment_target config.build_settings['SWIFT_VERSION'] = '5.0' config.build_settings['CODE_SIGN_STYLE'] = 'Automatic' config.build_settings['DEVELOPMENT_TEAM'] = '' # User to set config.build_settings['PROVISIONING_PROFILE_SPECIFIER'] = '' config.build_settings['ASSETCATALOG_COMPILER_APPICON_NAME'] = 'AppIcon' end # Known regions proj.root_object.build_settings.each do |setting| setting['LOCALIZATION'] = 'Base' end # Save the project proj.save("#{xcodeproj_path}/project.pbxproj") puts "Created Xcode project at #{target_dir}" puts "Bundle ID: #{bundle_id}" puts "To open: open \\\"#{xcodeproj_path}\\\"" # Note: User needs to add AppIcon in Assets.xcassets and set team in signing