summaryrefslogtreecommitdiffhomepage
path: root/dragon/ios_wizard.rb
diff options
context:
space:
mode:
Diffstat (limited to 'dragon/ios_wizard.rb')
-rw-r--r--dragon/ios_wizard.rb359
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