diff options
| author | _Tradam <[email protected]> | 2021-12-16 19:22:26 -0500 |
|---|---|---|
| committer | GitHub <[email protected]> | 2021-12-16 19:22:26 -0500 |
| commit | 5954b9beb4d4a3b4f248d72d1851195f030558a8 (patch) | |
| tree | fecd8aa840a25afdb502915b0fdb4d03b7ed339a /dragon/ios_wizard.rb | |
| parent | 2f845281f133849256b57bb08fd3e9ae57600784 (diff) | |
| parent | eaa29e72939f5edf61735ccbb73c36ee89369f65 (diff) | |
| download | dragonruby-game-toolkit-contrib-5954b9beb4d4a3b4f248d72d1851195f030558a8.tar.gz dragonruby-game-toolkit-contrib-5954b9beb4d4a3b4f248d72d1851195f030558a8.zip | |
Diffstat (limited to 'dragon/ios_wizard.rb')
| -rw-r--r-- | dragon/ios_wizard.rb | 359 |
1 files changed, 225 insertions, 134 deletions
diff --git a/dragon/ios_wizard.rb b/dragon/ios_wizard.rb index 0d48108..c040dea 100644 --- a/dragon/ios_wizard.rb +++ b/dragon/ios_wizard.rb @@ -1,16 +1,11 @@ +# coding: utf-8 # Copyright 2019 DragonRuby LLC # MIT License # ios_wizard.rb has been released under MIT (*only this file*). -class WizardException < Exception - attr_accessor :console_primitives +# Contributors outside of DragonRuby who also hold Copyright: Michał Dudziński - def initialize *console_primitives - @console_primitives = console_primitives - end -end - -class IOSWizard +class IOSWizard < Wizard def initialize @doctor_executed_at = 0 end @@ -23,23 +18,46 @@ class IOSWizard @steps ||= [] end - def steps_development_build + def prerequisite_steps [ :check_for_xcode, :check_for_brew, :check_for_certs, - :check_for_device, - :check_for_dev_profile, + ] + end + + def app_metadata_retrieval_steps + [ :determine_team_identifier, :determine_app_name, :determine_app_id, - :blow_away_temp, + ] + end + + def steps_development_build + [ + *prerequisite_steps, + + :check_for_device, + :check_for_dev_profile, + + *app_metadata_retrieval_steps, + :determine_devcert, + + :clear_tmp_directory, :stage_app, + :development_write_info_plist, + :write_entitlements_plist, :compile_icons, - :create_payload_directory, + :clear_payload_directory, + + :create_payload_directory_dev, + + :create_payload, :code_sign_payload, + :create_ipa, :deploy ] @@ -47,20 +65,28 @@ class IOSWizard def steps_production_build [ - :check_for_xcode, - :check_for_brew, - :check_for_certs, + *prerequisite_steps, + :check_for_distribution_profile, - :determine_team_identifier, - :determine_app_name, - :determine_app_id, - :blow_away_temp, + :determine_app_version, + + *app_metadata_retrieval_steps, + :determine_prodcert, + + :clear_tmp_directory, :stage_app, + :production_write_info_plist, + :write_entitlements_plist, :compile_icons, - :create_payload_directory, + :clear_payload_directory, + + :create_payload_directory_prod, + + :create_payload, :code_sign_payload, + :create_ipa, :print_publish_help ] @@ -96,6 +122,8 @@ class IOSWizard @steps = steps_development_build @steps = steps_production_build if @production_build @certificate_name = nil + @app_version = opts[:version] + @app_version = "1.0" if @opts[:env] == :dev && !@app_version init_wizard_status log_info "Starting iOS Wizard so we can deploy to your device." @start_at = Kernel.global_tick_count @@ -117,8 +145,10 @@ class IOSWizard log "=" * $console.console_text_width else log_error e.to_s + log e.__backtrace_to_org__ end + init_wizard_status $console.set_command "$wizards.ios.start env: :#{@opts[:env]}" end @@ -225,13 +255,70 @@ class IOSWizard return "profiles/development.mobileprovision" end + def ios_metadata_template + <<-S +# ios_metadata.txt is used by the Pro version of DragonRuby Game Toolkit to create iOS apps. +# Information about the Pro version can be found at: http://dragonruby.org/toolkit/game#purchase + +# teamid needs to be set to your assigned Team Id which can be found at https://developer.apple.com/account/#/membership/ +teamid= +# appid needs to be set to your application identifier which can be found at https://developer.apple.com/account/resources/identifiers/list +appid= +# appname is the name you want to show up underneath the app icon on the device. Keep it under 10 characters. +appname= +# devcert is the certificate to use for development/deploying to your local device +devcert= +# prodcert is the certificate to use for distribution to the app store +prodcert= +S + end + + def ios_metadata + contents = $gtk.read_file 'metadata/ios_metadata.txt' + + if !contents + $gtk.write_file 'metadata/ios_metadata.txt', ios_metadata_template + contents = $gtk.read_file 'metadata/ios_metadata.txt' + end + + kvps = contents.each_line + .reject { |l| l.strip.length == 0 || (l.strip.start_with? "#") } + .map do |l| + key, value = l.split("=") + [key.strip.to_sym, value.strip] + end.flatten + Hash[*kvps] + end + + def game_metadata + contents = $gtk.read_file 'metadata/game_metadata.txt' + + kvps = contents.each_line + .reject { |l| l.strip.length == 0 || (l.strip.start_with? "#") } + .map do |l| + key, value = l.split("=") + [key.strip.to_sym, value.strip] + end.flatten + Hash[*kvps] + end + + def raise_ios_metadata_required + raise WizardException.new( + "* mygame/metadata/ios_metadata.txt needs to be filled out.", + "You need to update metadata/ios_metadata.txt with a valid teamid, appname, appid, devcert, and prodcert.", + "Instructions for where the values should come from are within metadata/ios_metadata.txt." + ) + end + def determine_team_identifier - @team_name = (team_identifier_from_provisioning_profile @opts[:env]) - log_info "Team Identifer is: #{@team_name}" + @team_id = (ios_metadata.teamid || "") + raise_ios_metadata_required if @team_id.strip.length == 0 + log_info "Team Identifer is: #{@team_id}" end def determine_app_name - @app_name = (provisioning_profile_xml @opts[:env])[:children].first[:children].first[:children][1][:children].first[:data] + @app_name = (ios_metadata.appname || "") + raise_ios_metadata_required if @app_name.strip.length == 0 log_info "App name is: #{@app_name}." end @@ -255,37 +342,22 @@ class IOSWizard $gtk.parse_xml scrubbed end - def app_id_from_provisioning_profile environment - application_identifier_index = (provisioning_profile_xml environment)[:children][0][:children][0][:children][13][:children][0][:children][0][:data] - (provisioning_profile_xml environment)[:children][0][:children][0][:children][13][:children].each.with_index do |node, i| - if node[:children] && node[:children][0] && node[:children][0][:data] == "application-identifier" - application_identifier_index = i - break - end - end - - app_id_with_team_identifier = (provisioning_profile_xml environment)[:children].first[:children].first[:children][13][:children][application_identifier_index + 1][:children].first[:data] - team_identifer = team_identifier_from_provisioning_profile environment - app_id_with_team_identifier.gsub "#{team_identifer}.", "" + def determine_app_id + @app_id = ios_metadata.appid + raise_ios_metadata_required if @app_id.strip.length == 0 + log_info "App Identifier is set to: #{@app_id}" end - def team_identifier_from_provisioning_profile environment - team_identifer_index = (provisioning_profile_xml environment)[:children][0][:children][0][:children][13][:children][0][:children][0][:data] - - (provisioning_profile_xml environment)[:children][0][:children][0][:children][13][:children].each.with_index do |node, i| - if node[:children] && node[:children][0] && node[:children][0][:data] == "com.apple.developer.team-identifier" - team_identifer_index = i - break - end - end - - (provisioning_profile_xml environment)[:children].first[:children].first[:children][13][:children][team_identifer_index + 1][:children].first[:data] + def determine_devcert + @certificate_name = ios_metadata.devcert + raise_ios_metadata_required if @certificate_name.strip.length == 0 + log_info "Dev Certificate is set to: #{@certificate_name}" end - def determine_app_id - @app_id = app_id_from_provisioning_profile @opts[:env] - - log_info "App Identifier is set to : #{@app_id}" + def determine_prodcert + @certificate_name = ios_metadata.prodcert + raise_ios_metadata_required if @certificate_name.strip.length == 0 + log_info "Production (Distribution) Certificate is set to: #{@certificate_name}" end def set_app_name name @@ -303,16 +375,10 @@ class IOSWizard end end - def blow_away_temp + def clear_tmp_directory sh "rm -rf #{tmp_directory}" end - def stage_app - log_info "Staging." - sh "mkdir -p #{tmp_directory}" - sh "cp -R #{relative_path}/dragonruby-ios.app \"#{tmp_directory}/#{@app_name}.app\"" - end - def set_app_id id log_info = "App Id set to: #{id}" @app_id = id @@ -343,34 +409,13 @@ class IOSWizard def check_for_certs log_info "Attempting to find certificates on your computer." - if !cli_app_exist?(security_cli_app) - raise WizardException.new( - "* It doesn't look like you have #{security_cli_app}.", - "** 1. Open Disk Utility and run First Aid.", - { w: 700, h: 148, path: get_reserved_sprite("disk-utility.png") }, - ) - end - - if valid_certs.length == 0 - raise WizardException.new( - "* It doesn't look like you have any valid certs installed.", - "** 1. Open Xcode.", - "** 2. Log into your developer account. Xcode -> Preferences -> Accounts.", - { w: 700, h: 98, path: get_reserved_sprite("login-xcode.png") }, - "** 3. After loggin in, select Manage Certificates...", - { w: 700, h: 115, path: get_reserved_sprite("manage-certificates.png") }, - "** 4. Add a certificate for Apple Development.", - { w: 700, h: 217, path: get_reserved_sprite("add-cert.png") }, - ) - raise "You do not have any Apple development certs on this computer." - end - if @production_build - @certificate_name = valid_certs.find_all { |f| f[:name].include? "Distribution" }.first[:name] + @certificate_name = ios_metadata[:prodcert] else - @certificate_name = valid_certs.find_all { |f| f[:name].include? "Development" }.first[:name] + @certificate_name = ios_metadata[:devcert] end - log_info "I will be using Certificate: '#{@certificate_name}'." + + log_info "I will be using certificate: '#{@certificate_name}'." end def idevice_id_cli_app @@ -385,24 +430,6 @@ class IOSWizard "xcodebuild" end - def valid_certs - certs = sh("#{security_cli_app} -q find-identity -p codesigning -v").each_line.map do |l| - if l.include?(")") && !l.include?("Developer ID") && (l.include?("Development") || l.include?("Distribution")) - l.strip - else - nil - end - end.reject_nil.map do |l| - number, id, name = l.split(' ', 3) - name = name.gsub("\"", "") if name - { - number: 1, - id: id, - name: name - } - end - end - def connected_devices sh("idevice_id -l").strip.each_line.map do |l| l.strip @@ -444,7 +471,8 @@ XML log_info "Creating Entitlements.plist" - $gtk.write_file_root "tmp/ios/Entitlements.plist", entitlement_plist_string.gsub(":app_id", "#{@team_name}.#{@app_id}").strip + $gtk.write_file_root "tmp/ios/Entitlements.plist", entitlement_plist_string.gsub(":app_id", "#{@team_id}.#{@app_id}").strip + $gtk.write_file_root "tmp/ios/Entitlements.txt", entitlement_plist_string.gsub(":app_id", "#{@team_id}.#{@app_id}").strip sh "/usr/bin/plutil -convert binary1 \"#{tmp_directory}/Entitlements.plist\"" sh "/usr/bin/plutil -convert xml1 \"#{tmp_directory}/Entitlements.plist\"" @@ -482,15 +510,15 @@ XML <key>CFBundleExecutable</key> <string>:app_name</string> <key>CFBundleInfoDictionaryVersion</key> - <string>6.0</string> + <string>:app_version</string> <key>CFBundlePackageType</key> <string>APPL</string> <key>CFBundleShortVersionString</key> - <string>5.6</string> + <string>:app_version</string> <key>CFBundleSignature</key> <string>????</string> <key>CFBundleVersion</key> - <string>5.6</string> + <string>:app_version</string> <key>CFBundleIcons</key> <dict> <key>CFBundlePrimaryIcon</key> @@ -639,13 +667,13 @@ XML <key>CFBundleIdentifier</key> <string>:app_id</string> <key>CFBundleInfoDictionaryVersion</key> - <string>6.0</string> + <string>:app_version</string> <key>CFBundleName</key> <string>:app_name</string> <key>CFBundlePackageType</key> <string>APPL</string> <key>CFBundleShortVersionString</key> - <string>5.2</string> + <string>:app_version</string> <key>CFBundleSignature</key> <string>????</string> <key>CFBundleSupportedPlatforms</key> @@ -653,7 +681,7 @@ XML <string>iPhoneOS</string> </array> <key>CFBundleVersion</key> - <string>5.2</string> + <string>:app_version</string> <key>DTCompiler</key> <string>com.apple.compilers.llvm.clang.1_0</string> <key>DTPlatformBuild</key> @@ -739,6 +767,7 @@ XML info_plist_string.gsub!(":app_id", @app_id) $gtk.write_file_root "tmp/ios/#{@app_name}.app/Info.plist", info_plist_string.strip + $gtk.write_file_root "tmp/ios/Info.txt", info_plist_string.strip @info_plist_written = true end @@ -792,13 +821,13 @@ XML <key>CFBundleIdentifier</key> <string>:app_id</string> <key>CFBundleInfoDictionaryVersion</key> - <string>6.0</string> + <string>:app_version</string> <key>CFBundleName</key> <string>:app_name</string> <key>CFBundlePackageType</key> <string>APPL</string> <key>CFBundleShortVersionString</key> - <string>5.2</string> + <string>:app_version</string> <key>CFBundleSignature</key> <string>????</string> <key>CFBundleSupportedPlatforms</key> @@ -806,7 +835,7 @@ XML <string>iPhoneOS</string> </array> <key>CFBundleVersion</key> - <string>5.2</string> + <string>:app_version</string> <key>DTCompiler</key> <string>com.apple.compilers.llvm.clang.1_0</string> <key>DTPlatformBuild</key> @@ -890,8 +919,10 @@ XML info_plist_string.gsub!(":app_name", @app_name) info_plist_string.gsub!(":app_id", @app_id) + info_plist_string.gsub!(":app_version", @app_version) $gtk.write_file_root "tmp/ios/#{@app_name}.app/Info.plist", info_plist_string.strip + $gtk.write_file_root "tmp/ios/Info.txt", info_plist_string.strip @info_plist_written = true end @@ -913,28 +944,56 @@ XML "#{relative_path}/#{$gtk.cli_arguments[:dragonruby]}" end - def write_ip_address + def embed_mobileprovision + sh %Q[cp #{@provisioning_profile_path} "#{app_path}/embedded.mobileprovision"] + sh %Q[/usr/bin/plutil -convert binary1 "#{app_path}/Info.plist"] + end + + def clear_payload_directory + sh %Q[rm "#{@app_name}".ipa] + sh %Q[rm -rf "#{app_path}/app"] + sh %Q[rm -rf "#{app_path}/sounds"] + sh %Q[rm -rf "#{app_path}/sprites"] + sh %Q[rm -rf "#{app_path}/data"] + sh %Q[rm -rf "#{app_path}/fonts"] + end + + def stage_app + log_info "Staging." + sh "mkdir -p #{tmp_directory}" + sh "cp -R #{relative_path}/dragonruby-ios.app \"#{tmp_directory}/#{@app_name}.app\"" + sh %Q[cp -r "#{root_folder}/app/" "#{app_path}/app/"] + sh %Q[cp -r "#{root_folder}/sounds/" "#{app_path}/sounds/"] + sh %Q[cp -r "#{root_folder}/sprites/" "#{app_path}/sprites/"] + sh %Q[cp -r "#{root_folder}/data/" "#{app_path}/data/"] + sh %Q[cp -r "#{root_folder}/fonts/" "#{app_path}/fonts/"] + end + + def create_payload + sh %Q[mkdir -p #{tmp_directory}/ipa_root/Payload] + sh %Q[cp -r "#{app_path}" "#{tmp_directory}/ipa_root/Payload"] + sh %Q[chmod -R 755 "#{tmp_directory}/ipa_root/Payload"] + end + + def create_payload_directory_dev + # write dev machine's ip address for hotloading $gtk.write_file "app/server_ip_address.txt", $gtk.ffi_misc.get_local_ip_address.strip + + embed_mobileprovision + clear_payload_directory + stage_app end - def create_payload_directory - sh "cp #{@provisioning_profile_path} \"#{app_path}/embedded.mobileprovision\"" - sh "/usr/bin/plutil -convert binary1 \"#{app_path}/Info.plist\"" - write_ip_address - sh "rm \"#{@app_name}\".ipa" - sh "rm -rf \"#{app_path}/app\"" - sh "rm -rf \"#{app_path}/sounds\"" - sh "rm -rf \"#{app_path}/sprites\"" - sh "rm -rf \"#{app_path}/data\"" - sh "rm -rf \"#{app_path}/fonts\"" - sh "cp -r \"#{root_folder}/app/\" \"#{app_path}/app/\"" - sh "cp -r \"#{root_folder}/sounds/\" \"#{app_path}/sounds/\"" - sh "cp -r \"#{root_folder}/sprites/\" \"#{app_path}/sprites/\"" - sh "cp -r \"#{root_folder}/data/\" \"#{app_path}/data/\"" - sh "cp -r \"#{root_folder}/fonts/\" \"#{app_path}/fonts/\"" - sh "mkdir -p #{tmp_directory}/ipa_root/Payload" - sh "cp -r \"#{app_path}\" \"#{tmp_directory}/ipa_root/Payload\"" - sh "chmod -R 755 \"#{tmp_directory}/ipa_root/Payload\"" + def create_payload_directory_prod + # production builds does not hotload ip address + sh %Q[rm "#{root_folder}/app/server_ip_address.txt"] + + embed_mobileprovision + stage_app + + # production build marker + sh %Q[mkdir -p "#{app_path}/metadata/"] + sh %Q[touch metadata/DRAGONRUBY_PRODUCTION_BUILD] end def create_ipa @@ -967,10 +1026,22 @@ SCRIPT end def print_publish_help - log_info "Go to https://appstoreconnect.apple.com/apps and create an App if you haven't already done so." - log_info "Go to https://appleid.apple.com and create a 'Application Specific Password'." - log_info "To upload your app, Download Transporter from the App Store https://apps.apple.com/us/app/transporter/id1450874784?mt=12." - log_info "Your app is located at ./tmp/ios/#{@app_name}.ipa" + has_transporter = (sh "ls /Applications/Transporter.app").include? "Contents" + if !has_transporter + $gtk.openurl "https://apps.apple.com/us/app/transporter/id1450874784?mt=12" + $console.set_command "$wizards.ios.start env: :#{@opts[:env]}, version: \"#{@opts[:version]}\"" + raise WizardException.new( + "* To upload your app, Download Transporter from the App Store https://apps.apple.com/us/app/transporter/id1450874784?mt=12." + ) + else + sh "mkdir ./tmp/ios/intermediary_artifacts" + sh "mv \"#{tmp_directory}/#{@app_name}.app\" #{tmp_directory}/intermediary_artifacts/" + sh "mv \"#{tmp_directory}/do_zip.sh\" #{tmp_directory}/intermediary_artifacts" + sh "mv \"#{tmp_directory}/Entitlements.plist\" #{tmp_directory}/intermediary_artifacts" + sh "mv \"#{tmp_directory}/ipa_root\" #{tmp_directory}/intermediary_artifacts/" + sh "open /Applications/Transporter.app" + sh "open ./tmp/ios/" + end end def compile_icons @@ -991,4 +1062,24 @@ S sh "cp -r \"#{root_folder}/native/\" \"#{app_path}/native/\"" sh "CODESIGN_ALLOCATE=\"/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/codesign_allocate\" /usr/bin/codesign -f -s \"#{@certificate_name}\" --entitlements #{tmp_directory}/Entitlements.plist \"#{tmp_directory}/#{@app_name}.app/native/ios-device/ext.dylib\"" end + + def set_version version + @app_version = version + start env: @opts[:env], version: version + end + + def app_version + log_info "Attempting to retrieve App Version from metadata/ios_metadata.txt." + ios_version_number = (ios_metadata.version || "").strip + if ios_version_number.length == 0 + log_info "Not found. Attempting to retrieve App Version from metadata/game_metadata.txt." + ios_version_number = (game_metadata.version || "").strip + end + ios_version_number + end + + def determine_app_version + @app_version = app_version + return if @app_version + end end |
