mirror of
https://github.com/zhigang1992/RubyMotion.git
synced 2026-04-22 03:44:03 +08:00
Merge pull request #9 from lrz/xcassets
Support for Xcode asset catalogs.
This commit is contained in:
4
NEWS
4
NEWS
@@ -3,6 +3,10 @@
|
||||
* Added the `rake clean:all' task which deletes all build object files
|
||||
(ex. those in ~/Library/RubyMotion/build). We recommend using that task
|
||||
before building an App Store submission.
|
||||
* Added support for Xcode asset catalogs. This can be used to manage all your
|
||||
image assets in a visual way, including your application’s icons. You can
|
||||
create and edit a new catalog like so:
|
||||
$ mkdir resources/Images.xcassets && open -a Xcode resources/Image.xcassets
|
||||
* Fixed a long standing limitation in the compiler where overriding in Ruby
|
||||
an Objective-C method that accepts a C-level block was not possible.
|
||||
* Fixed a regression where `return' from a block would terminate the app.
|
||||
|
||||
@@ -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,6 +334,46 @@ EOS
|
||||
end
|
||||
end
|
||||
|
||||
preserve_resources = []
|
||||
|
||||
# Compile Asset Catalog bundles.
|
||||
assets_bundles = config.assets_bundles
|
||||
unless assets_bundles.empty?
|
||||
app_icons_asset_bundle = config.app_icons_asset_bundle
|
||||
if app_icons_asset_bundle
|
||||
app_icons_info_plist_path = config.app_icons_info_plist_path(platform)
|
||||
app_icons_options = "--output-partial-info-plist \"#{app_icons_info_plist_path}\" " \
|
||||
"--app-icon \"#{config.app_icon_name_from_asset_bundle}\""
|
||||
end
|
||||
|
||||
App.info 'Compile', assets_bundles.join(", ")
|
||||
app_resources_dir = File.expand_path(config.app_resources_dir(platform))
|
||||
FileUtils.mkdir_p(app_resources_dir)
|
||||
cmd = "\"#{config.xcode_dir}/usr/bin/actool\" --output-format human-readable-text " \
|
||||
"--notices --warnings --platform #{config.deploy_platform.downcase} " \
|
||||
"--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}\" " \
|
||||
"\"#{assets_bundles.map { |f| File.expand_path(f) }.join('" "')}\""
|
||||
$stderr.puts(cmd) if App::VERBOSE
|
||||
actool_output = `#{cmd} 2>&1`
|
||||
$stderr.puts(actool_output) if App::VERBOSE
|
||||
|
||||
# Split output in warnings and compiled files
|
||||
actool_output, actool_compilation_results = actool_output.split('/* com.apple.actool.compilation-results */')
|
||||
actool_compiled_files = actool_compilation_results.strip.split("\n")
|
||||
if actool_document_warnings = actool_output.split('/* com.apple.actool.document.warnings */').last
|
||||
# Propagate warnings to the user.
|
||||
actool_document_warnings.strip.split("\n").each { |w| App.warn(w) }
|
||||
end
|
||||
|
||||
# Remove the partial Info.plist line and preserve all other assets.
|
||||
actool_compiled_files.delete(app_icons_info_plist_path) if app_icons_asset_bundle
|
||||
preserve_resources.concat(actool_compiled_files.map { |f| File.basename(f) })
|
||||
|
||||
config.configure_app_icons_from_asset_bundle(platform) if app_icons_asset_bundle
|
||||
end
|
||||
|
||||
# Compile CoreData Model resources and SpriteKit atlas files.
|
||||
config.resources_dirs.each do |dir|
|
||||
if File.exist?(dir)
|
||||
@@ -378,6 +410,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)
|
||||
@@ -386,11 +426,17 @@ EOS
|
||||
'Info.plist', 'PkgInfo', 'ResourceRules.plist',
|
||||
convert_filesystem_encoding(config.name)
|
||||
]
|
||||
resources_exclude_extnames = ['.xib', '.storyboard', '.xcdatamodeld', '.lproj', '.atlas', '.xcassets']
|
||||
resources_paths = []
|
||||
config.resources_dirs.each do |dir|
|
||||
if File.exist?(dir)
|
||||
resources_paths << Dir.chdir(dir) do
|
||||
Dir.glob('**{,/*/**}/*').reject { |x| ['.xib', '.storyboard', '.xcdatamodeld', '.lproj', '.atlas'].include?(File.extname(x)) }.map { |file| File.join(dir, file) }
|
||||
Dir.glob('**{,/*/**}/*').reject do |x|
|
||||
# Find files with extnames to exclude or files inside bundles to
|
||||
# exclude (e.g. xcassets).
|
||||
resources_exclude_extnames.include?(File.extname(x)) ||
|
||||
resources_exclude_extnames.include?(File.extname(x.split('/').first))
|
||||
end.map { |file| File.join(dir, file) }
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -400,12 +446,7 @@ EOS
|
||||
if reserved_app_bundle_files.include?(res)
|
||||
App.fail "Cannot use `#{res_path}' as a resource file because it's a reserved application bundle file"
|
||||
end
|
||||
dest_path = File.join(app_resources_dir, res)
|
||||
if !File.exist?(dest_path) or File.mtime(res_path) > File.mtime(dest_path)
|
||||
FileUtils.mkdir_p(File.dirname(dest_path))
|
||||
App.info 'Copy', res_path
|
||||
FileUtils.cp_r(res_path, dest_path)
|
||||
end
|
||||
copy_resource(res_path, File.join(app_resources_dir, res))
|
||||
end
|
||||
|
||||
# Delete old resource files.
|
||||
@@ -415,6 +456,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 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
|
||||
@@ -446,6 +488,14 @@ EOS
|
||||
eval `#{@nfd} "#{string}"`
|
||||
end
|
||||
|
||||
def copy_resource(res_path, dest_path)
|
||||
if !File.exist?(dest_path) or File.mtime(res_path) > File.mtime(dest_path)
|
||||
FileUtils.mkdir_p(File.dirname(dest_path))
|
||||
App.info 'Copy', res_path
|
||||
FileUtils.cp_r(res_path, dest_path)
|
||||
end
|
||||
end
|
||||
|
||||
class << self
|
||||
def common_build_dir
|
||||
dir = File.expand_path("~/Library/RubyMotion/build")
|
||||
|
||||
@@ -57,6 +57,18 @@ module Motion; module Project;
|
||||
end
|
||||
end
|
||||
|
||||
def app_icons_info_plist_path(platform)
|
||||
File.expand_path(File.join(versionized_build_dir(platform), 'AppIcon.plist'))
|
||||
end
|
||||
|
||||
def configure_app_icons_from_asset_bundle(platform)
|
||||
path = app_icons_info_plist_path(platform)
|
||||
if File.exist?(path)
|
||||
content = `/usr/libexec/PlistBuddy -c 'Print :CFBundleIcons:CFBundlePrimaryIcon:CFBundleIconFiles' "#{path}"`.strip
|
||||
self.icons = content.split("\n")[1..-2].map(&:strip)
|
||||
end
|
||||
end
|
||||
|
||||
def validate
|
||||
# icons
|
||||
if !(icons.is_a?(Array) and icons.all? { |x| x.is_a?(String) })
|
||||
|
||||
@@ -34,8 +34,8 @@ module Motion; module Project;
|
||||
|
||||
def initialize(project_dir, build_mode)
|
||||
super
|
||||
@copyright = "Copyright © #{Time.now.year} #{`whoami`.strip}. All rights reserved."
|
||||
@icon = ''
|
||||
@copyright = "Copyright © #{Time.now.year} #{`whoami`.strip}. All rights reserved."
|
||||
@category = 'utilities'
|
||||
@frameworks = ['AppKit', 'Foundation', 'CoreGraphics']
|
||||
@embedded_frameworks = []
|
||||
@@ -45,6 +45,7 @@ module Motion; module Project;
|
||||
def platforms; ['MacOSX']; end
|
||||
def local_platform; 'MacOSX'; end
|
||||
def deploy_platform; 'MacOSX'; end
|
||||
def device_family; 'mac'; end
|
||||
|
||||
def validate
|
||||
# Embedded frameworks.
|
||||
@@ -67,6 +68,15 @@ module Motion; module Project;
|
||||
archs
|
||||
end
|
||||
|
||||
def app_icons_info_plist_path(platform)
|
||||
'/dev/null'
|
||||
end
|
||||
|
||||
# On OS X only one file is ever created. E.g. NAME.icns
|
||||
def configure_app_icons_from_asset_bundle(platform)
|
||||
self.icon = app_icon_name_from_asset_bundle
|
||||
end
|
||||
|
||||
def locate_compiler(platform, *execs)
|
||||
execs.each do |exec|
|
||||
cc = File.join('/usr/bin', exec)
|
||||
|
||||
@@ -322,5 +322,29 @@ EOS
|
||||
path = File.join(xcode_dir, 'usr/bin/TextureAtlas')
|
||||
File.exist?(path) ? path : nil
|
||||
end
|
||||
|
||||
def assets_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 = assets_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
|
||||
app_icons_asset_bundles.sort.first
|
||||
end
|
||||
|
||||
def app_icon_name_from_asset_bundle
|
||||
File.basename(app_icons_asset_bundle, '.appiconset')
|
||||
end
|
||||
end
|
||||
end; end
|
||||
|
||||
Reference in New Issue
Block a user