酷狗音乐MacCalyst实践总结
背景
近年来,苹果生态系统中的应用开发面临着越来越多的挑战。尤其是对于已经在多个平台发布应用的公司,如何减少开发人力投入并降低长期维护成本成了核心问题。我们团队在《酷狗音乐》的过程中,深刻感受到了这些问题的困扰。我们原本为iPad和Mac开发了不同版本,两个版本的代码库各自维护,不仅使得更新过程复杂,还让功能同步更加困难。得益于我们的iPad版本且已较成熟且已和手机版独立(改动影响面小),我们决定通过MacCatalyst技术将iPad应用扩展到Mac,以实现尽可能多的代码重用,也符合集团降本增效的治理宗旨。
MacCatalyst 简介
MacCatalyst是苹果公司自2019年随macOS Catalina 10.15起推出的一项技术,旨在帮助开发者将iPad应用移植到Mac平台。通过该技术,开发者可以在保留大部分iPad应用代码的基础上,迅速创建一个适配Mac系统的新应用。MacCatalyst在Xcode中得到了充分集成,并允许开发者利用现有的UIKit API,同时也能无缝地访问Mac特有的功能,比如菜单栏、鼠标输入等。
基本原理
苹果在其开发者工具的不断演进中展现了极高的前瞻性。基础框架如 Foundation、libSystem 和 CoreGraphics 已被优化为多平台兼容,使得同一套代码可以在不同平台上运行变得愈加可行。而对于特定平台需求较高的框架,苹果通过将其动态库“复制”并适配到 Mac 平台来实现支持,这主要归功于共用的运行时框架(runtime)。这种技术革新正是 Mac Catalyst 得以实现的关键。自 macOS Catalina 推出后,iOS 平台的主流动态库已被内置在 macOS 系统中。借助苹果提供的转换工具,iOS 上的 UIKit 控件可以有效地桥接至 macOS 的 AppKit,从而实现应用的跨平台功能。
演进过程
随着MacCatalyst的迭代与日渐成熟,苹果持续为其带来更新与优化,以下是近几年WWDC大会上带来的主要新功能:
- WWDC 2019:首次发布MacCatalyst,标志着将iOS生态与macOS生态统一的步伐正式开启,强调基础API的重用。
- WWDC 2020:增强了对多窗口支持的API,同时引入了对鼠标和键盘操作的优化。
- WWDC 2021:引入了对全屏模式及系统快捷键的更多支持,并改善了性能表现。
- WWDC 2022:增加了与macOS特性更紧密结合的功能,如在菜单栏添加自定义菜单和更好地支持系统级别的拖放功能。
- WWDC 2023:提升了 Mac Catalyst 的 UIKit 特征系统,增强了 SwiftUI 集成,改进了视图控制器生命周期,引入了动画化符号和图像效果,以及针对文档中心应用和多语言支持的优化。
这些更新让开发者看到了苹果在建设iOS生态与macOS生态统一的决心与成果,为开发者带来了更多的开发选择,这让我们对《酷狗音乐》的跨平台开发提供了强有力的技术可行性基础。
迁移准备
从Xcode 12.2开始,Xcode 便支持了开启App支持MacCatalyst的选项,时至今日的Xcode 16,界面上在不断优化,开启MacCatalyst支持很简单,以最新的Xcode 16为例,开启MacCatalyst支持的步骤如下:
- 打开Xcode项目:首先,使用Xcode打开现有的iPad项目,并确保所有依赖项和设置都已经正确配置。
- 选择目标(Target):在Xcode中,导航到“Targets”区域,选择你想要支持MacCatalyst的iPad应用目标。
- 开启Mac支持:点击“General”选项卡,找到“Supported Destinations”部分。点击“+”加号,添加Mac-Mac Catalyst,这将启用MacCatalyst支持。此操作会将目标扩展到macOS,Xcode 会自动生成相关配置,比如添加沙盒权限部分,自动处理跨平台的能力为多平台共享等
实践中解决的问题
二进制库处理
由于是历史项目,所以较多二三方二进制库都还是.a或者Framework单一形式存在的动态或者静态库,不满足MacCatalyst的使用,这里所有的三方库都要使用xcframework,有个注意点,如果使用 cocoapods,且一个 podspec 包含多个 xcframework,不可使用通配符,需类似这样处理:
xcframework_name_list = ['libfdk-aac', 'libffmpeg', 'libopencore-amrnb', 'librtmp', 'libshine', 'libx264']
xcframework_name_list.each do |name|
subspec_name = name.gsub(/^lib/, '')
s.subspec subspec_name do |subspec|
subspec.vendored_frameworks = "FFmpeg/Frameworks/#{name}.xcframework"
end
end
编译报错处理
在迁移过程中,编译错误是不可避免的,尤其是一些跨平台的相关API在MacCatalyst上并不支持。我们处理这些问题的策略包括:
- 逐个分析错误信息:阅读详细的错误日志,明确是哪部分代码导致了问题。
- 修改不兼容的API调用:针对这些问题,我们使用条件编译,以确保应用能够在MacCatalyst以及iPad下环境下都可正常运行。
条件编译判断代码
// OC
#if TARGET_OS_MACCATALYST
// coding here
#endif
// Swift
#if targetEnvironment(macCatalyst))
// coding here
#endif
平台特定功能屏蔽处理
对于一些只对于特定平台适用的使用习惯,比如
- 列表类界面的下拉刷新、上拉加载更多,这些在移动平台更加适用的行为在MacCatalyst平台需要特殊处理,比如使用类似网页的分页控件,刷新则在合适的位置提供刷新按钮
- 对于一些在iPad端运行良好可横向滚动的控件,在MacCatalyst端添加鼠标hover时的左右滚动按钮,以更适应桌面端的用户操作行为
项目运行配置
除了代码调整外,项目的配置文件也需要特别处理。常见的配置调整包括:
- 为不同destination配置不同Info.plist:iPad和MacCatalyst配置文件差异较大且影响严重,应做配置隔离;
- 准确处理membership:多平台开发中,平台特性的文件或资源在所难免,应准确处理代码的membership或者是否copy到对应bundle逻辑;
- 使用cocoapods插件:由于部分二三方库无法构建xcframework或者本身不支持MacCatalyst(比如GLKit只能转为使用Metal),这部分pod需要处理链接选项以及处理xcconfig的架构排除,使得不用重新pod便可同时运行iPad和MacCatalyst目标
root_path = Pathname.new(File.dirname(__FILE__)).realpath
mac_catalyst_satisfy_file = "#{root_path}/Script/mac_catalyst_satisfy.rb"
catalyst_gem_path = "#{root_path}/Script/MacCatalyst/dependency/cocoapods-catalyst-support-0.2.1.gem"
if File.exist?(mac_catalyst_satisfy_file) and File.exist?(catalyst_gem_path)
require mac_catalyst_satisfy_file
adapter = KuGou::MacCatalystAdapter.new
adapter.ensure_gem_installed(catalyst_gem_path)
end
require 'cocoapods-catalyst-support'
platform :ios, '11.0'
kg_catalyst_configuration do
ios 'KGShortVideoSDK'
ios 'KGSharedSDK'
...
end
使用AppKit开发桌面级功能
作为一款音乐类应用,提供桌面平台的菜单栏歌词和桌面歌词功能似乎是“理所当然”的需求。在使用MacCatalyst的过程中,我们也面临了这一挑战。由于MacCatalyst对NSWindow级别的控制存在局限性,对NSStatusBar的支持也相对有限,我们无法直接实现这些功能。因此,我们采用了Mac平台的Plugin机制,结合Cocoa和AppKit,成功开发并实现了桌面歌词和菜单栏歌词功能,为用户提供了更加符合桌面体验的交互方式。
桌面歌词
菜单栏歌词
持续集成遇到的问题解决
由于我们采用了Mac平台的Plugin机制,其构建参数与MacCatalyst的构建参数存在差异。如果仅构建主应用的target,xcodebuild会错误地将不支持的参数传递给Plugin的target导致归档失败。因此,在CI流程中,所有Plugin的代码必须单独构建(包括那些具有多个target的membership代码)。随后,在archive阶段,将这些Plugin嵌入到主应用的archive文件中。我们还实现了全自动打包流程,无需依赖外部工具,并完成了DMG的封装、美化、公证以及协议注入,显著提升了持续集成的效率和自动化水平。
成果展示
总结
通过使用MacCatalyst技术,我们成功将《酷狗音乐》iPad版移植到了Mac平台。借助MacCatalyst,我们实现了超过95%的代码重用,大幅降低了维护成本。同时,我们根据Mac用户的交互习惯,进行了针对性的优化,提供了流畅而自然的用户体验。
展望
展望未来,我们计划继续关注MacCatalyst的更新动向,积极拥抱苹果推出的新功能,以进一步提升用户体验。此外,我们也在探索如何更好地利用SwiftUI与MacCatalyst结合,为未来的开发带来更多灵活性。我们坚信,MacCatalyst将为更多开发者带来无限可能,而《酷狗音乐》也将在这个统一生态中继续为用户提供最佳的音乐体验。