与许多开发人员一样,我有一个应用程序通过UIView
子类使用OpenGL,layerClass:
方法返回[CAEAGLLayer class]
。
注意我不使用GLKit
或GLKView
或GLKViewController
当我点击“主页”将应用置于后台时,在applicationDidEnterBackground
之后,iOS调用我的视图layoutSubviews
两次,使用纵向和横向尺寸,尝试生成“应用快照”,如此处所述(请参阅“准备应用程序快照”):
这怎么可能有效?
此页面上的非常明确的建议似乎存在直接矛盾(请参阅“后台应用程序可能无法在图形硬件上执行命令”):
我们不能在applicationDidEnterBackground
如果我们不绘制,我们就无法生成快照。我们必须违反一条规则或另一条规则。
但我们也希望在两个方向都有很好的快照,这样当用户双击主页并转到App Switcher时,他们会看到合理的快照图像。
即使我通过创建OpenGL表面和绘图(与Apple dox相反,不会崩溃)暂时更改我的代码以完全实现layoutSubviews
之后的applicationDidEnterBackground
,然后我加倍 - 单击主页并以不同方向查看快照,只有我之前所处方向的快照是正确的。另一个是另一个快照的超级丑陋的重新缩放。 Apple似乎正在经历拍摄快照的动作,但实际上并没有拍摄它们。
我在iPad Mini上看到iOS 9.3.2上的这种行为。该行为未在大多数/所有iPhone设备上显示,因为它们不支持横向App Switcher。
更新:问题也会发生,并且更糟糕的是,当使用新的iOS 9“幻灯片”多任务处理功能并在正常的全屏应用和应用之间切换相同的应用时滑过另一个应用程序。 iOS似乎只捕获最后一个应用程序大小的快照,所以在使用640px宽的应用程序然后尝试使用App Switcher进入应用程序全屏后,我们在应用程序中看到一个奇怪的像素超出比例的快照切换器也在发射的第一秒。必须有一些方法来解决这个问题!
更新2 :我看过一些iOS应用,我知道它们只是OpenGL应用,如果你以纵向方式使用它们,那么回到Home并旋转到横向,然后加倍-click Home,你会看到肖像发布图像,而不是像我看到的那样可怕,扭曲,不对称的图像。虽然我更喜欢渲染快照图像,但我甚至很乐意看到启动图像。但是每个人都提到的选项ignoreSnapshotOnNextApplicationLaunch
,不起作用,因为它只会影响您在实际应用启动时看到的内容,而不会影响双击Home时在App Switcher中看到的内容,对于StackOverflow上的许多人来说,它实际上甚至都没有工作(甚至在发布时也没有)。
我们如何解决这个Catch-22?
这个StackOverflow线程(与我不同,OP在这里使用GLKit,但症状是相同的):
iOS OpenGL ES screen rotation while background apps bar visible
确认iOS 上的某些OpenGL应用能够在Home双按应用切换器中为两个方向都拥有正确的预览图像。他们是怎么做到的?
如何在App Switcher中以两个方向显示正确的快照?
以下是我单击“主页”按钮一次时来自iOS的AppDelegate
(appdel),ViewController
(eaglc)和View
(eaglv)调用的日志退出应用程序。您可以在didEnterBackground
之后看到快照的尝试:
+ 189.57ms appdel appWillResignActive + 0.74ms appdel appWillResignActive between_view_os_callbacks 0 + 4.11ms appdel appWillResignActive between_view_os_callbacks 0 done + 0.82ms appdel appWillResignActive activation_changed + 1.50ms appdel appWillResignActive activation_changed done + 0.47ms appdel appWillResignActive between_view_os_callbacks 1 + 2.68ms drawing rect [(144,1418)+(2,66)] (0 left) + 44.28ms swap_buffers glFlush() + 6.16ms swap_buffers presentRenderBuffer + 9.01ms appdel appWillResignActive between_view_os_callbacks 1 done + 0.61ms appdel save_state ..app saving data, no OpenGL here.. + 0.49ms appdel save_state calling glFinish + 0.34ms appdel save_state done + 0.25ms appdel appWillResignActive done + 492.72ms appdel applicationDidEnterBackground + 0.56ms appdel save_state ..app saving data, no OpenGL here.. + 0.65ms appdel save_state calling glFinish + 0.54ms appdel save_state done + 0.65ms eaglv let_go_of_frame_buffer_render_buffer app drops OpenGL frame_buffer and render_buffer here + 1.10ms appdel applicationDidEnterBackground done Now we are not supposed to do OpenGL, BUT... + 6.30ms eaglc supportedInterfaceOrientations + 5.74ms about_to_sleep between_view_os_callbacks + 1.30ms SKIPPING between_view_os_callbacks cuz app in background + 0.66ms about_to_sleep between_view_os_callbacks done + 135.85ms eaglc willRotateToInterfaceOrientation + 2.49ms appdel willChangeStatusBarFrame new=0,0 768x20 + 3.21ms appdel didChangeStatusBarFrame old=0,0 1024x20 we get a portrait layoutSubviews.... + 1.26ms eaglv layoutSubviews (initted=1, have_fbrb=0) + 1.80ms eaglv assure_frame_buffer_render_buffer + 0.95ms eaglv assure_fbrb scale ios=2 eaglv=2 + 0.90ms eaglv assure_fbrb (frame=1536,2048) + 1.04ms eaglv assure_fbrb (layer frame=1536,2048) + 0.92ms eaglv assure_fbrb in bg: will make fbrb later + 0.96ms eaglv layoutSubviews done + 3.11ms eaglc didRotateFromInterfaceOrientation + 149.07ms eaglc willRotateToInterfaceOrientation + 1.99ms appdel willChangeStatusBarFrame new=0,0 1024x20 + 2.35ms appdel didChangeStatusBarFrame old=0,0 768x20 then a landscape layoutSubviews... + 1.91ms eaglv layoutSubviews (initted=1, have_fbrb=0) + 1.09ms eaglv assure_frame_buffer_render_buffer + 0.91ms eaglv assure_fbrb scale ios=2 eaglv=2 + 1.65ms eaglv assure_fbrb (frame=2048,1536) + 0.92ms eaglv assure_fbrb (layer frame=2048,1536) + 0.93ms eaglv assure_fbrb in bg: will make fbrb later + 0.83ms eaglv layoutSubviews done + 2.79ms eaglc didRotateFromInterfaceOrientation and, adding insult to injury, we get this log message: Snapshotting a view that has not been rendered results in an empty snapshot. Ensure your view has been rendered at least once before snapshotting or snapshot after screen updates.