Files
RubyMotion/doc/ReferenceManual.textile
2011-12-05 21:02:59 +01:00

598 lines
32 KiB
Plaintext

h1. RubyMotion Reference Manual
h2. Abstract
This is the RubyMotion reference manual. It documents the latest available version of RubyMotion. This manual closely follows changes in RubyMotion, and it should always be up-to-date.
This is an exaustive manual that covers all the technical aspects of RubyMotion that the developer needs to be aware of in order to develop applications with it. It is not meant to be a guide or a tutorial. Tutorials are available from the same documentation center.
Basic knowledge of the Ruby language and programming concepts are required for this guide.
h2. Getting Started
h3. Overview
RubyMotion is a framework that permits the development of iOS applications using the Ruby programming language.
"iOS":http://www.apple.com/ios/ is Apple's mobile operating system, powering a variety of devices such as iPhone, iPod touch and iPad. Developers can write applications for iOS and submit them to the App Store, Apple's application distribution system.
Conceptually, RubyMotion is a combination of three modules:
* *Runtime*: a custom implementation of the Ruby language for iOS, tightly integrated with the native iOS runtime and customized for embedded devices constrains.
* *Tool*: a command-line toolchain to create and manage RubyMotion projects.
* *Library*: a high-level Ruby library sitting on top of the iOS SDK that facilitates the development of applications.
h3. Installation
An evaluation version of RubyMotion can be downloaded from "http://rubymotion.com":http://rubymotion.com. This version can create and build projects, and run them through the iOS simulator.
A license must be purchased in order to build projects for iOS hardware. This is needed for applications to be tested on device and submitted to the App Store.
RubyMotion installs itself into +/Library/Motion+. A symbolic link to the command-line interface is created as +/usr/bin/motion+.
h3. Software Updates
Software updates can be applied via the command-line.
<pre>
$ sudo motion update
</pre>
This command will grab the latest version of RubyMotion from the network and install it. You must be connected to the Internet to perform that command.
You can always see the version number of the version of RubyMotion installed on the computer.
<pre>
$ motion -v
1.0
</pre>
h2. Runtime
The RubyMotion runtime implements the Ruby language functionality required during the execution of an application. The object model, builtin classes and memory management system are part of the runtime.
Althrough similars in appearance, the RubyMotion runtime has a completely different implementation than "CRuby":http://www.ruby-lang.org/en/, the mainstream implementation. We will cover the main differences in the following sections.
The key feature of the RubyMotion runtime is its tight integration with iOS, which makes applications very efficient.
RubyMotion follows the Ruby 1.9 language specifications.
h3. Object Model
The object model of RubyMotion is based on "Objective-C":http://en.wikipedia.org/wiki/Objective-C, the underlying language runtime of the iOS SDK. Objective-C is an object-oriented flavor of C that has been, like Ruby, heavily influenced by the "Smalltalk":http://en.wikipedia.org/wiki/Smalltalk language.
Sharing a common ancestor, the object models of Ruby and Objective-C are conceptually similar. For instance, both languages have the notion of open classes, single inheritance, and single dynamic message dispatch.
RubyMotion implements the Ruby object model by using the "Objective-C runtime":http://developer.apple.com/library/ios/#documentation/Cocoa/Reference/ObjCRuntimeRef/Reference/reference.html, the library that powers the Objective-C language, and indirectly, the iOS SDK APIs.
In RubyMotion, Ruby classes, methods and objects are respectively Objective-C classes, methods and objects. And reciprocally, Objective-C classes, methods and objects are available in Ruby as if they were native.
By sharing the same object model infrastructure, Objective-C and RubyMotion APIs can be interchangeable at no additional performance expense.
h4. Objective-C Messages
RubyMotion lets the developer send and define Objective-C messages.
An Objective-C message, also called a selector, can look different than a typical Ruby message, if it contains more than one argument.
Unlike Ruby messages, Objective-C messages contain keywords. Each argument has a keyword associated to it, and the final Objective-C message is the combination of all keywords.
Let's take the following piece of Objective-C code which draws a string.
<pre>
[string drawAtPoint:point withFont:font];
</pre>
In this code, +string+, +point+ and +font+ are variables. The message keywords are +drawAtPoint:+ and +withFont:+. The complete message is the combination of these keywords, +drawAtPoint:withFont:+ , which is sent to the +string+ object, passing the +point+ and +font+ objects as arguments.
Objective-C messages can be sent from RubyMotion using a similar syntax.
<pre>
string.drawAtPoint(point, withFont:font)
</pre>
It is important to keep in mind that the message being sent here is +drawAtPoint:withFont:+. To illustrate more, the same message can be manually dispatched using the +send+ method.
<pre>
string.send(:'drawAtPoint:withFont:', point, font)
</pre>
Objective-C messages can also be defined in RubyMotion. Let's imagine we are building a class that should act as a proxy for our drawing code. The following piece of code defines the +drawAtPoint:withFont:+ message on the +DrawingProxy+ class.
<pre>
class DrawingProxy
def drawAtPoint(point, withFont:font)
@str.drawAtPoint(point, withFont:font)
end
end
</pre>
Note: The syntax used to define Objective-C selectors was added to RubyMotion and is not part of the Ruby standard.
h4. Reading Objective-C Interfaces
TBD
h4. Shortcuts
TBD
h3. Builtin Classes
Some of the builtin classes of RubyMotion are based on the "Foundation framework":http://developer.apple.com/library/ios/#documentation/Cocoa/Reference/Foundation/ObjC_classic/_index.html, the base layer of iOS.
The Foundation framework is an Objective-C framework, but due to the fact that RubyMotion is based on the Objective-C runtime, the classes that it defines can be naturally re-used in RubyMotion.
Foundation class names typically start with the +NS+ prefix, which arguably stands for NeXTSTEP, the system for which the framework was originally built.
Foundation comes with the root object class, +NSObject+, as well as a set of primitive object classes. In RubyMotion, +Object+ is an alias to +NSObject+, making +NSObject+ the root class of all Ruby classes. Also, some of the builtin classes inherit from Foundation types.
Here is a table showing the ancestors chain of a newly created class, +Hello+, as well as some of the Ruby builtin classes.
|_<. Ruby Class |_<. Ancestors |
| +Hello+ | +NSObject+ → +Kernel+ |
| +String+ | +NSMutableString+ → +NSString+ → +Comparable+ → +NSObject+ → +Kernel+ |
| +Array+ | +NSMutableArray+ → +NSArray+ → +Enumerable+ → +NSObject+ → +Kernel+ |
| +Hash+ | +NSMutableDictionary+ → +NSDictionary+ → +Enumerable+ → +NSObject+ → +Kernel+ |
| +Numeric+ | +Comparable+ → +NSNumber+ → +NSValue+ → +NSObject+ → +Kernel+ |
| +Time+ | +Comparable+ → +NSDate+ → +NSObject+ → +Kernel+ |
A direct consequence of hosting the Ruby builtin classes on Foundation is that instances respond to more messages. For instance, the +NSString+ class defines the +uppercaseString+ method. Since the +String+ class is a subclass of +NSString+, strings created in Ruby also respond to that method.
<pre>
'hello'.uppercaseString # => 'HELLO
</pre>
Respectively, the Ruby interface of these builtin classes is implemented on their Foundation counterparts. As an example, +Array+'s +each+ method is implemented on +NSArray+. This allows primitive types to always respond to the same interface, regardless of where they come from. +each+ will always work on all arrays.
<pre>
def iterate(ary)
ary.each { |x| p x }
end
iterate [42]
iterate NSArray.arrayWithObject(42)
</pre>
But the main purpose of this design is to allow the exchange of primitive types between Objective-C and Ruby at no performance cost, since they don't have to be converted. This is important as most of the types that will be exchanged in a typical application are likely going to be builtin types. A +String+ object created in Ruby can have its memory address passed as the argument of an Objective-C method that expects an +NSString+.
h4. Mutability
The Foundation framework ships a set of classes that have both mutable and immutable variants. Mutable objects can be modified, while immutable objects cannot.
Immutable Foundation types in RubyMotion behave like frozen objects (objects which received the +freeze+ message).
As an example, changing the content of an +NSString+ is prohibited, and an exception will be raised by the system if doing so. However, it is possible to change the content of an +NSMutableString+ instance.
<pre>
NSString.new.strip! # raises RuntimeError: can't modify frozen/immutable string
NSMutableString.new.strip! # works
</pre>
Strings created in RubyMotion inherit from +NSMutableString+, so they can be modifiedby default. The same goes for arrays and hashes.
However, the developer must be careful that it is very common for iOS SDK APIs to return immutable types. In these cases, the +dup+ or +mutableCopy+ messages can be sent to the object in order to get a mutable version of it, that can be modified later on.
h3. Interfacing with C
One does not need to be a C programmer in order to use RubyMotion, however some basic notions, explained in this section, will be required.
Objective-C is a superset of the C language. Objective-C methods can therefore accept and return C types.
Also, while Objective-C is the main programming language used in the iOS SDK, some frameworks are only available in C APIs.
RubyMotion comes with an interface that allows Ruby to deal with the C part of APIs.
h4. Basic Types
C, and indirectly Objective-C, has a set of basic types. It is common in iOS SDK APIs to accept or return these types.
An example are the following methods of +NSFileHandle+, which both respectively accept and return the C integer type, +int+.
<pre>
- (id)initWithFileDescriptor:(int)fd;
- (int)fileDescriptor;
</pre>
Basic C types cannot be created from Ruby directly, but are automatically converted from and to equivalent Ruby types.
The following piece of code uses the two +NSFileHandle+ methods described above. The first one, +initWithFileDescriptor:+, is called by passing a +Fixnum+. The second one, +fileDescriptor+, is called and a +Fixnum+ is returned back to Ruby.
<pre>
handle = NSFileHandle.alloc.initWithFileDescriptor(2)
handle.fileDescriptor # => 2
</pre>
This table describes all basic C types and discusses how they are converted from and to Ruby types.
|_<. C Type |_<. From Ruby to C |_<. From C to Ruby |
| +bool+ |/2. If the object is +false+ or +nil+, +false+, otherwise, +true+. Note: the +0+ fixnum will evaluate to +true+. |/2. Either +true+ or +false+. |
| +BOOL+ |||
| +char+ |/5. If the object is a +Fixnum+ or a +Bignum+, the value is returned. If the object is +true+ or +false+, +1+ or +0+ are respectively returned. If the object responds to the +to_i+ message, it is sent and the result is returned.|/5. Either a +Fixnum+ or a +Bignum+ object.|
| +short+ |||
| +int+ |||
| +long+ |||
| +long_long+ |||
| +float+ |/2. If the object is a +Float+, the value is returned. If the object is +true+ or +false+, +1.0+ or +0.0+ are respectively returned. If the object responds to the +to_f+ message, it is sent and the result is returned.|/2. A +Float+ object.|
| +double+ |||
When using an API that returns the +void+ C type, RubyMotion will return +nil+.
h4. Structures
C structures are mapped to classes in RubyMotion. Structures can be created in Ruby and passed to APIs expecting C structures. Similarly, APIs returning C structures will return an instance of the appropriate structure class.
A structure class has an accessor method for each field of the C structure it wraps.
As an example, the following piece of code creates a +CGPoint+ structure, sets its +x+ and +y+ fields, then passes it to the +drawAtPoint:withFont:+ method.
<pre>
pt = CGPoint.new
pt.x = 100
pt.y = 200
'Hello'.drawAtPoint(pt, withFont: font)
</pre>
It is possible to pass the field values directly to the constructor.
<pre>
pt = CGPoint.new(100, 200)
'Hello'.drawAtPoint(pt, withFont: font)
</pre>
RubyMotion will also accept arrays as a convenience. They must contain the same number and type of objects expected in the structure.
<pre>
'Hello'.drawAtPoint([100, 200], withFont: font)
</pre>
h4. Enumerations and Constants
C enumerations and constants are mapped as constants of the +Object+ class.
For instance, both +NSNotFound+ and +CGRectNull+, respectively an enumeration and a constant defined by Foundation, can be directly accessed.
<pre>
if ary.indexOfObject(obj) == NSNotFound
# ...
end
# ...
view = UIView.alloc.initWithFrame(CGRectNull)
</pre>
Note: some enumerations or constants defined in the iOS SDK may start with a lower-case letter, like +kCLLocationAccuracyBest+ (starting with +k+). Because Ruby constants must always start with a capital letter, their names must be corrected by changing the case of the first letter, becoming +KCLLocationAccuracyBest+ (starting with +K+) in Ruby.
<pre>
locationManager.desiredAccuracy = kCLLocationAccuracyBest # NameError: undefined local variable or method
locationManager.desiredAccuracy = KCLLocationAccuracyBest # works
</pre>
h4. Functions
C functions are available as methods of the +Object+ class. Inline functions, which are implemented in the framework header files, are also supported.
As an example, the +CGMakePoint+ function can be used in Ruby to create a +CGRect+ structure.
<pre>
pt = CGMakePoint(100, 200)
'Hello'.drawAtPoint(pt, withFont: font)
</pre>
Note: most functions in the iOS SDK start by a capital letter. For those who accept no argument, it is important to explicitely use parentheses when calling them, in order to avoid the expression to be evaluated as a constant lookup.
<pre>
NSHomeDirectory # NameError: uninitialized constant NSHomeDirectory
NSHomeDirectory() # works
</pre>
h4. Pointers
Pointers are a very basic data type of C. Conceptually, a pointer is a memory address that can point to an object.
In the iOS SDK, pointers are typically used as arguments to return objects by reference. As an example, the +error+ argument of this +NSData+ method expects a pointer that will be set to an +NSError+ object in case of failure.
<pre>
- (BOOL)writeToFile:(NSString *)path options:(NSDataWritingOptions)mask error:(NSError **)errorPtr
</pre>
RubyMotion introduces the +Pointer+ class in order to create and manipulate pointers. The type of the pointer to create must be provided in the +new+ constructor. A pointer instance responds to +[]+ to dereference its memory address, and +[]=+ to assign it to a new value.
The +NSData+ method above can be used like this in Ruby.
<pre>
# Create a new pointer to the object type.
error_ptr = Pointer.new(:object)
unless data.writeToFile(path, options: mask, error: error_ptr)
# De-reference the pointer.
error = error_ptr[0]
# Now we can use the `error' object.
$stderr.puts "Error when writing data: #{error}"
end
</pre>
In the case above, we need a pointer to an object. +Pointer.new+ can also be used to create pointers to various types, including the basic C types, but also structures.
+Pointer.new+ accepts either a +String+, which should be one of the "Objective-C runtime types":http://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html, or a +Symbol+, which should be a shortcut. We recommend the use of shortcuts.
Following is a table summarizing the pointers one can create.
|_<. C Type Pointer |_<. Runtime Type String |_<. Shortcut Symbol |
| +id * + | +'@'+ | +:object+ |
| +char * + | +'c'+ | +:char+ |
| +unsigned char * + | +'C'+ | +:uchar+ |
| +short * + | +'s'+ | +:short+ |
| +unsigned short * + | +'s'+ | +:ushort+ |
| +int * + | +'i'+ | +:int+ |
| +unsigned int * + | +'I'+ | +:uint+ |
| +long * + | +'l'+ | +:long+ |
| +unsigned long * + | +'L'+ | +:ulong+ |
| +long long * + | +'q'+ | +:long_long+ |
| +unsigned long long * + | +'Q'+ | +:ulong_long+ |
| +float * + | +'f'+ | +:float+ |
| +double * + | +'d'+ | +:double+ |
RubyMotion supports the creation of structure pointers, by passing their runtime type accordingly to +Pointer.new+, which can be retrieved by sending the +type+ message to the structure class in question. For instance, the following snippet creates a pointer to a +CGRect+ structure.
<pre>
rect_ptr = Pointer.new(CGRect.type)
</pre>
Pointers to C characters, also called C strings, are automatically converted from and to +String+ objects by RubyMotion.
h4. Function Pointers and Blocks
TBD
h3. Memory Management
RubyMotion provides automatic memory management; the developer does not need to reclaim unused objects.
Since memory can be limited on iOS hardware, the developer must be careful about not creating large object graphs.
RubyMotion implements a form of garbage collection called reference counting. An object has an initial reference count of zero, is incremented when a reference to it is created, and decremented when a reference is destroyed. When the count reaches zero, the object's memory is reclaimed by the collector.
Object cycles, when two or more objects refer to each other, are handled by the garbage collector.
RubyMotion's memory management system is designed to simplify the development process. Unlike traditional Objective-C programming, object references are automatically created and destroyed by the system. Similarly, because object cycles will be garbage-collected, the developer does not need to keep in mind the entire object graph of his project and accordingly use weak references.
h4. Immediate Types
The +Fixnum+ and +Float+ types in RubyMotion are immediates; they don't use memory resources to be created. The runtime uses a technique called "tagged pointers":http://en.wikipedia.org/wiki/Tagged_pointer to implement this.
The ability to use these types without affecting the memory usage is important as a sizable part of a real-world app is spent in control drawing, which can make intensive use of arithmetic algorithms.
h4. Objective-C Objects
Objects created by Objective-C APIs are automatically managed by RubyMotion. There is no need to send the +retain+, +release+ or +autorelease+ messages to them.
The following piece of code allocates two +NSDate+ objects using different constructions. In typical Objective-C, the returned objects would need to be differently managed. In RubyMotion, both objects will be entitled to garbage-collection.
<pre>
date1 = NSDate.alloc.init
date2 = NSDate.date
</pre>
h4. CoreFoundation Objects
Objects created by CoreFoundation-style APIs must be explicitely released by the developer, by using the +CFRelease()+ function. RubyMotion will not garbage-collect them otherwise.
<pre>
attributed_string = CFAttributedStringCreate(nil, 'Hello World', {})
do_something(attributed_string)
# At this point, attributed_string is leaking, we need to manually release it.
CFRelease(attributed_string)
# Now, attributed_string is entitled to garbage-collection.
</pre>
h3. Concurrency
The ability to run code concurrently became critical as multicore processors appeared on iOS devices. RubyMotion has been designed around this purpose.
RubyMotion has the concept of virtual machine objects, which wrap the state of a thread of execution. A piece of code is running through a virtual machine.
Virtual machines don't have locks, and there can be multiple virtual machines running at the same time, concurrently.
Unlike some Ruby implementations, race conditions are possible in RubyMotion, since there is no "Global Interpreter Lock":http://en.wikipedia.org/wiki/Global_Interpreter_Lock (GIL) to prohibit threads from running concurrently. The developer must be careful to secure concurrent access to shared resources.
Different options are available to write concurrent code in RubyMotion.
h4. Threads and Mutexes
The +Thread+ class spawns a new POSIX thread that will run concurrently with other threads. The +Mutex+ class wraps a POSIX mutex, and can be used to isolate concurrent access to a shared resource.
h4. Grand Central Dispatch
RubyMotion wraps the "Grand Central Dispatch":http://developer.apple.com/library/ios/#documentation/Performance/Reference/GCD_libdispatch_Ref/Reference/reference.html (GCD) concurrency library under the +Dispatch+ module. It is possible to execute both synchronously and asynchronously blocks of code under concurrent or serial queues.
Albeit more complicated to comprehend than regular threads, sometimes GCD offers a more elegant way to run code concurrently. GCD maintains for the developer a pool of threads and its APIs are architectured to avoid the need to use mutexes.
h2. Project Management
h3. Creation
RubyMotion projects are created by passing the +create+ command to +/usr/bin/motion+. RubyMotion projects are directories.
<pre>
$ motion create Hello
$ cd Hello
$ ls
Rakefile app resources
</pre>
The following table explains the anatomy of a project directory.
|_<. File/Directory |_<. Purpose |
|+Rakefile+ | This file contains the configuration of the project, as well as a default set of tasks. It can be edited to change the configuration or add new tasks. |
| +app/+ | This directory contains the Ruby code of the project. In a new project, a +main.rb+ file is created automatically. |
| +resources/+ | This directory contains the resources files of the project, such as images or sounds. In a new project, this directory is empty. |
h3. Configuration
The +rake config+ task will dump the project configuration. Each configuration variable has a sensible default value that can be manually overriden in the +Rakefile+ file.
|_<. Variable |_<. Discussion |
|+name+ | Project name, as a +String+. The default value is the name passed to +motion create+. |
|+version+ | Project version, as a +String+. The default value is +'1.0'+. |
|+identifier+ | Project identifier, as a +String+, in reverse DNS format. The default value is the concatenation of +"com.yourcompany."+ and the +name+ variable. |
|+delegate_class+ | Name of the application delegate class, as a +String+. The default value is +'AppDelegate'+ and the class is defined in +app/main.rb+.|
|+files+ | Project files, as an +Array+. The default value is the result of the following expression: +Dir.glob('./app/**/*.rb')+ (every +.rb+ file in the +app+ directory). |
|+frameworks+ | The names of iOS frameworks to link against, as an +Array+. It should contain the names of public iOS frameworks, typically present in +/System/Library/Frameworks+. The default value is +['UIKit', 'Foundation', 'CoreGraphics']+. |
|+build_dir+ | Directory for build products, as a +String+. The directory will be created by the build system if it does not exist yet. The default value is +'build'+.|
|+resources_dir+ | Directory for resources files, as a +String+. The default value is +'resources'+. |
|+icons+ | List of resource files to use for icons, as an +Array+. The files must conform to the "HIG guidelines":http://developer.apple.com/library/ios/#documentation/userexperience/conceptual/mobilehig/IconsImages/IconsImages.html. The default value is +[]+, an empty array. |
|+device_family+ | Family of devices to support. Possible values can be: +iphone+, +ipad+ or +[:iphone, :ipad]+ (for a universal application). The default value is +:iphone+.|
|+interface_orientations+ | Supported interface orientations. Value must be an +Array+ of one or more of the following symbols: +:portrait+, +:landscape_left+, :+landscape_right+:, and +:portrait_upside_down+. The default value is +[:portrait, :landscape_left, :landscape_right]+. |
|+platforms_dir+ | Platforms directory where to find SDKs, as a +String+. The default value is +'/Developer/Platforms'+. |
|+sdk_version+ | Version number of SDK to target, as a +String+. The default value is the version number of the most recent SDK in +platforms_dir+. Example: +'5.0'+|
|+codesign_certificate+ | The name of the certificate to use for codesigning, as a +String+. The default value is the first iPhone Developer certificate found in keychain. Example: +'iPhone Developer: Darth Vader (A3LKZY369Q)'+.|
|+provisioning_profile+ | Path to the provisioning profile to use for deployment, as a +String+. The default value is the first +.mobileprovision+ file found in +~/Library/MobileDevice/Provisioning+. |
Custom values for the configuration settings can be added by tweaking the +Motion::App.setup+ block in the +Rakefile+ file.
As an example, let's take the configuration block of a fictional video player application for the iPad. The device family setting has to change from its default value, iPhone, to iPad. Also, the application makes use of an additional framework, AVFoundation, for audio-video functionality.
<pre>
Motion::Project::App.setup do |app|
app.name = 'Awesome Video Player'
app.device_family = :ipad
app.frameworks << 'AVFoundation'
end
</pre>
h4. Files Dependencies
By default, RubyMotion will compile files in the regular sorting order of the filesystem. When a RubyMotion application starts, the main scope of each file will then be executed in that specific order.
Sometimes, the developer will want to customize the order, if for instance one file makes use of a constant defined in another.
<pre>
$ cat app/foo.rb
class Foo
end
$ cat app/bar.rb
class Bar < Foo
end
</pre>
In the example above, using the default order, +bar.rb+ will be compiled before +foo.rb+, resulting in a constant lookup error, because the +Foo+ constant has not been defined yet when we execute the code in +bar.rb+.
To fix that problem, the +files_dependencies+ method can be used in the +Rakefile+. This method accepts a +Hash+ which should be a set of files dependencies.
<pre>
Motion::Project::App.setup do |app|
# ...
app.files_dependencies 'app/foo.rb' => 'app/bar.rb'
end
</pre>
After this change, the build system will compile +bar.rb+ before +foo.rb+.
h4. Using 3rd-Party Libraries
The iOS SDK has a significant amount of functionality built-in that one can use from a RubyMotion project, however, sometimes a developer will need to use a 3rd-party library that provides a missing feature of iOS.
To vendor a 3rd-party library in a RubyMotion project, the source code must be available somewhere on the filesystem. It is recommended to keep the 3rd-party libraries required by the project at the same place, for instance under a +vendor+ directory.
The +vendor_project+ method can be called from the +Rakefile+. Its first argument must be the path to the 3rd-party library, for example +"vendor/OAuth2Client"+. Its second argument must be a symbol representing the project type, like +:xcode+. Other arguments can be provided as a list of key/value objects.
Here is a table summarizing project types and key/value objects. At the time of writing, only Xcode-based projects are supported.
|_<. Project Type |_<. Key |_<. Discussion |
|/3. +:xcode+ | +:xcodeproj+ | Name of the Xcode project file to use. Optional if there is one +.xcodeproj+ file in the directory. |
|| +:target+ | Name of the target to build. Optional if there is one target in the Xcode project file. |
|| +:configuration+ | Name of the configuration to build. If not provided, will use +"Release"+. |
As an example, assuming our video player project wants to make use of the OAuth2Client 3rd-library library, a +vendor+ directory would be created and the OAuth2Client source code would be added there.
<pre>
$ cd AwesomeVideoPlayer
$ ls vendor
OAuth2Client
</pre>
Then, the +Rakefile+ can be modified as such.
<pre>
Motion::Project::App.setup do |app|
# ...
app.vendor_project('vendor/OAuth2Client', :xcode,
:xcodeproj => 'OAuth2Client.xcodeproj',
:target => 'OAuth2Client',
:configuration => 'Release')
app.frameworks << 'Security' # OAuth2Client depends on Security.framework
end
</pre>
h4. Advanced Info.plist Settings
An iOS app has its configuration described into the +Info.plist+ file, which is located inside the application bundle.
In a RubyMotion project, the +Info.plist+ file is derived from the configuration object exposed in the +Rakefile+ file. For example, the +CFBundleName+ variable in +Info.plist+ is derived from the +name+ variable in the +Rakefile+. Most of the time, the configuration object will let the developer control the necessary settings of his project.
However, it might happen that the developer will want to change advanced settings of a project. The +Rakefile+ interface does not cover all the possibilities, but it exposes the internal +Info.plist+ data structure.
As an example, our video player might need to register a custom URI scheme, so that it can open custom URLs from the web browser. For instance, +x-videoplayer://play+. The "Info.plist reference":http://developer.apple.com/library/ios/#documentation/General/Reference/InfoPlistKeyReference/Introduction/Introduction.html suggests that the +CFBundleURLTypes+ key should be used.
In order to manually set the +CFBundleURLTypes+ key, the +info_plist+ method can be used, which returns a +Hash+ object which can be changed.
<pre>
Motion::Project::App.setup do |app|
# ...
app.info_plist['CFBundleURLTypes'] = [
{ 'CFBundleURLName' => 'com.mycompany.x-videoplayer',
'CFBundleURLSchemes' => ['x-videoplayer'] }
]
end
</pre>
h3. Build
The +rake build+ task builds the project into the temporary +build+ directory. Two different versions of the project will be built, one to run in the iOS simulator (on the Mac itself) and one to run on the iOS device.
The following steps are performed:
# It compiles each Ruby source code file into optimized machine code, translating the Ruby syntax tree into an intermediate representation language (using "LLVM":http://llvm.org/), then assembly. The compiler will generate code for either the Intel 32-bit (+i386+) or ARM (+armv6+, +armv7+) instruction sets and ABIs depending on the target.
# It links the machine code with the RubyMotion runtime statically to form an executable. The linker also includes metadata for the C APIs that the project uses, as well as 3rd-party libraries vendored from the configuration.
# It creates an +.app+ bundle and copies the executable there. The +Info.plist+ file is generated based on the project configuration. Each resource file in the +resources+ directory is copied in the bundle.
# It codesigns the bundle based on the certificate and provisioning profile specified in the project configuration.
Normally the user does not need to explicitly build the project, as the +build+ task is a dependency of the other tasks.
h3. Simulation
The +rake simulator+ task builds the project for the iOS simulator, and runs the application in the simulator.
The default +rake+ task is a shortcut to +rake simulator+.
h3. Archiving
The +rake archive+ task builds the project for the iOS device, and generates in the +build+ directory an +.ipa+ archive suitable for ad-hoc distribution or submissions to the App Store.
<pre>
$ rake archive
$ file build/Hello.ipa
build/Hello.ipa: Zip archive data, at least v1.0 to extract
</pre>
h3. Deployment
The +rake deploy+ task uploads an archive version of the application to an iOS device.
There must be one iOS device connected via USB to the Mac. The deployment task will attempt to upload the application to the first discovered iOS device on the USB channel.
The process will fail in the following cases:
* No iOS device was found on USB.
* The project builds on a version of iOS greater than the version of iOS running on the device.
* The project doesn't use the appropriate certificate and provisioning profile linked to the device.
* There is a USB connection issue when talking to the device.
Otherwise, the process returns successfully and the application is then available on the device springboard.
h2. Library
TBD.