开屏广告做为app启动时映入用户眼帘的第一界面,其重要性不言而喻。 因项目中开屏广告插件中业务愈来愈多,原来的的方式也已经没法知足需求。windows
开屏广告要实现要求:app
1.正常开屏时显示开屏广告,且不能显示状态栏,若是有开机引导图则先显示广告后显示引导图 若是还有其余的子view 则按顺序日后排。布局
2.app进入后台一段时间后再次进入前台也须要显示广告,并且广告不会被 Alert之外的其余视图(好比加在keywindow上的弹窗浮层等)挡住。spa
3.从3D touch ,通知栏唤起app时能够正常显示广告。插件
4.唤起app时若是当前的 keywindow是横向(例如咱们项目里从 h5页面唤起 AR看车页面时,AR会强制旋转屏幕)的,能够正常显示广告(广告依然是竖直显示)。code
5.点击跳过直接进入app首页,或者点击广告进入广告落地页,从广告页返回则直接返回到app首页。orm
在网上也查找了很多资料,其中大部分都是把开屏广告直接加载到keywindow上。首先前提条件咱们项目 开屏广告是个单独的插件,其次咱们项目里是设置了生命周期
Viewcontroller-based status bar appearance 这个属性为YES 的,so 状态栏的显示与隐藏须要调用ViewController的队列
- (BOOL)prefersStatusBarHidden{ return YES;//隐藏 }
这个方法来控制状态栏, 若是建立了view加在keywindow上,则状态栏的状态则不方便控制,再者当keywindow 强制被旋转式,要让view的子视图也跟着旋转也是件麻烦事。ip
或者是启动时把开屏广告做为 rootVC,广告结束以后在切换rootVC为tabbar 。还有一种是经过切换keyiwindow 的方式实现 。以上两种方法我也都作了尝试,能够知足部分需求,可是都没法完美的解决以上开屏的需求。
后台偶然的机会看到 window 的makeKeyAndVisibale方法的注解
- (void)makeKeyAndVisible;
Description
Shows the window and makes it the key window.
This is a convenience method to show the current window and position it in front of all other windows at the same level or lower. If you only want to show the window, change its hidden property to NO.
重点在最后一句: If you only want to show the window, change its hidden property to NO. 。
若是咱们想显示window just set its hidden属性为 NO 便可。 也就是咱们建立的window 默认隐藏的,当我调用 makeKeyAndVisible时,这个window才会成为keywindow而且可见。也就是说虽然app中只能有一个keywindow 可是能够有多个 window同时存在经过控制window的 level来控制显示的层级。window 的层级有下面几种:
typedef CGFloat UIWindowLevel; windowlevel 实际上是浮点型的值 UIKIT_EXTERN const UIWindowLevel UIWindowLevelNormal; // 默认值 值为1000.00 UIKIT_EXTERN const UIWindowLevel UIWindowLevelAlert; // Alert window所在层级 值为3000.00 UIKIT_EXTERN const UIWindowLevel UIWindowLevelStatusBar // 状态栏层级 值 2000.00
程序的keywindow的window level 是默认的 wndowLevelNormal 。
众所周知开屏广告实际上是在app启动以后,盖在了程序主界面之上 。 既然keywindow 的windowLevel 是normal 的,那么咱们就能够在app启动以后再建立一个window并设置windowLevel 比normal 高,这样就会盖住kewindow 显示广告了,在广告流程结束以后再把这个window 隐藏便可。
使用这种方式还有一个最大的优势,因为这是一个单独的window,咱们能够绑定一个 rootViewController,把开屏广告的view加在该rootViewController上,viewController有着完整可控的生命周期,而且能够经过 - (BOOL)prefersStatusBarHidden 方法控制状态栏的显示与隐藏, 经过
- (UIInterfaceOrientationMask)supportedInterfaceOrientations 控制屏幕的方向,除此以外,由于他是一个单独的window,并无加在keywindow上或者是其余视图上,只是window level 不一样,不会对其余的业务线产生影响,简直是一举多得!!!
下面列举出须要注意的几点:
1. 广告的window level 须要设置为 UIWindowLevelStatusBar - 1 ,不能比 statusBar的windowLevel高,不然立即有广告又有引导图的状况下,点击广告跳转到广告落地页(落地页要显示状态栏的),因为windowLevel比statusBar的高,会致使状态栏没法显示。
2.广告window的rootVC应该只支持垂直方向,此时rootVC的子view在屏幕旋转的时候仍会按照垂直方向的frame布局。
- (UIInterfaceOrientationMask)supportedInterfaceOrientations { return UIInterfaceOrientationMaskPortrait; }
3.须要特别注意: 在PLUS系列的手机,因为PLUS系列的手机在横屏的时候 手机的整个界面都会跟着旋转(非PLUS系列手机好像不会) ,若是PLUS系列手机是在横屏状态下启动的app,此时 viewDidLoad中 view.frame.size.width = MAX(屏幕宽,屏幕高) ,也就是说 view的宽等于手机垂直状态下的高了,拿7PLUS举个例子:此时 view.frame = (0,0,736,414) ,在掉用过 - (UIInterfaceOrientationMask)supportedInterfaceOrientations 方法以后,因为该rootVC只支持垂直方向此时 view的frame才是正确的, 拿7PLUS举个例子:此时 view.frame = (0,0,414,736) 。
4.在开平广告结束时候记得隐藏广告 window ,并设置为nil 。
以上就是此次开屏广告重构肯定下来的方案,既能完美知足各个需求,方便之后扩展需求,又能不对其余业务线产生影响。
----------------------------------------------------------------
2017-08-09更新
为了能有更好的通用性,能够建立一个 Manager类, 相似系统 Alert , 将这些view 放在一个队列里去统一管理,当上一个view 的流程结束后,才去展现下一页面 。