From 82a75cf09b099098a839670643a1ff02a878be96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eloy=20Dur=C3=A1n?= Date: Fri, 12 Sep 2014 17:10:56 +0200 Subject: [PATCH 1/3] [iOS] On >= 7, infer UILaunchImages metadata from resources/Default*.png Fixes http://hipbyte.myjetbrains.com/youtrack/issue/RM-596 --- lib/motion/project/template/ios/config.rb | 71 +++++++++- test/external/unit/project/ios_config_spec.rb | 131 ++++++++++++++++++ vm | 2 +- 3 files changed, 200 insertions(+), 4 deletions(-) create mode 100644 test/external/unit/project/ios_config_spec.rb diff --git a/lib/motion/project/template/ios/config.rb b/lib/motion/project/template/ios/config.rb index 589a3cc0..1292cc35 100644 --- a/lib/motion/project/template/ios/config.rb +++ b/lib/motion/project/template/ios/config.rb @@ -24,6 +24,7 @@ # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. require 'motion/project/xcode_config' +require 'motion/util/version' module Motion; module Project; class IOSConfig < XcodeConfig @@ -349,8 +350,60 @@ module Motion; module Project; end end - def info_plist_data(platform) - Motion::PropertyList.to_s({ + def launch_image_metadata(path) + filename = File.basename(path) + filename_components = File.basename(filename, File.extname(filename)).split(/-|@|~/) + name = filename_components.shift + scale = (filename_components.find { |c| c =~ /\dx/ } || 1).to_i + orientation = filename_components.find { |c| c =~ /Portrait|PortraitUpsideDown|Landscape|LandscapeLeft|LandscapeRight/ } || 'Portrait' + expected_height = filename_components.find { |c| c =~ /\d+h/ } + expected_height = expected_height.to_i if expected_height + + metadata = `/usr/bin/sips -g format -g pixelWidth -g pixelHeight '#{path}'`.strip + + format = metadata.match(/format: (\w+)/)[1] + unless metadata.include?('format: png') + App.fail "Launch Image `#{path}' not recognized as png file, but `#{format}' instead." + end + + width = metadata.match(/pixelWidth: (\d+)/)[1].to_i + height = metadata.match(/pixelHeight: (\d+)/)[1].to_i + width /= scale + height /= scale + if expected_height && expected_height != height + App.fail "Launch Image size (#{width}x#{height}) does not match the specified modifier `#{expected_height}h'." + end + + { + # For now I'm assuming that an image for an 'iOS 8'-only device, such as + # iPhone 6, will work fine with a min OS version of 7.0. + # + # Otherwise we would also have to reflect on the data and infer whether + # or not the device is a device such as the iPhone 6 and hardcode + # devices. + "UILaunchImageMinimumOSVersion" => "7.0", + "UILaunchImageName" => name, + "UILaunchImageOrientation" => orientation, + "UILaunchImageSize" => "{#{width}, #{height}}" + } + end + + # From iOS 7 and up we try to infer the launch images by looking for png + # files that start with 'Default'. + # + def launch_images + if Util::Version.new(deployment_target) >= Util::Version.new('7') + images = resources_dirs.map do |dir| + Dir.glob(File.join(dir, 'Default*.png')).map do |file| + launch_image_metadata(file) + end + end.flatten.compact + images unless images.empty? + end + end + + def merged_info_plist(platform) + ios = { 'MinimumOSVersion' => deployment_target, 'CFBundleResourceSpecification' => 'ResourceRules.plist', 'CFBundleSupportedPlatforms' => [deploy_platform], @@ -382,7 +435,19 @@ module Motion; module Project; 'DTCompiler' => 'com.apple.compilers.llvm.clang.1_0', 'DTPlatformVersion' => sdk_version, 'DTPlatformBuild' => sdk_build_version(platform), - }.merge(generic_info_plist).merge(dt_info_plist).merge(info_plist)) + } + + base = info_plist + # If the user has not explicitely specified launch images, try to find + # them ourselves. + if !base.include?('UILaunchImages') && launch_images = self.launch_images + base['UILaunchImages'] = launch_images + end + ios.merge(generic_info_plist).merge(dt_info_plist).merge(base) + end + + def info_plist_data(platform) + Motion::PropertyList.to_s(merged_info_plist(platform)) end def manifest_plist_data diff --git a/test/external/unit/project/ios_config_spec.rb b/test/external/unit/project/ios_config_spec.rb new file mode 100644 index 00000000..be624f43 --- /dev/null +++ b/test/external/unit/project/ios_config_spec.rb @@ -0,0 +1,131 @@ +require File.expand_path('../../../spec_helper', __FILE__) +#require 'motion/project/xcode_config' +require 'motion/project/template/ios/config' + +require 'tempfile' + +module Motion; module Project + describe IOSConfig do + describe "concerning UILaunchImages" do + before do + @config = IOSConfig.new(Dir.tmpdir, :development) + @config.deployment_target = '7.0' + end + + it "does not try to include UILaunchImages on a deployment target older than iOS 7" do + @config.deployment_target = '6.1' + Dir.expects(:glob).never + @config.launch_images + end + + it "infers the launch images from the specified resources by the Default prefix and png extname" do + Dir.expects(:glob).with(File.join(@config.resources_dirs.first, 'Default*.png')).returns(['resources/Default.png']) + @config.expects(:launch_image_metadata).with('resources/Default.png') + @config.launch_images + end + + it "disallows non-PNGs" do + @config.expects(:`).with("/usr/bin/sips -g format -g pixelWidth -g pixelHeight 'resources/Default.png'") + .returns(" format: jpeg\n pixelWidth: 320\n pixelHeight: 480\n") + App.expects(:fail) + @config.launch_image_metadata("resources/Default.png") + end + + it "disallows a height filename component not matching the actual height" do + @config.expects(:`).with("/usr/bin/sips -g format -g pixelWidth -g pixelHeight 'resources/Default-568h.png'") + .returns(" format: png\n pixelWidth: 320\n pixelHeight: 480\n") + App.expects(:fail) + @config.launch_image_metadata("resources/Default-568h.png") + end + + it "configures a non-retina iPhone < 5 image" do + @config.expects(:`).with("/usr/bin/sips -g format -g pixelWidth -g pixelHeight 'resources/Default.png'") + .returns(" format: png\n pixelWidth: 320\n pixelHeight: 480\n") + @config.launch_image_metadata("resources/Default.png").should == { + "UILaunchImageMinimumOSVersion" => "7.0", + "UILaunchImageName" => "Default", + "UILaunchImageOrientation" => "Portrait", + "UILaunchImageSize" => "{320, 480}" + } + end + + it "configures a retina iPhone < 5 image" do + @config.expects(:`).with("/usr/bin/sips -g format -g pixelWidth -g pixelHeight 'resources/Default@2x.png'") + .returns(" format: png\n pixelWidth: 640\n pixelHeight: 960\n") + @config.launch_image_metadata("resources/Default@2x.png").should == { + "UILaunchImageMinimumOSVersion" => "7.0", + "UILaunchImageName" => "Default", + "UILaunchImageOrientation" => "Portrait", + "UILaunchImageSize" => "{320, 480}" + } + end + + it "configures an iPhone 5 image" do + @config.expects(:`).with("/usr/bin/sips -g format -g pixelWidth -g pixelHeight 'resources/Default-568h@2x.png'") + .returns(" format: png\n pixelWidth: 640\n pixelHeight: 1136\n") + @config.launch_image_metadata("resources/Default-568h@2x.png").should == { + "UILaunchImageMinimumOSVersion" => "7.0", + "UILaunchImageName" => "Default", + "UILaunchImageOrientation" => "Portrait", + "UILaunchImageSize" => "{320, 568}" + } + end + + it "configures an iPhone 6 image" do + @config.expects(:`).with("/usr/bin/sips -g format -g pixelWidth -g pixelHeight 'resources/Default-667h@2x.png'") + .returns(" format: png\n pixelWidth: 750\n pixelHeight: 1334\n") + @config.launch_image_metadata("resources/Default-667h@2x.png").should == { + #"UILaunchImageMinimumOSVersion" => "8.0", + "UILaunchImageMinimumOSVersion" => "7.0", + "UILaunchImageName" => "Default", + "UILaunchImageOrientation" => "Portrait", + "UILaunchImageSize" => "{375, 667}" + } + end + + it "configures an iPhone 6+ image" do + @config.expects(:`).with("/usr/bin/sips -g format -g pixelWidth -g pixelHeight 'resources/Default-736h@3x.png'") + .returns(" format: png\n pixelWidth: 1242\n pixelHeight: 2208\n") + @config.launch_image_metadata("resources/Default-736h@3x.png").should == { + #"UILaunchImageMinimumOSVersion" => "8.0", + "UILaunchImageMinimumOSVersion" => "7.0", + "UILaunchImageName" => "Default", + "UILaunchImageOrientation" => "Portrait", + "UILaunchImageSize" => "{414, 736}" + } + end + + { + '' => 'Portrait', + '-Portrait' => 'Portrait', + '-PortraitUpsideDown' => 'PortraitUpsideDown', + '-Landscape' => 'Landscape', + '-LandscapeLeft' => 'LandscapeLeft', + '-LandscapeRight' => 'LandscapeRight', + }.each do |orientation_component, expected_orientation| + it "configures a non-retina iPad #{expected_orientation} image (e.g. iPad 2)" do + @config.expects(:`).with("/usr/bin/sips -g format -g pixelWidth -g pixelHeight 'resources/Default#{orientation_component}~ipad.png'") + .returns(" format: png\n pixelWidth: 768\n pixelHeight: 1024\n") + @config.launch_image_metadata("resources/Default#{orientation_component}~ipad.png").should == { + "UILaunchImageMinimumOSVersion" => "7.0", + "UILaunchImageName" => "Default", + "UILaunchImageOrientation" => expected_orientation, + "UILaunchImageSize" => "{768, 1024}" + } + end + + it "configures a retina iPad #{expected_orientation} image" do + @config.expects(:`).with("/usr/bin/sips -g format -g pixelWidth -g pixelHeight 'resources/Default#{orientation_component}@2x~ipad.png'") + .returns(" format: png\n pixelWidth: 1536\n pixelHeight: 2048\n") + @config.launch_image_metadata("resources/Default#{orientation_component}@2x~ipad.png").should == { + "UILaunchImageMinimumOSVersion" => "7.0", + "UILaunchImageName" => "Default", + "UILaunchImageOrientation" => expected_orientation, + "UILaunchImageSize" => "{768, 1024}" + } + end + end + end + end + +end; end diff --git a/vm b/vm index 2c7fb4e7..af6b91b7 160000 --- a/vm +++ b/vm @@ -1 +1 @@ -Subproject commit 2c7fb4e72f8d99ff3d9aa7040b0aefd657a2000c +Subproject commit af6b91b7bc821ee682c61ddbff984c82fdec0160 From 8b8817e2d31bb0897b2599ce854b30e9602401bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eloy=20Dur=C3=A1n?= Date: Fri, 12 Sep 2014 21:08:33 +0200 Subject: [PATCH 2/3] [vm] sync --- vm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vm b/vm index af6b91b7..787ef867 160000 --- a/vm +++ b/vm @@ -1 +1 @@ -Subproject commit af6b91b7bc821ee682c61ddbff984c82fdec0160 +Subproject commit 787ef8675897799021292c444062106ab8d64193 From aff6b0ba30bd6f2e7bfb08cbff51a102032367ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eloy=20Dur=C3=A1n?= Date: Fri, 12 Sep 2014 21:23:54 +0200 Subject: [PATCH 3/3] [NEWS] Document fix for iPhone 6/6+ launch images. --- NEWS | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/NEWS b/NEWS index 71d4d9fc..23a8c2dd 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,9 @@ = RubyMotion 2.33 = + * [iOS] Add support for iPhone 6/6+ launch images. Unless explicitely + specified, the Info.plist `UILaunchImages' key is populated from all PNG + files in the resource directories that start with Default. For iPhone 6/6+ + use the `-667h' and `-736h' filename modifiers. * [OSX] Fix a bug that made it impossible to build a OS X app on Yosemite with Xcode 6 GM, even when targeting 10.9. * Fixed a bug that ommitted class and protocol methods from the ctags.