记一则 macOS App 开发糟糕的向后兼容问题

2017 年 12 月 29 日,我悄悄发布了 Manico 2.4 版本,这个版本迁移到了 Swift 4.0,增加了一些小选项,总之是一个维护版本。因为是一个维护版本,所以我也没有多测试,就这样发布了,没想到升级至 Swift 过程中遇到了一个影响旧功能的问题,于是我要批评一下 Apple 的「向后兼容」问题。

Manico 2.4 的升级过程

Manico 2.4 从 Swift 3 升级至了 Swift 4,升级过程主要是一些 API 的重新命名,本来以为很轻松,但是没想到有些 API 不仅重新命名了,而且被标记为 macOS 10.13 Only 了。也就是说,Manico 2.3 + Swift 3 原本是 macOS 10.10+ 就可以运行的,现在升级至 Swift 4,啥功能都没变,就要变成 macOS 10.13 Only 了。

这个问题让我纠结了一下,Apple 的这个向后兼容怎么能做得这么差?!后来我还是咬咬牙把 Deployment Target 弄成了 macOS 10.13,反正迟早要更新的对吧,但没想到就此埋下了一个坑…

遇到问题

Manico 2.4 在 Mac App Store 上正式发布后,好像比较顺利,从使用数据看,不少用户升级上来了,并且没有 Crash,也没有收到用户报告的问题。于是昨天我也顺便发布了 Manico 的独立版本。后来,有个别用户报告无法在「自定义模式」把 App 拖进去,我尝试去重现一下,发现果然不行了,具体表现为把 App 拖进窗口里时,没有 + 号,也就是 Drop 不下,这是咋回事?!

Manico 2.4 Drop Issue

排查问题

既然是 Drap & Drop 不能工作了,那问题肯定出在 Drag & Drop 那一块,于是我检查代码变更记录,主要是在升级至 Swift 4 以后,发生了前面说的「API 重新命名」的事情,但是我仔细一看代码,不是重新命名这么简单,有这样一段代码:

collectionView.register(forDraggedTypes: [NSFilenamesPboardType, NSStringPboardType])
collectionView.registerForDraggedTypes([NSPasteboard.PasteboardType.fileURL, NSPasteboard.PasteboardType.string])

第一行是 Swift 3 的版本,第二行是 Swift 4 的版本,可以看到,API 发生了很大的变化,其中还有一个坑:NSFilenamesPboardType 变成了 NSPasteboard.PasteboardType.fileURL。这实际上不是一个东西,在 Swift 4 下,NSFilenamesPboardType 已经从 API 里面消失了,因此拖拽进来的数据,无法通过之前那样拿到了。这就是为什么数据 Drop 不下来的问题:

let filenames = pasteboard.propertyList(forType: NSFilenamesPboardType) as? [String]

刚开始我还想会不会 NSFilenamesPboardType 已经被标记为 deprecated 了,但是看了一下文档没有发现,并且在 Objective-C 下依然是可以用的。

用 Workaround 解决问题

通过搜索到 Stackoverflow,我也看到有不少开发者遇到了和我一样的问题。于是我学习了类似的方式,通过强制字符串生成 NSPasteboard.PasteboardType 来调用这个在 macOS 10.13 下不可用的 API:

extension NSPasteboard.PasteboardType {
    static let backwardsCompatibleFileURL: NSPasteboard.PasteboardType = {
        return NSPasteboard.PasteboardType("NSFilenamesPboardType")
    }()
}

通过在 Drag & Drop 时注册这个 PasteboardType 类型后,Manico 终于可以接受到正确的 Drag & Drop 信息了…同时,因为用了「隐藏」的 API,Manico 2.4 的 Deployment Target 又可以设置成 macOS 10.10 了。

总结

这是一起升级至 Swift 4 后因为 API 改动造成的升级事故,我不知道我这个 Workaround 在以后的版本会不会 broken。因此记一篇这样的文章供以后回顾。

2018 年 Swift 5.0 就要 ABI 稳定了,但是除了 ABI 稳定以外 API 也要稳定才好,这样的升级事故,我再也不想看到了…

突然想起之前传闻,今年 Apple 会推出一个把 iOS 应用可以方便移植至 macOS 平台的开发工具,有点小期待。

欢迎使用图拉鼎和他的团队开发的作品

One Switch - 多功能开关工具

常驻 macOS 菜单栏的开关工具,可以快速开关 AirPods、睡眠模式、切换黑暗模式等。

3 Comments

苹果现在鞭长莫及 小小的改动我都觉得苹果的代码 review 到底是不是实习生搞得 对历史 API 都不了解以前搞 Mac app 的时候 几乎不敢用新的 API 一用就出坑 唉

有用,感谢!!!😖苹果辣鸡,害我排查一天了

tualatrix 回复 @iHTCboy

苹果真的太垃圾了,向后兼容做的差到爆!

Leave a Comment