mirror of
https://github.com/zhigang1992/RubyMotion.git
synced 2026-06-13 01:29:00 +08:00
mac port
This commit is contained in:
committed by
Watson
parent
7a16c3cdf1
commit
06c18cc293
@@ -26,11 +26,15 @@ require 'motion/project/app'
|
||||
require 'motion/project/config'
|
||||
require 'motion/project/builder'
|
||||
require 'motion/project/vendor'
|
||||
require 'motion/project/template'
|
||||
require 'motion/project/plist'
|
||||
|
||||
App = Motion::Project::App
|
||||
if Motion::Project::App.template == nil
|
||||
warn "require 'lib/motion/project' is deprecated, please require 'lib/motion/project/template/ios' instead"
|
||||
require 'motion/project/template/ios'
|
||||
end
|
||||
|
||||
# Check for software updates.
|
||||
# Check for updates.
|
||||
system('/usr/bin/motion update --check')
|
||||
if $?.exitstatus == 2
|
||||
puts '=' * 80
|
||||
@@ -39,115 +43,6 @@ if $?.exitstatus == 2
|
||||
puts ''
|
||||
end
|
||||
|
||||
desc "Build the project, then run the simulator"
|
||||
task :default => :simulator
|
||||
|
||||
desc "Build everything"
|
||||
task :build => ['build:simulator', 'build:device']
|
||||
|
||||
namespace :build do
|
||||
desc "Build the simulator version"
|
||||
task :simulator do
|
||||
App.build('iPhoneSimulator')
|
||||
end
|
||||
|
||||
desc "Build the device version"
|
||||
task :device do
|
||||
App.build('iPhoneOS')
|
||||
App.codesign('iPhoneOS')
|
||||
end
|
||||
end
|
||||
|
||||
desc "Run the simulator"
|
||||
task :simulator => ['build:simulator'] do
|
||||
app = App.config.app_bundle('iPhoneSimulator')
|
||||
target = ENV['target'] || App.config.sdk_version
|
||||
|
||||
# Cleanup the simulator application sandbox, to avoid having old resource files there.
|
||||
if ENV['clean']
|
||||
sim_apps = File.expand_path("~/Library/Application Support/iPhone Simulator/#{target}/Applications")
|
||||
Dir.glob("#{sim_apps}/**/*.app").each do |app_bundle|
|
||||
if File.basename(app_bundle) == File.basename(app)
|
||||
rm_rf File.dirname(app_bundle)
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Prepare the device family.
|
||||
family_int =
|
||||
if family = ENV['device_family']
|
||||
App.config.device_family_int(family.downcase.intern)
|
||||
else
|
||||
App.config.device_family_ints[0]
|
||||
end
|
||||
retina = ENV['retina']
|
||||
|
||||
# Configure the SimulateDevice variable (the only way to specify if we want to run in retina mode or not).
|
||||
simulate_device = App.config.device_family_string(family_int, target, retina)
|
||||
default_simulator = `/usr/bin/defaults read com.apple.iphonesimulator "SimulateDevice"`.strip
|
||||
if default_simulator != simulate_device && default_simulator != "'#{simulate_device}'"
|
||||
system("/usr/bin/killall \"iPhone Simulator\" >& /dev/null")
|
||||
system("/usr/bin/defaults write com.apple.iphonesimulator \"SimulateDevice\" \"'#{simulate_device}'\"")
|
||||
end
|
||||
|
||||
# Launch the simulator.
|
||||
xcode = App.config.xcode_dir
|
||||
env = "DYLD_FRAMEWORK_PATH=\"#{xcode}/../Frameworks\":\"#{xcode}/../OtherFrameworks\""
|
||||
env << ' SIM_SPEC_MODE=1' if App.config.spec_mode
|
||||
sim = File.join(App.config.bindir, 'sim')
|
||||
debug = (ENV['debug'] ? 1 : (App.config.spec_mode ? '0' : '2'))
|
||||
App.info 'Simulate', app
|
||||
at_exit { system("stty echo") } if $stdout.tty? # Just in case the simulator launcher crashes and leaves the terminal without echo.
|
||||
sh "#{env} #{sim} #{debug} #{family_int} #{target} \"#{xcode}\" \"#{app}\""
|
||||
end
|
||||
|
||||
desc "Create an .ipa archive"
|
||||
task :archive => ['build:device'] do
|
||||
App.archive
|
||||
end
|
||||
|
||||
namespace :archive do
|
||||
desc "Create an .ipa archive for distribution (AppStore)"
|
||||
task :distribution do
|
||||
App.config_without_setup.build_mode = :release
|
||||
App.config.distribution_mode = true
|
||||
Rake::Task["build:device"].invoke
|
||||
App.archive
|
||||
end
|
||||
end
|
||||
|
||||
desc "Same as 'spec:simulator'"
|
||||
task :spec => ['spec:simulator']
|
||||
|
||||
namespace :spec do
|
||||
desc "Run the test/spec suite on the simulator"
|
||||
task :simulator do
|
||||
App.config.spec_mode = true
|
||||
Rake::Task["simulator"].invoke
|
||||
end
|
||||
|
||||
desc "Run the test/spec suite on the device"
|
||||
task :device do
|
||||
App.config.spec_mode = true
|
||||
ENV['debug'] ||= '1'
|
||||
Rake::Task["device"].invoke
|
||||
end
|
||||
end
|
||||
|
||||
desc "Deploy on the device"
|
||||
task :device => :archive do
|
||||
App.info 'Deploy', App.config.archive
|
||||
device_id = (ENV['id'] or App.config.device_id)
|
||||
unless App.config.provisioned_devices.include?(device_id)
|
||||
App.fail "Device ID `#{device_id}' not provisioned in profile `#{App.config.provisioning_profile}'"
|
||||
end
|
||||
env = "XCODE_DIR=\"#{App.config.xcode_dir}\""
|
||||
deploy = File.join(App.config.bindir, 'deploy')
|
||||
flags = Rake.application.options.trace ? '-d' : ''
|
||||
sh "#{env} #{deploy} #{flags} \"#{device_id}\" \"#{App.config.archive}\""
|
||||
end
|
||||
|
||||
desc "Clear build objects"
|
||||
task :clean do
|
||||
App.info 'Delete', App.config.build_dir
|
||||
@@ -166,44 +61,3 @@ task :config do
|
||||
puts key.ljust(22) + " : #{map[key].inspect}"
|
||||
end
|
||||
end
|
||||
|
||||
desc "Generate ctags"
|
||||
task :ctags do
|
||||
tags_file = 'tags'
|
||||
config = App.config
|
||||
if !File.exist?(tags_file) or File.mtime(config.project_file) > File.mtime(tags_file)
|
||||
bs_files = config.bridgesupport_files + config.vendor_projects.map { |p| Dir.glob(File.join(p.path, '*.bridgesupport')) }.flatten
|
||||
ctags = File.join(config.bindir, 'ctags')
|
||||
config = File.join(config.motiondir, 'data', 'bridgesupport-ctags.cfg')
|
||||
sh "#{ctags} --options=\"#{config}\" #{bs_files.map { |x| '"' + x + '"' }.join(' ')}"
|
||||
end
|
||||
end
|
||||
|
||||
desc "Create a .a static library"
|
||||
task :static do
|
||||
libs = %w{iPhoneSimulator iPhoneOS}.map do |platform|
|
||||
'"' + App.build(platform, :static => true) + '"'
|
||||
end
|
||||
fat_lib = File.join(App.config.build_dir, App.config.name + '-universal.a')
|
||||
App.info 'Create', fat_lib
|
||||
sh "/usr/bin/lipo -create #{libs.join(' ')} -output \"#{fat_lib}\""
|
||||
end
|
||||
|
||||
=begin
|
||||
# Automatically load project extensions. A project extension is a gem whose
|
||||
# name starts with `motion-' and which exposes a `lib/motion/project' libdir.
|
||||
require 'rubygems'
|
||||
Gem.path.each do |gemdir|
|
||||
Dir.glob(File.join(gemdir, 'gems', '*')).each do |gempath|
|
||||
base = File.basename(gempath)
|
||||
if md = base.match(/^(motion-.*)-((\d+\.)*\d+)/) and File.exist?(File.join(gempath, 'lib', 'motion', 'project'))
|
||||
ext_name = md[1]
|
||||
begin
|
||||
require ext_name
|
||||
rescue LoadError => e
|
||||
$stderr.puts "Can't autoload extension `#{ext_name}': #{e.message}"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
=end
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
# (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 'erb'
|
||||
require 'motion/project/template'
|
||||
|
||||
module Motion; module Project
|
||||
class App
|
||||
@@ -38,6 +38,8 @@ module Motion; module Project
|
||||
end
|
||||
|
||||
class << self
|
||||
attr_accessor :template
|
||||
|
||||
def config_mode
|
||||
@config_mode ||= begin
|
||||
if mode = ENV['mode']
|
||||
@@ -55,7 +57,7 @@ module Motion; module Project
|
||||
|
||||
def config_without_setup
|
||||
@configs ||= {}
|
||||
@configs[config_mode] ||= Motion::Project::Config.new('.', config_mode)
|
||||
@configs[config_mode] ||= Motion::Project::Config.make(@template, '.', config_mode)
|
||||
end
|
||||
|
||||
def config
|
||||
@@ -82,8 +84,8 @@ module Motion; module Project
|
||||
builder.codesign(config, platform)
|
||||
end
|
||||
|
||||
def create(app_name, template_name="ios")
|
||||
Template.new(app_name, template_name).generate
|
||||
def create(app_name, template_name=:ios)
|
||||
Motion::Project::Template.new(app_name, template_name).generate
|
||||
end
|
||||
|
||||
def log(what, msg)
|
||||
@@ -109,75 +111,5 @@ module Motion; module Project
|
||||
log what, msg unless VERBOSE
|
||||
end
|
||||
end
|
||||
|
||||
class Template
|
||||
# for ERB
|
||||
attr_reader :name
|
||||
|
||||
def initialize(app_name, template_name)
|
||||
@name = @app_name = app_name
|
||||
@template_name = template_name
|
||||
@template_directory = File.expand_path(File.join(__FILE__, "../template/#{@template_name}"))
|
||||
|
||||
unless app_name.match(/^[\w\s-]+$/)
|
||||
fail "Invalid app name"
|
||||
end
|
||||
|
||||
if File.exist?(app_name)
|
||||
fail "Directory `#{app_name}' already exists"
|
||||
end
|
||||
|
||||
unless File.exist?(@template_directory)
|
||||
fail "Invalid template name"
|
||||
end
|
||||
end
|
||||
|
||||
def generate
|
||||
App.log 'Create', @app_name
|
||||
FileUtils.mkdir(@app_name)
|
||||
|
||||
Dir.chdir(@app_name) do
|
||||
create_directories()
|
||||
create_files()
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def template_directory
|
||||
@template_directory
|
||||
end
|
||||
|
||||
def create_directories
|
||||
Dir.glob(File.join(template_directory, "**/")).each do |dir|
|
||||
dir.sub!("#{template_directory}/", '')
|
||||
FileUtils.mkdir_p(dir) if dir.length > 0
|
||||
end
|
||||
end
|
||||
|
||||
def create_files
|
||||
Dir.glob(File.join(template_directory, "**/*"), File::FNM_DOTMATCH).each do |src|
|
||||
dest = src.sub("#{template_directory}/", '')
|
||||
next if File.directory?(src)
|
||||
next if dest.include?(".DS_Store")
|
||||
|
||||
dest = replace_file_name(dest)
|
||||
if dest =~ /(.+)\.erb$/
|
||||
App.log 'Create', "#{@app_name}/#{$1}"
|
||||
File.open($1, "w") { |io|
|
||||
io.print ERB.new(File.read(src)).result(binding)
|
||||
}
|
||||
else
|
||||
App.log 'Create', "#{@app_name}/#{dest}"
|
||||
FileUtils.cp(src, dest)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def replace_file_name(file_name)
|
||||
file_name = file_name.sub("{name}", "#{@name}")
|
||||
file_name
|
||||
end
|
||||
end
|
||||
end
|
||||
end; end
|
||||
|
||||
@@ -88,7 +88,7 @@ module Motion; module Project;
|
||||
# LLVM bitcode.
|
||||
bc = File.join(objs_build_dir, "#{path}.#{arch}.bc")
|
||||
bs_flags = bs_files.map { |x| "--uses-bs \"" + x + "\" " }.join(' ')
|
||||
sh "/usr/bin/env VM_KERNEL_PATH=\"#{kernel}\" VM_OPT_LEVEL=\"#{config.opt_level}\" #{ruby} #{bs_flags} --emit-llvm \"#{bc}\" #{init_func} \"#{path}\""
|
||||
sh "/usr/bin/env VM_KERNEL_PATH=\"#{kernel}\" VM_OPT_LEVEL=\"#{config.opt_level}\" /usr/bin/arch -arch #{arch} #{ruby} #{bs_flags} --emit-llvm \"#{bc}\" #{init_func} \"#{path}\""
|
||||
|
||||
# Assembly.
|
||||
asm = File.join(objs_build_dir, "#{path}.#{arch}.s")
|
||||
@@ -180,8 +180,6 @@ module Motion; module Project;
|
||||
|
||||
# Generate init file.
|
||||
init_txt = <<EOS
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
extern "C" {
|
||||
void ruby_sysinit(int *, char ***);
|
||||
void ruby_init(void);
|
||||
@@ -213,17 +211,21 @@ RubyMotionInit(int argc, char **argv)
|
||||
const char *progname = argv[0];
|
||||
ruby_script(progname);
|
||||
}
|
||||
#if !__LP64__
|
||||
try {
|
||||
#endif
|
||||
void *self = rb_vm_top_self();
|
||||
EOS
|
||||
app_objs.each do |_, init_func|
|
||||
init_txt << "#{init_func}(self, 0);\n"
|
||||
end
|
||||
init_txt << <<EOS
|
||||
#if !__LP64__
|
||||
}
|
||||
catch (...) {
|
||||
rb_rb2oc_exc_handler();
|
||||
}
|
||||
#endif
|
||||
initialized = true;
|
||||
}
|
||||
}
|
||||
@@ -248,112 +250,7 @@ EOS
|
||||
end
|
||||
|
||||
# Generate main file.
|
||||
main_txt = <<EOS
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
extern "C" {
|
||||
void rb_define_global_const(const char *, void *);
|
||||
void rb_rb2oc_exc_handler(void);
|
||||
void rb_exit(int);
|
||||
void RubyMotionInit(int argc, char **argv);
|
||||
EOS
|
||||
if config.spec_mode
|
||||
spec_objs.each do |_, init_func|
|
||||
main_txt << "void #{init_func}(void *, void *);\n"
|
||||
end
|
||||
end
|
||||
main_txt << <<EOS
|
||||
}
|
||||
EOS
|
||||
|
||||
if config.spec_mode
|
||||
main_txt << <<EOS
|
||||
@interface SpecLauncher : NSObject
|
||||
@end
|
||||
|
||||
#include <dlfcn.h>
|
||||
|
||||
@implementation SpecLauncher
|
||||
|
||||
+ (id)launcher
|
||||
{
|
||||
[UIApplication sharedApplication];
|
||||
|
||||
// Enable simulator accessibility.
|
||||
// Thanks http://www.stewgleadow.com/blog/2011/10/14/enabling-accessibility-for-ios-applications/
|
||||
NSString *simulatorRoot = [[[NSProcessInfo processInfo] environment] objectForKey:@"IPHONE_SIMULATOR_ROOT"];
|
||||
if (simulatorRoot != nil) {
|
||||
void *appSupportLibrary = dlopen([[simulatorRoot stringByAppendingPathComponent:@"/System/Library/PrivateFrameworks/AppSupport.framework/AppSupport"] fileSystemRepresentation], RTLD_LAZY);
|
||||
CFStringRef (*copySharedResourcesPreferencesDomainForDomain)(CFStringRef domain) = (CFStringRef (*)(CFStringRef)) dlsym(appSupportLibrary, "CPCopySharedResourcesPreferencesDomainForDomain");
|
||||
|
||||
if (copySharedResourcesPreferencesDomainForDomain != NULL) {
|
||||
CFStringRef accessibilityDomain = copySharedResourcesPreferencesDomainForDomain(CFSTR("com.apple.Accessibility"));
|
||||
|
||||
if (accessibilityDomain != NULL) {
|
||||
CFPreferencesSetValue(CFSTR("ApplicationAccessibilityEnabled"), kCFBooleanTrue, accessibilityDomain, kCFPreferencesAnyUser, kCFPreferencesAnyHost);
|
||||
CFRelease(accessibilityDomain);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Load the UIAutomation framework.
|
||||
dlopen("/Developer/Library/PrivateFrameworks/UIAutomation.framework/UIAutomation", RTLD_LOCAL);
|
||||
|
||||
SpecLauncher *launcher = [[self alloc] init];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:launcher selector:@selector(appLaunched:) name:UIApplicationDidBecomeActiveNotification object:nil];
|
||||
return launcher;
|
||||
}
|
||||
|
||||
- (void)appLaunched:(id)notification
|
||||
{
|
||||
// Give a bit of time for the simulator to attach...
|
||||
[self performSelector:@selector(runSpecs) withObject:nil afterDelay:0.3];
|
||||
}
|
||||
|
||||
- (void)runSpecs
|
||||
{
|
||||
EOS
|
||||
spec_objs.each do |_, init_func|
|
||||
main_txt << "#{init_func}(self, 0);\n"
|
||||
end
|
||||
main_txt << "[NSClassFromString(@\"Bacon\") performSelector:@selector(run)];\n"
|
||||
main_txt << <<EOS
|
||||
}
|
||||
|
||||
@end
|
||||
EOS
|
||||
end
|
||||
main_txt << <<EOS
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
||||
int retval = 0;
|
||||
try {
|
||||
EOS
|
||||
main_txt << "[SpecLauncher launcher];\n" if config.spec_mode
|
||||
main_txt << <<EOS
|
||||
RubyMotionInit(argc, argv);
|
||||
EOS
|
||||
rubymotion_env =
|
||||
if config.spec_mode
|
||||
'test'
|
||||
else
|
||||
config.development? ? 'development' : 'release'
|
||||
end
|
||||
main_txt << "rb_define_global_const(\"RUBYMOTION_ENV\", @\"#{rubymotion_env}\");\n"
|
||||
main_txt << "rb_define_global_const(\"RUBYMOTION_VERSION\", @\"#{Motion::Version}\");\n"
|
||||
main_txt << <<EOS
|
||||
retval = UIApplicationMain(argc, argv, nil, @"#{config.delegate_class}");
|
||||
rb_exit(retval);
|
||||
}
|
||||
catch (...) {
|
||||
rb_rb2oc_exc_handler();
|
||||
}
|
||||
[pool release];
|
||||
return retval;
|
||||
}
|
||||
EOS
|
||||
main_txt = config.main_cpp_file_txt(spec_objs)
|
||||
|
||||
# Compile main file.
|
||||
main = File.join(objs_build_dir, 'main.mm')
|
||||
@@ -372,6 +269,10 @@ EOS
|
||||
|
||||
# Link executable.
|
||||
main_exec = config.app_bundle_executable(platform)
|
||||
unless File.exist?(File.dirname(main_exec))
|
||||
App.info 'Create', File.dirname(main_exec)
|
||||
FileUtils.mkdir_p(File.dirname(main_exec))
|
||||
end
|
||||
main_exec_created = false
|
||||
if !File.exist?(main_exec) \
|
||||
or File.mtime(config.project_file) > File.mtime(main_exec) \
|
||||
@@ -439,6 +340,7 @@ EOS
|
||||
end
|
||||
|
||||
# Copy resources, handle subdirectories.
|
||||
app_resources_dir = config.app_resources_dir(platform)
|
||||
reserved_app_bundle_files = [
|
||||
'_CodeSignature/CodeResources', 'CodeResources', 'embedded.mobileprovision',
|
||||
'Info.plist', 'PkgInfo', 'ResourceRules.plist',
|
||||
@@ -458,7 +360,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(bundle_path, res)
|
||||
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
|
||||
@@ -468,7 +370,7 @@ EOS
|
||||
|
||||
# Delete old resource files.
|
||||
resources_files = resources_paths.map { |x| path_on_resources_dirs(config.resources_dirs, x) }
|
||||
Dir.chdir(bundle_path) do
|
||||
Dir.chdir(app_resources_dir) do
|
||||
Dir.glob('*').each do |bundle_res|
|
||||
bundle_res = convert_filesystem_encoding(bundle_res)
|
||||
next if File.directory?(bundle_res)
|
||||
|
||||
@@ -47,44 +47,39 @@ module Motion; module Project
|
||||
end
|
||||
end
|
||||
|
||||
variable :files, :xcode_dir, :sdk_version, :deployment_target, :frameworks,
|
||||
:weak_frameworks, :framework_search_paths, :libs, :delegate_class, :name, :build_dir,
|
||||
:resources_dirs, :specs_dir, :identifier, :codesign_certificate,
|
||||
:provisioning_profile, :device_family, :interface_orientations, :version,
|
||||
:short_version, :icons, :prerendered_icon, :background_modes, :seed_id,
|
||||
:entitlements, :fonts, :status_bar_style, :motiondir, :detect_dependencies
|
||||
variable :name, :files, :build_dir, :specs_dir, :version, :motiondir
|
||||
|
||||
# Internal only.
|
||||
attr_accessor :build_mode, :spec_mode, :distribution_mode, :dependencies
|
||||
attr_accessor :build_mode, :spec_mode, :distribution_mode, :dependencies,
|
||||
:template, :detect_dependencies
|
||||
|
||||
ConfigTemplates = {}
|
||||
|
||||
def self.register(template)
|
||||
ConfigTemplates[template] = self
|
||||
end
|
||||
|
||||
def self.make(template, project_dir, build_mode)
|
||||
klass = ConfigTemplates[template]
|
||||
unless klass
|
||||
$stderr.puts "Config template `#{template}' not registered"
|
||||
exit 1
|
||||
end
|
||||
config = klass.new(project_dir, build_mode)
|
||||
config.template = template
|
||||
config
|
||||
end
|
||||
|
||||
def initialize(project_dir, build_mode)
|
||||
@project_dir = project_dir
|
||||
@files = Dir.glob(File.join(project_dir, 'app/**/*.rb'))
|
||||
@info_plist = {}
|
||||
@dependencies = {}
|
||||
@detect_dependencies = true
|
||||
@frameworks = ['UIKit', 'Foundation', 'CoreGraphics']
|
||||
@weak_frameworks = []
|
||||
@framework_search_paths = []
|
||||
@libs = []
|
||||
@delegate_class = 'AppDelegate'
|
||||
@build_mode = build_mode
|
||||
@name = 'Untitled'
|
||||
@resources_dirs = [File.join(project_dir, 'resources')]
|
||||
@build_dir = File.join(project_dir, 'build')
|
||||
@specs_dir = File.join(project_dir, 'spec')
|
||||
@device_family = :iphone
|
||||
@bundle_signature = '????'
|
||||
@interface_orientations = [:portrait, :landscape_left, :landscape_right]
|
||||
@version = '1.0'
|
||||
@short_version = '1'
|
||||
@status_bar_style = :default
|
||||
@background_modes = []
|
||||
@icons = []
|
||||
@prerendered_icon = false
|
||||
@vendor_projects = []
|
||||
@entitlements = {}
|
||||
@spec_mode = false
|
||||
@build_mode = build_mode
|
||||
@detect_dependencies = true
|
||||
end
|
||||
|
||||
OSX_VERSION = `/usr/bin/sw_vers -productVersion`.strip.sub(/\.\d+$/, '').to_f
|
||||
@@ -115,40 +110,6 @@ module Motion; module Project
|
||||
self
|
||||
end
|
||||
|
||||
def xcode_dir
|
||||
@xcode_dir ||= begin
|
||||
xcode_dot_app_path = '/Applications/Xcode.app/Contents/Developer'
|
||||
|
||||
# First, honor /usr/bin/xcode-select
|
||||
xcodeselect = '/usr/bin/xcode-select'
|
||||
if File.exist?(xcodeselect)
|
||||
path = `#{xcodeselect} -print-path`.strip
|
||||
if path.match(/^\/Developer\//) and File.exist?(xcode_dot_app_path)
|
||||
@xcode_error_printed ||= false
|
||||
$stderr.puts(<<EOS) unless @xcode_error_printed
|
||||
===============================================================================
|
||||
It appears that you have a version of Xcode installed in /Applications that has
|
||||
not been set as the default version. It is possible that RubyMotion may be
|
||||
using old versions of certain tools which could eventually cause issues.
|
||||
|
||||
To fix this problem, you can type the following command in the terminal:
|
||||
$ sudo xcode-select -switch /Applications/Xcode.app/Contents/Developer
|
||||
===============================================================================
|
||||
EOS
|
||||
@xcode_error_printed = true
|
||||
end
|
||||
return path if File.exist?(path)
|
||||
end
|
||||
|
||||
# Since xcode-select is borked, we assume the user installed Xcode
|
||||
# as an app (new in Xcode 4.3).
|
||||
return xcode_dot_app_path if File.exist?(xcode_dot_app_path)
|
||||
|
||||
App.fail "Can't locate any version of Xcode on the system."
|
||||
end
|
||||
unescape_path(@xcode_dir)
|
||||
end
|
||||
|
||||
def unescape_path(path)
|
||||
path.gsub('\\', '')
|
||||
end
|
||||
@@ -165,44 +126,12 @@ EOS
|
||||
App.fail "Can't locate binary `#{name}' on the system."
|
||||
end
|
||||
|
||||
def xcode_version
|
||||
@xcode_version ||= begin
|
||||
txt = `#{locate_binary('xcodebuild')} -version`
|
||||
vers = txt.scan(/Xcode\s(.+)/)[0][0]
|
||||
build = txt.scan(/Build version\s(.+)/)[0][0]
|
||||
[vers, build]
|
||||
end
|
||||
end
|
||||
|
||||
def validate
|
||||
# Xcode version
|
||||
App.fail "Xcode 4.x or greater is required" if xcode_version[0] < '4.0'
|
||||
|
||||
# sdk_version
|
||||
['iPhoneSimulator', 'iPhoneOS'].each do |platform|
|
||||
sdk_path = File.join(platforms_dir, platform + '.platform',
|
||||
"Developer/SDKs/#{platform}#{sdk_version}.sdk")
|
||||
unless File.exist?(sdk_path)
|
||||
App.fail "Can't locate #{platform} SDK #{sdk_version} at `#{sdk_path}'"
|
||||
end
|
||||
end
|
||||
|
||||
# deployment_target
|
||||
if deployment_target > sdk_version
|
||||
App.fail "Deployment target `#{deployment_target}' must be equal or lesser than SDK version `#{sdk_version}'"
|
||||
end
|
||||
unless File.exist?(datadir)
|
||||
App.fail "iOS deployment target #{deployment_target} is not supported by this version of RubyMotion"
|
||||
end
|
||||
|
||||
# icons
|
||||
if !(icons.is_a?(Array) and icons.all? { |x| x.is_a?(String) })
|
||||
App.fail "app.icons should be an array of strings."
|
||||
end
|
||||
# Do nothing, for now.
|
||||
end
|
||||
|
||||
def supported_versions
|
||||
@supported_versions ||= Dir.glob(File.join(motiondir, 'data/*')).select{|path| File.directory?(path)}.map do |path|
|
||||
@supported_versions ||= Dir.glob(File.join(motiondir, 'data', template.to_s, '*')).select{|path| File.directory?(path)}.map do |path|
|
||||
File.basename path
|
||||
end
|
||||
end
|
||||
@@ -316,58 +245,6 @@ EOS
|
||||
end
|
||||
end
|
||||
|
||||
def frameworks_dependencies
|
||||
@frameworks_dependencies ||= begin
|
||||
# Compute the list of frameworks, including dependencies, that the project uses.
|
||||
deps = frameworks.dup.uniq
|
||||
slf = File.join(sdk('iPhoneSimulator'), 'System', 'Library', 'Frameworks')
|
||||
deps.each do |framework|
|
||||
framework_path = File.join(slf, framework + '.framework', framework)
|
||||
if File.exist?(framework_path)
|
||||
`#{locate_binary('otool')} -L \"#{framework_path}\"`.scan(/\t([^\s]+)\s\(/).each do |dep|
|
||||
# Only care about public, non-umbrella frameworks (for now).
|
||||
if md = dep[0].match(/^\/System\/Library\/Frameworks\/(.+)\.framework\/(.+)$/) and md[1] == md[2]
|
||||
deps << md[1]
|
||||
deps.uniq!
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if @framework_search_paths.empty?
|
||||
deps = deps.select { |dep| File.exist?(File.join(datadir, 'BridgeSupport', dep + '.bridgesupport')) }
|
||||
end
|
||||
deps
|
||||
end
|
||||
end
|
||||
|
||||
def frameworks_stubs_objects(platform)
|
||||
stubs = []
|
||||
(frameworks_dependencies + weak_frameworks).uniq.each do |framework|
|
||||
stubs_obj = File.join(datadir, platform, "#{framework}_stubs.o")
|
||||
stubs << stubs_obj if File.exist?(stubs_obj)
|
||||
end
|
||||
stubs
|
||||
end
|
||||
|
||||
def bridgesupport_files
|
||||
@bridgesupport_files ||= begin
|
||||
bs_files = []
|
||||
deps = ['RubyMotion'] + (frameworks_dependencies + weak_frameworks).uniq
|
||||
deps << 'UIAutomation' if spec_mode
|
||||
deps.each do |framework|
|
||||
supported_versions.each do |ver|
|
||||
next if ver < deployment_target || sdk_version < ver
|
||||
bs_path = File.join(datadir(ver), 'BridgeSupport', framework + '.bridgesupport')
|
||||
if File.exist?(bs_path)
|
||||
bs_files << bs_path
|
||||
end
|
||||
end
|
||||
end
|
||||
bs_files
|
||||
end
|
||||
end
|
||||
|
||||
def spec_core_files
|
||||
@spec_core_files ||= begin
|
||||
# Core library + core helpers.
|
||||
@@ -400,345 +277,7 @@ EOS
|
||||
end
|
||||
|
||||
def datadir(target=deployment_target)
|
||||
File.join(motiondir, 'data', target)
|
||||
end
|
||||
|
||||
def platforms_dir
|
||||
File.join(xcode_dir, 'Platforms')
|
||||
end
|
||||
|
||||
def platform_dir(platform)
|
||||
File.join(platforms_dir, platform + '.platform')
|
||||
end
|
||||
|
||||
def sdk_version
|
||||
@sdk_version ||= begin
|
||||
versions = Dir.glob(File.join(platforms_dir, 'iPhoneOS.platform/Developer/SDKs/iPhoneOS*.sdk')).map do |path|
|
||||
File.basename(path).scan(/iPhoneOS(.*)\.sdk/)[0][0]
|
||||
end
|
||||
if versions.size == 0
|
||||
App.fail "Can't find an iOS SDK in `#{platforms_dir}'"
|
||||
end
|
||||
supported_vers = versions.reverse.find { |vers| File.exist?(datadir(vers)) }
|
||||
unless supported_vers
|
||||
App.fail "RubyMotion doesn't support any of these SDK versions: #{versions.join(', ')}"
|
||||
end
|
||||
supported_vers
|
||||
end
|
||||
end
|
||||
|
||||
def deployment_target
|
||||
@deployment_target ||= sdk_version
|
||||
end
|
||||
|
||||
def sdk(platform)
|
||||
path = File.join(platform_dir(platform), 'Developer/SDKs',
|
||||
platform + sdk_version + '.sdk')
|
||||
escape_path(path)
|
||||
end
|
||||
|
||||
def locate_compiler(platform, *execs)
|
||||
paths = [File.join(platform_dir(platform), 'Developer/usr/bin')]
|
||||
paths.unshift File.join(xcode_dir, 'Toolchains/XcodeDefault.xctoolchain/usr/bin')
|
||||
|
||||
execs.each do |exec|
|
||||
paths.each do |path|
|
||||
cc = File.join(path, exec)
|
||||
return escape_path(cc) if File.exist?(cc)
|
||||
end
|
||||
end
|
||||
App.fail "Can't locate compilers for platform `#{platform}'"
|
||||
end
|
||||
|
||||
def archs
|
||||
@archs ||= begin
|
||||
h = {}
|
||||
%w{iPhoneSimulator iPhoneOS}.each do |platform|
|
||||
h[platform] = Dir.glob(File.join(datadir, platform, '*.bc')).map do |path|
|
||||
path.scan(/kernel-(.+).bc$/)[0][0]
|
||||
end
|
||||
end
|
||||
h
|
||||
end
|
||||
end
|
||||
|
||||
def arch_flags(platform)
|
||||
archs[platform].map { |x| "-arch #{x}" }.join(' ')
|
||||
end
|
||||
|
||||
def common_flags(platform)
|
||||
"#{arch_flags(platform)} -isysroot \"#{unescape_path(sdk(platform))}\" -miphoneos-version-min=#{deployment_target} -F#{sdk(platform)}/System/Library/Frameworks"
|
||||
end
|
||||
|
||||
def cflags(platform, cplusplus)
|
||||
"#{common_flags(platform)} -fexceptions -fblocks -fobjc-legacy-dispatch -fobjc-abi-version=2" + (cplusplus ? '' : ' -std=c99')
|
||||
end
|
||||
|
||||
def ldflags(platform)
|
||||
ldflags = common_flags(platform)
|
||||
ldflags << " -fobjc-arc" if deployment_target < '5.0'
|
||||
ldflags
|
||||
end
|
||||
|
||||
def bundle_name
|
||||
@name + (spec_mode ? '_spec' : '')
|
||||
end
|
||||
|
||||
def app_bundle(platform)
|
||||
File.join(versionized_build_dir(platform), bundle_name + '.app')
|
||||
end
|
||||
|
||||
def app_bundle_dsym(platform)
|
||||
File.join(versionized_build_dir(platform), bundle_name + '.dSYM')
|
||||
end
|
||||
|
||||
def app_bundle_executable(platform)
|
||||
File.join(app_bundle(platform), name)
|
||||
end
|
||||
|
||||
def archive
|
||||
File.join(versionized_build_dir('iPhoneOS'), bundle_name + '.ipa')
|
||||
end
|
||||
|
||||
def identifier
|
||||
@identifier ||= "com.yourcompany.#{@name.gsub(/\s/, '')}"
|
||||
spec_mode ? @identifier + '_spec' : @identifier
|
||||
end
|
||||
|
||||
def device_family_int(family)
|
||||
case family
|
||||
when :iphone then 1
|
||||
when :ipad then 2
|
||||
else
|
||||
App.fail "Unknown device_family value: `#{family}'"
|
||||
end
|
||||
end
|
||||
|
||||
def device_family_string(family, target, retina)
|
||||
device = case family
|
||||
when :iphone, 1
|
||||
"iPhone"
|
||||
when :ipad, 2
|
||||
"iPad"
|
||||
end
|
||||
case retina
|
||||
when 'true'
|
||||
device + ((family == 1 and target >= '6.0') ? ' (Retina 4-inch)' : ' (Retina)')
|
||||
when '3.5'
|
||||
device + ' (Retina 3.5-inch)'
|
||||
when '4'
|
||||
device + ' (Retina 4-inch)'
|
||||
else
|
||||
device
|
||||
end
|
||||
end
|
||||
|
||||
def device_family_ints
|
||||
ary = @device_family.is_a?(Array) ? @device_family : [@device_family]
|
||||
ary.map { |family| device_family_int(family) }
|
||||
end
|
||||
|
||||
def interface_orientations_consts
|
||||
@interface_orientations.map do |ori|
|
||||
case ori
|
||||
when :portrait then 'UIInterfaceOrientationPortrait'
|
||||
when :landscape_left then 'UIInterfaceOrientationLandscapeLeft'
|
||||
when :landscape_right then 'UIInterfaceOrientationLandscapeRight'
|
||||
when :portrait_upside_down then 'UIInterfaceOrientationPortraitUpsideDown'
|
||||
else
|
||||
App.fail "Unknown interface_orientation value: `#{ori}'"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def background_modes_consts
|
||||
@background_modes.map do |mode|
|
||||
case mode
|
||||
when :audio then 'audio'
|
||||
when :location then 'location'
|
||||
when :voip then 'voip'
|
||||
when :newsstand_content then 'newsstand-content'
|
||||
when :external_accessory then 'external-accessory'
|
||||
when :bluetooth_central then 'bluetooth-central'
|
||||
else
|
||||
App.fail "Unknown background_modes value: `#{mode}'"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def status_bar_style_const
|
||||
case @status_bar_style
|
||||
when :default then 'UIStatusBarStyleDefault'
|
||||
when :black_translucent then 'UIStatusBarStyleBlackTranslucent'
|
||||
when :black_opaque then 'UIStatusBarStyleBlackOpaque'
|
||||
else
|
||||
App.fail "Unknown status_bar_style value: `#{@status_bar_style}'"
|
||||
end
|
||||
end
|
||||
|
||||
def info_plist
|
||||
@info_plist
|
||||
end
|
||||
|
||||
def dt_info_plist
|
||||
{
|
||||
}
|
||||
end
|
||||
|
||||
def info_plist_data
|
||||
ios_version_to_build = lambda do |vers|
|
||||
# XXX we should retrieve these values programmatically.
|
||||
case vers
|
||||
when '4.3'; '8F191m'
|
||||
when '5.0'; '9A334'
|
||||
when '5.1'; '9B176'
|
||||
else; '10A403' # 6.0 or later
|
||||
end
|
||||
end
|
||||
Motion::PropertyList.to_s({
|
||||
'BuildMachineOSBuild' => `sw_vers -buildVersion`.strip,
|
||||
'MinimumOSVersion' => deployment_target,
|
||||
'CFBundleDevelopmentRegion' => 'en',
|
||||
'CFBundleName' => @name,
|
||||
'CFBundleDisplayName' => @name,
|
||||
'CFBundleExecutable' => @name,
|
||||
'CFBundleIdentifier' => identifier,
|
||||
'CFBundleInfoDictionaryVersion' => '6.0',
|
||||
'CFBundlePackageType' => 'APPL',
|
||||
'CFBundleResourceSpecification' => 'ResourceRules.plist',
|
||||
'CFBundleShortVersionString' => @short_version,
|
||||
'CFBundleSignature' => @bundle_signature,
|
||||
'CFBundleSupportedPlatforms' => ['iPhoneOS'],
|
||||
'CFBundleVersion' => @version,
|
||||
'CFBundleIconFiles' => icons,
|
||||
'CFBundleIcons' => {
|
||||
'CFBundlePrimaryIcon' => {
|
||||
'CFBundleIconFiles' => icons,
|
||||
'UIPrerenderedIcon' => prerendered_icon,
|
||||
}
|
||||
},
|
||||
'UIAppFonts' => fonts,
|
||||
'UIDeviceFamily' => device_family_ints.map { |x| x.to_s },
|
||||
'UISupportedInterfaceOrientations' => interface_orientations_consts,
|
||||
'UIStatusBarStyle' => status_bar_style_const,
|
||||
'UIBackgroundModes' => background_modes_consts,
|
||||
'DTXcode' => begin
|
||||
vers = xcode_version[0].gsub(/\./, '')
|
||||
if vers.length == 2
|
||||
'0' + vers + '0'
|
||||
else
|
||||
'0' + vers
|
||||
end
|
||||
end,
|
||||
'DTXcodeBuild' => xcode_version[1],
|
||||
'DTSDKName' => "iphoneos#{sdk_version}",
|
||||
'DTSDKBuild' => ios_version_to_build.call(sdk_version),
|
||||
'DTPlatformName' => 'iphoneos',
|
||||
'DTCompiler' => 'com.apple.compilers.llvm.clang.1_0',
|
||||
'DTPlatformVersion' => sdk_version,
|
||||
'DTPlatformBuild' => ios_version_to_build.call(sdk_version)
|
||||
}.merge(dt_info_plist).merge(info_plist))
|
||||
end
|
||||
|
||||
def pkginfo_data
|
||||
"AAPL#{@bundle_signature}"
|
||||
end
|
||||
|
||||
def codesign_certificate
|
||||
@codesign_certificate ||= begin
|
||||
cert_type = (distribution_mode ? 'Distribution' : 'Developer')
|
||||
certs = `/usr/bin/security -q find-certificate -a`.scan(/"iPhone #{cert_type}: [^"]+"/).uniq
|
||||
if certs.size == 0
|
||||
App.fail "Can't find an iPhone Developer certificate in the keychain"
|
||||
elsif certs.size > 1
|
||||
App.warn "Found #{certs.size} iPhone Developer certificates in the keychain. Set the `codesign_certificate' project setting. Will use the first certificate: `#{certs[0]}'"
|
||||
end
|
||||
certs[0][1..-2] # trim trailing `"` characters
|
||||
end
|
||||
end
|
||||
|
||||
def device_id
|
||||
@device_id ||= begin
|
||||
deploy = File.join(App.config.bindir, 'deploy')
|
||||
device_id = `#{deploy} -D`.strip
|
||||
if device_id.empty?
|
||||
App.fail "Can't find an iOS device connected on USB"
|
||||
end
|
||||
device_id
|
||||
end
|
||||
end
|
||||
|
||||
def provisioning_profile(name = /iOS Team Provisioning Profile/)
|
||||
@provisioning_profile ||= begin
|
||||
paths = Dir.glob(File.expand_path("~/Library/MobileDevice/Provisioning\ Profiles/*.mobileprovision")).select do |path|
|
||||
text = File.read(path)
|
||||
text.force_encoding('binary') if RUBY_VERSION >= '1.9.0'
|
||||
text.scan(/<key>\s*Name\s*<\/key>\s*<string>\s*([^<]+)\s*<\/string>/)[0][0].match(name)
|
||||
end
|
||||
if paths.size == 0
|
||||
App.fail "Can't find a provisioning profile named `#{name}'"
|
||||
elsif paths.size > 1
|
||||
App.warn "Found #{paths.size} provisioning profiles named `#{name}'. Set the `provisioning_profile' project setting. Will use the first one: `#{paths[0]}'"
|
||||
end
|
||||
paths[0]
|
||||
end
|
||||
end
|
||||
|
||||
def read_provisioned_profile_array(key)
|
||||
text = File.read(provisioning_profile)
|
||||
text.force_encoding('binary') if RUBY_VERSION >= '1.9.0'
|
||||
text.scan(/<key>\s*#{key}\s*<\/key>\s*<array>(.*?)\s*<\/array>/m)[0][0].scan(/<string>(.*?)<\/string>/).map { |str| str[0].strip }
|
||||
end
|
||||
private :read_provisioned_profile_array
|
||||
|
||||
def provisioned_devices
|
||||
@provisioned_devices ||= read_provisioned_profile_array('ProvisionedDevices')
|
||||
end
|
||||
|
||||
def seed_id
|
||||
@seed_id ||= begin
|
||||
seed_ids = read_provisioned_profile_array('ApplicationIdentifierPrefix')
|
||||
if seed_ids.size == 0
|
||||
App.fail "Can't find an application seed ID in the provisioning profile `#{provisioning_profile}'"
|
||||
elsif seed_ids.size > 1
|
||||
App.warn "Found #{seed_ids.size} seed IDs in the provisioning profile. Set the `seed_id' project setting. Will use the last one: `#{seed_ids.last}'"
|
||||
end
|
||||
seed_ids.last
|
||||
end
|
||||
end
|
||||
|
||||
def entitlements_data
|
||||
dict = entitlements
|
||||
if distribution_mode
|
||||
dict['application-identifier'] ||= seed_id + '.' + identifier
|
||||
else
|
||||
# Required for gdb.
|
||||
dict['get-task-allow'] = true if dict['get-task-allow'].nil?
|
||||
end
|
||||
Motion::PropertyList.to_s(dict)
|
||||
end
|
||||
|
||||
def fonts
|
||||
@fonts ||= begin
|
||||
resources_dirs.flatten.inject([]) do |fonts, dir|
|
||||
if File.exist?(dir)
|
||||
Dir.chdir(dir) do
|
||||
fonts.concat(Dir.glob('*.{otf,ttf}'))
|
||||
end
|
||||
else
|
||||
fonts
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def gen_bridge_metadata(headers, bs_file)
|
||||
sdk_path = self.sdk('iPhoneSimulator')
|
||||
includes = headers.map { |header| "-I'#{File.dirname(header)}'" }.uniq
|
||||
a = sdk_version.scan(/(\d+)\.(\d+)/)[0]
|
||||
sdk_version_headers = ((a[0].to_i * 10000) + (a[1].to_i * 100)).to_s
|
||||
extra_flags = OSX_VERSION >= 10.7 ? '--no-64-bit' : ''
|
||||
sh "RUBYOPT='' /usr/bin/gen_bridge_metadata --format complete #{extra_flags} --cflags \"-isysroot #{sdk_path} -miphoneos-version-min=#{sdk_version} -D__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__=#{sdk_version_headers} -I. #{includes.join(' ')}\" #{headers.map { |x| "\"#{x}\"" }.join(' ')} -o \"#{bs_file}\""
|
||||
File.join(motiondir, 'data', template.to_s, target)
|
||||
end
|
||||
end
|
||||
end; end
|
||||
|
||||
98
lib/motion/project/template.rb
Normal file
98
lib/motion/project/template.rb
Normal file
@@ -0,0 +1,98 @@
|
||||
# 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 'erb'
|
||||
|
||||
module Motion; module Project
|
||||
class Template
|
||||
# for ERB
|
||||
attr_reader :name
|
||||
|
||||
def initialize(app_name, template_name)
|
||||
@name = @app_name = app_name
|
||||
@template_name = template_name.to_s
|
||||
@template_directory = File.expand_path(File.join(__FILE__, "../template/#{@template_name}"))
|
||||
|
||||
unless app_name.match(/^[\w\s-]+$/)
|
||||
fail "Invalid app name"
|
||||
end
|
||||
|
||||
if File.exist?(app_name)
|
||||
fail "Directory `#{app_name}' already exists"
|
||||
end
|
||||
|
||||
unless File.exist?(@template_directory)
|
||||
fail "Invalid template name"
|
||||
end
|
||||
end
|
||||
|
||||
def generate
|
||||
App.log 'Create', @app_name
|
||||
FileUtils.mkdir(@app_name)
|
||||
|
||||
Dir.chdir(@app_name) do
|
||||
create_directories()
|
||||
create_files()
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def template_directory
|
||||
@template_directory
|
||||
end
|
||||
|
||||
def create_directories
|
||||
template_files = File.join(template_directory, 'files')
|
||||
Dir.glob(File.join(template_files, "**/")).each do |dir|
|
||||
dir.sub!("#{template_files}/", '')
|
||||
FileUtils.mkdir_p(dir) if dir.length > 0
|
||||
end
|
||||
end
|
||||
|
||||
def create_files
|
||||
template_files = File.join(template_directory, 'files')
|
||||
Dir.glob(File.join(template_files, "**/*"), File::FNM_DOTMATCH).each do |src|
|
||||
dest = src.sub("#{template_files}/", '')
|
||||
next if File.directory?(src)
|
||||
next if dest.include?(".DS_Store")
|
||||
|
||||
dest = replace_file_name(dest)
|
||||
if dest =~ /(.+)\.erb$/
|
||||
App.log 'Create', "#{@app_name}/#{$1}"
|
||||
File.open($1, "w") { |io|
|
||||
io.print ERB.new(File.read(src)).result(binding)
|
||||
}
|
||||
else
|
||||
App.log 'Create', "#{@app_name}/#{dest}"
|
||||
FileUtils.cp(src, dest)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def replace_file_name(file_name)
|
||||
file_name = file_name.sub("{name}", "#{@name}")
|
||||
file_name
|
||||
end
|
||||
end
|
||||
end; end
|
||||
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
161
lib/motion/project/template/ios.rb
Normal file
161
lib/motion/project/template/ios.rb
Normal file
@@ -0,0 +1,161 @@
|
||||
# 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/app'
|
||||
|
||||
App = Motion::Project::App
|
||||
App.template = :ios
|
||||
|
||||
require 'motion/project'
|
||||
require 'motion/project/template/ios/config'
|
||||
|
||||
desc "Build the project, then run the simulator"
|
||||
task :default => :simulator
|
||||
|
||||
desc "Build everything"
|
||||
task :build => ['build:simulator', 'build:device']
|
||||
|
||||
namespace :build do
|
||||
desc "Build the simulator version"
|
||||
task :simulator do
|
||||
App.build('iPhoneSimulator')
|
||||
end
|
||||
|
||||
desc "Build the device version"
|
||||
task :device do
|
||||
App.build('iPhoneOS')
|
||||
App.codesign('iPhoneOS')
|
||||
end
|
||||
end
|
||||
|
||||
desc "Run the simulator"
|
||||
task :simulator => ['build:simulator'] do
|
||||
app = App.config.app_bundle('iPhoneSimulator')
|
||||
target = ENV['target'] || App.config.sdk_version
|
||||
|
||||
# Cleanup the simulator application sandbox, to avoid having old resource files there.
|
||||
if ENV['clean']
|
||||
sim_apps = File.expand_path("~/Library/Application Support/iPhone Simulator/#{target}/Applications")
|
||||
Dir.glob("#{sim_apps}/**/*.app").each do |app_bundle|
|
||||
if File.basename(app_bundle) == File.basename(app)
|
||||
rm_rf File.dirname(app_bundle)
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Prepare the device family.
|
||||
family_int =
|
||||
if family = ENV['device_family']
|
||||
App.config.device_family_int(family.downcase.intern)
|
||||
else
|
||||
App.config.device_family_ints[0]
|
||||
end
|
||||
retina = ENV['retina']
|
||||
|
||||
# Configure the SimulateDevice variable (the only way to specify if we want to run in retina mode or not).
|
||||
simulate_device = App.config.device_family_string(family_int, target, retina)
|
||||
default_simulator = `/usr/bin/defaults read com.apple.iphonesimulator "SimulateDevice"`.strip
|
||||
if default_simulator != simulate_device && default_simulator != "'#{simulate_device}'"
|
||||
system("/usr/bin/killall \"iPhone Simulator\" >& /dev/null")
|
||||
system("/usr/bin/defaults write com.apple.iphonesimulator \"SimulateDevice\" \"'#{simulate_device}'\"")
|
||||
end
|
||||
|
||||
# Launch the simulator.
|
||||
xcode = App.config.xcode_dir
|
||||
env = "DYLD_FRAMEWORK_PATH=\"#{xcode}/../Frameworks\":\"#{xcode}/../OtherFrameworks\""
|
||||
env << ' SIM_SPEC_MODE=1' if App.config.spec_mode
|
||||
sim = File.join(App.config.bindir, 'sim')
|
||||
debug = (ENV['debug'] ? 1 : (App.config.spec_mode ? '0' : '2'))
|
||||
App.info 'Simulate', app
|
||||
at_exit { system("stty echo") } if $stdout.tty? # Just in case the simulator launcher crashes and leaves the terminal without echo.
|
||||
sh "#{env} #{sim} #{debug} #{family_int} #{target} \"#{xcode}\" \"#{app}\""
|
||||
end
|
||||
|
||||
desc "Create an .ipa archive"
|
||||
task :archive => ['build:device'] do
|
||||
App.archive
|
||||
end
|
||||
|
||||
namespace :archive do
|
||||
desc "Create an .ipa archive for distribution (AppStore)"
|
||||
task :distribution do
|
||||
App.config_without_setup.build_mode = :release
|
||||
App.config.distribution_mode = true
|
||||
Rake::Task["build:device"].invoke
|
||||
App.archive
|
||||
end
|
||||
end
|
||||
|
||||
desc "Same as 'spec:simulator'"
|
||||
task :spec => ['spec:simulator']
|
||||
|
||||
namespace :spec do
|
||||
desc "Run the test/spec suite on the simulator"
|
||||
task :simulator do
|
||||
App.config.spec_mode = true
|
||||
Rake::Task["simulator"].invoke
|
||||
end
|
||||
|
||||
desc "Run the test/spec suite on the device"
|
||||
task :device do
|
||||
App.config.spec_mode = true
|
||||
ENV['debug'] ||= '1'
|
||||
Rake::Task["device"].invoke
|
||||
end
|
||||
end
|
||||
|
||||
desc "Deploy on the device"
|
||||
task :device => :archive do
|
||||
App.info 'Deploy', App.config.archive
|
||||
device_id = (ENV['id'] or App.config.device_id)
|
||||
unless App.config.provisioned_devices.include?(device_id)
|
||||
App.fail "Device ID `#{device_id}' not provisioned in profile `#{App.config.provisioning_profile}'"
|
||||
end
|
||||
env = "XCODE_DIR=\"#{App.config.xcode_dir}\""
|
||||
deploy = File.join(App.config.bindir, 'deploy')
|
||||
flags = Rake.application.options.trace ? '-d' : ''
|
||||
sh "#{env} #{deploy} #{flags} \"#{device_id}\" \"#{App.config.archive}\""
|
||||
end
|
||||
|
||||
desc "Generate ctags"
|
||||
task :ctags do
|
||||
tags_file = 'tags'
|
||||
config = App.config
|
||||
if !File.exist?(tags_file) or File.mtime(config.project_file) > File.mtime(tags_file)
|
||||
bs_files = config.bridgesupport_files + config.vendor_projects.map { |p| Dir.glob(File.join(p.path, '*.bridgesupport')) }.flatten
|
||||
ctags = File.join(config.bindir, 'ctags')
|
||||
config = File.join(config.motiondir, 'data', 'bridgesupport-ctags.cfg')
|
||||
sh "#{ctags} --options=\"#{config}\" #{bs_files.map { |x| '"' + x + '"' }.join(' ')}"
|
||||
end
|
||||
end
|
||||
|
||||
desc "Create a .a static library"
|
||||
task :static do
|
||||
libs = %w{iPhoneSimulator iPhoneOS}.map do |platform|
|
||||
'"' + App.build(platform, :static => true) + '"'
|
||||
end
|
||||
fat_lib = File.join(App.config.build_dir, App.config.name + '-universal.a')
|
||||
App.info 'Create', fat_lib
|
||||
sh "/usr/bin/lipo -create #{libs.join(' ')} -output \"#{fat_lib}\""
|
||||
end
|
||||
303
lib/motion/project/template/ios/config.rb
Normal file
303
lib/motion/project/template/ios/config.rb
Normal file
@@ -0,0 +1,303 @@
|
||||
# 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/xcode_config'
|
||||
|
||||
module Motion; module Project;
|
||||
class IOSConfig < XcodeConfig
|
||||
register :ios
|
||||
|
||||
variable :device_family, :interface_orientations, :background_modes,
|
||||
:status_bar_style
|
||||
|
||||
def initialize(project_dir, build_mode)
|
||||
super
|
||||
@frameworks = ['UIKit', 'Foundation', 'CoreGraphics']
|
||||
@device_family = :iphone
|
||||
@interface_orientations = [:portrait, :landscape_left, :landscape_right]
|
||||
@background_modes = []
|
||||
@status_bar_style = :default
|
||||
end
|
||||
|
||||
def platforms; ['iPhoneSimulator', 'iPhoneOS']; end
|
||||
def local_platform; 'iPhoneSimulator'; end
|
||||
def deploy_platform; 'iPhoneOS'; end
|
||||
|
||||
def locate_compiler(platform, *execs)
|
||||
paths = [File.join(platform_dir(platform), 'Developer/usr/bin')]
|
||||
paths.unshift File.join(xcode_dir, 'Toolchains/XcodeDefault.xctoolchain/usr/bin')
|
||||
|
||||
execs.each do |exec|
|
||||
paths.each do |path|
|
||||
cc = File.join(path, exec)
|
||||
return escape_path(cc) if File.exist?(cc)
|
||||
end
|
||||
end
|
||||
App.fail "Can't locate compilers for platform `#{platform}'"
|
||||
end
|
||||
|
||||
def common_flags(platform)
|
||||
super + " -miphoneos-version-min=#{deployment_target}"
|
||||
end
|
||||
|
||||
def device_family_int(family)
|
||||
case family
|
||||
when :iphone then 1
|
||||
when :ipad then 2
|
||||
else
|
||||
App.fail "Unknown device_family value: `#{family}'"
|
||||
end
|
||||
end
|
||||
|
||||
def device_family_string(family, target, retina)
|
||||
device = case family
|
||||
when :iphone, 1
|
||||
"iPhone"
|
||||
when :ipad, 2
|
||||
"iPad"
|
||||
end
|
||||
case retina
|
||||
when 'true'
|
||||
device + ((family == 1 and target >= '6.0') ? ' (Retina 4-inch)' : ' (Retina)')
|
||||
when '3.5'
|
||||
device + ' (Retina 3.5-inch)'
|
||||
when '4'
|
||||
device + ' (Retina 4-inch)'
|
||||
else
|
||||
device
|
||||
end
|
||||
end
|
||||
|
||||
def device_family_ints
|
||||
ary = @device_family.is_a?(Array) ? @device_family : [@device_family]
|
||||
ary.map { |family| device_family_int(family) }
|
||||
end
|
||||
|
||||
def interface_orientations_consts
|
||||
@interface_orientations.map do |ori|
|
||||
case ori
|
||||
when :portrait then 'UIInterfaceOrientationPortrait'
|
||||
when :landscape_left then 'UIInterfaceOrientationLandscapeLeft'
|
||||
when :landscape_right then 'UIInterfaceOrientationLandscapeRight'
|
||||
when :portrait_upside_down then 'UIInterfaceOrientationPortraitUpsideDown'
|
||||
else
|
||||
App.fail "Unknown interface_orientation value: `#{ori}'"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def background_modes_consts
|
||||
@background_modes.map do |mode|
|
||||
case mode
|
||||
when :audio then 'audio'
|
||||
when :location then 'location'
|
||||
when :voip then 'voip'
|
||||
when :newsstand_content then 'newsstand-content'
|
||||
when :external_accessory then 'external-accessory'
|
||||
when :bluetooth_central then 'bluetooth-central'
|
||||
else
|
||||
App.fail "Unknown background_modes value: `#{mode}'"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def status_bar_style_const
|
||||
case @status_bar_style
|
||||
when :default then 'UIStatusBarStyleDefault'
|
||||
when :black_translucent then 'UIStatusBarStyleBlackTranslucent'
|
||||
when :black_opaque then 'UIStatusBarStyleBlackOpaque'
|
||||
else
|
||||
App.fail "Unknown status_bar_style value: `#{@status_bar_style}'"
|
||||
end
|
||||
end
|
||||
|
||||
def device_id
|
||||
@device_id ||= begin
|
||||
deploy = File.join(App.config.bindir, 'deploy')
|
||||
device_id = `#{deploy} -D`.strip
|
||||
if device_id.empty?
|
||||
App.fail "Can't find an iOS device connected on USB"
|
||||
end
|
||||
device_id
|
||||
end
|
||||
end
|
||||
|
||||
def app_bundle(platform)
|
||||
File.join(versionized_build_dir(platform), bundle_name + '.app')
|
||||
end
|
||||
|
||||
def app_bundle_executable(platform)
|
||||
File.join(app_bundle(platform), name)
|
||||
end
|
||||
|
||||
def app_resources_dir(platform)
|
||||
app_bundle(platform)
|
||||
end
|
||||
|
||||
def info_plist_data
|
||||
ios_version_to_build = lambda do |vers|
|
||||
# XXX we should retrieve these values programmatically.
|
||||
case vers
|
||||
when '4.3'; '8F191m'
|
||||
when '5.0'; '9A334'
|
||||
when '5.1'; '9B176'
|
||||
else; '10A403' # 6.0 or later
|
||||
end
|
||||
end
|
||||
Motion::PropertyList.to_s({
|
||||
'MinimumOSVersion' => deployment_target,
|
||||
'CFBundleResourceSpecification' => 'ResourceRules.plist',
|
||||
'CFBundleSupportedPlatforms' => [deploy_platform],
|
||||
'CFBundleIconFiles' => icons,
|
||||
'CFBundleIcons' => {
|
||||
'CFBundlePrimaryIcon' => {
|
||||
'CFBundleIconFiles' => icons,
|
||||
'UIPrerenderedIcon' => prerendered_icon,
|
||||
}
|
||||
},
|
||||
'UIAppFonts' => fonts,
|
||||
'UIDeviceFamily' => device_family_ints.map { |x| x.to_s },
|
||||
'UISupportedInterfaceOrientations' => interface_orientations_consts,
|
||||
'UIStatusBarStyle' => status_bar_style_const,
|
||||
'UIBackgroundModes' => background_modes_consts,
|
||||
'DTXcode' => begin
|
||||
vers = xcode_version[0].gsub(/\./, '')
|
||||
if vers.length == 2
|
||||
'0' + vers + '0'
|
||||
else
|
||||
'0' + vers
|
||||
end
|
||||
end,
|
||||
'DTXcodeBuild' => xcode_version[1],
|
||||
'DTSDKName' => "iphoneos#{sdk_version}",
|
||||
'DTSDKBuild' => ios_version_to_build.call(sdk_version),
|
||||
'DTPlatformName' => 'iphoneos',
|
||||
'DTCompiler' => 'com.apple.compilers.llvm.clang.1_0',
|
||||
'DTPlatformVersion' => sdk_version,
|
||||
'DTPlatformBuild' => ios_version_to_build.call(sdk_version)
|
||||
}.merge(generic_info_plist).merge(dt_info_plist).merge(info_plist))
|
||||
end
|
||||
|
||||
def main_cpp_file_txt(spec_objs)
|
||||
main_txt = <<EOS
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
extern "C" {
|
||||
void rb_define_global_const(const char *, void *);
|
||||
void rb_rb2oc_exc_handler(void);
|
||||
void rb_exit(int);
|
||||
void RubyMotionInit(int argc, char **argv);
|
||||
EOS
|
||||
if spec_mode
|
||||
spec_objs.each do |_, init_func|
|
||||
main_txt << "void #{init_func}(void *, void *);\n"
|
||||
end
|
||||
end
|
||||
main_txt << <<EOS
|
||||
}
|
||||
EOS
|
||||
|
||||
if spec_mode
|
||||
main_txt << <<EOS
|
||||
@interface SpecLauncher : NSObject
|
||||
@end
|
||||
|
||||
#include <dlfcn.h>
|
||||
|
||||
@implementation SpecLauncher
|
||||
|
||||
+ (id)launcher
|
||||
{
|
||||
[UIApplication sharedApplication];
|
||||
|
||||
// Enable simulator accessibility.
|
||||
// Thanks http://www.stewgleadow.com/blog/2011/10/14/enabling-accessibility-for-ios-applications/
|
||||
NSString *simulatorRoot = [[[NSProcessInfo processInfo] environment] objectForKey:@"IPHONE_SIMULATOR_ROOT"];
|
||||
if (simulatorRoot != nil) {
|
||||
void *appSupportLibrary = dlopen([[simulatorRoot stringByAppendingPathComponent:@"/System/Library/PrivateFrameworks/AppSupport.framework/AppSupport"] fileSystemRepresentation], RTLD_LAZY);
|
||||
CFStringRef (*copySharedResourcesPreferencesDomainForDomain)(CFStringRef domain) = (CFStringRef (*)(CFStringRef)) dlsym(appSupportLibrary, "CPCopySharedResourcesPreferencesDomainForDomain");
|
||||
|
||||
if (copySharedResourcesPreferencesDomainForDomain != NULL) {
|
||||
CFStringRef accessibilityDomain = copySharedResourcesPreferencesDomainForDomain(CFSTR("com.apple.Accessibility"));
|
||||
|
||||
if (accessibilityDomain != NULL) {
|
||||
CFPreferencesSetValue(CFSTR("ApplicationAccessibilityEnabled"), kCFBooleanTrue, accessibilityDomain, kCFPreferencesAnyUser, kCFPreferencesAnyHost);
|
||||
CFRelease(accessibilityDomain);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Load the UIAutomation framework.
|
||||
dlopen("/Developer/Library/PrivateFrameworks/UIAutomation.framework/UIAutomation", RTLD_LOCAL);
|
||||
|
||||
SpecLauncher *launcher = [[self alloc] init];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:launcher selector:@selector(appLaunched:) name:UIApplicationDidBecomeActiveNotification object:nil];
|
||||
return launcher;
|
||||
}
|
||||
|
||||
- (void)appLaunched:(id)notification
|
||||
{
|
||||
// Give a bit of time for the simulator to attach...
|
||||
[self performSelector:@selector(runSpecs) withObject:nil afterDelay:0.3];
|
||||
}
|
||||
|
||||
- (void)runSpecs
|
||||
{
|
||||
EOS
|
||||
spec_objs.each do |_, init_func|
|
||||
main_txt << "#{init_func}(self, 0);\n"
|
||||
end
|
||||
main_txt << "[NSClassFromString(@\"Bacon\") performSelector:@selector(run)];\n"
|
||||
main_txt << <<EOS
|
||||
}
|
||||
|
||||
@end
|
||||
EOS
|
||||
end
|
||||
main_txt << <<EOS
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
||||
int retval = 0;
|
||||
try {
|
||||
EOS
|
||||
main_txt << "[SpecLauncher launcher];\n" if spec_mode
|
||||
main_txt << <<EOS
|
||||
RubyMotionInit(argc, argv);
|
||||
EOS
|
||||
main_txt << define_global_env_txt
|
||||
main_txt << <<EOS
|
||||
retval = UIApplicationMain(argc, argv, nil, @"#{delegate_class}");
|
||||
rb_exit(retval);
|
||||
}
|
||||
catch (...) {
|
||||
rb_rb2oc_exc_handler();
|
||||
}
|
||||
[pool release];
|
||||
return retval;
|
||||
}
|
||||
EOS
|
||||
end
|
||||
end
|
||||
end; end
|
||||
@@ -1,6 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
$:.unshift("/Library/RubyMotion/lib")
|
||||
require 'motion/project'
|
||||
require 'motion/project/template/ios'
|
||||
|
||||
Motion::Project::App.setup do |app|
|
||||
# Use `rake config' to see complete project settings.
|
||||
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
45
lib/motion/project/template/osx.rb
Normal file
45
lib/motion/project/template/osx.rb
Normal file
@@ -0,0 +1,45 @@
|
||||
# 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/app'
|
||||
|
||||
App = Motion::Project::App
|
||||
App.template = :osx
|
||||
|
||||
require 'motion/project'
|
||||
require 'motion/project/template/osx/config'
|
||||
|
||||
desc "Build the project, then run it"
|
||||
task :default => :run
|
||||
|
||||
desc "Build the project"
|
||||
task :build do
|
||||
App.build('MacOSX')
|
||||
end
|
||||
|
||||
desc "Run the project"
|
||||
task :run => 'build' do
|
||||
exec = App.config.app_bundle_executable('MacOSX')
|
||||
App.info 'Run', exec
|
||||
sh exec
|
||||
end
|
||||
111
lib/motion/project/template/osx/config.rb
Normal file
111
lib/motion/project/template/osx/config.rb
Normal file
@@ -0,0 +1,111 @@
|
||||
# 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/xcode_config'
|
||||
|
||||
module Motion; module Project;
|
||||
class OSXConfig < XcodeConfig
|
||||
register :osx
|
||||
|
||||
variable :copyright
|
||||
|
||||
def initialize(project_dir, build_mode)
|
||||
super
|
||||
@copyright = "Copyright © #{Time.now.year} #{`whoami`.strip}. All rights reserved."
|
||||
@frameworks = ['AppKit', 'Foundation', 'CoreGraphics']
|
||||
end
|
||||
|
||||
def platforms; ['MacOSX']; end
|
||||
def local_platform; 'MacOSX'; end
|
||||
def deploy_platform; 'MacOSX'; end
|
||||
|
||||
def locate_compiler(platform, *execs)
|
||||
execs.each do |exec|
|
||||
cc = File.join('/usr/bin', exec)
|
||||
return escape_path(cc) if File.exist?(cc)
|
||||
end
|
||||
App.fail "Can't locate compilers for platform `#{platform}'"
|
||||
end
|
||||
|
||||
def archs; { 'MacOSX' => ['x86_64'] }; end
|
||||
|
||||
def common_flags(platform)
|
||||
super + " -mmacosx-version-min=#{deployment_target}"
|
||||
end
|
||||
|
||||
def app_bundle(platform)
|
||||
File.join(versionized_build_dir(platform), bundle_name + '.app', 'Contents')
|
||||
end
|
||||
|
||||
def app_bundle_executable(platform)
|
||||
File.join(app_bundle(platform), 'MacOS', name)
|
||||
end
|
||||
|
||||
def app_resources_dir(platform)
|
||||
File.join(app_bundle(platform), 'Resources')
|
||||
end
|
||||
|
||||
def info_plist_data
|
||||
Motion::PropertyList.to_s({
|
||||
'NSHumanReadableCopyright' => copyright,
|
||||
'NSPrincipalClass' => 'NSApplication'
|
||||
}.merge(generic_info_plist).merge(dt_info_plist).merge(info_plist))
|
||||
end
|
||||
|
||||
def main_cpp_file_txt(spec_objs)
|
||||
main_txt = <<EOS
|
||||
#import <AppKit/AppKit.h>
|
||||
|
||||
extern "C" {
|
||||
void rb_define_global_const(const char *, void *);
|
||||
void rb_rb2oc_exc_handler(void);
|
||||
void rb_exit(int);
|
||||
void RubyMotionInit(int argc, char **argv);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
||||
#if !__LP64__
|
||||
try {
|
||||
#endif
|
||||
RubyMotionInit(argc, argv);
|
||||
#{define_global_env_txt}
|
||||
NSApplication *app = [NSApplication sharedApplication];
|
||||
[app setDelegate:[NSClassFromString(@"#{delegate_class}") new]];
|
||||
[app run];
|
||||
rb_exit(0);
|
||||
#if !__LP64__
|
||||
}
|
||||
catch (...) {
|
||||
rb_rb2oc_exc_handler();
|
||||
}
|
||||
#endif
|
||||
[pool release];
|
||||
return 0;
|
||||
}
|
||||
EOS
|
||||
end
|
||||
end
|
||||
end; end
|
||||
16
lib/motion/project/template/osx/files/.gitignore
vendored
Normal file
16
lib/motion/project/template/osx/files/.gitignore
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
.repl_history
|
||||
build
|
||||
tags
|
||||
app/pixate_code.rb
|
||||
resources/*.nib
|
||||
resources/*.momd
|
||||
resources/*.storyboardc
|
||||
.DS_Store
|
||||
nbproject
|
||||
.redcar
|
||||
#*#
|
||||
*~
|
||||
*.sw[po]
|
||||
.eprj
|
||||
.sass-cache
|
||||
.idea
|
||||
8
lib/motion/project/template/osx/files/Rakefile.erb
Normal file
8
lib/motion/project/template/osx/files/Rakefile.erb
Normal file
@@ -0,0 +1,8 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
$:.unshift("/Library/RubyMotion/lib")
|
||||
require 'motion/project/template/osx'
|
||||
|
||||
Motion::Project::App.setup do |app|
|
||||
# Use `rake config' to see complete project settings.
|
||||
app.name = '<%= name %>'
|
||||
end
|
||||
@@ -0,0 +1,4 @@
|
||||
class AppDelegate
|
||||
def applicationDidFinishLaunching(notification)
|
||||
end
|
||||
end
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 2.3 KiB |
@@ -0,0 +1,9 @@
|
||||
describe "Application '<%= name %>'" do
|
||||
before do
|
||||
@app = UIApplication.sharedApplication
|
||||
end
|
||||
|
||||
it "has one window" do
|
||||
@app.windows.size.should == 1
|
||||
end
|
||||
end
|
||||
383
lib/motion/project/xcode_config.rb
Normal file
383
lib/motion/project/xcode_config.rb
Normal file
@@ -0,0 +1,383 @@
|
||||
# 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.
|
||||
|
||||
module Motion; module Project;
|
||||
class XcodeConfig < Config
|
||||
variable :xcode_dir, :sdk_version, :deployment_target, :frameworks,
|
||||
:weak_frameworks, :framework_search_paths, :libs, :resources_dirs,
|
||||
:identifier, :codesign_certificate, :provisioning_profile,
|
||||
:short_version, :icons, :prerendered_icon, :seed_id, :entitlements,
|
||||
:fonts, :delegate_class
|
||||
|
||||
def initialize(project_dir, build_mode)
|
||||
super
|
||||
@info_plist = {}
|
||||
@dependencies = {}
|
||||
@frameworks = []
|
||||
@weak_frameworks = []
|
||||
@framework_search_paths = []
|
||||
@libs = []
|
||||
@bundle_signature = '????'
|
||||
@short_version = '1'
|
||||
@icons = []
|
||||
@prerendered_icon = false
|
||||
@vendor_projects = []
|
||||
@entitlements = {}
|
||||
@delegate_class = 'AppDelegate'
|
||||
@spec_mode = false
|
||||
end
|
||||
|
||||
def xcode_dir
|
||||
@xcode_dir ||= begin
|
||||
xcode_dot_app_path = '/Applications/Xcode.app/Contents/Developer'
|
||||
|
||||
# First, honor /usr/bin/xcode-select
|
||||
xcodeselect = '/usr/bin/xcode-select'
|
||||
if File.exist?(xcodeselect)
|
||||
path = `#{xcodeselect} -print-path`.strip
|
||||
if path.match(/^\/Developer\//) and File.exist?(xcode_dot_app_path)
|
||||
@xcode_error_printed ||= false
|
||||
$stderr.puts(<<EOS) unless @xcode_error_printed
|
||||
===============================================================================
|
||||
It appears that you have a version of Xcode installed in /Applications that has
|
||||
not been set as the default version. It is possible that RubyMotion may be
|
||||
using old versions of certain tools which could eventually cause issues.
|
||||
|
||||
To fix this problem, you can type the following command in the terminal:
|
||||
$ sudo xcode-select -switch /Applications/Xcode.app/Contents/Developer
|
||||
===============================================================================
|
||||
EOS
|
||||
@xcode_error_printed = true
|
||||
end
|
||||
return path if File.exist?(path)
|
||||
end
|
||||
|
||||
# Since xcode-select is borked, we assume the user installed Xcode
|
||||
# as an app (new in Xcode 4.3).
|
||||
return xcode_dot_app_path if File.exist?(xcode_dot_app_path)
|
||||
|
||||
App.fail "Can't locate any version of Xcode on the system."
|
||||
end
|
||||
unescape_path(@xcode_dir)
|
||||
end
|
||||
|
||||
def xcode_version
|
||||
@xcode_version ||= begin
|
||||
txt = `#{locate_binary('xcodebuild')} -version`
|
||||
vers = txt.scan(/Xcode\s(.+)/)[0][0]
|
||||
build = txt.scan(/Build version\s(.+)/)[0][0]
|
||||
[vers, build]
|
||||
end
|
||||
end
|
||||
|
||||
def platforms; raise; end
|
||||
def local_platform; raise; end
|
||||
def deploy_platform; raise; end
|
||||
|
||||
def validate
|
||||
# Xcode version
|
||||
App.fail "Xcode 4.x or greater is required" if xcode_version[0] < '4.0'
|
||||
|
||||
# sdk_version
|
||||
platforms.each do |platform|
|
||||
sdk_path = File.join(platforms_dir, platform + '.platform',
|
||||
"Developer/SDKs/#{platform}#{sdk_version}.sdk")
|
||||
unless File.exist?(sdk_path)
|
||||
App.fail "Can't locate #{platform} SDK #{sdk_version} at `#{sdk_path}'"
|
||||
end
|
||||
end
|
||||
|
||||
# deployment_target
|
||||
if deployment_target > sdk_version
|
||||
App.fail "Deployment target `#{deployment_target}' must be equal or lesser than SDK version `#{sdk_version}'"
|
||||
end
|
||||
unless File.exist?(datadir)
|
||||
App.fail "iOS deployment target #{deployment_target} is not supported by this version of RubyMotion"
|
||||
end
|
||||
|
||||
# icons
|
||||
if !(icons.is_a?(Array) and icons.all? { |x| x.is_a?(String) })
|
||||
App.fail "app.icons should be an array of strings."
|
||||
end
|
||||
|
||||
super
|
||||
end
|
||||
|
||||
def platforms_dir
|
||||
File.join(xcode_dir, 'Platforms')
|
||||
end
|
||||
|
||||
def platform_dir(platform)
|
||||
File.join(platforms_dir, platform + '.platform')
|
||||
end
|
||||
|
||||
def sdk_version
|
||||
@sdk_version ||= begin
|
||||
versions = Dir.glob(File.join(platforms_dir, "#{deploy_platform}.platform/Developer/SDKs/#{deploy_platform}*.sdk")).map do |path|
|
||||
File.basename(path).scan(/#{deploy_platform}(.*)\.sdk/)[0][0]
|
||||
end
|
||||
if versions.size == 0
|
||||
App.fail "Can't find an iOS SDK in `#{platforms_dir}'"
|
||||
end
|
||||
supported_vers = versions.reverse.find { |vers| File.exist?(datadir(vers)) }
|
||||
unless supported_vers
|
||||
App.fail "RubyMotion doesn't support any of these SDK versions: #{versions.join(', ')}"
|
||||
end
|
||||
supported_vers
|
||||
end
|
||||
end
|
||||
|
||||
def deployment_target
|
||||
@deployment_target ||= sdk_version
|
||||
end
|
||||
|
||||
def sdk(platform)
|
||||
path = File.join(platform_dir(platform), 'Developer/SDKs',
|
||||
platform + sdk_version + '.sdk')
|
||||
escape_path(path)
|
||||
end
|
||||
|
||||
def frameworks_dependencies
|
||||
@frameworks_dependencies ||= begin
|
||||
# Compute the list of frameworks, including dependencies, that the project uses.
|
||||
deps = frameworks.dup.uniq
|
||||
slf = File.join(sdk(local_platform), 'System', 'Library', 'Frameworks')
|
||||
deps.each do |framework|
|
||||
framework_path = File.join(slf, framework + '.framework', framework)
|
||||
if File.exist?(framework_path)
|
||||
`#{locate_binary('otool')} -L \"#{framework_path}\"`.scan(/\t([^\s]+)\s\(/).each do |dep|
|
||||
# Only care about public, non-umbrella frameworks (for now).
|
||||
if md = dep[0].match(/^\/System\/Library\/Frameworks\/(.+)\.framework\/(.+)$/) and md[1] == md[2]
|
||||
deps << md[1]
|
||||
deps.uniq!
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if @framework_search_paths.empty?
|
||||
deps = deps.select { |dep| File.exist?(File.join(datadir, 'BridgeSupport', dep + '.bridgesupport')) }
|
||||
end
|
||||
deps
|
||||
end
|
||||
end
|
||||
|
||||
def frameworks_stubs_objects(platform)
|
||||
stubs = []
|
||||
(frameworks_dependencies + weak_frameworks).uniq.each do |framework|
|
||||
stubs_obj = File.join(datadir, platform, "#{framework}_stubs.o")
|
||||
stubs << stubs_obj if File.exist?(stubs_obj)
|
||||
end
|
||||
stubs
|
||||
end
|
||||
|
||||
def bridgesupport_files
|
||||
@bridgesupport_files ||= begin
|
||||
bs_files = []
|
||||
deps = ['RubyMotion'] + (frameworks_dependencies + weak_frameworks).uniq
|
||||
deps << 'UIAutomation' if spec_mode
|
||||
deps.each do |framework|
|
||||
supported_versions.each do |ver|
|
||||
next if ver < deployment_target || sdk_version < ver
|
||||
bs_path = File.join(datadir(ver), 'BridgeSupport', framework + '.bridgesupport')
|
||||
if File.exist?(bs_path)
|
||||
bs_files << bs_path
|
||||
end
|
||||
end
|
||||
end
|
||||
bs_files
|
||||
end
|
||||
end
|
||||
|
||||
def archs
|
||||
@archs ||= begin
|
||||
h = {}
|
||||
platforms.each do |platform|
|
||||
h[platform] = Dir.glob(File.join(datadir, platform, '*.bc')).map do |path|
|
||||
path.scan(/kernel-(.+).bc$/)[0][0]
|
||||
end
|
||||
end
|
||||
h
|
||||
end
|
||||
end
|
||||
|
||||
def arch_flags(platform)
|
||||
archs[platform].map { |x| "-arch #{x}" }.join(' ')
|
||||
end
|
||||
|
||||
def common_flags(platform)
|
||||
"#{arch_flags(platform)} -isysroot \"#{unescape_path(sdk(platform))}\" -F#{sdk(platform)}/System/Library/Frameworks"
|
||||
end
|
||||
|
||||
def cflags(platform, cplusplus)
|
||||
"#{common_flags(platform)} -fexceptions -fblocks -fobjc-legacy-dispatch -fobjc-abi-version=2" + (cplusplus ? '' : ' -std=c99')
|
||||
end
|
||||
|
||||
def ldflags(platform)
|
||||
ldflags = common_flags(platform)
|
||||
ldflags << " -fobjc-arc" if deployment_target < '5.0'
|
||||
ldflags
|
||||
end
|
||||
|
||||
def bundle_name
|
||||
@name + (spec_mode ? '_spec' : '')
|
||||
end
|
||||
|
||||
def app_bundle_dsym(platform)
|
||||
File.join(versionized_build_dir(platform), bundle_name + '.dSYM')
|
||||
end
|
||||
|
||||
def archive
|
||||
File.join(versionized_build_dir(deploy_platform), bundle_name + '.ipa')
|
||||
end
|
||||
|
||||
def identifier
|
||||
@identifier ||= "com.yourcompany.#{@name.gsub(/\s/, '')}"
|
||||
spec_mode ? @identifier + '_spec' : @identifier
|
||||
end
|
||||
|
||||
def info_plist
|
||||
@info_plist
|
||||
end
|
||||
|
||||
def dt_info_plist
|
||||
{}
|
||||
end
|
||||
|
||||
def generic_info_plist
|
||||
{
|
||||
'BuildMachineOSBuild' => `sw_vers -buildVersion`.strip,
|
||||
'CFBundleDevelopmentRegion' => 'en',
|
||||
'CFBundleName' => @name,
|
||||
'CFBundleDisplayName' => @name,
|
||||
'CFBundleIdentifier' => identifier,
|
||||
'CFBundleExecutable' => @name,
|
||||
'CFBundleInfoDictionaryVersion' => '6.0',
|
||||
'CFBundlePackageType' => 'APPL',
|
||||
'CFBundleShortVersionString' => @short_version,
|
||||
'CFBundleSignature' => @bundle_signature,
|
||||
'CFBundleVersion' => @version
|
||||
}
|
||||
end
|
||||
|
||||
def pkginfo_data
|
||||
"AAPL#{@bundle_signature}"
|
||||
end
|
||||
|
||||
def codesign_certificate
|
||||
@codesign_certificate ||= begin
|
||||
cert_type = (distribution_mode ? 'Distribution' : 'Developer')
|
||||
certs = `/usr/bin/security -q find-certificate -a`.scan(/"iPhone #{cert_type}: [^"]+"/).uniq
|
||||
if certs.size == 0
|
||||
App.fail "Can't find an iPhone Developer certificate in the keychain"
|
||||
elsif certs.size > 1
|
||||
App.warn "Found #{certs.size} iPhone Developer certificates in the keychain. Set the `codesign_certificate' project setting. Will use the first certificate: `#{certs[0]}'"
|
||||
end
|
||||
certs[0][1..-2] # trim trailing `"` characters
|
||||
end
|
||||
end
|
||||
|
||||
def provisioning_profile(name = /iOS Team Provisioning Profile/)
|
||||
@provisioning_profile ||= begin
|
||||
paths = Dir.glob(File.expand_path("~/Library/MobileDevice/Provisioning\ Profiles/*.mobileprovision")).select do |path|
|
||||
text = File.read(path)
|
||||
text.force_encoding('binary') if RUBY_VERSION >= '1.9.0'
|
||||
text.scan(/<key>\s*Name\s*<\/key>\s*<string>\s*([^<]+)\s*<\/string>/)[0][0].match(name)
|
||||
end
|
||||
if paths.size == 0
|
||||
App.fail "Can't find a provisioning profile named `#{name}'"
|
||||
elsif paths.size > 1
|
||||
App.warn "Found #{paths.size} provisioning profiles named `#{name}'. Set the `provisioning_profile' project setting. Will use the first one: `#{paths[0]}'"
|
||||
end
|
||||
paths[0]
|
||||
end
|
||||
end
|
||||
|
||||
def read_provisioned_profile_array(key)
|
||||
text = File.read(provisioning_profile)
|
||||
text.force_encoding('binary') if RUBY_VERSION >= '1.9.0'
|
||||
text.scan(/<key>\s*#{key}\s*<\/key>\s*<array>(.*?)\s*<\/array>/m)[0][0].scan(/<string>(.*?)<\/string>/).map { |str| str[0].strip }
|
||||
end
|
||||
private :read_provisioned_profile_array
|
||||
|
||||
def provisioned_devices
|
||||
@provisioned_devices ||= read_provisioned_profile_array('ProvisionedDevices')
|
||||
end
|
||||
|
||||
def seed_id
|
||||
@seed_id ||= begin
|
||||
seed_ids = read_provisioned_profile_array('ApplicationIdentifierPrefix')
|
||||
if seed_ids.size == 0
|
||||
App.fail "Can't find an application seed ID in the provisioning profile `#{provisioning_profile}'"
|
||||
elsif seed_ids.size > 1
|
||||
App.warn "Found #{seed_ids.size} seed IDs in the provisioning profile. Set the `seed_id' project setting. Will use the last one: `#{seed_ids.last}'"
|
||||
end
|
||||
seed_ids.last
|
||||
end
|
||||
end
|
||||
|
||||
def entitlements_data
|
||||
dict = entitlements
|
||||
if distribution_mode
|
||||
dict['application-identifier'] ||= seed_id + '.' + identifier
|
||||
else
|
||||
# Required for gdb.
|
||||
dict['get-task-allow'] = true if dict['get-task-allow'].nil?
|
||||
end
|
||||
Motion::PropertyList.to_s(dict)
|
||||
end
|
||||
|
||||
def fonts
|
||||
@fonts ||= begin
|
||||
resources_dirs.flatten.inject([]) do |fonts, dir|
|
||||
if File.exist?(dir)
|
||||
Dir.chdir(dir) do
|
||||
fonts.concat(Dir.glob('*.{otf,ttf}'))
|
||||
end
|
||||
else
|
||||
fonts
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def gen_bridge_metadata(headers, bs_file)
|
||||
sdk_path = self.sdk(local_platform)
|
||||
includes = headers.map { |header| "-I'#{File.dirname(header)}'" }.uniq
|
||||
a = sdk_version.scan(/(\d+)\.(\d+)/)[0]
|
||||
sdk_version_headers = ((a[0].to_i * 10000) + (a[1].to_i * 100)).to_s
|
||||
extra_flags = OSX_VERSION >= 10.7 ? '--no-64-bit' : ''
|
||||
sh "RUBYOPT='' /usr/bin/gen_bridge_metadata --format complete #{extra_flags} --cflags \"-isysroot #{sdk_path} -miphoneos-version-min=#{sdk_version} -D__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__=#{sdk_version_headers} -I. #{includes.join(' ')}\" #{headers.map { |x| "\"#{x}\"" }.join(' ')} -o \"#{bs_file}\""
|
||||
end
|
||||
|
||||
def define_global_env_txt
|
||||
rubymotion_env =
|
||||
if spec_mode
|
||||
'test'
|
||||
else
|
||||
development? ? 'development' : 'release'
|
||||
end
|
||||
"rb_define_global_const(\"RUBYMOTION_ENV\", @\"#{rubymotion_env}\");\nrb_define_global_const(\"RUBYMOTION_VERSION\", @\"#{Motion::Version}\");\n"
|
||||
end
|
||||
end
|
||||
end; end
|
||||
Reference in New Issue
Block a user