十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

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

SDL3 iOS 开发指南:基于 SDL3.xcframework 与 Xcode 工程的构建、集成与系统级适配

SDL3 iOS 开发指南:基于 SDL3.xcframework 与 Xcode 工程的构建、集成与系统级适配 SDL3 iOS 开发指南基于 SDL3.xcframework 与 Xcode 工程的构建、集成与系统级适配【免费下载链接】SDLSimple DirectMedia Layer项目地址: https://gitcode.com/GitHub_Trending/sd/SDLSimple DirectMedia LayerSDL3为 iOS、tvOS 与 visionOS 提供了完整的一站式构建与集成方案。本文以仓库中的 docs/README-ios.md 为骨架结合 Xcode/SDL/SDL.xcodeproj/project.pbxproj 中的工程目标配置、include/SDL3/SDL_main.h 的头文件式 main 实现以及 src/video/uikit/ 的 UIKit 驱动源码系统讲解从零构建 SDL3、以 xcframework 或 Xcode 工程两种方式接入 iOS 应用、处理高 DPI、应用生命周期、软键盘、蓝牙鼠标、沙盒文件系统、Game Center 动画回调以及向旧版本 iOS 部署的完整技术路线读者可直接将本文的步骤与代码应用到自己的 SDL3 iOS 项目中。环境要求与构建基础SDL3 的 iOS 构建链要求如下以 docs/README-ios.md 为准Xcode12.2 或更新版本iOS SDK14.2 或更新版本部署目标iOS 11.0、tvOS 11.0、visionOS 1.3 及更新版本。构建 SDL 本身非常简单只需两步用 Xcode 打开位于仓库 Xcode/SDL 下的SDL.xcodeproj在 Xcode 中选择目标target并点击 Build 即可。从 Xcode/SDL/SDL.xcodeproj/project.pbxproj 可以看到工程内已为 iOS 与 tvOS 分别设置了IPHONEOS_DEPLOYMENT_TARGET 11.0与TVOS_DEPLOYMENT_TARGET 11.0即工程产物默认支持部署到 iOS 11.0 / tvOS 11.0 及以上的系统。使用 SDL3.xcframework 集成 iOS 应用推荐什么是 xcframework为什么需要它在 Apple SiliconARM 架构Mac 出现之前iOS 真机始终是 ARM 处理器而模拟器则固定为 i386 或 x86_64开发者可以把真机与模拟器用的库合并进一个普通 framework。但 Apple Silicon Mac 出现后CPU 类型已不足以区分平台——模拟器也可能运行在 ARM 上普通 framework 会因架构冲突而无法同时满足真机与模拟器。为此 Apple 在 Xcode 11 中引入了xcframework一种超级框架uber-framework可以同时承载任意处理器架构与任意目标 OS 平台的组合。在 Xcode/SDL/SDL.xcodeproj/project.pbxproj 中SDL3.xcframework是 SDL.xcodeproj 的一个 aggregate target。该 target 的构建脚本会先对 macOS、iphoneos、iphonesimulator、appletvos、appletvsimulator 等平台逐一执行 archive再用xcodebuild -create-xcframework汇总为一个SDL3.xcframework产出位置在SDL.xcodeproj同级的 Products 目录中。使用上有三个关键注意点Xcode 版本xcframework 构建脚本在 Xcode 版本低于 11.0 时会直接报错退出因此该 target 需要 Xcode 11 及以上版本Apple Silicon 交叉编译限制Intel Mac 无法为 Apple Silicon Mac 交叉编译。如果需要 Apple SiliconAS兼容性必须在 Apple Silicon Mac 上完成构建获取方式既可以自行构建SDL3.xcframework也可以直接下载官方发布版本中的磁盘镜像资源*.dmg解压得到。SDL3 的 header-only SDL_main告别 libSDL3main 静态库在 Apple 平台上main()不能存在于动态加载的库中。与 SDL2 需要链接静态库libSDL3main.lib或拷贝.c源文件不同SDL3 将 SDL_main 以内联inline方式实现于 include/SDL3/SDL_main.h因此无需链接额外的libSDL3main静态库无需从 SDL3 源码中拷贝任何.c文件。使用方式非常直接在包含标准int main(int argc, char *argv[])的源文件顶部#include SDL3/SDL_main.h即可获得一个 header-only 的 SDL_main 实现——它内部会调用SDL_RunApp()来启动你的标准 main 函数。从源码看include/SDL3/SDL_main.h 在SDL_PLATFORM_IOS || SDL_PLATFORM_TVOS分支下会定义SDL_MAIN_NEEDED并通过宏#define main SDL_main将你的main重写为SDL_main随后自动#include SDL3/SDL_main_impl.h插入平台实现而 src/video/uikit/SDL_uikitappdelegate.m 中的SDL_RunApp会保存参数并调用UIApplicationMain接管运行循环最终由 UIKit 委托在启动完成后再回调SDL_main。这就是头文件即入口背后真实存在的调用链。将 SDL3.xcframework 接入 iOS 工程的完整步骤在 Xcode 中新建工程选择iOS Game模板语言选Objective-C游戏技术选Metal在工程主视图中删除除Assets与LaunchScreen之外的所有文件选中工程进入General标签页滚动到Frameworks, Libraries, and Embedded Content将SDL3.xcframework拖入仍然在该区域为SDL3.xcframework选择Embed Sign加入你平时编写 SDL 程序所需的源文件并在包含main()的源文件顶部添加#include SDL3/SDL_main.h添加应用所需的所有资源Assets完成开始开发。解决 xcframework 头文件搜索失败的问题xcframework 的使用体验与普通 framework 类似但已知会出现构建系统找不到 xcframework 内头文件的问题。修复方法在Target → Build Settings → Framework Search Paths中加入 xcframework 所在路径并勾选recursive递归——这一步至关重要同时在Build Settings → Sub-Directories to Exclude in Recursive Searches中移除*.framework——同样关键清理 Build 文件夹Clean Build Folder下次构建时构建系统即可正确解析以下任意一种包含方式#include SDL3/SDL_main.h #include SDL3/SDL.h #include SDL3/SDL_main.h以 SDL3 Xcode 工程方式集成兼容旧版 Xcode若你仍在使用 Xcode 11 之前的旧版本无法使用 xcframework则可以把 SDL3 的 Xcode 工程直接加入自己的工程新建工程选择iOS Game模板、Objective-C语言、Metal游戏技术删除除Assets与LaunchScreen外的所有文件右键工程选择Add Files...加入 SDL 工程文件 Xcode/SDL/SDL.xcodeproj进入工程Info标签页在Custom iOS Target Properties中删除 Main storyboard file base name 这一行进入Build Settings标签页选择All编辑Header Search Path把左侧的 SDL Public Headers 文件夹拖入进入Build Phases标签页在Link Binary With Libraries中添加来自 Framework-iOS 的SDL3.framework进入General标签页滚动到Frameworks, Libraries, and Embedded Content为 SDL 库选择Embed Sign加入 SDL 程序源文件并在包含main()的源文件顶部添加#include SDL3/SDL_main.h添加应用所需资源完成。App Store 上架移除嵌入的 SDL3.framework嵌入 SDL3 Xcode 工程后SDL3.framework会成为你应用的 target 之一从而被包含在 App Store 提交所需的Archive产物中——这会导致上架失败。解决方案是在Embed Sign步骤之后通过一个 Run Script 脚本阶段将其移除进入Build Phases标签页点击并选择New Run Script Phase滚动到 Run Script位于 Embed SDL3 Framework 之后输入以下脚本if [ -d $INSTALL_ROOT/Library ]; then echo Removing SDL3.framework from INSTALL_ROOT for archiving rm -rf $INSTALL_ROOT/Library fi在脚本输入框下方取消勾选 For install builds only 与 Based on dependency analysis 两个 Run Script 选项在 Build Settings 中将User Script Sandboxing设置为No。官方文档同时注明关于图标等 App Store 要求的信息仍有待补充TODO。高分屏Retina / High-DPI与窗口尺寸SDL 中窗口和显示模式的尺寸一律以点point为单位而非像素pixel。以 iPhone 6 为例窗口尺寸在点是 375 × 667在像素则是 750 × 1334。iOS 应用按惯例以点组织内容尺寸这样不同设备可以拥有不同的像素密度Retina 屏与非 Retina 屏应用无需特别关心。关键 API 行为如下SDL_GetWindowSize()与鼠标坐标返回的是点当设备支持更高像素密度时窗口的实际像素密度会更高可用SDL_GetWindowSizeInPixels()查询可绘制屏幕帧缓冲drawable framebuffer的像素尺寸SDL 2D 渲染 API 默认已自动处理这一切默认提供以点为单位渲染区域调用SDL_SetRenderLogicalPresentation()即可访问更高密度的分辨率。在 include/SDL3/SDL_video.h 中SDL_GetWindowSize的文档也明确说明当窗口处于高像素密度显示器上时需用SDL_GetWindowSizeInPixels()或SDL_GetRenderOutputSize()获取真实的客户区像素尺寸并提示 drawable 尺寸在窗口创建后可能变化应在收到SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED事件后重新查询。对 OpenGL ES 开发者还需注意glViewport等 OpenGL ES 函数期望的是像素尺寸而非点。因此当用 OpenGL ES 做 2D 渲染时应使用以点为单位来自SDL_GetWindowSize()的正交投影矩阵从而无论在何种 Retina 设备上都能以相同缩放比例显示内容。获取全屏分辨率必须在 Info.plist 声明 Launch Screen要想获得全屏分辨率必须在应用的Info.plist中包含 Launch Screen 键例如keyUILaunchScreen/key dict/如果未指定启动屏幕系统会认为应用需要旧版兼容模式从而只提供受限分辨率的屏幕。应用事件Application Events与生命周期处理iOS 应用遵循固定的生命周期SDL 会通过应用事件application events向你通知状态变化。这些事件交付后OS 可能不会再给应用任何处理时间因此必须在事件回调中立即处理。典型的事件过滤器实现如下bool HandleAppEvents(void *userdata, SDL_Event *event) { switch (event-type) { case SDL_EVENT_TERMINATING: /* 终止应用。 在从本函数返回之前完成所有清理工作。 */ return false; case SDL_EVENT_LOW_MEMORY: /* 应用被暂停且 iOS 需要更多内存时收到该事件。 尽可能释放更多内存。 */ return false; case SDL_EVENT_WILL_ENTER_BACKGROUND: /* 准备进入后台。停止循环等。 用户按下 Home 键或接到来电时会触发。 */ return false; case SDL_EVENT_DID_ENTER_BACKGROUND: /* 如果用户接受了将应用送入后台的操作则触发。 如果用户接到了电话并取消则会收到 SDL_EVENT_DID_ENTER_FOREGROUND 事件并重启循环。 收到该事件后你只有 5 秒时间保存所有状态 否则应用将被终止。 此刻你的应用并不处于活动状态。 */ return false; case SDL_EVENT_WILL_ENTER_FOREGROUND: /* 应用即将回到前台。 在此恢复所有状态。 */ return false; case SDL_EVENT_DID_ENTER_FOREGROUND: /* 在此重启循环。 应用重新进入交互状态并获得 CPU。 */ return false; default: /* 无需特殊处理交回事件队列 */ return true; } } int main(int argc, char *argv[]) { SDL_SetEventFilter(HandleAppEvents, NULL); /* ... 运行你的主循环 ... */ return 0; }需要特别注意的是如果你使用的是 main callbacks主回调模式而非标准 Cmain()那么你的SDL_AppEvent()回调会在这些事件到达时自动执行无需再调用SDL_SetEventFilter。键盘屏幕软键盘支持SDL 键盘 API 已扩展以支持 iOS 的屏幕软键盘相关声明位于 include/SDL3/SDL_keyboard.h函数作用SDL_StartTextInput()启用文本事件并显示屏幕软键盘注SDL3 中实际签名为SDL_StartTextInput(SDL_Window *window)需传入目标窗口SDL_StopTextInput()禁用文本事件并隐藏屏幕软键盘SDL_TextInputActive()返回文本事件是否已启用即屏幕软键盘是否可见从 include/SDL3/SDL_keyboard.h 的文档看启用文本输入后窗口会收到SDL_EVENT_TEXT_INPUT与SDL_EVENT_TEXT_EDITING事件文本输入事件默认不会上报需要显式调用开启。这一机制同时作用于 IME 输入法某些平台启用软键盘/IME 后部分按键事件会被系统截获这是符合预期的行为。鼠标iPad 蓝牙鼠标支持iOS 现已支持 iPad 上的蓝牙鼠标但默认情况下系统会把鼠标输入以触摸事件的形式上报。为了让 SDL 看到真实的鼠标事件需要在Info.plist中设置键UIApplicationSupportsIndirectInputEvents为truekeyUIApplicationSupportsIndirectInputEvents/key true/从 iOS 17 开始该键默认即为true。文件读写iOS 沙盒与正确的存储位置iPhone 上每个应用都运行在自己的沙盒sandbox中沙盒内含独立的应用主目录application home directory应用不能访问该目录之外的任何文件。当 SDL 应用启动时SDL 会把工作目录设置为main bundle即应用资源存放处但该目录不可写。因此文档类文件写入SDL_GetUserFolder(SDL_FOLDER_DOCUMENTS)返回的目录偏好设置类文件写入SDL_GetPrefPath()返回的目录。从源码看src/filesystem/cocoa/SDL_sysfilesystem.m 中SDL_GetUserFolder的SDL_FOLDER_DOCUMENTS分支对应NSDocumentDirectory同时该文件还揭示了 tvOS 的一个特殊限制——tvOS 没有持久化的本地存储唯一的落盘位置是随时可能被系统清空的缓存目录因此 tvOS 上存档数据很可能在会话之间丢失若要持久保存需借助 iCloud 存储。这一点对同时面向 iOS/tvOS 的开发者非常重要。iPhone 上的 SDL 平台限制窗口Windows仅支持全尺寸、单窗口应用。无法在 iPhone OS 上创建多窗口 SDL 应用。应用窗口会铺满整个屏幕不过可以选择是否显示菜单栏向SDL_CreateWindow()传入SDL_WINDOW_BORDERLESS标志即可切换。纹理TexturesiOS 上最优的纹理格式为SDL_PIXELFORMAT_ABGR8888、SDL_PIXELFORMAT_XBGR8888与SDL_PIXELFORMAT_RGB24原文中 ABGR8888 出现两次结合上下文此处应指 ARGB/ABGR 系 8888 格式族实际以头文件 include/SDL3/SDL_pixels.h 中像素格式枚举为准。CoreBluetooth.framework 与手柄支持SDL_JOYSTICK_HIDAPI默认处于禁用状态。启用它可以访问更多游戏手柄设备但它要求应用在访问蓝牙硬件前获得用户授权。而通过 Made For iOSMFi认证的控制器无需此授权——因为 SDL 不需要直接通过原始蓝牙与它们通信所以很多应用可以不加此功能。如果启用 HIDAPI 手柄支持需要链接CoreBluetooth.framework在Info.plist中加入类似下面的使用说明keyNSBluetoothPeripheralUsageDescription/key stringMyApp would like to remain connected to nearby bluetooth Game Controllers and Game Pads even when youre not using the app./stringGame Center 与动画回调Game Center 集成可能要求应用拆解主循环把控制权交还给系统。具体做法是不再运行无限主循环而是把每一帧渲染放进回调函数通过以下函数注册bool SDL_SetiOSAnimationCallback(SDL_Window * window, int interval, SDL_iOSAnimationCallback callback, void *callbackParam);该函数在 include/SDL3/SDL_system.h 中声明SDL_iOSAnimationCallback类型即void (SDLCALL *)(void *userdata)它会把给定函数注册为动画回调随后必须从main()返回让 Cocoa 事件循环接管。示例extern C void ShowFrame(void*) { /* ... 处理事件、帧逻辑与渲染 ... */ } int main(int argc, char *argv[]) { /* ... 初始化游戏 ... */ #ifdef SDL_PLATFORM_IOS // 为计分与匹配初始化 Game Center InitGameCenter(); // 在 iOS 上让游戏运行在窗口动画回调中 // 使 Game Center 等功能正常工作。 SDL_SetiOSAnimationCallback(window, 1, ShowFrame, NULL); #else while ( running ) { ShowFrame(0); DelayFrame(); } #endif return 0; }从源码实现看src/video/uikit/SDL_uikitappdelegate.m 与 src/video/uikit/SDL_uikitviewcontroller.m 中SDL_SetiOSAnimationCallback通过CADisplayLink驱动回调按屏幕刷新节奏触发。同样地如果使用 main callbacks 模式SDL_AppIterate()回调已经替你完成了这项工作无需再使用SDL_SetiOSAnimationCallback——这从 src/main/ios/SDL_sysmain_callbacks.m 可以得到印证该文件在 iOS 上创建一个绑定到CADisplayLink的SDLIosMainCallbacksDisplayLink对象在每个刷新周期调用SDL_IterateMainCallbacks(true)驱动SDL_AppIterate并会自动适配高于 60Hz 的高刷新率屏幕若Info.plist中声明CADisableMinimumFrameDurationOnPhone为true/还能在手机上启用高刷新率。向旧版本 iOS 部署SDL 支持部署到比最新版 Xcode 所支持的更旧的 iOS 版本最低可回溯到iOS 11.0。步骤如下从 Apple 开发者网站下载旧版 Xcodedeveloper.apple.com/download/more中的历史版本列表打开旧版 Xcode 与新版 Xcode 的包内容将Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport下的文件夹复制合并过去打开文件Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/SDKSettings.plist在键Root/DefaultProperties/DEPLOYMENT_TARGET_SUGGESTED_VALUES中加入你想要部署的 iOS 版本号打开工程将部署目标Deployment Target设为目标 iOS 版本最后从应用链接的框架列表中移除GameController并在 Build Settings 的Other Linker Flags中添加-weak_framework GameController。-weak_framework GameController的作用是弱链接 GameController 框架在旧系统上该框架不存在时应用仍可正常启动只有在运行到相关调用时才可能缺失——这是同时支持新旧系统手柄 API 的常用手段。小结在 docs/README-ios.md 的基础上本文结合 Xcode/SDL/SDL.xcodeproj/project.pbxproj、include/SDL3/SDL_main.h、src/video/uikit/ 与 src/filesystem/cocoa/SDL_sysfilesystem.m 等仓库源码梳理了 SDL3 在 iOS 平台上的完整技术要点两种工程集成方式xcframework 与内嵌 Xcode 工程、头文件式 SDL_main 的实现原理、点/像素坐标系与 Retina 处理、Launch Screen 全屏要求、应用生命周期事件、软键盘、蓝牙鼠标、沙盒文件系统与 tvOS 存储限制、手柄授权与 Game Center 动画回调以及向 iOS 11.0 旧版本部署的完整流程。开发者可以据此在自己的 iOS/tvOS 工程中稳定落地 SDL3并规避 App Store 上架、蓝牙权限、高刷新率等常见坑点。【免费下载链接】SDLSimple DirectMedia Layer项目地址: https://gitcode.com/GitHub_Trending/sd/SDL创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表