7

fir-mac 开发笔记

 2 years ago
source link: https://www.isaced.com/post-286.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

fir-mac 开发笔记

练手 Cocoa 开发,开发并开源了一款 fir.im 的 Mac 客户端,此篇主要记录其开发历程,总结一下遇到的问题

某一天突然翻到自己 GitHub 下有一个空仓库,名字叫 fir-mac,提交时间在 2016 年 6 月 22 号,恍然大悟原来又是弃坑项目之一。 由于从事 iOS 开发后一直对 macOS 开发比较感兴趣,感觉 Mac 应用有一种天生的美感,更是在 OS X 10.10 Yosemite 之后的扁平化、毛玻璃、各种窗口细节的优化感到和往日使用 Windows 的差异;那既然都已入苹果的坑,何不顺势玩玩 Cocoa 桌面开发呢, 业余时间前后写了 MyMacMusicPlayerCubicBezier,也算小入了一点点 Cocoa 的门,想继续找项目在实战中磨练自己,然后因为有段时间用 fir.im 比较多,隧萌生了为其做一个 Mac 客户端的想法。

开发之前首先得想想会遇到最大的问题是什么?那应该是 fir 的接口,官方有没有开放接口?接口有没有限制?这是我作为一个第三方开发人员无法控制的事情,所辛 fir 在很早的时候就开放了他们的 API 及其文档,并且借口都比较齐全,证明他们对此是保持开放态度,那么接口的障碍没有了还有其他问题吗? 这时我就预估一下了应用的整体功能模块,以及大致实现方法,把项目难点提前筛出来看看,fir-mac 作为一个基于 Mac 系统的 GUI 客户端,首先是 UI 的搭建,最初想法,用一个列表(NSTableView)呈现账户下所有的应用,然后点击应用可以展开其详细信息,感觉应该可以实现,当然 UI 动画、优化什么的暂且先不提,毕竟先得把功能做出来才是第一步。

功能上主要参考 fir web 端,包括上传应用、查看应用列表、查看应用详情,差不多就这样,简简单单实实在在。

sketch

后来有朋友在微博上评论说想要扫二维码下载的功能,很快也增加进去了。 如果你是本软件的使用者,有什么功能上的意见或想法欢迎与我联系哦。

UI 最终成品基本上也继承与最初的想法而来,简单的 List,弹开应用详情,采用 Vertical Split View Controller 分栏设计,把左右两边分开并各自独立 NSViewController,从而使业务逻辑分离开来,在 Storyboard 上看起来是这个样子:

TableView

右边的块区域用了 NSBox 作收纳子元素和框样式,隐藏掉了 Title,想想在 iOS 上搞这个还得弄个 UIView 设设圆角什么的。(有时候总会想到 CocoaTouch 里的东西去) Cocoa 里原生提供了三种列表组建,分别是 TableView、Outline View、Source List,而 Outline View、Source List 都是基于 NSOutlineView 的定制,而 NSOutlineViewNSTableView 的定制,所以归其总都是 NSTableView 一个东西。

TableView

fir-mac 左边侧边栏的列表则用的 TableView,自定义其 Cell 来展示的:

CustomCell

最后的实际运行效果如下:

screenshot

可以看到其实和 Storyboard 相似度很高,开发此类小应用使用 Storyboard 构建 UI 效率非常高,并且因为窗口设计成固定大小,要么缩小要么关闭,不能缩放,所以也不用去拉 AutoLayout,真的省心。

困难1:接口的调试

从最开始本以为很简单的 form-upload 操作,废了两晚上时间才搞定,因为 fir 的应用包是存在静态文件服务器上的,而且后端采用了不同的云存储商,所以上传文件需要两个步骤,第一步先获取凭证,第二步再用拿到的凭证进行表单上传,因为应用二进制和应用图标是分开上传,所以一次提交应用的操作其实会发三个请求,[拿 Token] -> 上传图标 -> 上传应用。 有点不明白的是应用图标本身也是从其应用文件中提取出来的,为什么不把这一步拿到服务端做呢?为了节省服务器资源吗?还有其应用信息,感觉放到服务端做会更可靠,因为 fir 不止一个客户端工具去做上传,比如 Website、Command Line Tool,各种 IDE 插件,每个端都需要去编写这套包解析和两次上传请求,首先维护成本增高,解析提交的数据还不一定是可靠内容,造成脏数据提交到服务端。 好吧先不纠结这个接口设计了,想说的是为啥在一个上传文件的功能上绕了弯路,最后找到问题是因为一个参数的参数名写错了,并且服务端没有错误反馈,仍然返回的请求成功,这我就懵了,然后抓了一下 web 所请求的参数值,拿过来用错误的参数名提交居然也成功了。这就是为啥蒙圈在这这么久的原因。

困难2:包解析

本以为 fir 的接口如上文所说是由服务端解析应用包,提取出应用信息比如应用名、版本号等等,结果发现其实是本地解析拿到这些信息然后再提交给接口,拿 iOS 的包来说,后缀为 .ipa,在 macOS 本地的流程大致如下:

  1. mktemp 命令创建临时目录
  2. unzip 解压 .ipa 到临时目录
  3. 逐级目录查找到 Payload 文件夹
  4. 读取 Info.plist 文件
  5. 根据 CFBundleIdentifierCFBundleShortVersionString… 提取出应用信息和 ICON 图标
  6. 删除之前生成的临时目录

mktemp 是一个 linux 命令会在系统层级创建一个临时目录,路径是随机名大致如下 /var/folders/r3/x98gzjpn7rxct9y4rtnjsv5m0000gn/T/,不会重复保证一定安全性

unzip 是 linux 下解压 zip 文件的命令,通过参数 -d 来指定解压目的地为之前生成的临时目录

读取 Info.plist 文件本打算用 defaults 命令来完成,后来发现实在不如读取进 Dict 操作方便

以上便是用户选择一个 .ipa 文件提交上传前所需做的工作,由于 Android 包 .apk 数据结构又不一样,所以支持 Android 应用上传需要另外编写一套解析逻辑,故目前 .apk 上传还未支持。(话说写这个真累,项目开源欢迎有志之士共享一份力量!)

由于应用主要建立在与 fir.im 接口的 HTTP 通信上,所以引入了 Alamofire 来做所有的网络请求,包括数据拉取和文件上传;然后因为接口返回所有数据格式均为 JSON,为了人性化编程又引入了 SwiftyJSON;项目列表还存在网络图加载,为了省事也直接用了 Kingfisher;因为有了这些项目的积淀,我们才能把更多的注意力放在其他事情上,避免很多重复而基础的工作,感谢开源!

关于选择开源协议,一直都没有太深刻的理解,只知道 MIT 最开放自由,那就 MIT 咯,后来看到微博上大家评论说 MIT 难道不怕又被翻去上架卖钱吗?之前就有 PPRows 的事情,PPRows 的作者也来跟我说让我换掉开源协议。 翻看了一下,像开发组件大部分都采用 MIT,宽松,但是很多完整项目都采用了 GPL-3.0,比如 PHP CMS 系统 Drupal ,播放器 iina、SQLite 数据库浏览器 sqlitebrowser 等等,他们采用 GPL-3.0 更是为了限制商业使用。作为一个开源作者的心愿首先肯定是希望自己的项目能发展起来,项目被他人商业化估计很多作者都是不愿看到的事,开源界关于协议版权的闹的事情已经很多了,希望那些不劳而获通过开源项目结合流量与市场榨取用户的人,能把更多注意力放在做事情本身,而不是一点蝇头小利和旁门左道。

一不小心吐槽了一番,本文差不多就这样结束了,如果你还没有 star 这个项目,赶紧来吧:https://github.com/isaced/fir-mac


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK