news 2026/9/24 16:40:38

用 GN 构建 Skottie iOS 示例应用:Metal / CPU / OpenGL 三种后端完整指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
用 GN 构建 Skottie iOS 示例应用:Metal / CPU / OpenGL 三种后端完整指南
  • 图形学

【免费下载链接】skia

Skia is a complete 2D graphic library for drawing Text, Geometries, and Images. See documentation for contribution instructions.

项目地址:https://gitcode.com/gh_mirrors/ski/skia
点击查看免费下载

导读

本文以 Skia 仓库中的 tools/skottie_ios_app/README.md 为主线,完整讲解如何将 Skottie(Skia 的 Lottie 动画渲染模块)示例应用skottie_example编译为 iOS.app包,并分别针对Metal纯 CPUOpenGL三种渲染后端给出可直接复制的 GN 参数配置与构建命令。读完本文,你将掌握args.gn中各关键开关(skia_use_metalskia_enable_ganeshskia_enable_pdfskia_use_expat)的实际作用,理解示例应用内部的视图/上下文分层结构,以及三种后端在源码层面是如何被选择与实现的,从而能够根据自己的设备与性能需求快速搭建、定制 Skottie iOS 演示环境。

1. Skottie iOS 示例应用是什么

skottie_ios_app是 Skia 仓库中一个独立的 iOS 示例工程,其唯一产物是名为skottie_example的应用 bundle。它把 modules/skottie 模块包装成 Objective-C 接口,在一个可滚动的UIScrollView中依次加载并播放打包进 bundle 的多段 Lottie 动画 JSON(见 BUILD.gn 中data_sources列出的resources/skottie/下的动画资源)。

从源码结构看,该示例的核心设计是将渲染后端动画控制逻辑解耦:

  • SkiaContext.h 定义统一接口:makeViewWithController:withFrame:负责为某个动画控制器创建对应后端的UIViewgetViewController:用于反向取回控制器;
  • SkottieViewController.h 提供loadAnimation:seek:togglePausedcurrentTimeanimationDurationSeconds等 Objective-C 接口,把modules/skottie/include/Skottie.hskottie::Animation封装为可被 UIKit 直接调用的对象;
  • 具体后端实现在 SkiaMetalContext.mm、SkiaGLContext.mm、SkiaUIContext.mm 三个文件中。

main.mm中,应用通过预编译宏选择后端:

#if defined(SK_GANESH) && defined(SK_METAL) [self setSkiaContext:MakeSkiaMetalContext()]; #elif defined(SK_GANESH) && defined(SK_GL) [self setSkiaContext:MakeSkiaGLContext()]; #else [self setSkiaContext:MakeSkiaUIContext()]; #endif

也就是说,args.gn中的配置最终会决定SK_GANESHSK_METALSK_GL这三个宏是否定义,进而决定运行时使用哪个渲染后端。这也解释了为什么同一个工程、三份构建配置可以分别产出 Metal、CPU、OpenGL 三种版本。

2. 构建前置条件与目录准备

三种后端的构建流程完全一致,都需要以下前置条件:

  1. Skia 源码根目录:下文用$SKIA_ROOT_DIRECTORY指代(即克隆 Skia 仓库后所在的目录);
  2. GN 与 Ninjabin/gn genninja命令来自 Skia 内置的bin/工具链(bin/gn),首次使用时tools/git-sync-deps会同步第三方依赖;
  3. Xcode 与 iOS SDK:编译.appbundle 及后续安装到模拟器/真机都需要完整的 Xcode 环境;gn/ios.gni中定义了 iOS 应用 bundle 的打包逻辑(ios_app_bundle模板)。

每次构建都需要新建独立的输出目录并写入args.gn。下面按 Metal / CPU / OpenGL 三个后端分别给出完整的构建命令。三组命令均以cd $SKIA_ROOT_DIRECTORY开头,因此以下命令均需在仓库根目录下执行。

2.1 准备命令速查

步骤命令作用
进入仓库根目录cd $SKIA_ROOT_DIRECTORY定位源码根
创建输出目录mkdir -p out/ios_arm64_mtl隔离各后端产物
写入构建参数cat > out/ios_arm64_mtl/args.gn <<EOM ... EOM生成 GN 参数文件
同步依赖tools/git-sync-deps拉取/校验第三方依赖
生成构建文件bin/gn gen out/ios_arm64_mtl解析 args.gn 生成 ninja 文件
编译ninja -C out/ios_arm64_mtl skottie_example构建.appbundle

注意:bin/gn是 Skia 仓库自带的 GN 二进制,不要与系统安装的 GN 混淆;tools/git-sync-deps是仓库根目录下的 Python 脚本 tools/git-sync-deps,用于同步 DEPS 中声明的依赖。

3. 后端一:Metal(GPU 加速,真机推荐)

Metal 是 Apple 提供的低开销 GPU 图形 API,是 iOS 上性能最好的 Skia Ganesh 后端,适合在真机上运行。

cd $SKIA_ROOT_DIRECTORY mkdir -p out/ios_arm64_mtl cat > out/ios_arm64_mtl/args.gn <<EOM target_os="ios" target_cpu="arm64" skia_use_metal=true skia_use_expat=false skia_enable_pdf=false EOM tools/git-sync-deps bin/gn gen out/ios_arm64_mtl ninja -C out/ios_arm64_mtl skottie_example

构建完成后,将out/ios_arm64_mtl/skottie_example.app安装到 iOS 设备即可(可通过 Xcode 的 Devices 面板或xcrun simctl安装)。

3.1 参数解读

  • target_os="ios":目标平台为 iOS,触发gn/ios.gni中的 iOS bundle 模板逻辑;
  • target_cpu="arm64":64 位 ARM 架构,覆盖现代 iPhone/iPad 与 Apple Silicon 模拟器;
  • skia_use_metal=true:启用 Metal 支持,编译时定义SK_METAL,Ganesh 使用 Metal 后端;
  • skia_use_expat=false:禁用 expat(XML 解析库),Skottie 不需要它,可减小体积与构建时间;
  • skia_enable_pdf=false:禁用 PDF 相关代码,进一步精简产物。

注意,此配置中未显式关闭 Ganesh,即skia_enable_ganesh保持默认开启(true)。这正是 BUILD.gn 中skia_enable_ganesh && skia_use_metal分支生效的条件:此时会额外编译SkMetalViewBridge.mmSkiaMetalContext.mm,并链接Metal.frameworkMetalKit.framework(见 BUILD.gn 第 60-64 行)。

3.2 源码实现:Metal 视图如何工作

Metal 后端由 SkiaMetalContext.mm 实现。初始化时创建MTLDeviceMTLCreateSystemDefaultDevice)、MTLCommandQueue,并用它们构造GrDirectContext

GrMtlBackendContext backendContext = {}; backendContext.fDevice.reset((__bridge void*)[self metalDevice]); backendContext.fQueue.reset((__bridge void*)[self metalQueue]); fDContext = GrDirectContexts::MakeMetal(backendContext, GrContextOptions());

渲染视图SkiaMtkView继承自MTKView,在drawRect:中通过SkMtkViewToSurfaceMTKViewcurrentDrawable包装为SkSurface,调用[viewController draw:... toCanvas:...]完成 Skottie 帧渲染,随后:

fDContext->flushAndSubmit(surface.get()); id<MTLCommandBuffer> commandBuffer = [fQueue commandBuffer]; [commandBuffer presentDrawable:[self currentDrawable]]; [commandBuffer commit];

值得注意的细节是帧率控制:视图创建时设置setPreferredFramesPerSecond:30(30 FPS);并且当动画处于暂停状态时,通过setEnableSetNeedsDisplay:pausedsetPaused:pausedMTKView停止连续绘制,实现暂停即省电的效果。

4. 后端二:CPU(无 GPU 依赖,模拟器友好)

CPU 后端不依赖任何图形 API,使用 Skia 的 raster 路径把动画逐帧画到内存位图再上屏,适合在 iOS 模拟器或无 GPU 环境下运行,也便于调试。

cd $SKIA_ROOT_DIRECTORY mkdir -p out/ios_arm64_cpu cat > out/ios_arm64_cpu/args.gn <<EOM target_cpu="arm64" target_os="ios" skia_enable_ganesh=false skia_enable_pdf=false skia_use_expat=false EOM tools/git-sync-deps bin/gn gen out/ios_arm64_cpu ninja -C out/ios_arm64_cpu skottie_example

构建完成后,将out/ios_arm64_cpu/skottie_example.app安装到设备或模拟器即可。

4.1 参数解读

  • skia_enable_ganesh=false显式关闭 Ganesh GPU 渲染层,这是 CPU 后端与 Metal/OpenGL 后端的根本区别。此时SK_GANESH宏不定义,main.mm中的#if defined(SK_GANESH) && defined(SK_METAL)#elif defined(SK_GANESH) && defined(SK_GL)均不成立,最终落入#else分支调用MakeSkiaUIContext()
  • target_cpu="arm64"/target_os="ios":与 Metal 配置相同;
  • skia_enable_pdf=falseskia_use_expat=false:精简依赖与产物。

从 BUILD.gn 的源码结构看,当skia_enable_ganesh为 false 时,两个 GPU 上下文文件都不会参与编译,而是仅编译SkiaUIContext.mm,并且不会链接任何 Metal/OpenGL 框架。

4.2 源码实现:CPU 视图如何工作

CPU 后端由 SkiaUIContext.mm 实现。SkiaUIView内部维护一块SkBitmap fBackBuffer作为后备缓冲:

  1. drawRect:中按当前 view 尺寸重新分配位图(尺寸变化时才重建);
  2. 构造SkCanvas canvas(fBackBuffer),调用[viewController draw:... toCanvas:&canvas ...]让 Skottie 把动画帧画进位图;
  3. 通过SkCGDrawBitmap把位图交给 CoreGraphics 上屏;
  4. 使用NSTimerkFrameRate = 1.0 / 30.0(30 FPS)调度下一次setNeedsDisplay;暂停状态下则不调度,从而停止重绘。

这段实现也印证了 README 中“CPU 后端”命名背后的机制:所有渲染都在 CPU 内存中完成,不涉及任何 GPU 命令队列。

5. 后端三:OpenGL(Ganesh + OpenGLES)

OpenGL 后端使用 Ganesh 的 OpenGL 实现(iOS 上即 OpenGLES),适合需要在 Ganesh 框架下对比 Metal/GL 渲染差异的场景。

cd $SKIA_ROOT_DIRECTORY mkdir -p out/ios_arm64_gl cat > out/ios_arm64_gl/args.gn <<EOM target_cpu="arm64" target_os="ios" skia_enable_ganesh=true skia_use_metal=false skia_enable_pdf=false skia_use_expat=false EOM tools/git-sync-deps bin/gn gen out/ios_arm64_gl ninja -C out/ios_arm64_gl skottie_example

构建完成后,将out/ios_arm64_gl/skottie_example.app安装到设备或模拟器即可。

5.1 参数解读

  • skia_enable_ganesh=true:显式启用 Ganesh GPU 渲染层(与默认值一致,写出来更清晰);
  • skia_use_metal=false显式关闭 Metal,避免与 OpenGL 后端同时启用产生歧义;
  • 由于skia_use_gl默认开启且本配置未修改,Ganesh 将采用 OpenGL 后端,SK_GL宏被定义;
  • skia_enable_pdf=falseskia_use_expat=false:与前面两个配置一致的精简项。

对照 BUILD.gn 与第 65-69 行的框架列表:此时命中skia_enable_ganesh && skia_use_gl分支,仅追加编译SkiaGLContext.mm,并链接GLKit.frameworkOpenGLES.framework

5.2 源码实现:OpenGL 视图如何工作

OpenGL 后端由 SkiaGLContext.mm 实现。其核心步骤包括:

  • 初始化时配置GLKView的 drawable 格式:GLKViewDrawableColorFormatRGBA8888、24 位深度缓冲、8 位模板缓冲(见configure_glkview_for_skia,源码第 23-27 行);
  • 渲染时查询当前绑定帧缓冲(glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &fboid)),并通过GrBackendRenderTargets::MakeGLGL_RGBA8帧缓冲包装为SkSurface,然后照常调用[viewController draw:... toCanvas:...]渲染 Skottie 帧;
  • 渲染完成后由 Ganesh 的 OpenGL 后端负责flush到默认帧缓冲,GLKView负责上屏。

从代码结构可以推断,三个后端的差异被严格隔离在“创建SkiaContext/UIView”这一层,SkottieViewController的动画加载、seek、暂停/播放逻辑在三种后端间完全复用。

6. 三种后端配置对比与选型

配置项MetalCPUOpenGL
target_os"ios""ios""ios"
target_cpu"arm64""arm64""arm64"
skia_enable_ganesh默认 truefalsetrue
skia_use_metaltrue不要求false
skia_enable_pdffalsefalsefalse
skia_use_expatfalsefalsefalse
运行时上下文MakeSkiaMetalContext()MakeSkiaUIContext()MakeSkiaGLContext()
额外框架Metal、MetalKitGLKit、OpenGLES
适用场景真机 GPU 渲染模拟器/无 GPUGanesh + GL 对比

选型建议(基于仓库实现事实,非性能断言):

  • 真机验证 Skottie 渲染效果:优先 Metal,它是 iOS 上 Skia 主推的 GPU 后端;
  • 模拟器或 CI 无 GPU 环境:用 CPU 后端,零图形框架依赖,构建最轻;
  • 需要 Ganesh 抽象层下的跨后端对比:同时构建 Metal 与 OpenGL 两套,观察同一动画在不同 GPU 后端的表现差异。

7. 运行示例应用:界面与交互

skottie_example的运行界面由 main.mm 构建:应用启动后,AppViewController读取 bundle 内data目录下所有.json动画资源,为每个可成功加载的动画创建一个SkottieViewController,并按动画原始宽高比计算高度,依次垂直排列进UIStackView,整体放入UIScrollView以支持滚动浏览多段动画。

交互方面,main.mm在根视图注册了UITapGestureRecognizerhandleTap:):点击屏幕会遍历所有SkiaViewController并调用togglePaused,即点击即可暂停/恢复所有动画,暂停状态会通过setNeedsDisplay立即反映到界面。

SkottieViewController的播放控制能力来自其内部的SkTimeKeeperSkAnimationDraw(见 SkottieViewController.mm):

  • SkAnimationDraw负责用skottie::Animation::Builder从 JSON 数据构建动画,并在尺寸变化时计算居中缩放矩阵,然后fAnimation->render(canvas)渲染当前帧;
  • SkTimeKeeper负责时间轴:基于SkTime::GetNSecs()的单调时钟计算播放位置,支持seek:(暂停时直接改播放时刻、运行时重置起点)、setStopAtEnd:(播到结尾自动暂停)以及togglePaused(暂停时记录当前时刻,恢复时校准时钟偏移)。

这两个类的实现恰好对应 SkottieViewController.h 中暴露的 Objective-C 接口(isPausedtogglePausedseek:currentTimeanimationDurationSecondssize等),如果你想把该示例改造为自己的播放器,直接复用这些接口即可。

8. 自定义与扩展建议

在保持仓库只读的前提下,你可以基于现有结构做如下扩展(仅需在本地副本中修改后重新构建):

  1. 更换/增加动画资源:参考 BUILD.gn 的data_sources,把自己生成的 Lottie JSON 加入列表,重启应用即可在滚动列表中看到新动画;
  2. 限制动画列表main.mm中遍历pathsForResourcesOfType:@"json" inDirectory:@"data",可以改为只加载指定文件名;
  3. 调整帧率:Metal 视图的setPreferredFramesPerSecond:30与 CPU 视图的kFrameRate = 1.0/30.0是两处可调的帧率参数,可按需改高或改低;
  4. 改变交互handleTap:目前统一切换所有动画的暂停状态,可改为只切换被点击的那个视图对应的控制器(getViewController:接口已为此准备好);
  5. 自定义渲染回调SkiaViewController draw:toCanvas:atSize:协议可被任意自定义控制器实现,不限于 Skottie,可作为在 iOS 上测试任意 Skia 绘制内容的宿主。

9. 常见问题排查

  • bin/gn gen报错找不到工具链:确认已安装 Xcode 并完成xcode-select -p配置;首次构建务必先执行tools/git-sync-deps
  • 安装.app失败(真机):检查设备是否信任开发者证书,.app需通过 Xcode 或xcrun devicectl安装并完成签名(示例产物默认面向开发调试场景);
  • CPU 后端动画不刷新:确认skia_enable_ganesh=false已写入 args.gn;若宏选择逻辑生效,main.mm会调用MakeSkiaUIContext(),其NSTimer调度依赖isPaused状态,暂停时不会重绘,属于预期行为;
  • Metal 后端在模拟器上无画面MTLCreateSystemDefaultDevice在部分模拟器环境可能返回 nil(SkiaMetalContext.mm第 87-91 行会打印 "Metal is not supported on this device" 并返回 nil 上下文,main.mm检测到空上下文会abort),此时请改用 CPU 后端配置。

10. 延伸阅读

  • 示例工程构建定义:tools/skottie_ios_app/BUILD.gn
  • Skottie 渲染模块:modules/skottie/include/Skottie.hskottie::Animation的构建与渲染接口)
  • 后端上下文接口:tools/skottie_ios_app/SkiaContext.h
  • 动画控制器封装:tools/skottie_ios_app/SkottieViewController.h 与 tools/skottie_ios_app/SkottieViewController.mm
  • iOS 打包模板:gn/ios.gniios_app_bundle
  • 应用入口与交互逻辑:tools/skottie_ios_app/main.mm
  • 示例动画资源:resources/skottie/(BUILD.gndata_sources所列 JSON)

通过本文给出的三套args.gn与构建命令,你可以在同一份 Skia 源码上分别产出 Metal、CPU、OpenGL 三个版本的 Skottie iOS 示例应用,并借助源码理解每一份配置背后实际的渲染链路,为后续基于 Skottie 的 iOS 动画业务开发打好基础。

  • 图形学

【免费下载链接】skia

Skia is a complete 2D graphic library for drawing Text, Geometries, and Images. See documentation for contribution instructions.

项目地址:https://gitcode.com/gh_mirrors/ski/skia
点击查看免费下载

相关推荐

上一篇:3大核心技术突破:MouseClick如何重新定义鼠标自动化效率
下一篇:MouseClick:从手动点击到智能自动化的技术演进与实战指南

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/24 16:35:07

王者荣耀弱网对抗:帧同步如何扛住460?

地铁,晚高峰,进站前最后三十秒。 你正在开团。屏幕右上角那个绿色的数字,突然变成了刺眼的红色: 460你做好了准备——画面冻结、角色僵直、然后瞬移回城泉水。 但这一次,什么都没发生。 你的技能照常释放,动画照常播放。只是敌人的走位,看起来慢了半拍。 三秒后,数字跳…

作者头像 李华
网站建设 2026/9/24 16:33:09

四路can转4G在现场应用中有什么问题?

一、现场使用 SG‑CAN‑4G‑410 网关&#xff0c;电脑通过网口配置设备&#xff0c;配置软件搜索不到设备&#xff0c;需要从哪些方面排查处理。 首先确认设备供电正常&#xff0c;PWR 电源灯常亮&#xff0c;RUN 系统指示灯处于闪烁运行状态&#xff1b;电脑网线连接设备 LAN …

作者头像 李华