diff --git a/lib/motion/project/builder.rb b/lib/motion/project/builder.rb index a043dbb6..508d718b 100644 --- a/lib/motion/project/builder.rb +++ b/lib/motion/project/builder.rb @@ -312,14 +312,6 @@ EOS end end - # Create bundle/Info.plist. - bundle_info_plist = File.join(bundle_path, 'Info.plist') - if !File.exist?(bundle_info_plist) or File.mtime(config.project_file) > File.mtime(bundle_info_plist) - App.info 'Create', bundle_info_plist - File.open(bundle_info_plist, 'w') { |io| io.write(config.info_plist_data(platform)) } - sh "/usr/bin/plutil -convert binary1 \"#{bundle_info_plist}\"" - end - # Create bundle/PkgInfo. bundle_pkginfo = File.join(bundle_path, 'PkgInfo') if !File.exist?(bundle_pkginfo) or File.mtime(config.project_file) > File.mtime(bundle_pkginfo) @@ -342,18 +334,34 @@ EOS end end + preserve_resources = [] + # Compile Asset Catalog bundles. - app_icons = [] - xcassets = config.xcassets_bundles.map { |f| File.expand_path(f) } - unless xcassets.empty? - if app_icons_asset_bundle = config.app_icons_asset_bundle - app_icons = config.deploy_platform == 'iPhoneOS' ? config.icons : [config.icon] - app_icons_name = File.basename(app_icons_asset_bundle, '.appiconset') + xcassets_bundles = [] + config.resources_dirs.each do |dir| + if File.exist?(dir) + xcassets_bundles.concat(Dir.glob(File.expand_path(File.join(dir, '*.xcassets')))) + end + end + unless xcassets_bundles.empty? + ios = config.deploy_platform == 'iPhoneOS' + + app_icons_asset_bundles = xcassets_bundles.map { |b| Dir.glob(File.join(b, '*.appiconset')) }.flatten + if app_icons_asset_bundles.size > 1 + App.warn "Found #{app_icons_asset_bundles.size} app icon sets across all " \ + "xcasset bundles. Only the first one (alphabetically) " \ + "will be used." + end + if app_icons_asset_bundle = app_icons_asset_bundles.sort.first + preserve_resources = ios ? config.icons : [config.icon] + app_icon_name = File.basename(app_icons_asset_bundle, '.appiconset') # TODO We can potentially use the plist output to identify the icon # names for the config, instead of parsing the JSON. This also # guards against the Contents.json format changing. - app_icons_options = "--output-partial-info-plist /dev/null --app-icon \"#{app_icons_name}\"" + app_icons_info_plist = ios ? File.expand_path(File.join(build_dir, 'AppIcon.plist')) : '/dev/null' + app_icons_options = "--output-partial-info-plist \"#{app_icons_info_plist}\" --app-icon \"#{app_icon_name}\"" end + app_resources_dir = File.expand_path(config.app_resources_dir(platform)) FileUtils.mkdir_p(app_resources_dir) sh "\"#{config.xcode_dir}/usr/bin/actool\" --output-format human-readable-text " \ @@ -361,7 +369,25 @@ EOS "--minimum-deployment-target #{config.deployment_target} " \ "#{Array(config.device_family).map { |d| "--target-device #{d}" }.join(' ')} " \ "#{app_icons_options} " \ - "--compress-pngs --compile \"#{app_resources_dir}\" \"#{xcassets.join('" "')}\"" + "--compress-pngs --compile \"#{app_resources_dir}\" \"#{xcassets_bundles.join('" "')}\"" + + # Extract the app icon file(s) name(s) and assign it to the config. + if app_icons_asset_bundle + if ios + app_icons_info_plist_content = `/usr/libexec/PlistBuddy -c 'Print :CFBundleIcons:CFBundlePrimaryIcon:CFBundleIconFiles' "#{app_icons_info_plist}"`.strip + if app_icons_info_plist_content.include?('Does Not Exist') + App.fail 'TODO' + end + lines = app_icons_info_plist_content.split("\n") + if lines.size < 2 + App.fail 'TODO' + end + config.icons = lines[1..-2] + else + # On Mac there is only ever one icns file. + config.icon = app_icon_name + end + end end # Compile CoreData Model resources and SpriteKit atlas files. @@ -400,6 +426,14 @@ EOS end end + # Create bundle/Info.plist. + bundle_info_plist = File.join(bundle_path, 'Info.plist') + if !File.exist?(bundle_info_plist) or File.mtime(config.project_file) > File.mtime(bundle_info_plist) + App.info 'Create', bundle_info_plist + File.open(bundle_info_plist, 'w') { |io| io.write(config.info_plist_data(platform)) } + sh "/usr/bin/plutil -convert binary1 \"#{bundle_info_plist}\"" + end + # Copy resources, handle subdirectories. app_resources_dir = config.app_resources_dir(platform) FileUtils.mkdir_p(app_resources_dir) @@ -438,7 +472,7 @@ EOS next if File.directory?(bundle_res) next if reserved_app_bundle_files.include?(bundle_res) next if resources_files.include?(bundle_res) - next if app_icons.include?(File.basename(bundle_res)) + next if preserve_resources.include?(File.basename(bundle_res)) App.warn "File `#{bundle_res}' found in app bundle but not in resource directories, removing" FileUtils.rm_rf(bundle_res) end diff --git a/lib/motion/project/template/ios/config.rb b/lib/motion/project/template/ios/config.rb index 3e7ab630..c5ab5833 100644 --- a/lib/motion/project/template/ios/config.rb +++ b/lib/motion/project/template/ios/config.rb @@ -38,6 +38,7 @@ module Motion; module Project; @interface_orientations = [:portrait, :landscape_left, :landscape_right] @background_modes = [] @status_bar_style = :default + @icons = [] @prerendered_icon = false @manifest_assets = [] end @@ -56,39 +57,6 @@ module Motion; module Project; end end - def icons - @icons ||= app_icons_from_asset_bundle - end - - def app_icons_from_asset_bundle - unless @app_icons_from_asset_bundle - @app_icons_from_asset_bundle = [] - - if app_icon_set = app_icons_asset_bundle - begin - require 'rubygems' - require 'json' - rescue LoadError - App.fail "Using application icons from Xcode asset catalogs " \ - "requires the `json' gem to be installed. You can do " \ - "so by typing `[sudo] gem install json' in your " \ - "terminal or by adding `gem \"json\"' to your Gemfile." - end - app_icon_filename = File.basename(app_icon_set, File.extname(app_icon_set)) - images = JSON.parse(File.read(File.join(app_icon_set, 'Contents.json')))['images'] - images.each do |image| - if image_src = image['filename'] - image_src = File.join(app_icon_set, image_src) - if File.exist?(image_src) - @app_icons_from_asset_bundle << "#{app_icon_filename}#{image['size']}@#{image['scale']}.png" - end - end - end - end - end - @app_icons_from_asset_bundle - end - def validate # icons if !(icons.is_a?(Array) and icons.all? { |x| x.is_a?(String) }) diff --git a/lib/motion/project/template/osx/config.rb b/lib/motion/project/template/osx/config.rb index 7a4da964..481dea49 100644 --- a/lib/motion/project/template/osx/config.rb +++ b/lib/motion/project/template/osx/config.rb @@ -34,6 +34,7 @@ module Motion; module Project; def initialize(project_dir, build_mode) super + @icon = '' @copyright = "Copyright © #{Time.now.year} #{`whoami`.strip}. All rights reserved." @category = 'utilities' @frameworks = ['AppKit', 'Foundation', 'CoreGraphics'] @@ -67,16 +68,6 @@ module Motion; module Project; archs end - def icon - @icon ||= begin - if app_icon_set = app_icons_asset_bundle - File.basename(app_icon_set, File.extname(app_icon_set)) << '.icns' - else - '' - end - end - end - def locate_compiler(platform, *execs) execs.each do |exec| cc = File.join('/usr/bin', exec) diff --git a/lib/motion/project/xcode_config.rb b/lib/motion/project/xcode_config.rb index f5c66547..e943ca39 100644 --- a/lib/motion/project/xcode_config.rb +++ b/lib/motion/project/xcode_config.rb @@ -322,25 +322,5 @@ EOS path = File.join(xcode_dir, 'usr/bin/TextureAtlas') File.exist?(path) ? path : nil end - - def xcassets_bundles - xcassets_bundles = [] - resources_dirs.each do |dir| - if File.exist?(dir) - xcassets_bundles.concat(Dir.glob(File.join(dir, '*.xcassets'))) - end - end - xcassets_bundles - end - - def app_icons_asset_bundle - app_icons_asset_bundles = xcassets_bundles.map { |b| Dir.glob(File.join(b, '*.appiconset')) }.flatten - if app_icons_asset_bundles.size > 1 - App.warn "Found #{app_icons_asset_bundles.size} AppIcon sets across all " \ - "xcasset bundles. Only the first one (alphabetically) " \ - "will be used." - end - app_icons_asset_bundles.sort.first - end end end; end