
fastlane frameit 设备边框资源生成向导解析使用 Rakefile 制作并上传 iPhone/iPad 官方设备边框【免费下载链接】fastlane The easiest way to automate building and releasing your iOS and Android apps项目地址: https://gitcode.com/GitHub_Trending/fa/fastlane在 fastlane 生态中frameit负责给应用截图一键套上真实的 iPhone、iPad 等设备边框。边框资源本身并非代码内置而是由frameit/frames_generator/目录下的 Rake 向导从 Facebook 提供的设备图集中产出、再托管到独立仓库供客户端下载。本文围绕该向导文档 frameit/frames_generator/README.md 展开结合其 Rakefile、Gemfile 与 frameit 客户端的下载/解析源码完整讲解“如何准备并发布一套新的设备边框资源”、生成目录结构的意义以及生成的files.json、version.txt、offsets.json是如何被 frameit 消费的读完可独立完成一次设备边框资源的新增、清洗、测量、上传与验证。为什么边框资源要单独生成与托管自 2016 年 10 月起frameit 改用 Facebook 官方设备图集Facebook frameset 中的设备外观素材来制作边框。原因正如 README 所述Apple 官方有时会移除或更改部分旧图片让“套边框”成为不断变化的目标a moving target。将原始素材抽取出来、统一清洗并托管到独立仓库是为了让边框行为可控、可版本化、可持续更新。因此框架内部形成了一个清晰的上下游关系上游frameit/frames_generator/的 Rake 向导把 Facebook 的原始 PNG 处理为规范命名的边框资源并发布到 GitHub 上的fastlane/frameit-frames仓库gh-pages分支下游frameit客户端通过 frame_downloader.rb 从https://fastlane.github.io/frameit-frames拉取这些资源缓存到本地新版缓存在~/.fastlane/frameit/version再按屏幕截图匹配对应的边框模板。frames_generator目录内还保留了一个legacy/子目录见 legacy里面存放的是已经从 Facebook frameset 中移除、但仍有用户需要的旧机型边框例如Apple iPad Pro Gold.png、Samsung Galaxy S7 Black.png等。向导在收集素材时会把这些 legacy 图片与最新素材一并纳入产出。运行向导前的准备目录与运行方式在 frameit/frames_generator/README.md 中明确指出只要在该目录下执行rake即可启动“准备新设备素材”的交互式向导。默认任务task(default: [:generate_device_frames])在 Rakefile 第 289 行定义指向核心任务generate_device_frames。向导是半自动交互式的它在每一步关键动作前都会暂停等待你在终端按任意键继续由confirm方法实现确保你不会在未准备好的情况下误操作。依赖与 Gemfile运行向导需要安装 Ruby 依赖Gemfile 定义了以下 gemssource(https://rubygems.org) gem colored gem mini_magick, ~ 4.9.0 # To open, edit and export PSD files and support ImageMagick 7 gem pry gem rake关键依赖说明mini_magick ~ 4.9.0核心图像处理库注释明确写明是为了兼容ImageMagick 7框架打开、编辑、导出图片以及测量屏幕插槽都依赖它。这也是一个硬性版本前提——从源码看measure_slot依赖 ImageMagick 7.x 的connected-components能力若版本过旧会直接报错并退出Rakefile 第 243-246 行colored在终端输出红/黄/绿等彩色提示pry调试用rake任务调度。向导的完整执行流程结合 Rakefile 第 84-163 行的task(:generate_device_frames)实现一次完整的资源生成过程包含以下步骤1. 下载并解压 Facebook 最新设备图向导会打印 Facebook 设备资源下载地址https://design.facebook.com/toolsandresources/devices/提示你手动下载 zip 并把内容整体拷贝到./raw目录如果raw目录不存在会自动创建mkdir(raw) unless File.directory?(raw)随后用system(open ./raw)打开该目录方便你把解压内容拖进去确认后按任意键继续。2. 确认 iPad 重命名方案在运行前向导会把当前生效的 iPad 版本重命名映射IPAD_RENAMING_SCHEME打印出来提醒你核对其与 Facebook 最新命名是否一致如不一致需要先更新脚本中的常量。映射内容如下IPAD_PRO_12_9_VERSION 4th generation IPAD_AIR_VERSION 2019 IPAD_MINI_VERSION 2019 IPAD_RENAMING_SCHEME { iPad Pro 11 iPad Pro (11-inch), iPad Pro 13 iPad Pro (12.9-inch) (#{IPAD_PRO_12_9_VERSION}), iPad Pro iPad Pro, # dont rename the iPad Pro 1st or 2nd gen from the legacy folder iPad Air iPad Air (#{IPAD_AIR_VERSION}), iPad Mini iPad Mini (#{IPAD_MINI_VERSION}), iPad iPad 10.2 # must be the last one so that only iPad without any version will be renamed to 10.2 }这段设计的背后原因是Facebook 提供的 iPad 文件不包含版本号只有 iPad Pro、iPad Air、iPad Mini、iPad如果不做重命名新版本会直接覆盖旧版本文件破坏向后兼容性。注意iPad iPad 10.2必须放在最后这样才能保证只有不带任何版本限定的裸iPad会被重命名为 10.2见 Rakefile 第 81 行的注释。3. 清理并重建输出目录脚本以当前时间戳Time.now.to_i.to_s作为版本号创建输出目录current_time Time.now.to_i.to_s output File.join(output, current_time) sh(rm -rf output) mkdir_p(output) unless File.directory?(output)这意味着一轮运行只会生成最新一批资源先清空旧的output再写入带时间戳的新版本目录。4. 收集素材并跳过不需要的设备素材来源通过 glob 汇总覆盖手机、电脑、平板三类外加 legacy 目录Rakefile 第 111 行Dir[raw/Phones/*/Device/*.png] Dir[raw/Computers/Apple*/Device/*.png] Dir[raw/Tablets/*/Device/*.png] Dir[raw/Tablets/*/Device/Device without Pencil/*.png] Dir[legacy/*.png]其中会按should_skip_device?过滤掉DEVICES_TO_SKIP列表命中的文件。跳过清单包括三类典型情况DEVICES_TO_SKIP [ Apple iMac, # we dont currently support iMac # some super old Android devices: Nokia 220, Nokia 230, Nokia C3-00, Nokia Asha 230, Samsung Galaxy Y, # unsupported platforms: Microsoft Lumia 950, Microsoft Surface Pro, # unsupported sides: Xiaomi Mi Mix Alpha Back, Xiaomi Mi Mix Alpha Side, Landscape ]即当前不支持形态如 iMac、过旧 Android、非受支持平台、不支持的方向/侧面横屏 Landscape、Xiaomi Mi Mix Alpha 的 Back/Side。凡是文件名包含上述任一关键词的图片都会被排除。5. 复制、改名、清洗并逐张测量对每张未被跳过的图片依次执行Rakefile 第 115-125 行复制到时间戳输出目录文件名清洗sanitize_filename并移动到规整后的路径图像清洗convert_image_resource去白边测量插槽measure_slot得到屏幕区域在原图中的几何信息记录到内存结构供后续生成offsets.json。如果处理完后图片总数不足 10 张raise ... if image_assets.count 10向导会判定素材拷贝有误并中止提示检查./raw内容。文件名清洗规则Facebook 的命名并不一致sanitize_filenameRakefile 第 178-193 行通过一系列替换统一命名filename .gsub(Grey, Gray) # 部分 Apple 设备把 Gray 写作 Grey .gsub(Golden, Gold) # 部分把 Gold 写作 Golden .gsub((PRODUCT)Red, Red) # 消除 (PRODUCT)RED 商标前缀 .gsub((PRODUCT)RED, Red) .gsub(Space Black, Black) # iPhone 14 Pro/Pro Max 的 Space Black - Black .gsub(Deep Purple, Purple) # iPhone 14 Pro/Pro Max 的 Deep Purple - Purple .gsub( - Portrait, ) # iPad Pro 只保留竖版 .gsub( - , ) # Google Pixel 型号与颜色间的短横线 .gsub( – , ) # 部分 Apple 设备使用的 en dash .gsub( — , ) # 部分 Apple 设备使用的 em dash .gsub(Note10, Note 10) # 补全 Samsung Note 10 缺失的空格 .gsub(Mi Mix Alpha Front, Mi Mix Alpha)最后调用perform_ipad_renaming套用上文的重命名方案。这套清洗的意义在于客户端是按“设备名 颜色”的文件名去匹配模板的见后文 TemplateFinder命名不统一将直接导致模板找不到。去白边trimconvert_image_resourceRakefile 第 209-217 行利用 MiniMagick 裁掉真机图四周多余的空白image.combine_options do |co| co.fuzz(90%) # 颜色差异阈值用于吸收阴影见 fastlane PR #14199 co.trim(repage) # repage 移除元数据 endfuzz(90%)是关键参数它把“看起来接近白色”的像素包括设备投下的阴影都当作边缘处理从而保证裁切后画面干净。屏幕插槽测量measure_slotRakefile 第 219-270 行是本向导最具技术含量的部分它通过 ImageMagick 7 的connected-component analysis连通域分析找出图片中的最大白色矩形即“屏幕插槽”。处理管线如下magick.channel(alpha) # 只针对 alpha 通道 magick.threshold(99%) # 半透明像素全部变为全透明去除圆角屏内阴影干扰 magick.channel. # 重置通道选择 magick.alpha(background) # 透明像素统一为同一背景色使连通域能被识别为单一区域 magick.negate # 黑白反转 magick.define(connected-components:verbosetrue) magick.define(connected-components:area-threshold100) magick.connected_components(8) # 8 邻域连通 magick.auto_level它之所以先对 alpha 通道做 99% 阈值化是因为部分机型如 Samsung Galaxy S9屏幕内有表现圆角的阴影会干扰连通域检测、报 “too many objects” 错误。脚本解析连通域输出的第二行最大区域用正则/(\d)x(\d)\(\d)\(\d)/取出x、y、width、height。源码注释给出了典型的命令输出示例Objects (id: bounding-box centroid area mean-color): 494: 640x113667239 386.5,806.5 727040 srgb(255,255,255) 4: 767x160500 385.4,801.2 478199 srgb(0,0,0)其中面积最大的640x113667239即屏幕槽其含义是屏幕宽640、高1136左上角相对原图偏移67239。此功能要求 ImageMagick 7.x 及以上若版本过老脚本会捕获异常并输出红色提示 “The functionality of slot measurements does not work with ImageMagick older than 7.x” 后退出。设备名规整sanitize_device_nameRakefile 第 272-287 行负责把“文件名”转成纯“设备名”剔除厂商前缀与颜色词去掉Apple、各类破折号并特殊修正Nexus 5x - Nexus 5X目录写Nexus 5X而文件写Nexus 5x最后用DEVICE_COLORS把颜色词从名字里切掉。颜色词表是有讲究的多词颜色必须排在前面Rakefile 第 23 行注释否则如 Space Gray 会被误切成 SpaceGray。DEVICE_COLORS [ Space Gray, Rose Gold, Jet Black, Matte Black, ..., Black, White, Gold, Silver, Blue, Red, ... ]6. 生成三个元数据文件素材处理完成后向导在时间戳目录内生成三个关键文件files.json按字母序排列的全部 PNG 文件名数组客户端据此逐个下载资源见下文 FrameDownloaderversion.txt本次运行的时间戳字符串作为客户端识别资源版本的标识offsets.json每个设备在“竖版portrait”下的插槽偏移与宽度{ portrait: { iPad Air 2: { offset: 112224, width: 1536 }, iPhone 5c: { offset: 67239, width: 640 }, iPhone 6s Plus: { offset: 102379, width: 1242 } } }完整示例见仓库中的 frameit/frames_generator/offsets.json。7. 多颜色偏移一致性检查因为同型号不同颜色的物理尺寸应该一致向导会做一次“体检”若同一设备的各颜色图片测出的x/y/width不一致会逐条以红色列出每个文件的测量值Rakefile 第 147-154 行并提示你决定保留offset中的现有值还是用列表中的更合适值替换。这能提前发现 Facebook 素材中可能存在的瑕疵。8. 产出两个版本目录并发布脚本把时间戳目录整体复制一份为output/latestcp_r(output, output/latest)随后打开output目录供检查。最终产出如下output/ ├── unix时间戳/ # 用户可在 Framefile 中显式锁定该版本 └── latest/ # 客户端默认使用的“最新”版本README 明确说明时间戳目录用于用户在其Framefile中指定特定版本时使用latest 目录则是默认使用的最新版本。发布方式克隆fastlane/frameit-frames仓库、检出gh-pages分支用本地output/latest覆盖远端latest目录并把时间戳目录整体复制到仓库根目录然后推送。发布后运行 frameit 的帧更新命令Rakefile 提示fastlane frameit update_frames即可验证一切是否如预期工作。仓库内实际可用的对应命令为fastlane frameit download_frames其定义见 commands_generator.rb底层调用Frameit::FrameDownloader.new.download_frames。生成的资源如何被 frameit 消费理解资源生成逻辑后再看客户端如何消费能让你对整套“版本锁定—下载—模板匹配—插槽对齐”链路有完整认识。下载与版本目录frame_downloader.rbframe_downloader.rb 中的FrameDownloader#download_frames从https://fastlane.github.io/frameit-frames拉取资源读取version.txt告知用户当前使用的帧版本并提示可用device_frame_version在Framefile.json中锁定解析files.json逐个下载全部 PNG下载offsets.json最后才写入本地version.txt——这样即使下载中途被中断也能通过版本文件是否存在来判断是否完整从而正确断点重试。本地模板路径由templates_path计算优先使用旧的~/.frameit/devices_frames_2/version否则落到新的~/.fastlane/frameit/version其中version由Frameit.frames_version决定。版本选择机制module.rbmodule.rb 中frames_version的默认值是latest它会扫描当前目录下所有Framefile.json若其中定义了非空的device_frame_version则使用该时间戳值作为版本。这正是 README 所说“用户指定特定版本”的落地实现frames_version latest config_files Dir[./**/Framefile.json] if config_files.count 0 config ConfigParser.new.load(config_files.first) if config.data[device_frame_version].to_s.length 0 frames_version config.data[device_frame_version] end end模板文件名匹配template_finder.rbtemplate_finder.rb 的create_file_name把模板命名为设备名 颜色无颜色时仅设备名因此 Rakefile 对文件名的清洗规则统一 Gray/Gold、去掉商标前缀等直接决定了客户端能否命中模板def self.create_file_name(device_name, color) return #{device_name} #{color} unless color.nil? return device_name end若指定颜色的模板不存在会回退到默认颜色并给出重要提示若仍找不到且是 3.5 英寸设备则会提示这类边框已停产并跳过该截图。插槽对齐offsets.rb 与 editor.rboffsets.rb 读取下载目录内的offsets.json以portrait下的设备名为 key 返回{ offset xy, width w }并实现了与生成端逻辑一致的sanitize_device_name源码注释也强调应与 frames_generator 保持同步。该偏移在 editor.rb 的put_into_frame中第 145 行Offsets.image_offset(screenshot)被用来把真实截图精确缩放到设备屏幕插槽位置。何时需要重新运行向导README 的结论性说明是每当你希望更新设备素材时都需要运行一次这个向导。典型触发场景包括Facebook frameset 发布了新型号设备新增 iPhone/iPad/Android 机型Facebook 调整了既有设备图集删除、改名或更换了部分图片需要重新托管因授权或托管方变动而失效的旧素材。每次运行都会产生新的时间戳版本目录与新的latest因此历史上锁过某个device_frame_version的用户不会因你的更新而受到影响做到了平滑演进。操作注意事项与前提条件汇总本向导是面向 fastlane/frameit 资源维护者的发布工具不是普通用户的日常命令普通用户只需运行fastlane frameit download_frames获取最新边框需要手动从 Facebook 下载原始图集并放入./raw向导不代劳下载每次 iPad 迭代需要先在IPAD_RENAMING_SCHEME常量中登记新版本号与命名映射运行依赖 ImageMagick 7.x 与mini_magick ~ 4.9.0若想增删跳过设备、扩充颜色词表分别调整DEVICES_TO_SKIP与DEVICE_COLORS常量即可发布目标仓库是独立的frameit-framesgh-pages分支与 fastlane 主仓库解耦上传后才能被客户端下载本仓库为只读镜像运行向导与上传操作应在你自己维护的发布环境中进行。小结frameit/frames_generator这套 Rake 向导把“Facebook 原始素材 → 规范命名的边框资源包”的复杂过程高度自动化它负责跳过不支持的设备、统一命名风格、剔除厂商商标前缀、为 iPad 补齐版本号、去白边、通过连通域分析自动测量每台设备的屏幕插槽并输出files.json、version.txt、offsets.json三个客户端协议文件最终以时间戳 latest双目录的形式发布。配合下游 frame_downloader.rb、module.rb、template_finder.rb、offsets.rb 的消费逻辑即可完整理解 fastlane 设备边框资源从“生成”到“下载、锁定、匹配、对齐”的整条技术链路。若你需要在仓库中扩展阅读可继续对比 Rakefile 的生成端清洗规则与 offsets.rb 的消费端命名处理二者保持一致是整个体系可靠运行的关键。【免费下载链接】fastlane The easiest way to automate building and releasing your iOS and Android apps项目地址: https://gitcode.com/GitHub_Trending/fa/fastlane创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考