夜雨聆风学习资料网

ARTICLE · 1046048

TypePHP 开发苹果 iPhone/iOS Native App

TypePHP 开发苹果 iPhone/iOS Native App

用 PHP 开发 iOS App,听起来有点离谱。但 TypePHP 确实可以做到:界面布局、状态、点击逻辑全部用 PHP 写,编译成一个 arm64 的原生可执行文件,装到 iPhone 上直接运行。

先看效果,下面是运行在真机上的演示视频:

关注
重播 分享
  • 标题、说明文字、状态文字,原生 UILabel
  • 「点击计数」「重置」「English」三个按钮,原生 UIButton
  • 点「点击计数」状态文字会累加,点「English」整个界面切换中英文。

这些控件全部由 UIKit 渲染,手感、字体、深色模式都是系统原生的。而业务代码一行 Objective-C / Swift 都没有,全在 PHP 里。


一、分工:PHP 写逻辑,Objective-C++ 只做一层薄桥

TypePHP 的开发方式和普通 PHP 项目一样,只是多了一个约定:你需要什么原生能力,就在桥接文件里声明一个函数。

示例 App 只用到 6 个原生函数:

PHP 侧调用
作用
ui_app_run()
进入 iOS 应用生命周期
ui_create_window()
创建窗口,设定逻辑画布尺寸
ui_add_label()
添加文本,返回控件 ID
ui_add_button()
添加按钮,返回控件 ID
ui_set_control_text()
修改控件文字
ui_show_window()
显示窗口

这层桥本身是 Objective-C++(.mm),属于你的 App,代码量很小。剩下的事情——界面怎么排、按钮点了做什么、状态怎么变——全部是 PHP。

另外,TypePHP 编译后是机器指令,App 里不会包含任何 PHP 源码


二、代码长什么样

官方示例在 examples/apple-native/

examples/apple-native/├── php-src/│   ├── application.php        # 界面与交互逻辑(PHP)│   └── ios-main.php           # iOS 入口(PHP)├── ios-src/│   ├── uikit_bridge.stub.php  # 声明给 PHP 用的原生函数│   └── uikit_bridge.mm        # UIKit 实现(Objective-C++)├── ios.yml                    # 编译配置└── package-ios-app.sh         # 打包签名脚本

ios-main.php 是 iOS 的入口,一共十几行:

<?php/** iOS 启动完成后,由桥回调 */functiontypephp_application_did_launch()void{    HelloApplication::build('UIKit');    ui_show_window();}/** 每个控件被点击时,由桥回调,参数是控件 ID */functiontypephp_application_control_activated(int $controlId)void{    HelloApplication::handleEvent($controlId);}functionmain()void{    ui_app_run('TypePHP iOS Hello');}

界面部分就是普通的 PHP,buildPhoneLayout() 里描述布局:

privatestaticfunctionbuildPhoneLayout()void{    ui_create_window('TypePHP Native Hello'390844);self::$titleLabel       = ui_add_label(''246723427630true);self::$descriptionLabel = ui_add_label(''3054433010416false);self::$statusLabel      = ui_add_label(''304543305818true);self::$countButton      = ui_add_button(''30354330581);self::$resetButton      = ui_add_button(''30280158522);self::$languageButton   = ui_add_button(''202280158523);}

点击逻辑也是普通 PHP:

publicstaticfunctionhandleEvent(int $controlId)void{if ($controlId === self::$languageButton) {self::$isChinese = !self::$isChinese;self::renderText();return;    }if ($controlId === self::$resetButton) {self::$clickCount = 0;self::renderStatus();return;    }if ($controlId === self::$countButton) {self::$clickCount++;self::renderStatus();    }}

ui_add_label() / ui_add_button() 会返回一个自增的控件 ID,桥在按钮被点击时把这个 ID 回调给 typephp_application_control_activated()。所以在 PHP 里,事件处理就是一次普通的方法调用


三、编译

在 TypePHP 仓库根目录执行,用 ios.yml 作为配置:

export PHPX_HOME=/path/to/phpxphp bin/tpc.php examples/apple-native/ios.yml --no-progress

产物是 examples/apple-native/typephp_ios_hello,可以确认一下:

$ file typephp_ios_hellotypephp_ios_hello: Mach-O 64-bit executable arm64$ otool -l typephp_ios_hello | grep -A3 LC_BUILD_VERSION      cmd LC_BUILD_VERSION platform 2          # iOS    minos 15.0

ios.yml 里跟 iOS 相关的其实就几行:

target-platform:arm64-apple-ios15.0# 交叉编译目标cpp-compiler:xcrun--sdkiphoneosclang++# 用 Xcode 的 iPhoneOS 工具链cxx-flags:--fobjc-arc# 桥接文件开启 ARC--miphoneos-version-min=15.0ld-flags:--frameworkUIKit--frameworkFoundation--frameworkCoreGraphics

四、打包与签名

iOS 必须签名才能安装,先准备好描述文件(.mobileprovision)和开发者证书,然后:

export TYPEPHP_IOS_PROVISIONING_PROFILE=/path/to/profile.mobileprovisionexport TYPEPHP_IOS_CODE_SIGN_IDENTITY='Apple Development: Your Name (TEAMID)'# 描述文件的 Bundle ID 和示例不一致时,用这个覆盖export TYPEPHP_IOS_BUNDLE_IDENTIFIER='your.provisioned.bundle.identifier'sh examples/apple-native/package-ios-app.sh

脚本会组装 .app、拷贝图标、做签名并校验,最后输出:

Created and signed .../dist/TypePHP iOS Hello.app

五、装到 iPhone 上运行

先列出设备,拿到 <device-id>

xcrun devicectl list devices

然后安装:

xcrun devicectl device install app \    --device <device-id> \'examples/apple-native/dist/TypePHP iOS Hello.app'

装完之后直接启动(也可以直接在手机上点图标):

xcrun devicectl device process launch --device <device-id> swoole.typephp

手机上就会出现文章开头那个原生界面。第一次安装后需要在「设置 → 通用 → VPN 与设备管理」里信任你的开发者证书,之后就不用再操作了。


六、改成你自己的界面

理解了上面三个函数,就可以把示例改成任何你想要的样子:

  • 坐标是左上角为原点的逻辑画布,示例用 390 x 844(iPhone 竖屏)。桥负责换算成 UIKit 坐标,并随屏幕尺寸等比缩放,所以不用自己处理像素和刘海。
  • ui_add_label($text, $x, $y, $w, $h, $fontSize, $bold):文字控件。
  • ui_add_button($title, $x, $y, $w, $h, $style):按钮,style 为 1(实心蓝)/ 2(浅蓝)/ 3(灰色)。
  • ui_set_control_text($id, $text):更新文字,用来做实时状态展示。
  • 按钮点击统一通过 typephp_application_control_activated($id) 回调,用 ID 区分即可。

比如想加一个「打招呼」按钮,只要在布局里加一行,再在事件里加一个分支:

// 布局self::$helloButton = ui_add_button('打个招呼'30200330522);// 事件if ($controlId === self::$helloButton) {    ui_set_control_text(self::$statusLabel, '你好,TypePHP!');}

需要 UIKit 之外的能力(定位、相机、网络状态……)时,在 uikit_bridge.mm 里加一个 php_ 前缀的函数,并在 .stub.php 里声明,PHP 侧就能直接调用。


七、几点说明

  • 只支持真机。 目前 iOS 目标只提供 iphoneos arm64,没有模拟器目标,必须签名。
  • 桥是手写的,不是自动绑定。 与 Android/JNI 那种反射桥不同,Apple 平台每个 App 自己维护 .mm 文件——好处是完全可控、体积小,代价是用到什么系统能力就写哪几个函数。
  • 描述文件会过期。 个人开发者账号签发的开发描述文件有效期较短(通常 7 天),过期后用 Xcode 重新签发一次即可。
  • 构建环境:macOS + 完整版 Xcode + 对应版本的全静态 libphp.a / libphpx.aPHPX_HOME/ios/iphoneos-arm64)。

同一套 application.php,换个入口和桥接文件,就能编译成 macOS 的 AppKit 应用;Android 侧也有对应的 arm64 原生方案。一份 PHP 业务代码,落到桌面和移动端原生 UI 上——这是 TypePHP 在服务端之外的一个新方向。

技术社区

TypePHP 由识沃科技(Swoole 团队)主导研发。欢迎添加识沃客服微信,加入技术交流群,与开发者直接交流、获取最新版本与构建指南。

识沃客服

相关学习资料