ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

RubyMotion iOS开发实战:纯代码UIKit布局、真机调试与签名发布指南

RubyMotion iOS开发实战:纯代码UIKit布局、真机调试与签名发布指南 1. 为什么第二篇要绕开语法糖专攻 UIKit 和签名RubyMotion 的 iOS 开发系列写到第二篇我默认你已经过了motion create demo的兴奋期也知道了rake能编出原生 App。但你很可能卡在下一个路口页面怎么写控件怎么布局为什么真机跑不起来如果你带着这几个问题往下看这篇会帮你省下至少一个星期的试错时间。如果还没有装好环境建议立刻回头补第一篇因为这里不会再讲怎么装依赖和初始化项目。RubyMotion 最有意思的地方是它用 Ruby 语法调用整个 UIKit但底层生成的还是原生机器码没有 WebView、没有 JavaScript 桥App 启动速度和内存表现和 Objective-C 写的没差别。这句话换个角度看你不是在 Ruby 里写 iOS而是用 Ruby 写 iOS。这两者差别很大决定你遇到问题时查阅哪类文档。Ruby 侧只负责语法组织和简化表达点击事件、生命周期的名字、AutoLayout 的行为全部按 UIKit 的规则来。很多从纯 Ruby 转过来的朋友栽跟头就是因为只记得 Ruby 的灵活忘了 iOS 系统的那套回调约定。接着说第二篇的思路。系列第一篇讲的是motion create、rake和 Ruby 类如何映射成 Objective-C 类算是热身。第二篇要直接面对真实开发纯代码 UI 怎么写才不别扭页面跳转和生命周期需要注意什么模拟器黑屏怎么救真机免费签名怎么过以及发布上架时哪些坑和 RubyMotion 无关。下面每个章节都能对应到真实工程的一个阶段你按顺序走完一个可运行的 App 就算真正落地了。适合谁读如果你是 Ruby 党对 Xcode 的工程文件、证书配置、模拟器协作还没建立直觉请重点看第 4 和第 6 章如果你已经是 iOS 原生开发想换个语言体验前 3 章读起来会很快但建议别跳过 Rakefile 那节因为 RubyMotion 的构建流程和 CocoaPods 之间的摩擦很可能让你惊讶。这三个角色我都见过各自的痛点很不一样Ruby 党容易轻视 UIKit 规则iOS 原生开发者容易受不了 Ruby 的动态性而新手则需要同时补两边。所以我尽量把每一步都拆得具体一点能贴代码就贴代码不搞抽象的心法。1.1 RubyMotion 的定位是编译器不是解释器RubyMotion 通常被理解成用 Ruby 写 iOS这个说法没错但不够准确。它更接近一种把 Ruby 源码编译成机器码的闭源编译器同时把运行时和 Objective-C runtime 打通。你写的每一个 Ruby 类最终会变成 Objective-C 类方法通过 runtime 动态派发所以和 Cocoa 的交互几乎是无缝的。这也是它能保持接近原生性能的原因App 里没有嵌入解释器每一行 Ruby 在编译阶段都被翻译成可执行的机器指令、或可被 runtime 转发的 Objective-C 结构。这个定位决定了你能用 Ruby 生态里的一部分 gem但又不是全部。因为要经过编译期转换纯 Ruby gem 里如果用了太多运行时元编程、eval、C 扩展很可能在 RubyMotion 里直接报错。很多人第一次接触 RubyMotion想着把自己的 Rails 代码搬进来结果报了一堆unexpected token和unknown type就是因为没理解这条边界。所以不要把 RubyMotion 当成Ruby 解释器跑在手机上它是一个有严格前端约束的编译器。1.2 第二篇的主线先跑通 UI再谈真机和发布如果你已经会把Hello显示在界面上恭喜你接下来就是最难熬的一段布局和交互。很多 RubyMotion 教程只会列代码不解释为什么addTarget的方法名要写成字符串也不解释为什么motion build --release后签名总失败。第二篇的主线就是把这些没人写的部分补全。我建议你跟着这篇文章的节奏这么做先在模拟器上把一个纯代码页面跑通包括一个 UILabel、一个 UIButton 和一个点击事件然后处理导航栈让两个页面互跳最后再碰真机和证书。不要一上来就集成 AFNetworking、Alamofire 或各种增强 gem那样只会把问题混在一起排查时分不清是谁的错。等项目骨架简化到只剩必要组件后再引入网络层、数据层你会发现很多诡异错误其实是依赖版本和 Xcode 版本打架。1.3 环境版本和必要的 RubyMotion 认知这篇的示例基于 RubyMotion 6.x。新版已经支持 Apple Silicon Mac 和多个 Xcode 版本但如果你还在用老版本某些rake任务的名字会不一样。我建议至少升级到 6.3 之后的版本它修复了不少模拟器 SDK 路径问题。如果你用的是教育版或免费试用版请注意它可能限制同时运行的任务数但对单机开发影响不大。Xcode 方面如果你只用模拟器开发14 和 15 差别不大如果要做真机调试iOS 16 以上设备必须处理开发者模式。RubyMotion 官方文档有时滞后于 Xcode 发布所以遇到invalid active developer path这类错误先去执行xcode-select -p确认命令行工具指向的是当前 Xcode而不是残留的 Command Line Tools。这个问题很常见而且和 RubyMotion 本身关系不大属于 macOS 工具链的基本排查。2. 第一个能跑的 RubyMotion 页面这样搭最舒服2.1 用 Rakefile 掌控工程设置motion create HelloRuby后根目录的 Rakefile 是核心。RubyMotion 没有.pbxproj所有 target、签名、资源文件、依赖都在 Rakefile 里配置。它的基本结构是Motion::Project::App.setup do |app| app.name HelloRuby app.identifier com.example.helloruby app.spec_files Dir.glob(spec/**/*.rb) app.files Dir.glob(app/**/*.rb) app.deployment_target 15.0 app.development true endapp.files默认包含app/**/*.rb基本不用改。app.deployment_target决定了最低支持的 iOS 系统建议按你的目标用户设。app.identifier不要乱填真机签名和推送都要用到它而且上架后 App ID 不能随意修改前缀。Rakefile 本身是一段 Ruby 代码所以你可以在里面写变量、循环、条件分支轻松实现 debug/release 两套配置。这种灵活性是 Xcode 工程文件给不了的比如你可以用一个环境变量让不同开发者使用不同证书也可以读取 CI 平台上自动生成的参数来切换构建 target。但也因为它是代码如果你写错变量名或调用了不存在的方法构建时才会炸出来。因此在项目初期就加上 RuboCop 或者rake static做静态检查能省掉很多低级错误。2.2 纯代码构建 UIKit不拖 StoryboardRubyMotion 入门最大的坎是很多教程说要删除 Storyboard用纯代码写 UI。对我极度推荐纯代码。不是故事板不好而是在 RubyMotion 里维护 Storyboard 的成本太高——你要为每个 ViewController 写一个对应的 Ruby 类还要处理IBOutlet和 selector 名称错误难查。纯代码的方式就是直接创建一个UIViewController子类重写viewDidLoad在里面创建控件、设置约束、挂上事件。来看一个实际可跑的示例。我建了一个HomeController它继承自UIViewController在viewDidLoad里创建了一个 UILabel 和约束class HomeController UIViewController def viewDidLoad super view.backgroundColor UIColor.systemBackgroundColor label UILabel.alloc.initWithFrame(CGRectZero) label.text 欢迎回来 label.font UIFont.preferredFontForTextStyle(UIFontTextStyleHeadline) label.textAlignment NSTextAlignmentCenter label.translatesAutoresizingMaskIntoConstraints false view.addSubview(label) NSLayoutConstraint.activateConstraints([ label.centerXAnchor.constraintEqualToAnchor(view.centerXAnchor), label.centerYAnchor.constraintEqualToAnchor(view.centerYAnchor), label.leadingAnchor.constraintGreaterThanOrEqualToAnchor(view.safeAreaLayoutGuide.leadingAnchor, constant:20) ]) end endtranslatesAutoresizingMaskIntoConstraints false在纯代码布局里几乎必写否则你加了约束也不会按预期生效。UILabel.alloc.initWithFrame(CGRectZero)和UILabel.new都能行然后通过约束决定真正位置。唯一要注意的是viewDidLoad里一定要调用super不然系统的 view 装载过程会不完整轻则控件不显示重则启动崩溃。这是纯 Ruby 背景开发者最容易漏掉的一步。2.3 为什么不要迷信 motion-layout 这种 DSLRubyMotion 社区有个 gem 叫 motion-layout能用 DSL 写类似 Android 的约束。我早期用过确实能少写不少NSLayoutConstraint的样板。但问题在于它的 API 是一套字符串 DSL对复杂约束、比例约束以及 SafeArea 支持不全出了布局警告时你反而要去理解它翻译成 UIKit 约束后发生了什么。如果你只做简单页面可以直接用 frame 计算比如label.frame [[20, 100], [width - 40, 32]]。这种写法的好处是直观坏处是屏幕旋转或 iPad 分屏时会错位。我的建议是单页静态控件用 frame动态布局和自适应用原生 AutoLayout 约束。RubyMotion 里写 AutoLayout 的代码量虽然比 Objective-C 少一点但比 Swift 的语法还是啰嗦要不要用第三方 DSL取决于你能接受多少黑魔法。像motion-layout这种 DSL 确实能提升开发速度但遇到系统升级导致 API 变化时你只能等 gem 作者更新这种维护风险是隐性成本。2.4 事件的 selector 字符串千万别说错UIControl 的addTarget要求传一个字符串方法名。在 RubyMotion 里action:did_tap_button:会被转换成 Objective-C selector匹配到同名 Ruby 方法。如果方法名带冒号说明它接受一个 sender 参数没有冒号则不传参。这两个不能混否则点击没反应。我写过不少次方法名少个冒号导致事件不触发查了半天。所以我的建议是button action 统一起名为did_tap_xxx:放进一个固定位置然后在viewDidLoad末尾用一段集中addTarget。这里也想提醒addTarget的 target 参数是self会被 UIKit 以 weak 方式持有。如果你的按钮被父视图持有而 controller 也要释放事件不会导致 retain cycle但反过来如果闭包通过 block 捕获了 controllercontroller 又被按钮持有就很容易泄漏。用 Target-Action 而非闭包至少能避开一半的循环引用问题。3. 生命周期和页面跳转RubyMotion 没帮你省这部分3.1 生命周期方法名一个都不能拼错viewDidLoad、viewWillAppear:、viewDidDisappear:在 RubyMotion 里你直接定义同名 Ruby 方法。注意冒号带参数的方法名必须和系统 selector 完全一致。比如viewWillAppear:接收一个animated参数如果漏了冒号iOS 不会在你进入页面时调用它你可能会在页面显示前错过数据请求。常见错误是写了def viewWillAppear而没有animatedRubyMotion 可能不会报警页面正常显示但你的 viewWillAppear 没触发。所以一开始花 10 分钟把这几个生命周期方法打印一遍确认触发顺序比反复猜强。我通常会在基类里把生命周期统一打NSLog然后用Motion::Log控制级别只在 debug 时输出。这样一旦页面的生命周期不符合预期第一眼就能发现是方法名写错还是系统调用被父类拦截。3.2 push、present 和返回时的内存注意UINavigationController 的 push 和 pop 大家都懂但需要提醒一点RubyMotion 的闭包和 block 在 UIKit 里用多了容易出现 retain cycle。比如你在一个 UIButton 的闭包回调里引用了self而 self 又持有这个 button那么 controller 就释放不了。轻则一个页面反复进入后内存涨重则 App 莫名其妙卡死。用 Target-Action 就能规避一部分。present 一个 modal 时如果modalPresentationStyle是 pageSheet在 iPad 上右上角的关闭按钮不会被你的 dismiss 代码自动接管用户下拉关闭时不会触发你预设的销毁逻辑。你要根据业务决定是否要隐藏这个系统关闭按钮或者在viewDidDisappear里处理退出逻辑。另外从 presented controller 调用presentingViewController.dismissViewControllerAnimated也是常见写法注意别在 dismiss 后再访问 presented controller 的 view否则会触发重建带来额外的崩溃隐患。3.3 SafeArea、分屏和横幅绕不开的 iOS 行为iOS 15 以后导航栏配置出现了新的UINavigationBarAppearance如果你不设置页面滚动时导航栏会变透明标题字体也可能跟随系统。RubyMotion 里可以直接调用这个类但代码比较长。我在项目里把导航栏配置封装成一个基类方法所有子 controller 继承它保证视觉一致。分屏和 SafeArea如果你的 App 要在 iPad 分屏下工作布局锚点不要写死到view.bounds一定要用safeAreaLayoutGuide。keyWindow的获取也很重要老项目用UIApplication.sharedApplication.keyWindow在 iOS 13 以后会提示 deprecated最好用UIApplication.sharedApplication.connectedScenes找到 active scene 里的 window。写自定义横幅通知时这个 window 获取方式直接决定你的横幅能不能盖在正确的层级。很多人做仿 iOS 通知横幅功能动画做得像模像样但到了原生层却不知道用addSubview到哪个 window就是没搞清楚 UIWindow 的层级结构。4. 真机调试和免费证书这是 RubyMotion 劝退重灾区4.1 模拟器黑屏先别急着怪代码RubyMotion 模拟器调试除了跑起来还包括每次改代码后的增量编译。但你在魔术般快速编译的同时也会遇到黑屏、闪退、Failed to launch等随机 bug。此时先执行rake clean再看是不是 Xcode 和模拟器 SDK 冲突。如果还不行xcrun simctl list devices确认当前 Simulator 运行时存在。我之前遇到过一台公司的 Mac因为装了多个 Xcode 版本xcrun一直指向旧工具链导致新模拟器无法启动。模拟器缓存问题比想象中多。CoreSimulator 服务卡住时所有模拟器都会变得很慢。sudo killall -9 com.apple.CoreSimulator.CoreSimulatorService是社区里通用的大招执行后模拟器和 Simulator.app 需要重新启动。只要你的代码逻辑不涉及持久化状态这招基本无害。不过要提醒这个命令会把当前所有模拟器杀干净如果你的 App 状态存在模拟器里下一次启动会像全新开机一样。所以有调试数据时慎用这招。4.2 真机安装开发者模式、信任证书和 RakefileiOS 16 之后真机调试第一步不是连上 Xcode而是打开设置 - 隐私与安全性 - 开发者模式。如果你找不到这个入口说明这台设备没有处于开发者模式开关状态或是被 MDM 策略限制了。打开后手机会重启然后再次连接 Mac。RubyMotion 连真机时电脑上首次会弹是否信任此电脑手机上也有一份信任此电脑两个都要点。然后才是签名。个人免费账号在 Xcode 里登录后Rakefile 里可以设置app.codesign_certificate iPhone Developer: Your Name (TEAMID) app.provisioning_profile /path/to/Your.mobileprovision如果你不用 Xcode 创建配置文件RubyMotion 会在编译时提示no identity found。最快的解法先在 Xcode 里随便开一个 iOS 工程在 Signing Capabilities 里选择你的 Personal Team让 Xcode 自动把这个设备加入 provisioning profile然后关掉那个工程再用rake device跑 RubyMotion 真机目标。很多不信任开发者的弹窗都在这个阶段解决。还有一个小技巧真机调试时模拟器编译产物和真机编译产物是分开的如果发现 Xcode 里证书正常但rake还报错先看看是不是上次 rootless 安装导致 RubyMotion 的模拟器缓存没清。4.3 免费证书的七天限制怎么安排开发节奏免费证书不是无限用的个人 Apple ID 创建的开发证书大约七天会失效。意思是你昨天还能跑今天突然启动就崩或者 Xcode 提示a valid provisioning profile for this executable was not found。这个限制没办法绕只能用付费开发者账号或者每周重新签名一次。开发阶段我一般会把重新签名排成周任务或者做一个收尾脚本每次固定时间拉最新状态给真机重跑一遍。收费账号的签名在开发者中心创建RubyMotion 会用钥匙串里的证书自动匹配。这里有个细节免费证书的 Team ID 是个人 ID你上架时必须用付费账号重新生成 Provisioning Profile不能把测试真机签名直接提交 App Store Connect。我在项目里专门写了两个 Rakefile 任务一个rake device:debug一个rake archive:release分别用不同的app.codesign_certificate变量避免把证书弄混。如果团队有多个人建议在 Rakefile 里读取环境变量BUILD_SIGN_CERT不要在代码里硬编码证书名。免费证书的坑远不止七天失效。我在项目中遇到过的错误整理成一张速查表错误信息常见原因处理办法no identity found钥匙串中没有匹配的开发者证书到 Xcode 账号里添加 Apple ID等待证书生成Your device is not registered设备 UUID 未加入 provisioning profile在开发者网站或 Xcode 的 Devices 窗口注册设备code signing certificate ... couldnt be foundRakefile 里的证书名和钥匙串不一致用security find-identity -p codesigning -v查真实名称provisioning profile ... doesnt include signing certificateprofile 和证书不匹配重新下载并安装正确的 mobileprovision4.4 崩溃定位.ips文件里的秘密真机崩溃时控制台可能只输出App was terminated by signal 11。更可靠的方式是在 Mac 上打开~/Library/Logs/DiagnosticReports找以 App 名开头的.ips文件。这个文件有 JSON 结构里面exceptionReason和faultingThread能告诉你崩溃线程和调用栈。RubyMotion 的调用栈是 Objective-C selector对应关系可以通过motion symbolize任务映射成 Ruby 方法名不过前提是你保留了build里的 debug symbols。如果崩溃发生在 launch 阶段除了符号化还要检查是否缺少NSPhotoLibraryUsageDescription这类权限描述或者尝试在application:didFinishLaunchingWithOptions:里加一个NSLog看启动流程走到哪一步。这种给流程打点的手段比盯着空白屏幕猜要高效得多。我见过最离谱的崩溃是启动时某个资源文件没被正确打包导致读取 nil 后访问内存这种现象在真机上常见模拟器反而不容易复现所以真机崩溃不要只看模拟器 debug 日志。5. 第三方库、资源和自动化RubyMotion 的现实世界5.1 CocoaPods 接入的边界RubyMotion 可以接 CocoaPods但不像原生 Podfile 那么常规。在 Rakefile 里app.pods do pod AFNetworking, ~ 4.0 end然后运行rake pod:install。注意 RubyMotion 对 Pod 的解析依赖 podspec 中的静态库设置。如果那个 Pod 用了 Swift、dynamic framework、或者在新版本 Xcode 里编译不过你的rake build就会挂在 Pod 阶段这不是 RubyMotion 的 bug而是兼容边界。我建议把 Pod 版本锁死pod AFNetworking, 4.0.1不要用波浪号除非你想体会每天构建都变的心情。选库时有几条经验优先选 Objective-C 写的、更新频率低的库避免选重度依赖 networking 或 UI 的 Swift 库如果你真的需要某个 Swift Pod可以考虑在工程里用app.vendor_project引入编译好的 framework但 RubyMotion 对 Swift 框架的桥接仍不完美。实际项目中网络层我用的是 RubyMotion 的AFMotion封装而不是直接 Pod AFNetworking省掉很多头疼。AFMotion本质是 AFNetworking 的 Ruby 包装API 简洁社区维护也还算稳定。5.2 Resources 资源文件和 Asset CatalogRubyMotion 把resources目录下的文件打包到 App 资源里UIImage.imageNamed(icon.png)就能读。因为不走 Xcode 的 Asset Catalog所以如果你的图标要支持多尺寸还是得在 Rakefile 里用app.icons明确声明所有尺寸。例如app.icons { iPhone [Icon.png, Icon2x.png, Icon3x.png], iPad [Icon-76.png, Icon-762x.png, Icon-152.png] }LaunchScreen 更麻烦建议直接用 Storyboard 文件放在resources里同时也要在 Rakefile 里指定app.launchscreen_storyboard LaunchScreen。资源文件更新不同步的老问题我归因于rake clean次数太少导致的隐性缓存所以遇到改动资源不生效第一时间 clean不要折腾Simulator - Device - Erase All Content and Settings。在团队协作中我还会给资源文件加版本号比如logo_2.png虽然难看点但能避免证书和资源的缓存歧义。5.3 自动化测试能做到什么程度RubyMotion 自带rake spec可以写单元测试和部分功能测试。spec目录下按 Ruby 的 RSpec 风格写跑得很快。但 UI 自动化就尴尬了RubyMotion 没有官方提供与 XCUITest 的完整桥接你可以在spec里驱动 UI 事件吗有 gem 如motion-fixtures做小范围 UI 测试和 Appium 结合也可以但需要你额外写 Ruby 服务端脚本。这意味着 UI 自动化的成本不低。我的实际做法是核心的业务逻辑用rake spec覆盖UI 上的自动化依赖原生 XCUITest。这不是 RubyMotion 的缺陷而是 iOS 自动化测试本来就比较封闭。若项目以 RubyMotion 为主你可以在 Run Script 阶段调用 Xcode 的xcodebuild test把原生 UI 测试 target 和 RubyMotion 编译产物放一起。不过这属于进阶玩法不建议第一版就做先把核心 ruby 逻辑测好UI 层靠回归清单人工过更加现实。5.4 与原生 SDK 混编和桥接技巧RubyMotion 要集成第三方原生 SDK通常有两个方案一个是 CocoaPods 包装另一个是app.vendor_project直接引入 SDK 的源码目录。后者更可控也更容易踩坑。vendor_project的声明大概长这样app.vendor_project(vendor/MySDK, :static, headers: [vendor/MySDK/include])引入后Ruby 层就能通过MySDK模块调用。需要注意SDK 头文件如果有 C 接口你可能需要额外指定cflags或者提供一个 Objective-C 包装层。我倾向于写一层薄薄的兼容层只暴露几个 Ruby 友好的方法避免 RubyMotion 和 C/Swift API 直接纠缠。桥接的核心原则是不要在 Ruby 层直接展开复杂的 C 结构体最好由 Objective-C 类封装后返回字典、数组等 Ruby 好用对象。在实际开发中我甚至会给第三方 SDK 做一个SDKBridge类把所有extern C函数封装成SDKBridge的类方法Ruby 端只调用这个类。这样无论 SDK 底层怎么变只要接口不变Ruby 层代码几乎不用动。这是 RubyMotion 混编不被劝退的关键。6. 构建发布从签名到 App Store 的完整避坑清单6.1 Release 构建与签名校验发布版通常用motion build --release。这个命令会生成build/iPhoneOS-.../YourApp.app。在打包之前先在 Rakefile 里确认 Release 模式的codesign_certificate指向 iPhone Distribution 证书。你也可以不指定直接用 Xcode 的xcodebuild生成 .ipa但 Rakefile 才是 RubyMotion 最可控的地方。构建完成后用codesign -dvvvv app/YourApp.app查看签名信息重点看AuthorityiPhone Distribution: ...和TeamIdentifier是否一致。如果发现是iPhone Developer说明你用了开发签名上传到 TestFlight 多半会被拒。建议在 Rakefile 里设置app.codesign_certificate iPhone Distribution: Your Company (TEAMID) app.provisioning_profile /path/to/distribution.mobileprovision如果你的 app 有扩展组件比如通知扩展、今日组件需要在 Rakefile 里用app.extensions单独配置否则扩展签名很容易被漏掉导致整个 Archive 非法。这一步在原生 Xcode 工程里由 target 自动处理但在 RubyMotion 里需要手动声明。6.2 TestFlight 和浏览器唤起安装的配置TestFlight 上架前同样要过一遍 App Store Connect 的审核但外部测试审核比正式上架快。上传 .ipa 时可以直接用 Transporter 或xcrun altool。altool命令大概如下xcrun altool --upload-app -f YourApp.ipa -t ios -u youexample.com -p app-specific-password注意密码要用 App 专用密码不能直接用 Apple ID 密码。浏览器唤起安装 App 有两种正规姿势Universal Links 和自定义 URL Scheme。RubyMotion 里需要配置app.info_plist里的CFBundleURLTypes或associatedDomains。我一般建议优先 Universal Links因为它的体验更接近系统级跳转而且不会因为 App 未安装时弹出无法打开而被浏览器拦截。设置 Universal Links 后后端要托管 apple-app-site-association 文件这个麻烦程度不小但安全性远高于 URL Scheme。URL Scheme 容易被其他 App 抢注Universal Links 虽然也没有彻底解决所有安全问题但至少由系统校验域名声明。6.3 上架被拒的常见原因和 RubyMotion 没关系很多 RubyMotion 开发者被拒后第一反应是是不是 RubyMotion 编译的 App 不被认可。其实苹果不会因为语言和工具链拒绝你除非你的二进制存在异常内存或隐私调用。被拒最多的还是缺少权限用途说明用相机、相册、定位时必须添加Info.plist描述文案。App 内购买项目没有恢复购买按钮。界面在 iPhone 和 iPad 分屏下布局变形。使用了私有 API 或UIApplication的未公开方法。这些和 RubyMotion 无关。你只要把原生 App 会遇到的问题过一遍审核就能过。另外NSAllowsArbitraryLoads设为 YES 会加大被拒风险能用 HTTPS 就不要开纯 HTTP 权限。如果你的 App 有登录功能记得提供注销入口苹果审核对账号状态保留很敏感这也不是 RubyMotion 专属要求。6.4 日常版本迭代的维护心得RubyMotion 项目的维护我最看重的是 Rakefile 的版本管理和Gemfile.lock。如果几个 Mac 上都要开发必须把 Gemfile 锁定版本否则 gem 更新可能导致编译行为变化。就像 Lockfile 对 Node 和 Python 项目的作用RubyMotion 也一样需要稳定依赖。其次保持 Xcode 版本稳定。RubyMotion 官方发布新的 Xcode 支持往往滞后别在正式项目里赶时髦升级系统工具链。每做一个迭代先用rake clean后完整构建一次确保 Release 环境无缓存依赖。我遇到过 debug 正常、release 崩溃的情况最后发现是NSLog条件编译和app.optimize的不同路径导致。在 release 模式下RubyMotion 会做更多优化某些未初始化的 Ruby 变量行为会不一样所以必须保持preflight 构建的习惯。7. 项目适配性判断与维护技巧7.1 什么项目适合 RubyMotion什么不适合文章写到这里第 7 章就是最真实的经验部分。我在接 RubyMotion 项目之前曾经以为它只是个玩具。真做下来发现写 UI 时 Ruby 的紧凑确实能提升效率一个简单的页面加逻辑代码量比 Objective-C 少一半。但它的社区小、资料旧排查问题比 Swift 项目更需要耐心。所以不要盲目上 RubyMotion先问自己三个问题团队里 Ruby 程序员多不多App 的 UI 复杂度是不是集中在表单、列表、详情页是否必须深度集成最新 Swift 生态 SDK我的实际体会是RubyMotion 适合的目标非常明确团队里 Ruby 程序员多产品周期短UI 复杂度不高需要快速出原生 App。如果项目要求大量 Swift SDK 集成或者团队只有 Objective-C/Swift 背景那用 RubyMotion 反而增加沟通成本。这个适不适合的判断比写代码本身更重要。很多技术选型失败不是工具不行是团队和场景没对上。如果你的项目只是内部工具UI 规模不大RubyMotion 的快速迭代特性会非常舒服反之如果你在做金融类 App需要接入大量风控和加密 SDK那混编成本可能远超它带来的开发效率增益这时候就老实退回原生。7.2 我推荐的一套维护小技巧最后分享一个小技巧在 Rakefile 里加一个rake log:device任务把真机日志实时拉到终端这样你调试时不用一直盯 Xcode 的 Console。我的写法是desc Show device log task :log:device do exec idevicesyslog end需要提前装libimobiledevice但真机接上后真的省不少事。另外建议在.gitignore里加上build/和.bundle/避免大量编译产物和 gem 依赖进入仓库。如果你要给不同客户出包可以把证书名、Bundle Identifier、图标路径都做成 Rakefile 里的可配置常量毕竟 RubyMotion 最大的优势就是构建脚本是真正的代码这份灵活性不用白不用。下一篇我打算聊聊怎么用 RubyMotion 做更复杂的网络层封装和离线存储大家有遇到 RubyMotion 的奇葩编译问题欢迎在留言区一起交流。
返回列表