Издательский дом ООО "Гейм Лэнд"ЖУРНАЛ ХАКЕР 116, АВГУСТ 2008 г.

XCoding под iPhone

Дмитрий «Dem@n» Тарасов (admin@dtarasov.ru)

Хакер, номер #116, стр. 116-090-1

Введение в разработку ПО для iPhone

Прошел уже год с момента выпуска iPhone 1.0. Можно долго рассуждать по поводу значимости этого события, а также критиковать маркетинговую политику Apple по отношению к ряду стран, в числе которых и Россия. Но факт есть факт: iPhone – революционное мобильное устройство, задающее планку для остальных производителей. Попытаемся разобраться, как писать и распространять для него программные продукты.

Сегодня сложно найти в метро такой вагон, в котором не было бы владельца трендовой мобилки. Популярность устройства привела к формированию целого сообщества пользователей iPhone, среди которых оказалось много опытных программистов, за короткий срок умудрившихся взломать защиту устройства от использования SIM-карт любых операторов сотовой связи. После публикации средств «jailbreaking» (модификация прошивки с целью снятия ограничений) разлоченные iPhone можно без проблем заказать в интернете, а также купить на рынке электронной техники. Для нас с тобой это означает возможность приложить свои жилистые лапы к процессу разработки ПО для iPhone.

Разработка приложений с использованием движка Safari

До официальной публикации SDK у разработчиков не было возможности легальной разработки native – приложений для iPhone и iPod Touch. Учитывая огромный интерес к iPhone, Apple пошла на компромисс: позволила сторонним разработчикам создавать так называемые виджеты – приложения, выполняемые в веб–браузере Safari, интегрированном в iPhone и iPod Touch. Основным отличием виджетов от native–приложений является необходимость написания кода не на Objective C, а с использованием стандартных веб–технологий вроде HTML, CSS, JavaScript и AJAX. С точки зрения пользователя такое приложение отличается тем, что выполняется в веб-браузере и открывается не путем выбора иконки из главного меню устройства, а при выборе закладки. Для ознакомления с процессом создания и развертывания виджетов для iPhone рекомендую почитать книгу «Professional iPhone and iPod Touch Programming», а также заглянуть на http://developer.apple.com/webapps/.

Неофициальный и официальный методы разработки

Отсутствие официальной возможности создавать ПО не остановило энтузиастов. Они подготовили средства разработки, позволяющие создавать полноценный софт для JailBreaked iPhone. В процессе JailBreaking на аппарат устанавливается софтина с немудреным названием Installer. С ее помощью пользователи могут скачивать и устанавливать необходимый софт из каталога, который формируется из репозиториев (их адреса прописываются вручную в Installer). Так что JailBreaking – не только разлочка, но и процедура, позволяющая получить полный доступ к файловой системе iPhone. Описание процесса без труда можно найти в Сети, поэтому мы не будем на этом останавливаться.

Софт, распространяющийся через Installer, написан с использованием «неофициального» процесса разработки. До недавнего времени иного пути создания и даже установки стороннего ПО в iPhone не было. Но в марте этого года Apple осчастливили-таки общественность публикацией первой беты SDK. С тех пор на офсайте разработчиков Apple периодически публикуются новые версии беты SDK и документации (на момент написания статьи наиболее актуальной была восьмая). SDK представляет собой IDE XCode, набор необходимых библиотек, эмулятор и другие инструменты. В статье мы рассмотрим обе методики разработки софта, но предварительно нужно сказать несколько слов о технологиях, использующихся при разработке ПО для iPhone.

iPhone OS

Технологии, лежащие в основе ОС, принято представлять в виде слоев. Чем выше слой – тем выше уровень абстракции и тем чаще он используется для разработки. Нижние содержат технологии, предназначенные для выполнения низкоуровневых функций вроде базового ввода/вывода. При этом многие технологии ОС близки по духу к использующимся в настольной операционке.

Нижним слоем архитектуры в нашем случае является Core OS. Ядро iPhone OS базируется на адаптированном варианте ядра Mac OS X. Как водится, ядро служит для управления файловой системой, потоками, базовыми интерфейсами, межпроцессорным и сетевым взаимодействием, драйверами, виртуальной памятью т.д. Уровнем выше расположен Core Services Layer, предоставляющий приложениям необходимые фундаментальные сервисы (типы данных, port’n’socket communication, потоки и т.д.). Разработчику редко когда приходится обращаться к этому слою напрямую, но вышележащие слои делают так постоянно. Media Layer содержит аудио-, видео- и графические технологии, играющие важную роль в iPhone OS. Данный уровень представляет собой удобный фреймворк, позволяющий быстро и легко использовать мультимедиа при разработке.

Самый верхний слой – Cocoa Touch Layer. Он предоставляет высокоуровневый API, предназначенный для создания графических приложений, а также для управления событиями. Любые пользовательские интерфейсы iPhone OS и взаимодействие с пользователем проектируются с использованием Cocoa Touch. Технология является модифицированной версией фреймворка Cocoa, который используется при разработке ПО для Mac OS X. Поэтому она имеет ряд схожих с ним черт, но содержит и нововведения, связанные с кардинально отличающимся механизмом ввода информации в iPhone (мышку и клавиатуру заменяют прикосновения к экрану) и необходимые для доступа к встроенным в iPhone приложениям вроде Contacts и Photos.

Ищите леопарда

Чтобы программировать под iPhone, нужен Mac с установленной Mac OS X Leopard. Грустно, но это так. Вообще говоря, можно развернуть среду разработки на Unix и даже пытаться писать из-под VMWare, но это связано с рядом сложностей, которые мы не в состоянии охватить в рамках журнального материала, поэтому здесь и далее мы будем полагать, что работа идет в Mac OS X Leopard. Кроме того, необходимо установить и сконфигурировать SDK. Описание процесса настройки рабочей станции для «неофициальной» разработки можно прочитать в замечательной книжке «iPhone Open Application Development», которую легко найти в Сети.

Objective C

При разработке приложений для iPhone OS, а также MacOS 10.5 и выше используется язык программирования Objective C 2.0. Он является своеобразной надстройкой над ANSI C, предназначенной для гибкого объектно-ориентированного программирования. Не совсем понятно, чем Apple не угодил С++. Многие концепции Objective C заимствованы у одного из первых объектно-ориентированных языков Smalltalk. Тем не менее, программа для iPhone может содержать как код на Objective C, так и на C или C++.

При компиляции используются инструменты GNU Compilers Collection, которые распознают принадлежность кода к конкретному подвиду GNU C/C++ по расширению файла. В частности, C – код содержится в файлах с расширением *.c; C++ – код в *.mm; Objective C – в *.m.

Особенности Objective C

В Objective C, как и в C++, присутствуют классификаторы доступа к переменным – членам класса (@private, @protected, @public и @package). Разница в том, что эти классификаторы действуют только для объектов того же класса или его наследников. Для доступа к переменным – членам из других классов – необходимо реализовать соответствующие методы. Например, чтобы иметь возможность получать размеры объекта класса прямоугольника из объекта класса окна, понадобится реализовать в первом метод, возвращающий размеры.

Отличительным типом данных в Objective C является тип id, использующийся при динамической типизации.

Конструкция вида id anObject – это объявление указателя на объект. Ключевым словом для нулевого объекта (то есть для указателя, который ни на что не указывает) будет nil. Сам по себе id не несет абсолютно никакой информации об объекте (помимо того, что это, собственно, объект). Необходимые знания о методах и переменных – членах конкретного объекта – получаются при использовании так называемой isa-переменной, указывающей, к какому конкретно классу он относится. Само собой, этот подход имеет смысл применять только, если заранее неизвестно, к какому классу относится объект (или их совокупность).

Object Messaging

В Objective C принята концепция – объектам оправляются сообщения в случае необходимости вызова какого-либо метода. Скажем, конструкция [receiver message] означает, что объекту receiver посылается сообщение message. По своей сути оно является именем метода с указанием его параметров. К примеру, вызов метода setWidth(int) объекта класса CRect выглядит так:

[myRect setWidth:20.0];

Как видно, параметры метода отделяются от его названия двоеточием. Если обязательных параметров несколько, они также отделяются друг от друга с помощью двоеточия:

[myRect setOrigin:30.0 :50.0]

Необязательные аргументы при этом разделяются запятыми:

[receiver makeArray:array, member1, member2, member3]

Здесь метод makeArray имеет один обязательный параметр – array и 3 необязательных – member1, member2 и member3.

Как и в C, методы могут возвращать значения. В следующем примере булевой переменной isCompleted возвращается значение булевого метода isCompleted:

BOOL isCompleted;

isCompleted = [myOperation isCompleted];

Обрати внимание, что имя переменной и метода могут совпадать. Сообщения бывают вложенными, например, одному объекту прямоугольника можно присвоить размеры другого:

[myRect setSize:[anotherRect size]];

Не запрещается посылать сообщения nil-объектам. Иногда это полезно, например, когда необходимо узнать, инициализирован ли объект. Сообщение, вызывающее возвращающий значение метод, будет равно нулю.

Создание объектов

В Objective C объявление класса обязательно должно содержаться в файле-заголовке с расширением *.h, а реализация – в файле *.m. Объявление класса выделяется с помощью директивы @interface, а реализация – директивой @implementation. Объявление простого класса может выглядеть, например, так:

#import <UIKit/UIKit.h>

@interface SimpleClass : NSObject {

//объявление переменных

}

//объявление свойств и методов

@end

Выделение памяти для нового объекта осуществляется путем отправки сообщения alloc классу, экземпляр которого требуется создать. Создание экземпляра класса Rectangle может выглядеть так:

Id myRect;

myRect = [Rectangle alloc];

Метод alloc выделяет память для объекта, а также инициализирует нулевыми значениями все его переменные-члены – за исключением переменной isa, указывающей на принадлежность объекта к конкретному классу. Чтобы можно было использовать объект, необходимо провести более тщательную инициализацию. Обычно она выполняется путем вызова метода из семейства init:

myRect = [[Rectangle alloc] init]

Подобная инициализация обязательна для кода, содержащего отправку объекту сообщений. Вообще, существует несколько разновидностей методов инициализации. Каждый из них приемлем для объектов конкретного класса, но все начинаются с init. Например, инициализацию класса Rectangle на самом деле следовало бы проводить с помощью метода initWithPosition, принимающего аргумент size.

Для получения подробной информации по Objective C советую ознакомиться с материалами сайта http://developer.apple.com/iphone, а также почитать документ «The Objective-C 2.0 Programming Language», который можно там же и скачать.

Неофициальный Hello World

Рассмотрим процесс создания несложного приложения с использованием неофициального SDK. Информацию по установке и настройке можно получить в книге «iPhone Open Application Development» либо на http://code.google.com/p/iphone-dev.

Анатомия любого приложения для iPhone проста до крайности. Приложение, по сути, – это директория с именем вида HelloWorld.app, содержащая исполняемый файл приложения, файл манифеста и ресурсы.

Приведем пример. В простейшем случае директория содержит обязательные файлы:

  • Default.png – картинка с расширением 320х480 пикселей, отображающаяся в устройстве в момент инициализации приложения
  • HelloWorld – собственно, исполняемый файл приложения
  • Icon.png – иконка приложения, отображающаяся в SpringBoard
  • Info.plist – своего рода манифест приложения, файл, подготовленный в XML-формате и содержащий информацию, необходимую для инициализации приложения.

Наличие файлов Default.png, Icon.png и Info.plist обязательно для успешного старта приложения.

Проект же программы примерно выглядит так:

  • HelloWorld.app – созданная вручную директория, куда мы поместили ресурсы, исполняемый файл и манифест
  • main.m – файл, содержащий код функции main, с которой традиционно для C начинается выполнение программы
  • HelloWorld.h и HelloWorld.m – исходники класса приложения
  • MainView.h и MainView.m – исходники окна приложения
  • Makefile – файл, содержащий команды для sdk, необходимые для компиляции и сборки приложения

Шаблон проекта вместе с указанными файлами можно скачать по адресу http://dtarasov.ru/iphone/files/helloworld.rar или взять на нашем крутом DVD.

Рассмотрим исходники проекта поближе:

main.m:

#import <UIKit/UIKit.h>

#import “HelloWorld.h”

int main(int argc, char** argv)

{

NSAutoreleasePool* pool =

[[NSAutoreleasePool alloc] init];

return UIApplicationMain(argc,argv,

[HelloWorld class]);

}

Каждое приложение для iPhone содержит такое определение функции main. В первой и второй строках содержится директива #import, которая выполняет схожую с #inlude функцию. Но помимо простого подключения файла, #import следит за тем, чтобы заголовок класса не включался в проект более одного раза, заменяя тем самым стандартный workaround:

#ifndef _MYCLASS_H

#define _MYCLASS_H

...

#endif

В теле функции main создается пул очистки, который необходим для освобождения памяти, занимаемой удаляемыми объектами, а также создается и инициализируется объект приложения. После чего запускается цикл обработки событий.

HelloWorld.h:

#import <CoreFoundation/CoreFoundation.h>

#import <UIKit/UIKit.h>

@interface HelloWorld : UIApplication

{

UIWindow* window;

UIView* mainView;

}

-(void)applicationDidFinishLaunching:

(NSNotification*)aNotification’

@end

В этом примере объявляется класс HelloWorld, который наследуется от UIApplication. Объект создается из функции main. Переменные-члены данного класса – это объекты классов UIWindow и UIView. Перед тем, как отобразить элементы пользовательского интерфейса, необходимо создать окно, которое сможет их содержать, и наполнить его контентом. Переменная window необходима для создания, собственно, окна, а mainView, являющаяся объектом класса UIView, – для наполнения окна конкретным содержанием. При этом окно может содержать несколько переменных класса UIView. Метод applicationDidFinishLaunching унаследован от UIApplication, который вызывается после загрузки приложения в память. Он часто переопределяется для выполнения операции начального отображения пользовательского интерфейса следующим образом:

HelloWorld:

#import “HelloWorld.h”

#import “MainView.h”

@implementation HelloWorld

-(void) applicationDidFinishLaunching:

(NSNotification*) aNotification

{

Window = [[UIWindow alloc]

initWithContentRect:[UIHardware

fullScreenApplicationContentRect]];

CGRect windowRect = [UIHardware

fullScreenApplicationRect];

windowRect.origin.x = windowRect.origin.y = 0.0f;

mainView = [[MainView alloc]

initWithFrame:windowRect];

[window setContentView: mainView];

[window orderFront: self];

[window makeKey: self];

[window _setHidden: NO];

}

@end

Здесь мы создали окно, инициализировали, а также поместили в него контент, созданный объектом класса MainView.

MainView.h:

#import <CoreFoundation/CoreFoundation.h>

#import <UIKit/UIKit.h>

#import <UIKit/UITextView.h>

@interface MainView : UIView

{

UITextView* textView;

}

А тут мы помещаем в определение MainView переменную-член класса UITextView. Она понадобится для отображения текста.

MainView.m:

#import “MainView.h”

@implementation MainView

-(id)initWithFrame:(CGRect)rect

{

If((self==[super initWithFrame:rect])!=nil)

{

textView = [[UITextView alloc]

initWithFrame: rect];

[textView setTextSize: 18];

[textView setText:@”Hello, World”];

[self addSubview: textView];

}

return self;

}

@end

После успешной инициализации объекта MainView мы создаем новый объект, унаследованный от UITextView, который в свою очередь наследуется от UIVew. UITextView позволяет настраивать параметры отображаемого текста, что мы и делаем. А затем «накладываем» textView на mainView.

На этом этапе приложение готово к сборке. Нужно только соответствующим образом подготовить makefile (см. пример из указанной выше ссылки).

Все, – открываем консоль, набираем команды make и make package. Наше приложение готово к заливке в iPhone.

Для этого в устройстве должны быть установлены пакеты BSD Subsystem и OpenSSH (можно найти в инсталлере). На устройство можно передавать файлы посредством scp. Чтобы перенести наше приложение в iPhone, выполняем следующую команду:

scp –r HelloWorld.app root@iPhone_ip:/Applications,

где iPhone_ip – ip устройства в локальной WiFi-сети. В ответ появится запрос пароля. Для iPhone первого поколения следует ввести «alpine». Чтобы иконка приложения появилась в меню устройства, нужно либо перезапустить его, либо приконнектиться к нему по ssh и выполнить команду $killall SpringBoard.

Использование официального SDK

Официальный набор инструментов можно скачать, зарегистрировавшись на http://developer.apple.com/iphone. Там же доступна документация по использованию и общим вопросам разработки для iPhone 2.0. Важно понимать, что созданный с использованием официального SDK софт ориентирован на запуск под iPhone версии 2.0. На момент написания статьи получить прошивку 2.0 и загрузить написанное в XCode-приложение (IDE, идущее в комплекте с SDK) могли лишь разработчики, участвующие в Apple Developer Program. Проблема в том, что найти человека, которому удалось стать участником Apple Developer Program, автору не удалось. Это может быть связано с тем, что ADP на момент подготовки материала еще не была запущена, либо с тем, что на период бета-тестированя SDK Apple решили подстраховаться и дать возможность полноценной разработки ПО лишь избранным компаниям. Вероятнее всего, к моменту, когда ты прочтешь эти строки, финальная версия SDK уже станет доступна и внесет ясность относительно перспектив софта, написанного с его использованием.

DVD

Упомянутые в статье доки, сорцы и прочий полезный стафф, как обычно, ждут тебя на нашем диске!

Содержание
ttfb: 7.965087890625 ms