内容


使用 Eclipse CDT 编写本机 iPhone 应用程序

Windows 和 Linux 开发人员如何能够避开 iPhone SDK 并使用开源工具编写 iPhone 应用程序

Comments

开始之前

关于本教程

2008 年 7 月,在介绍 Apple iPhone 3G 和 iPhone OS V2.0 时,Apple Computer 发布了用于由第三方创建本机 iPhone 和 Apple iPod Touch 应用程序的应用程序开发环境的产品版本。但是应用程序开发环境仅适用于 Apple Mac OS X,只能为这个令人兴奋的平台开发本机应用程序,而使用 Microsoft® Windows® 和 Linux® 操作系统的开发人员无法使用该环境。

本教程将探究 Eclipse C Development Tooling(CDT)项目及如何与基于 C- 和 C++ 的项目结合使用。在本教程中,您将安装开源工具以帮助您为 Windows 和 Linux 上的 iPhone 平台开发本机应用程序,并了解用 Objective-C 编写的基本 iPhone 应用程序的源代码。

目标

本教程将向您展示在使用开源 GNU Compiler Collection(GCC)的情况下,如何使用 Eclipse 和 CDT 插件开发适用于 iPhone 平台的应用程序。使用这些工具编译 iPhone 的 Objective-C 示例应用程序。

先决条件

本教程是为具备初、中级技能和经验的 C 和 C++ 程序员撰写的。您应当对如何使用 UNIX® 命令行 shell 有一般了解,并且具备 C 语言的使用知识。iPhone Cocoa Touch 本机应用程序开发框架是用 Objective-C 编写并且基于 Mac OS X 中的 Cocoa 框架。本教程并未要求您熟悉 Objective-C 和 Mac OS X Cocoa 应用程序开发框架,但是此类技能对于理解 iPhone 平台十分有帮助。建议在学习完本入门教程后进一步研究如何进行 Cocoa 开发。

系统要求

要继续学习本教程,您需要:

  • 配备至少具有 1.5 GB 可用磁盘空间的 Windows 或 Linux 计算机。
  • 安装 Eclipse。
  • 将数据写入文件系统的 /usr/local 目录(对于 Windows 用户,C:/cygwin/usr/local)中的权限。
  • 通过安装插件修改 Eclipse 配置的权限。

iPhone 和 iPod Touch 平台

iPhone 平台及其同系 iPod Touch 分别是支持 WiFi 的移动电话和 Internet 移动设备,配有最新的图形用户界面(GUI)、功能强大的集成 Web 浏览器及各种各样的其他应用程序 —— 例如电子邮件、日历、联系人、记事本、通过集成 Google Maps 得到的基本 Geographic Information System(GIS)功能 —— 以及电影和音乐播放等娱乐功能。

iPhone 平台与 Mac OS X 一样基于 Darwin 操作系统及 Objective-C Cocoa 框架,并且经过修改可以适应配有 128 MB RAM、GB 级闪存及多触点触摸屏的基于 Advanced RISC Machines(ARM)的嵌入式设备。该平台还配备了用于检测设备方向和移动的加速计以及与 Sony PSP 和 PS2 控制台功能相匹敌的 3-D 图形。

Darwin、Objective-C 和 Cocoa Touch 框架

Objective-C 是扩展的 C 语言集,它向 C 语言中添加面向对象的功能,但是其语法与 C++ 语法有很大差别。二十世纪八十年代后期和九十年代早期,NeXT Computer 使用 Objective-C 作为其 NextStep 和 OpenStep 操作系统的首选开发语言。二十世纪九十年代中期,Apple 获得了 NeXT Computer 的技术并将 NextStep 和 OpenStep 的大部分内容吸收到 Mac OS 操作系统中,通过技术组合开发出 Darwin 和 Mac OS X。Darwin 是基于开源 UNIX 的操作系统,Apple 创建它作为 Mac OS X 平台的内核。

同 NextStep 和 OpenStep 一样,Mac OS X 和 iPhone 的开发工具也是基于 Objective-C 的。Apple 为 Mac OS X 创建了基于 Objective-C 的开发框架:Cocoa。iPhone 平台与 Mac OS X 平台一样基于 Darwin 操作系统内核及 Objective-C Cocoa 框架。Cocoa Touch 是 iPhone 的开发框架。

C++ 和 Objective-C 都是面向对象的 C 语言扩展。但是 C++ 与 Objective-C 之间存在关键差别。Objective-C 是一门语言并且是对象生命周期管理运行时,然而 C++ 只是一门语言,并且完全由程序员管理对象生命周期。其他主要差别是两者之间面向对象操作的语法。C++ 将扩展 C struct 处理语法,然而 Objective-C 创造了新的带有作用域的方括号语法。表 1 展示了两种语言之间的主要语法差异。

表 1. C++ 与 Objective-C 之间的主要语法差异
面向对象的概念C++Objective-C说明
方法调用object_or_class.method(2, 4);[object_or_class methodWithParam1: 2 param2: 4];C++ 扩展用于访问 struct 的元素的 C 语言语法,并将其重用于针对类或对象的方法调用。Objective-C 创造了带有作用域的方括号语法和以冒号为结尾的命名参数。
对象实例化 UIView contentView = new UIView(x, y, width, height); UIView contentView = [[UIView alloc] initWithFrame: CGRectMake(x, y, width, height)]; 在 C++ 中,new 关键字将为对象分配内存,并且调用一个与传入到代码中的参数最匹配的已声明构造函数。在 Objective-C 中,调用类的 alloc 方法,该方法将返回该类的未实例化对象。然后,对 alloc 所返回的对象调用 init 方法以设置实例的初始值。
类定义
class MyClass
{
private:
int myVariable;
void privateMethod();
public:
void setMyVariable(int param);
}
@interface MyClass : NSObject {
int myVariable;
}

@private
- (void)privateMethod;
@public
- (void)setMyVariable: (int)param;
@end
C++ 通过在 structclass 内添加方法定义来扩展 C struct 定义语法。它还添加了 privatepublic 关键字(以及本例中未使用的 protected 关键字)来提供封装的面向对象特性。在 Objective-C 中,@interface@end 关键字用于定义类的属性。Objective-C 将使用 @private@public@protected 关键字,它们的含义与 C++ 中类似命名的关键字等效。Objective-C 中的类必须从另一个类中继承。在本例中为 NSObject 类,然而在 C++ 中,类可以是它自己的类层次结构的顶点。
类及实例方法
class MyClass
{
private:
static int classVariable;
int instanceVariable;
public:
static void classMethod();
void instanceMethod(int param);
}
@interface MyClass : NSObject {
int instanceVariable;
}

+ (void)classMethod;
- (void)instanceMethod: (int)param;
@end
C++ 在类主体中使用 static 关键字来表示类或变量是一个类方法。Objective-C 在类方法的前面使用一个前置 +,并在实例方法的前面使用一个前置的 -
方法声明
MyClass::privateMethod() {
myVariable++;
}

MyClass::setMyVariable(int param) {
myVariable = param;
}
@implementation MyClass
- (void)privateMethod {
myVariable++;
}

- (void)setMyVariable: (int)param {
myVariable = param;
}
@end
C++ 添加作用域操作符 :: 以声明方法属于特定类。Objective-C 使用 @implementation@end 关键字把一组方法标记为属于特定类。

从 iPhone 中移除应用程序限制

解密 iPhone 应用程序开发内幕并揭示如何创建您自己的 iPhone 应用程序。

破解(Jailbreak)

Apple 在发布 iPhone 时,并不看重自由的应用程序开发环境,同时引述了保护手机供应商数据网络以免受到黑客手机上运行的恶意应用程序的攻击的需求。在 2008 年 3 月发布 iPhone 软件开发包(SDK)时,主要功能之一是只允许 iPhone 运行同时满足以下条件的应用程序:带有 Apple 签名;使用分发给与 Apple 有合作关系的 iPhone 开发人员的惟一序列号。

从 2007 年 9 月开始,自称为 iPhone Dev Team 的团队开发了一些方法,移除了 Apple 用于限定 iPhone 操作的限制。该团队还帮助创建了用于为设备编译程序的开源工具。

iPhone Dev Team 还创建了从 iPhone 和 iPod Touch 移除限制的工具。这些工具允许 iPhone 拥有者使用网络设备而非美国的 AT&T 或者允许在没有 iPhone 运营商的国家/地区使用 iPhone。此过程称为破解(unlocking)

本教程只介绍 “破解”,其中包含允许非 Apple 授权的应用程序运行在设备中。注意这些工具的使用不受 Apple 支持,并且如果 Apple 拥有第三方软件修改的证据,则可能导致设备的保修单无效。

破解工具:QuickPwn、XPwn、Pwnage 和 WinPwn

iPhone Dev Team 编写了一系列工具用于破解 iPhone 和 iPod Touch,每个工具都具有用户友好性和复杂性。在 参考资料 中可以获得安装详细信息和指向联机文档的链接。

如果拥有 iPhone、已经通过 Apple 在您所在的国家/地区内授权的服务提供商帐户使用它,并且只需要在设备中运行您自己开发的应用程序,则需要一种快速而简单的破解解决方案。同样地,如果拥有 iPod Touch,只需要一个简单的破解工具。

破解设备

QuickPwn 将快速执行破解任务。只需要下载适用于您的设备的正确 iPhone OS 版本(撰写本文时仅支持 iPhone OS 2.0 版至 2.0.2 版)。然后,根据软件中的指示信息,用 USB 充电/数据线将其与计算机连接起来并将 iPhone 置为 DFU 模式。10 分钟之内即可破解 您的设备。

如果您要在目前没有 Apple 授权的移动服务供应商的国家/地区内使用 iPhone,或者需要通过所在国家/地区中非指定 iPhone 服务供应商使用 iPhone,iPhone Dev Team 提供了 Xpwn、Pwnage(参见图 1)或 WinPwn。

图 1. Pwnage 是用于破解和解锁 iPhone 的最佳工具
Pwnage 是用于破解和解锁 iPhone 的最佳工具
Pwnage 是用于破解和解锁 iPhone 的最佳工具

安装详细信息及指向联机文档的链接位于 参考资料 小节中。实际上,Xpwn、Pwnage 和 WinPwn 允许您在计算机中创建破解版的 iPhone OS。然后使用 iTunes 把破解的 OS 下载到 iPhone 中。这听起来复杂,但实际做起来十分简单。工具将执行所有复杂工作并使用 Apple 在 iTunes 中使用的相同自动化机制升级 iPhone OS。

进行开发准备

在破解并重新启动了设备后,您的设备现在已经预先安装了完整的 UNIX 命令行及若干个实用程序,可以方便以后的开发。但是要利用该命令行并开始开发,则必须在设备中安装 OpenSSH 安全远程 shell 客户机和服务器、Linker Identity Editor、Respring 实用程序才能重新启动指示板。使用这些工具可以将程序传递到 iPhone 中并登录以在设备中执行命令,用伪造的密钥给代码签名以使 iPhone 运行它,并重置指示板来显示新拷贝的应用程序。

通过使用 APT 的包管理器前端 Cydia,可以在破解后的 iPhone 中轻松地安装软件。对于前一句话,Linux 用户可能会立刻觉得头疼:附带 Ubuntu 的基于 Debian 的 Linux 发行版中使用的 APT 包管理?是的,确实如此,我的朋友。

在运行 Cydia 之前,确保已经连接到手机数据网络或 WiFi — 最好是后者,因为 OpenSSH 比较庞大。运行 Cydia,等到它从内置源中下载包清单文件后,单击位于 Cydia 窗口底部的 Search。搜索并安装 openssh。然后搜索并安装 ldid。最后,搜索并安装 respring

现在已经在 iPhone 上安装了 OpenSSH,接下来需要确保它的安全性。所有 iPhone 都配有两个用户帐户:root 和 mobile。两个用户帐户都有相同的密码:alpine。登录到设备中并更改这两个帐户的密码。使用不同的密码 — 并且应当容易记忆。将设备连接到 WiFi 网络中(如果尚未这样做)并使用 Settings 应用程序查找其 IP 地址。

注:第一次通过 OpenSSH 连接到 iPhone 时,设备可能需要花费一分钟左右才能显示出响应,因为它正在生成惟一的系统密钥。后续连接应当是近乎即时完成的。

您现在可以开始为设备创建您自己的软件。下一节将介绍如何安装实现 iPhone 编程的工具链。

安装必备工具

在开发人员提及工具链 时,他们指的是一起使用的编译程序、汇编程序、链接程序及其他工具,用于从源代码和库开始构建适用于特定平台的可执行文件。Apple 为其 iPhone SDK 使用的 iPhone 工具链实际上是基于开源的 GCC — Linux、Sun Solaris 和 Berkeley Software Distribution(BSD)开发所使用的同一条工具链。由于它的开源天性,因此 iPhone SDK 的基本源代码实际上是可用的。iPhone Dev Team 的成员已经生成了一些指令和补丁,使其他平台中的开发人员能够构建和使用 iPhone SDK 的基本源代码。这就是我们接下来要做的。

在开始之前还有一些要求。您必须已经安装适用于所运行平台的工具链。必须安装可以将 GCC 源代码转换为适用于相应操作系统的可执行文件的工具。根据平台的不同,可以安装适用于 WindowsLinux 的工具。

在 Windows 中安装必备工具:Cygwin

Cygwin 是为 Windows 创建类似 UNIX 环境的一套 Windows 程序。Cygwin 团队并未使用虚拟化或模拟,而是创建了实现很多 UNIX 应用程序编程接口(API)的 Windows 动态载入库,然后继续修补许多常见 UNIX 工具的源代码,直至这些工具在 Windows 上的编译和运行足够稳定。他们对该环境的优化已经超过 13 年。要获得可以下载 Cygwin 安装程序的 Cygwin 站点的链接,请参阅 参考资料。Cygwin 安装程序实际上只是一次非常小的下载,因为您已在上一节安装 Cygwin 时下载了组成 Cygwin 发行版的其余程序。

要安装并配置 Cygwin:

  1. 下载 Cygwin 安装程序,运行该安装程序并在每次出现提示时单击 Next 直至看到下面所示的窗口。
    图 2. 安装过程中的 Cygwin 根目录选择部分
    安装过程中的 Cygwin 根目录选择部分
    安装过程中的 Cygwin 根目录选择部分
  2. 确保位于此窗口底部的选项与图 2 中的选项相匹配,否则您在使用本教程下一节中下载的示例代码和工具链源代码时会遇到问题。如果将 Cygwin 安装到不同于图 2 中所示目录的其他目录中,则必须牢记该目录并在本教程的其他各节提供的步骤中做出更改以匹配安装选项。建议您尽量保持简单性并按示例操作。
  3. 继续完成 Cygwin 安装窗口,保留选择默认选项,直至看到镜像选择屏幕,如下所示:
    图 3. 安装过程中的 Cygwin 镜像选择部分
    安装过程中的 Cygwin 镜像选择部分
    安装过程中的 Cygwin 镜像选择部分
  4. 选择距离您较近的镜像站点以在不同位置分布带宽使用。例如,尝试使用位于本州或本省的大学中的镜像。如果不能将任何 URL 识别为 “本地” URL,则选择 cygwin.osuosl.org 或 mirrors.kernels.org。如果遇到网络中的防火墙或代理服务器问题,则选择以 HTTP 为开头而非以 FTP 为开头的 URL 可能会有帮助。
  5. 继续进行安装,直至看到包选择窗口,如下所示:
    图 4. 安装过程中的 Cygwin 包选择部分
    安装过程中的 Cygwin 包选择部分
    安装过程中的 Cygwin 包选择部分
  6. 展开 Devel 类别,如下所示:
    图 5. 展开 Devel 类别以显示该类别内的包
    展开 Devel 类别以显示该类别内的包
    展开 Devel 类别以显示该类别内的包
  7. 对于 autoconf、binutils、bison、flex、gcc-c++ 和 make 包,单击所需包左侧的 Skip,如下所示。在选中 Binary 栏复选框和包的版本号之后单击 Skip 可以显示 “跳过” 的位置。注意实际版本号可能与显示的版本号不同,因为包一直在不断更新。
    图 6. 选择要包含在安装中的包
    选择要包含在安装中的包
    选择要包含在安装中的包
  8. 向下滚动,并展开 Net,如下所示:
    图 7. 展开 Net 类别显示它的包
    展开 Net 类别显示它的包
    展开 Net 类别显示它的包
  9. 选择 openssh 和 openssl 包,如图 8 所示:
    图 8. 选择 openssh 和 openssl 包
    选择 openssh 和 openssl 包
    选择 openssh 和 openssl 包
  10. 单击 Next。Cygwin 安装程序将从镜像站点中下载包并将其安装到先前指定的目录中。即使使用 2 GB 以上的宽带,不仅对于 Cygwin 包,而且对于镜像的其他开源软件,此过程也可能花费长达一个小时的时间,因为这些镜像的请求量非常大。

当 Cygwin 完成下载并安装包后,可以选择是否需要 Cygwin 在桌面上或在 “开始” 菜单中安装快捷方式按钮,然后就完成了所有操作。您刚刚已经安装了在 Windows 中本机运行的 GCC 工具链和完整的类似 UNIX 的环境。现在可以直接转到 “通过源代码安装 iPhone 工具链” 一节。

在 Linux 中安装必备工具

对于 Gentoo Linux 用户来说,一个好消息是他们很可能已经安装了所需安装的全部内容并且可以直接学习 “通过源代码安装 iPhone 工具链” 一节。如果使用的是 Debian、Ubuntu 或基于两者的任何一个发行版,则通过使用 apt-get 命令安装 bison、flex、build-essentials 和 autoconf 包,可以安装编译 iPhone 工具链所需的软件:

sudo apt-get install build-essential bison flex autoconf

如果使用的是 SuSE 或 Red Hat Linux 或者两者的任何派生版本(例如 CentOS),则需要安装 autoconf、binutils、bison、gcc、g++、flex,并使用 yum

sudo yum install bison flex autoconf binutils gcc gcc-c++ make

如果使用的是任何其他 Linux 发行版,请查阅文档以获得安装包的指导信息。需要安装为基于 yum 的系统列出的包。注意 gcc-c++ 在您的系统中可能使用不同的名称或者可能附带在 GCC 中。在安装了必备包后,则可以转到 “通过源代码安装 iPhone 工具链” 一节。

通过源代码安装 iPhone 工具链

下载工具链源代码

为什么通过源代码而非下载二进制文件构建工具链?一言以蔽之:许可。源代码包含较少的发行限制,是开源的。iPhone Dev Team 使用公共资源库中的源代码构建工具链并修改了代码,因此它可以在 Linux 和 Cygwin 中编译。

我打包了编译工具链所需的源代码并在 参考资料 小节中提供了一个链接。下载该文件并将其复制到用户帐户的 home 文件夹中。如果使用的是 Cygwin 并且 Cygwin 安装在推荐目录中,请将其复制到 C:/cygwin/home/yourusername 中。用您喜好的与 gzipped tar 兼容的工具解压缩该包,然后您将在 home 目录中找到名为 iphone-2.0-toolchain 的文件夹。

从 Apple 下载 iPhone 固件

接下来,获取 iPhone 固件并将其添加到工具链源代码中。需要的 Apple 代码是 iPhone V2.0 固件。它与获取的版本有重大关系:第一代 iPhone 需要使用 iPhone OS V2.0 固件,其文件名为 iPhone1,1_2.0_5A347_Restore.ipsw。要获得 Pwnage 或 WinPwn 的任何 how-to 文章了解下载链接,请查阅 参考资料

固件恢复文件只不过是一个 ZIP 文件。在拥有固件后,请将扩展名更改为 .zip 并用平台中任意一个解压缩实用程序打开它。在 ZIP 文件中,可以找到名为 018-3785-2.dmg 的文件。将此 DMG 文件复制到用户帐户的 home 文件夹中,该文件夹紧挨着先前的 iphone-2.0-toolchain 文件夹(Windows 用户:我们指的是 Cygwin 用户的 home 文件夹,而不是 Windows 用户的 home 文件夹)。

挂载操作系统映像

此 DMG 文件是设备中的操作系统分区的实际加密映像。必须先解密此文件,然后才能安装映像并提取所需的文件。幸运的是,iPhone Dev Team 编写了用于解密分区映像的工具并且已经获取并发布了加密密钥。下一步是编译映像解密程序并使用它获取可以挂载的已解密映像。打开终端会话(在 Windows 中,使用 Cygwin 快捷方式,而不要使用 Windows 命令行),然后键入以下内容:

gcc ~/iphone-2.0-toolchain/src/vfdecrypt.c -o ~/vfdecrypt -lcrypto

这条命令将把 DMG 解密程序代码编译为 home 文件夹中名为 vfdecrypt 的可执行文件。现在可以解密 DMG 文件。

~/vfdecrypt -i ~/018-3785-2.dmg -o ~/decrypted.dmg -k \ 
2cfca55aabb22fde7746e6a034f738b7795458be9902726002a8341995558990f41e3755

注意这是独立的两行,并且不要漏掉第一行末尾的反斜杠(\)。它实际上是一条命令,但是我们用反斜杠把它分为两行,以避免由于该命令的长度而引起的误解。您可能需要粘贴这两行代码,而非手动输入这么长的解密密钥。

在解密了 DMG 之后,请安装它并提取内容。Linux 用户可以安装 HFS 驱动程序并安装 DMG。如果您的发行版只有只读的 HFS 驱动程序也没关系,因为只需要复制一些文件。Windows 用户可以使用 PowerISO 或 Transmac(请参阅 参考资料)打开 DMG 文件并复制所需文件。

复制必需的文件夹

现在您已经挂载或打开了解密的 DMG,接下来必须复制其中的三个文件夹。假定 decrypted.dmg 指向所挂载的卷,而不管您是在 Linux 中挂载了它还是用 Transmac 或 PowerISO 打开了该文件。文件夹包括 decrypted.dmg/usr/lib、decrypted.dmg/System/Library/Frameworksdecrypted.dmg/System/Library/PrivateFrameworks。iphone-2.0-toolchain 文件夹中包括两个文件夹:iphone-fs/System/Library/ 和 iphone-fs/usr/。将 lib 文件夹复制到 iphone-fs/usr/ 中。将 Frameworks 和 PrivateFrameworks 复制到 iphone-fs/System/Library/ 中。以下步骤将帮助阐明需要复制的文件夹及其粘贴位置:

  1. 将 lib 文件夹临时复制到桌面上,如图 9 所示(您不久就将把它移到所属位置中)。
    图 9. 把 lib 文件夹复制到桌面上
    把 lib 文件夹复制到桌面上
    把 lib 文件夹复制到桌面上
  2. 将 Frameworks 和 PrivateFrameworks 文件夹临时复制到桌面上,如下所示:
  3. 将 lib 文件夹临时复制到桌面上,如图 9 所示(您不久就将把它移到所属位置中)。
    图 10. 复制 Frameworks 和 PrivateFrameworks 文件夹
    复制 Frameworks 和 PrivateFrameworks 文件夹
    复制 Frameworks 和 PrivateFrameworks 文件夹
  4. 把 lib 文件夹从桌面移到 iphone-fs/usr 文件夹中。
  5. 把 Frameworks 和 PrivateFrameworks 同时移到 iphone-fs//System/Library 文件夹中,如下所示:
  6. 将 lib 文件夹临时复制到桌面上,如图 9 所示(您不久就将把它移到所属位置中)。
    图 11. lib 文件夹进入 lib 文件夹,而 Frameworks 和 PrivateFrameworks 文件夹进入 /System/Library
    lib 文件夹进入 lib 文件夹,而 Frameworks 和 PrivateFrameworks 文件夹进入 /System/Library
    lib 文件夹进入 lib 文件夹,而 Frameworks 和 PrivateFrameworks 文件夹进入 /System/Library

编译工具链

在将文件夹复制到目标位置后,可以卸载 DMG 或者关闭 Transmac 或 PowerISO。现在,打开一个终端并键入以下命令:

cd ~/iphone-2.0-toolchain
./make-toolchain

这些命令将最终开始编译 iPhone 工具链并且将其安装到系统的 /usr/local 中。在分配给虚拟机(VM)640 MB RAM 的 VMware 中,运行 Microsoft Windows XP 的 2.0-GHz Core 2 Duo MacBook 执行此过程将花费大约两个小时。在等待几分钟后,您将看到大量无用信息非常快速地滚动。不必担心:这意味着它在工作!您只需担心它在显示若干错误行后是否停止并返回到 shell 提示符下,如下所示:

图 12. 构建过程中的示例错误行
构建过程中的示例错误行

如果构建过程停止,但您并未看到如图 12 中所示的那些错误行,则已经成功完成编译过程。现在您已经构建了工具链,已经准备好开始为 iPhone 创建您自己的软件。接下来,必须安装 Eclipse CDT 并且探究如何使用它在 Eclipse 内编写 C 和 C++ 程序。

用 Eclipse CDT 进行 C 和 C++ 开发

安装 Eclipse CDT 和其他插件

要在 Eclipse 中使用 Objective-C,需要安装两个软件:Eclipse CDT(用于管理 makefile 文件和项目文件)和 Eclipse 编辑器插件(用于提供 Objective-C 语法突出显示)。Color Editor 插件将提供 140 多种语言的语法突出显示。

如果尚未安装 Eclipse 或者不想把所有这些插件集成到 Eclipse 安装中,请查阅 EasyEclipse 项目(请参阅 参考资料)并下载适用于 C 和 C++ 发行版的 EasyEclipse。EasyEclipse 包括 Eclipse、Eclipse CDT、Subclipse 和用于管理源代码修改的 CVS 插件,以及用于语法突出显示的几个插件和默认支持不同语言(包括 Objective-C)的编辑器。在面向 Windows、Linux 和 Mac OS X 的单一下载中可以找到所有这些工具和插件。

如果已经手动安装 Eclipse 并且在添加插件时未遇到问题,则可以将两者轻松地添加到 Eclipse 副本中。要安装 Color Editor,请下载该插件并将 JAR 释放到 Eclipse 插件目录中。要安装 Eclipse CDT,请转到 Eclipse CDT 下载页面并查找您使用的 Eclipse 版本的正确 URL。在 Eclipse 中,转到 Help > Software Update > Find and Install... > Search for new features to install > New Remote Site... 并输入您的 Eclipse 版本的正确 CDT URL。继续安装并重新启动 Eclipse(有关 CDT 和 Color Editor,请参阅 参考资料)。

创建 Eclipse CDT 项目

在安装 Eclipse CDT 和 Color Editor 后,通过安装 EasyEclipse 或手动添加插件,可以开始用 C 或 C++ 编程。

首先为 Eclipse CDT 创建一个简单项目:

  1. 运行 Eclipse。在工作台中,选择 File > New > Project 以打开 New Project 窗口。
  2. 选择 General > Project,然后单击 Next,如下所示:
    图 13. New Project 窗口
    New Project 窗口
    New Project 窗口
  3. 将项目命名为 HelloWorld
  4. 如果使用的是 Windows,请将默认位置更改为 C:/cygwin/home/yourusername/HelloWorld,然后单击 Finish

    新项目将显示在工作台的 Project Explorer 中。如果 Eclipse 询问您是否切换到 C/C++ Perspective,请单击 Yes

  5. 在项目中创建两个文件:Makefile 和 HelloWorld.c。
  6. 将清单 1 中的代码复制到 Makefile 中。
    清单 1. Makefile 的内容
    CC=gcc
    CXX=g++
    LD=$(CC)
    
    all:    HelloWorld
    
    HelloWorld:    HelloWorld.o
        $(LD) $(LDFLAGS) -o $@ $^
    
    %.o:    %.c
        $(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $@
    
    clean:
        rm *.o HelloWorld
  7. 将清单 2 中的代码复制到 HelloWorld.c 中。
    清单 2. HelloWorld.c 的内容
    #include <stdio.h>
    
    int main(void) {
      printf("Hello, world!\n");
      return 0;
    }

运行项目

现在可以运行此项目。打开一个终端,并将目录切换到创建项目的位置。在其中,键入 make 命令并检查构建错误。如果正确创建了 Makefile 和 HelloWorld.c 文件,则应当不会有错误,并且在控制台中生成的输出应当只是两行:

gcc -c   HelloWorld.c -o HelloWorld.o
gcc  -o HelloWorld HelloWorld.o

在命令行中键入 make 将调用名为 make 的程序解析 makefile,这实际上告诉 make 它应当把 HelloWorld.c 编译到名为 HelloWorld.o 的对象文件中,把 HelloWorld.o 与标准的 C 库暗中链接在一起,并生成名为 HelloWorld 的可执行文件。这就是由 make 作为控制台输出生成的两条命令的意义所在。

如果以前在 UNIX 中用 C 进行过编程,这可能不是令人兴奋的特性。但是,最好通过以下命令执行已编译且链接的程序,检验简单的 C 代码和 makefile 文件是否工作正常:

./HelloWorld

这应当在控制台中生成 “Hello, world!” 输出。现在,使用新工具链修改 makefile 文件并生成在 iPhone 中运行的可执行文件。

创建 iPhone 的可执行文件

要创建这样一个可执行文件,需要用以下代码覆盖 makefile 文件的前两行:

CC=/usr/local/bin/arm-apple-darwin9-gcc
CXX=/usr/local/bin/arm-apple-darwin9-g++

这条命令将告诉 make 使用新的 iPhone 工具链,而不使用先前使用过的系统工具链。在命令行中键入 make clean,然后 make 程序将在底部运行 clean 规则,这将删除上一个版本的 makefile 文件以前生成的可执行文件和对象文件。

现在可以键入 make,然后系统将调用新工具链,而非系统工具链。这将为 iPhone 生成 HelloWorld.o 对象文件和 HelloWorld 可执行文件。将其复制到设备中以查看您的工具链是否正常工作。将设备连接到 WiFi 网络中,在 Settings 应用程序中查找其 IP 地址并用类似于下面的命令向其发送 HelloWorld 可执行文件(用您设备的 IP 地址替换 IPHONE_IP)。

scp HelloWorld root@IPHONE_IP:~/

执行程序

现在,通过 ssh 登录以执行程序。再次用您设备的 IP 地址替换 IPHONE_IP

ssh root@IPHONE_IP

登录后,您已经位于 iPhone 的根用户提示符下。

./HelloWorld

而且我打赌您对控制台中的 “Killed” 输出感到失望。在这里,iPhone 可执行文件装载程序要求所有可执行文件都被签名。iPhone Dev Team 曾经设法从 iPhone OS V2.0 中删除几乎所有限制,但是他们不希望被可执行文件装载程序搞得太复杂。还有机会:您可以通过随 Cydia 一起安装的 Linker Identity Editor 实用程序使用 ldid 命令。ldid 命令将生成一个伪造的可执行签名以骗过可执行文件装载程序。

ldid -S HelloWorld
./HelloWorld

这一次,一切顺利。您已经在设备中成功地运行几分钟前亲自编写和编译过的代码。您得出了 iPhone 初级程序员在此时可得出的惟一合乎逻辑的结论:让我们把 GUI 放入其中!

编译和构建 Cocoa Touch iPhone 本机应用程序包

假定先前的试验都成功,现在是时候开始行动了。您将创建一个可以通过在 iPhone 的触摸屏中触摸其图标来启动的简单 GUI 应用程序。

修改项目 makefile 文件

首先通过修改项目的 makefile 文件并编写一些 Objective-C 代码来创建 GUI 应用程序。为了保持简单性,examples/GUI/HelloWorldiPhone 中的 iphone-2.0-toolchain 文件夹含有样例程序代码。获取该 makefile 文件及该文件夹中的所有其他文件,并用它覆盖 Eclipse 项目文件。删除 HelloWorld.c,您将把它替换为用 Objective-C 编写的 HelloWorld.m。

在 Eclipse 中打开清单 3 所示的新 makefile 文件并查看它。

清单 3. 新 makefile 文件
CC=/usr/local/bin/arm-apple-darwin9-gcc
CXX=/usr/local/bin/arm-apple-darwin9-g++
LD=$(CC)

CFLAGS=-I/usr/local/lib/gcc/arm-apple-darwin9/4.2.1/include \
    -isysroot /usr/local/iphone-sysroot

LDFLAGS=-framework CoreFoundation -framework Foundation -framework UIKit \
    -lobjc -bind_at_load -isysroot /usr/local/iphone-sysroot

all:    HelloWorld.app

HelloWorld.app:    HelloWorld Info.plist
    mkdir -p HelloWorld.app
    cp Info.plist HelloWorld Default.png icon.png HelloWorld.app/

HelloWorld:    HelloWorld.o HelloWorldApp.o
    $(LD) $(LDFLAGS) -o $@ $^

%.o:    %.m
    $(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $@

clean:
    rm -rf *.o HelloWorld HelloWorld.app

此 makefile 文件版本将添加 CFLAGSLDFLAGS,它们将告诉编译程序和链接程序到何处去查找它所包含的文件和库文件。注意 -framework 链接程序参数。这些参数将告诉链接程序在准备 iPhone 工具链时使用从 iPhone 固件中获取的框架。

CC 编译规则也已经更改。您不再把 .c 文件编译为 .o 文件;现在将关注 .m 文件。正如使用 HelloWorld.m 替换 HelloWorld.c 时您推断的那样,.m(代表模块)是 Objective-C 程序的源文件。

名为 HelloWorld.app 的程序有一个附加规则。查看规则下面的命令,它看上去是放置可执行文件和一些其他文件(如 Info.plist)的文件夹。清单 4 显示了该文件。

清单 4. Info.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN"
 "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>CFBundleDevelopmentRegion</key>
    <string>en</string>
    <key>CFBundleExecutable</key>
    <string>HelloWorld</string>
    <key>CFBundleIdentifier</key>
    <string>com.pjtrix.helloworld</string>
    <key>CFBundleInfoDictionaryVersion</key>
    <string>0.1</string>
    <key>CFBundleName</key>
    <string>HelloWorld</string>
    <key>CFBundlePackageType</key>
    <string>APPL</string>
    <key>CFBundleShortVersionString</key>
    <string>1.0.0</string>
    <key>CFBundleSignature</key>
    <string>????</string>
    <key>CFBundleVersion</key>
    <string>1.0</string>
</dict>
</plist>

iPhone 指示板 UI 将使用 Info.plist 文件得出可执行文件的名称及怎样调用触摸屏上的图标。Info.plist 用于把 HelloWorld.app 从包含一些内容的文件夹转换为真正的 iPhone 应用程序包。注意 Info.plist 的名称中有一个大写的 I:iPhone 指示板十分严格并要求使用精确命名的包中的文件。

该包也包含两个图形文件:Default.png 和 icon.png。iPhone 指示板将使用 icon.png 在指示板中作为程序的图标。在用户等待可执行文件装载并显示其 UI 时,Default.png 用于在屏幕中显示一张虚拟图形。

注:icon.png 文件名必须全部小写,否则将不会显示。同样地,Default.png 必须拥有大写的 D,否则它将不会在应用程序启动时显示。

现在,继续研究应用程序的实际内容:关键的 Objective-C 代码。

Objective-C 代码

从 HelloWorld.m 开始,如清单 5 所示:

清单 5. HelloWorld.m
//
//  HelloWorldApp.h
//  HelloWorld
//
//  Created by PJ Cabrera on 08/18/2008.
//  Copyright PJ Cabrera 2008. All rights reserved.
//

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import "HelloWorldApp.h"

int main(int argc, char *argv[]) {
    // This autorelease pool is managed by the UI's event dispatcher. It autoreleases 
    // any allocated objects that fall out of scope. The iPhone's implementation of 
    // Objective-C 2.0 does not have garbage collection yet, but autorelease pools and 
    // proper release of allocated objects is still a good practice.
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

    // This is where UI execution gets started. This instantiates the UIApplication
    // subclass and UIApplicationDelegate subclass specified as string parameters. 
    // The name of an UIApplication subclass can be passed as both UIApplication and 
    // UIApplicationDelegate.
    UIApplicationMain(argc, argv, @"HelloWorldApp", @"HelloWorldApp");

    // Force release of the autorelease pool and all objects still allocated.
    [pool release];
    return 0;
}

看上去它并没有与 C 有太多不同。Foundation 和 UIKit 是在 Cocoa Touch 平台中使用得最多的两个 Objective-C 框架。Foundation 是在 Cocoa 和 Cocoa Touch 中定义字符串、列表和基本的面向对象层次结构的位置。UIKit 将定义 iPhone 应用程序中的大量 UI 元素。

作为 C 的扩展集,Objective-C 的应用程序启动是按照与 C 中完全相同的方法定义的:它全部从 main 函数开始。main 函数中的第一行代码是这些代码中第一部分 Objective-C 代码。在那里,您将分配并初始化 Objective-C 类的实例 NSAutoreleasePool,它用于管理内存。在 Mac OS X 和 Objective-C V2 中,它更类似垃圾回收,但是在此版本的 iPhone OS 中并未在 iPhone Objective-C 环境中完全实现它。

第二行代码是 UI 框架开始执行的位置。UIApplicationMain 将把在最后两个字符串参数中命名的类实例化,并在这两个获得应用程序轮询的类实例中调用具体方法。在 UI 退出时将调用最后一段代码。它将释放自动释放池(auto-release pool)并返回到调用环境中。

现在,查看 HelloWorldApp.m。这是 UIApplicationMain 移动操作的位置。把下面的文件载入 Eclipse。

清单 6. HelloWorldApp.m
//
//  HelloWorldApp.m
//  HelloWorld
//
//  Created by PJ Cabrera on 08/18/2008.
//  Copyright PJ Cabrera 2008. All rights reserved.
//

#import "HelloWorldApp.h"

@implementation HelloWorldApp

- (void)applicationDidFinishLaunching:(UIApplication *)application {
    // Create a "full-screen" window to hold the UI.
    window = [[UIWindow alloc] initWithContentRect: 
        [UIHardware fullScreenApplicationContentRect] ];

    // Create a view to hold the window contents.
    contentView = [[UIView alloc] initWithFrame: CGRectMake(0.0f, 0.0f, 320.0f, 480.0f)];

    // Create a navigation bar for the top of the view, with two buttons.
    // The buttons do not do anything in this example.
    nav = [[UINavigationBar alloc] initWithFrame: CGRectMake(0.0f, 0.0f, 320.0f, 48.0f)];
    [nav pushNavigationItem:[[UINavigationItem alloc] initWithTitle:@"Hello World"]];
    [nav showButtonsWithLeftTitle: @"Left" rightTitle: @"Right"];
    [nav setBarStyle: 0];
    [contentView addSubview: nav];

    // Create a text view, this is a basic text editor, with incorporated keyboard.
    text = [[UITextView alloc] initWithFrame: CGRectMake(0.0f, 48.0f, 320.0f, 480.0f)];
    [text setText: [[NSString alloc] 
        initWithString: @"Hello World\nCocoa Touch Application"]];
    [contentView addSubview: text];

    // UIWindow con only hold one view, the contentView. The contentView can hold many 
    // navigation controllers, which control the different views in your application.
    window.contentView = contentView;

    // These three instructions effectively show the window.
    [window orderFront: self];
    [window makeKey: self];
    [window _setHidden: NO];
}

- (void)dealloc {
    // Release the UI elements as they were allocated
    [text release];
    [nav release];
    [contentView release];
    [window release];

    // And don't forget to call the parent class dealloc
    [super dealloc];
}

@end

UIApplicationMain 实例化 HelloWorldApp 类时,应用程序执行将从名为 applicationDidFinishLaunching 的方法重新开始。这是创建从用户角度启动应用程序的初始 UI 元素的位置。首先,函数通过调用 UIHardware 类方法 fullScreenApplicationContentRect 来分配窗口实例并初始化屏幕大小。

接下来,它将分配并初始化 UIView 实例,该实例将保存所有其他屏幕元素。包含本例中仅用于显示的带有 LeftRight 两个按钮的导航栏。还有一个较大的 UITextView 实例,其中包含单独两行文本 “Hello, World” 和 “Cocoa Touch Application”。最后,将此视图设为窗口的主视图,并将窗口设为接收输入并且可见。

如果运行 make 且一切运行正常,则 make 应当已经创建了 HelloWorld.app 文件夹并将 Info.plist 文件、icon.png 和 Default.png 图像、HelloWorld 可执行文件复制到其中。将该文件夹复制到设备中。像以前一样,在下面的命令中把 IPHONE_IP 替换为您的 iPhone 的 IP 地址。

scp -r HelloWorld.app root@IPHONE_IP:/Applications/
ssh root@IPHONE_IP

在登录到设备中后,给可执行文件签名以使其可以运行。

ldid -S /Applications/HelloWorld.app/HelloWorld

访问您的应用程序

要从 iPhone 指示板访问您的应用程序,需要把整个应用程序包复制到 iPhone 文件系统的根目录中名为 Applications 的文件夹中。但是为了在指示板中显示应用程序而无需重新启动设备,接下来运行在教程的开头安装的 Respring 应用程序,然后 “重新触发” 指示板。

在重新触发指示板后,HelloWorld 应用程序将显示在其他图标之间。触摸它以启动并查看:位于顶部带有 LeftRight 两个按钮的导航栏;以及带有位于两个独立行的 “Hello World” 和 “Cocoa Touch Application” 的大文本视图。并且还有一个很大的惊喜:触摸文本区域,然后键盘将从屏幕的底部弹出以执行键入。在创建文本区域时,将 “自动” 附带键盘。您无需编写代码即可启用键盘。

结束语

使用 Eclipse 为 iPhone 编写应用程序并不是一帆风顺。Objective-C 不受重构工具的支持,此时设置远程调试并不容易(即使 GDB 支持 Objective-C 调试),并且必须安装诸如 Color Editor 之类的第三方插件才能突出显示 Objective-C 代码的语法。我本来可以花费更多时间设置 Eclipse CDT 以允许在 Eclipse 中进行编译而非在命令行中使用 make。但是这样一来,这将变成 Eclipse CDT 教程,而不是 Cocoa Touch 教程。

随着时间的推移,我希望能够吸引一群开发人员来帮助我扩展 Eclipse CDT 的 Objective-C 支持。如果需要了解在不使用 iPhone SDK 的情况下,在 Windows 或 Linux 中使用 Eclipse 进行 Cocoa Touch 开发的更多信息,您可以通过电子邮件与我联系,并且我可以指导您获得更多信息。同样地,如果您在阅读本教程时遇到任何难点(例如在构建工具链或者运行示例时遇到问题),也请与我联系。

我希望本教程可以引领您入门。编写 iPhone 应用程序会有很多乐趣。


相关主题


评论

添加或订阅评论,请先登录注册

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=Open source
ArticleID=351768
ArticleTitle=使用 Eclipse CDT 编写本机 iPhone 应用程序
publish-date=10132008