分享近期Mac应用开发的一些想法
前言
这段时间做的几个Mac需求,都属于非常规需求,网上找不到标准答案,只能自己调研,自己设计思路,然后结合产品设计最后实现功能。其中有一些思路值得记录分享一下。本文不会公开全部细节,只记录思路。
拦截全局URL跳转
需求背景:通常在App内点击某个URL,系统会帮我们打开默认的浏览器并且跳转到对应网站上。现在有个需求,要实现拦截URL跳转逻辑, 根据后台配置的网址策略,选择不同浏览器打开。因为我们的软件是一款安全管控软件,不同浏览器能打开不同的域名,所以做这样一个需求可以极大提高用户使用体验。
这个需求有两大要点,第一是针对那些被我们的软件注入了动态库的App,在这类App里拦截点击URL的动作,并重新根据策略使用指定浏览器打开,是一件比较常规的事,大概就是找到相关的函数然后Hook,修改逻辑即可。
有难度的是如何拦截用户电脑上那些不被管控的App的跳转事件呢?经过一番调研之后,我给出了三个方案。
第一个是给普通App注入一个轻量级的动态库,用来拦截跳转,这个会造成全局稳定性问题,不是最优选。
第二个是在内核里面事件拦截,这个方案有太多的未知性,安全风险更大,不是最优选。
第三个是,最后经过一番讨论,转变了一下思路,想出了一个看似不可行实际上确很靠谱的方案。安装我们的软件时,内部再额外附带一个App(网址分配服务
),允许接受http等相关web服务的事件,类似普通浏览器,然后再通过产品体验优化引导,最后让用户很自然的把我们的网址分配进程设置成默认浏览器,这样就实现了对全局Web跳转事件的拦截了,用了一个简单的方案实现了复杂的问题,很巧妙。
网址分配服务
的主要工作,就是接收网址跳转事件,根据获取的网址策略,分配到真实浏览器去打开,当然这其中会设计很多业务逻辑,这里就不多说了,其中有一个业务层面的思路值得提一下。
按照业务需求,网址分配服务
只有当主程序处于登录状态时才会把URL转发到被管控的浏览器上,否则只能把URL转发到普通的浏览器。针对这个需求点,一开始我想到的是如何把主程序的登录状态通过跨进程通讯传给网址分配服务进程,这个就涉及到进程通讯了,用套接字,文件,还是共享内存,XPC,然后又涉及到进程突然中断时状态不准确等常见的进程间通讯的问题,很麻烦,想了好多方案。
最后和同事讨论的时候,经同事提醒想到了一个非常简单可靠的方案,当主程序正在运行时,则把所有需要由被管控的浏览器打开的请求,都直接转发给主程序,主程序再内部判断登录状态再决定最终打开哪个浏览器,这样直接绕过进程间的状态同步了,到达需求的效果。
由此可见,解决问题的思路很重要,如果能把复杂的问题简单化,最终BUG少程序运行稳健,比起高大上的解决方案往往获利更多。
App免复制技术
需求背景:我们的管控软件在运行的时候,需要让用户导入App到不同的管控空间中,不同空间的App拥有不同的权限。早期采用普通复制,占用了大量磁盘空间。Mac系统的磁盘空间一般都比较少,普通的MacBook大部分只有256GB,甚至还有很多128GB的,所以这个问题是比较严重的,必须解决空间占用问题。
比较容易想到的方法就是软链接,导入空间内的不是完整的App,而是一个软链接,这样就不占用空间了,但是软链接运行时实际上是和原文件是同一个,这样会有一个问题,当用户已经运行了空间中的App,再运行普通App时,launchd会直接把空间中的App激活,导致不符合用户习惯,让用户无法多开普通App。
解决思路,一开始也是想到注入Finder.app, 注入launchd进程,但是这些都增加了系统的不稳定性,而且还存在很多技术障碍。后来灵机一动,把复杂问题简单化,减少磁盘占用还有另一个方法,采用硬链接也可以解决空间占用问题。
不过问题也来了,Mac上的App本质是一个文件夹,名字以.app结尾,软链接可以直接基于文件夹创建,但是硬链接不行啊,硬链接只能基于文件创建。另外硬链接也无法在不同挂在盘之间创建,总体限制还是比较多的。
但是,有思路才是最重要的,问题始终都是可以解决的。最后成功解决各个难题,配合优秀的产品设计,获得了比较好的用户体验。
总结
以上就是近段时间完成的主要难题,考虑到项目的保密性,没有公开全部细节。但是也不难看出,解决问题的思路很重要,开阔的思维和丰富的横向知识,再配合团队头脑风暴,配合产品体验设计,最终也能解决问题。