背景
FinClip 小程序iOS端最初的打开方式,是一个小程序对应一个新的导航控制器,然后以present的方式打开。
为何要这么设计呢?
其实,小程序应该是一个相对独立且完整的模块,所以使用一个独立的导航控制器,即可以避免被别的小程序影响,也可以避免被宿主app影响。
这个设计在微信、支付宝、抖音等应用中是非常合适的,因为第三方小程序是内嵌在这些超级应用中,所以小程序的功能都是非常完整且独立的。
探索
那小程序能否支持以push方式打开呢?
只是纯粹考虑能否做到的话,答案是能。
我们做过一次探索:如果以导航控制器的push方式打开,意味着需要宿主app和小程序共用一个导航控制器。其实push打开小程序肯定是可以的?因为小程序其实是loading页,多个小程序页组成,这些都是可以放进同一个导航控制器的。所以,打开是没问题的。
但是随之而来的问题也更多:
- 导航栏问题。每个应用都有自己的主题颜色,但是小程序也有自己独立的主题颜色:比如京东小程序是红色;美团小程序是黄色;沃尔玛小程序是蓝色。如果共用一个导航控制器,那必然会出现不同页面去修改导航栏主题的情况;而且有的宿主页面可能会隐藏导航栏;导航栏的显示和隐藏也必然会遇到问题。
- 页面栈问题。大多数应用都会有某个页面返回指定页面的场景,如果小程序页面和宿主页面在同一个页面栈,就会出现小程序返回导致原生页面出栈;或原生页面返回导致小程序页面出栈,最终导致页面混乱,小程序页面栈与实际页面无法匹配出错。
- 小程序生命周期问题。每个页面都有自己的生命周期,每个小程序也有自己的生命周期;共用一个导航控制器,会导致小程序的生命周期无法自己自由控制。
- scheme打开小程序异常。打开小程序可以主动触发,也可能由第三方应用触发,而宿主应用的页面层级是千奇百怪的,如果当前顶层页面正好是一个不包含导航控制器的独立页面,我们如何再通过scheme打开小程序呢?
如果要保持小程序的独立导航控制器呢?
那是不能的,主要是因为系统限制了导航控制器作为导航控制器的子控制器。

第一个方案
我们注意到,有的客户仅仅是期望打开小程序的动画方式与应用中页面跳转的方式保持一致。
所以,我们首先支持了自定义动画,设计了两种动画效果:present动画、push动画,使得客户可以选择present 动画方式显示小程序,也可以选择push动画方式展示小程序。
探索的第二个方案
难道真的不能push的方式打开小程序吗?
其实还真有,但是有一些场景还是避免不了会有问题,除非咱们可以不考虑这些问题。
方案如下:
我们尝试创建一个普通的UIViewController,作为小程序导航控制器的容器。

然后,每次打开小程序时,都是先创建一个UIViewControoler作为一个容器控制器,然后创建一个新的导航控制器,作为小程序的页面容器,最终用app的导航控制器push容器控制器。
代码的简略效果如下:
UIViewController *containerVC = [[UIViewController alloc] init];
FatNavigationController *fatNavC = [[FatNavigationController alloc] initWithRootViewController:[[FatViewController alloc] init]];
[containerVC addChildViewController:fatNavC];
[containerVC.view addSubview:fatNavC.view];
[self.navigationController pushViewController:containerVC animated:YES];
以上方案,80%的小程序场景都可以实现,还有少量的问题:
- 宿主app的方向浸入性问题。小程序的页面是支持横屏、竖屏、自由旋转三种设置的。由于小程序和宿主app页面共用一个导航控制器,那么意味着宿主app的导航控制器需要支持横竖屏,所以得重写宿主app的supportedInterfaceOrientations函数,且只能返回顶层页面方向。
- scheme 打开小程序问题。需要避免宿主app中出现不包含导航控制器的页面。
- 小程序打开小程序的实现问题。
- 侧滑关闭小程序动画问题。这里小程序根页面的侧滑动画会失效。
- 宿主页面返回导致小程序意外被关闭问题。
所以,小程序和宿主页面共用一个导航控制器,其实是一个糟糕的设计,要完全实现小程序这么复杂场景。还需要继续探索新的技术方案,欢迎大家留言讨论。

被折叠的 条评论
为什么被折叠?



