From 1d681f1680d88edb45ac1ef3ef09f12a1b24eb76 Mon Sep 17 00:00:00 2001 From: Mark Villacampa Date: Tue, 26 Aug 2014 20:09:56 +0200 Subject: [PATCH] Added support for extensions through the ExtensionTarget --- lib/motion/project/target.rb | 3 +- lib/motion/project/target/extension_target.rb | 159 ++++++++++++++++++ .../ios-custom-keyboard/files/Rakefile.erb | 21 ++- .../project/template/ios-extension-builder.rb | 10 +- .../project/template/ios-extension-config.rb | 11 +- .../project/template/ios-framework/config.rb | 7 +- lib/motion/project/xcode_config.rb | 2 + 7 files changed, 190 insertions(+), 23 deletions(-) create mode 100644 lib/motion/project/target/extension_target.rb diff --git a/lib/motion/project/target.rb b/lib/motion/project/target.rb index 8c5b2ee7..10a00724 100644 --- a/lib/motion/project/target.rb +++ b/lib/motion/project/target.rb @@ -23,4 +23,5 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -require 'motion/project/target/framework_target' \ No newline at end of file +require 'motion/project/target/framework_target' +require 'motion/project/target/extension_target' \ No newline at end of file diff --git a/lib/motion/project/target/extension_target.rb b/lib/motion/project/target/extension_target.rb new file mode 100644 index 00000000..8d6af25a --- /dev/null +++ b/lib/motion/project/target/extension_target.rb @@ -0,0 +1,159 @@ +# encoding: utf-8 + +# Copyright (c) 2012, HipByte SPRL and contributors +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +require 'motion/project/builder' + +module Motion; module Project + class ExtensionTarget + include Rake::DSL if Object.const_defined?(:Rake) && Rake.const_defined?(:DSL) + + attr_accessor :type + + def initialize(path, type, config, opts) + @path = path + @full_path = File.expand_path(path) + @type = type + @config = config + @opts = opts + end + + def build(platform) + @platform = platform + + command = if platform == 'iPhoneSimulator' + "build:simulator" + else + if @config.distribution_mode + "archive:distribution" + else + "build:device" + end + end + + success = system("cd #{@full_path} && bundle exec rake #{command}") + unless success + App.fail "Target '#{@path}' failed to build" + end + end + + def copy_products(platform) + src_path = src_extension_path + dest_path = dest_extension_path + FileUtils.mkdir_p(File.join(@config.app_bundle(platform), 'PlugIns')) + + extension_path = File.join(dest_path, extension_name) + + if !File.exist?(extension_path) or File.mtime(src_path) > File.mtime(extension_path) + App.info 'Copy', src_path + FileUtils.cp_r(src_path, dest_path) + + # Modify CFBundleIdentifier + extension_dir = File.join(dest_extension_path, extension_name) + info_plist = File.join(extension_dir, 'Info.plist') + extension_bundle_name = `/usr/libexec/PlistBuddy -c "print CFBundleName" #{info_plist}`.strip + extension_bundle_indentifer = "#{@config.identifier}.#{extension_bundle_name}" + `/usr/libexec/PlistBuddy -c "set CFBundleIdentifier #{extension_bundle_indentifer}" #{info_plist}` + end + end + + def codesign(platform) + extension_dir = File.join(dest_extension_path, extension_name) + + # Create bundle/ResourceRules.plist. + resource_rules_plist = File.join(extension_dir, 'ResourceRules.plist') + unless File.exist?(resource_rules_plist) + App.info 'Create', resource_rules_plist + File.open(resource_rules_plist, 'w') do |io| + io.write(<<-PLIST) + + + + + rules + + .* + + Info.plist + + omit + + weight + 10 + + ResourceRules.plist + + omit + + weight + 100 + + + + +PLIST + end + end + + # Copy the provisioning profile + bundle_provision = File.join(extension_dir, "embedded.mobileprovision") + App.info 'Create', bundle_provision + FileUtils.cp @config.provisioning_profile, bundle_provision + + # Codesign executable + codesign_cmd = "CODESIGN_ALLOCATE=\"#{File.join(@config.platform_dir(platform), 'Developer/usr/bin/codesign_allocate')}\" /usr/bin/codesign" + if File.mtime(@config.project_file) > File.mtime(extension_dir) \ + or !system("#{codesign_cmd} --verify \"#{extension_dir}\" >& /dev/null") + App.info 'Codesign', extension_dir + # TODO remove one of these + sh "#{codesign_cmd} -f -s \"#{@config.codesign_certificate}\" --resource-rules=\"#{resource_rules_plist}\" \"#{extension_dir}\"" + sh "#{codesign_cmd} -f -s \"#{@config.codesign_certificate}\" --preserve-metadata=\"identifier,entitlements,resource-rules\" \"#{extension_dir}\"" + end + end + + def clean + system("cd #{@full_path} && bundle exec rake clean") + end + + def build_dir(config, platform) + platform + '-' + config.deployment_target + '-' + config.build_mode_name + end + + def src_extension_path + @src_extension_path ||= begin + path = File.join(@path, 'build', build_dir(@config, @platform), '*.appex') + Dir[path].sort_by{ |f| File.mtime(f) }.first + end + end + + def dest_extension_path + File.join(@config.app_bundle(@platform), 'PlugIns') + end + + def extension_name + File.basename(src_extension_path) + end + + end +end;end \ No newline at end of file diff --git a/lib/motion/project/template/ios-custom-keyboard/files/Rakefile.erb b/lib/motion/project/template/ios-custom-keyboard/files/Rakefile.erb index d3737e5b..c70c1299 100644 --- a/lib/motion/project/template/ios-custom-keyboard/files/Rakefile.erb +++ b/lib/motion/project/template/ios-custom-keyboard/files/Rakefile.erb @@ -1,15 +1,24 @@ # -*- coding: utf-8 -*- +$:.unshift("/Library/RubyMotion/lib") +require 'motion/project/template/ios-extension.rb' + +begin + require 'bundler' + Bundler.require +rescue LoadError +end Motion::Project::App.setup do |app| # Use `rake config' to see complete project settings. - app.extension do |ext| - ext.name = '<%= extension_name %>' - ext.type = "keyboard-service" - ext.attributes = { + app.name = '<%= name %>' + app.info_plist['NSExtension'] = { + "NSExtensionAttributes" => { "IsASCIICapable" => false, "PrefersRightToLeft" => false, "PrimaryLanguage" => "en-US", "RequestsOpenAccess" => false - } - end + }, + "NSExtensionPointIdentifier" => "com.apple.keyboard-service", + "NSExtensionPrincipalClass" => "KeyboardViewController" + } end diff --git a/lib/motion/project/template/ios-extension-builder.rb b/lib/motion/project/template/ios-extension-builder.rb index 919f3173..6718cefd 100644 --- a/lib/motion/project/template/ios-extension-builder.rb +++ b/lib/motion/project/template/ios-extension-builder.rb @@ -404,11 +404,11 @@ EOS 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) - App.info 'Create', bundle_pkginfo - File.open(bundle_pkginfo, 'w') { |io| io.write(config.pkginfo_data) } - end + # bundle_pkginfo = File.join(bundle_path, 'PkgInfo') + # if !File.exist?(bundle_pkginfo) or File.mtime(config.project_file) > File.mtime(bundle_pkginfo) + # App.info 'Create', bundle_pkginfo + # File.open(bundle_pkginfo, 'w') { |io| io.write(config.pkginfo_data) } + # end # Compile IB resources. config.resources_dirs.each do |dir| diff --git a/lib/motion/project/template/ios-extension-config.rb b/lib/motion/project/template/ios-extension-config.rb index 1d3199a8..bcd8e098 100644 --- a/lib/motion/project/template/ios-extension-config.rb +++ b/lib/motion/project/template/ios-extension-config.rb @@ -391,7 +391,8 @@ 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)) + }.merge(generic_info_plist).merge(dt_info_plist).merge(info_plist) + .merge({ 'CFBundlePackageType' => 'XPC!' })) end def manifest_plist_data @@ -522,13 +523,11 @@ EOS RubyMotionInit(argc, argv); EOS main_txt << < 'FMWK' }) - end - def info_plist_data(platform) Motion::PropertyList.to_s({ 'MinimumOSVersion' => deployment_target, @@ -393,7 +389,8 @@ 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)) + }.merge(generic_info_plist).merge(dt_info_plist).merge(info_plist) + .merge({ 'CFBundlePackageType' => 'FMWK' })) end def manifest_plist_data diff --git a/lib/motion/project/xcode_config.rb b/lib/motion/project/xcode_config.rb index 3b197561..a4b28b14 100644 --- a/lib/motion/project/xcode_config.rb +++ b/lib/motion/project/xcode_config.rb @@ -464,6 +464,8 @@ EOS case type when :framework @targets << Motion::Project::FrameworkTarget.new(path, type, self, opts) + when :extension + @targets << Motion::Project::ExtensionTarget.new(path, type, self, opts) else App.fail("Unsupported target type '#{type}'") end