跃迁引擎

空気を読んだ雨降らないでよ

iOS Research & Development


iOS & macCatalyst 混编应用实践

背景

需求开发一款通用的 macAPP 来辅助 DSL 项目的快速调试,要求拥有与移动端完全相同的渲染效果,所以需要从 iOS 端移植 DSL 渲染引擎的代码到 macOS 系统上运行

项目搭建

搭建的总体流程与创建一个 iOS 别无二致,需要选择 macCatalyst 模式运行(M1设备选择Rosetta 模式运行),唯一需要注意的点是在PROJECT里勾选 macCatalyst,让 xcode 对 iOS 代码进行兼容

问题 & 解决方案

1.报错:your app is missing the User Selected File Read app sandbox entitlement

问题描述:在迁移至macCatalyst时,选择文件报错权限问题导致crash

解决方案:选择”YourAppName.entitlements”,然后添加一个名为”com.apple.security.files.user-selected.read-write”的key,类型选为”Boolean”,值设置为”1”

2.macCatalyst 混编 iOS 如何固定屏幕尺寸

问题描述:mac的应用默认可以无限制拉伸尺寸,这对 iOS 迁移过去的 UI设计非常不友好,需要对屏幕尺寸进行固定

解决方案:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
// Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
// If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
// This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
guard let windowScene = (scene as? UIWindowScene) else { return }

#if targetEnvironment(macCatalyst)
// 固定窗口大小
// https://developer.apple.com/forums/thread/117581
if let sizeRestrictions: UISceneSizeRestrictions = windowScene.sizeRestrictions {
// iPhone13Pro Max
windowScene.title = ycScreenTitle
sizeRestrictions.minimumSize = CGSize(width: ycScreenWidth, height: ycScreenHeight)
sizeRestrictions.maximumSize = sizeRestrictions.minimumSize
}
#endif
}

3.如何解决 ‘keyWindow’ was deprecated in iOS 13.0 的问题

在 macCatalyst 上该 API 已废弃,需要更换其他方式获取

解决方案:

1
2
// keywindow
UIApplication.shared.windows.filter {$0.isKeyWindow}.first

4.在 macCatalyst 上使用 UIDocumentPickerViewController

需要在 mac 使用读取本机文档的功能,但是由于是混编代码又不能直接使用传统 macOS 的 NS 代码,所以需要寻求 UI 相关代码

解决方案:

1
2
3
4
5
6
7
8
9
10
let picker = DocumentPickerViewController(
supportedTypes: ["log"],
onPick: { url in
print("url : \(url)")
},
onDismiss: {
print("dismiss")
}
)
UIApplication.shared.windows.first?.rootViewController?.present(picker, animated: true)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class DocumentPickerViewController: UIDocumentPickerViewController {
private let onDismiss: () -> Void
private let onPick: (URL) -> ()

init(supportedTypes: [String], onPick: @escaping (URL) -> Void, onDismiss: @escaping () -> Void) {
self.onDismiss = onDismiss
self.onPick = onPick

super.init(documentTypes: supportedTypes, in: .open)

allowsMultipleSelection = false
delegate = self
}

required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}

extension DocumentPickerViewController: UIDocumentPickerDelegate {
func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
onPick(urls.first!)
}

func documentPickerWasCancelled(_ controller: UIDocumentPickerViewController) {
onDismiss()
}
}

5.把 macAPP 打包成 dmg 文件

问题:无法cd进入/Volumes/kRender,因为它不是一个文件夹

解决方案:直接 cd /Volumes/kRender,注意不带 .dmg,而且 iTerm 也有快捷方式可以直接打开到路径(原谅我找不到怎么操作了)

问题:转换时,提示“操作失败,状态为35:资源暂时不可用”

解决方案:需要推出之前的磁盘映像(即kRender)

问题:推出磁盘时提示:推出“kRender”失败,因为它当前正在使用中

原因可能是磁盘正在被占用

解决方案:https://blog.csdn.net/fxtxz2/article/details/120828839

使用 sudo lsof /Volumes/kRender 查询资源占用,然后配合 kill -9 杀死进程,再尝试推出

最近的文章

洋葱学园 iOS 端组件化重构之路[一]-现状梳理

背景当前,洋葱学园 iOS 端工程的组件化水平过低,在影响工程师开发效率的同时,又难以兜住持续集成的影响范围,不利于整体工程的高质量建设,已无法满足日益增长的工程预期与精细化控制的需求。 现存问题如下 缺乏组件必要的独立运作能力 缺乏统一中间件进行调度 无法进行单元测试,回归测试成本高 组件间 …

, , 开始阅读
更早的文章

DSL Native+ 动态化方案设计

为什么要有动态化? 应“变”:随着互联网红利的消失,整个移动市场的关注从“流量”转成了“留量”,大部分的移动产品也都告别了初期的抢占市场,对某个业务领域的精细化打磨、避免 App 发布漫长的周期,在出现问题时还能即时对线上进行中止血,成为了所有业务的基本诉求。 提“效”:动态化往往和跨端化一桌而 …

, , 开始阅读
comments powered by Disqus