iOS OpenGL Catch-22:OpenGL后台规则和App Switcher的"应用程序快照"

Lou*_*ini 9 opengl-es objective-c ipad ios layoutsubviews

像许多开发人员一样,我有一个通过UIView子类使用OpenGL的应用程序,该子类的layerClass:方法返回[CAEAGLLayer class].

注意我没有使用GLKitGLKViewGLKViewController

当我点击Home将应用程序放入后台时applicationDidEnterBackground,iOS调用我的视图layoutSubviews两次,使用纵向和横向大小,尝试生成"应用程序快照",如此处所述(请参阅"准备应用程序快照"):

https://developer.apple.com/library/ios/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/StrategiesforHandlingAppStateTransitions/StrategiesforHandlingAppStateTransitions.html#//apple_ref/doc/uid/TP40007072-CH8-SW10

这怎么可能有效呢?

这里似乎有一个直接的矛盾与此页面上非常明确的建议(请参阅"后台应用程序可能无法在图形硬件上执行命令"):

https://developer.apple.com/library/ios/documentation/3DDrawing/Conceptual/OpenGLES_ProgrammingGuide/ImplementingaMultitasking-awareOpenGLESApplication/ImplementingaMultitasking-awareOpenGLESApplication.html#//apple_ref/doc/uid/TP40008793-CH5-SW1

以后我们不能用OpenGL绘制任何东西 applicationDidEnterBackground

如果我们不绘制,我们就无法生成快照.我们必须违反一条规则或另一条规则.

但我们也希望在两个方向都有很好的快照,这样当用户双击主页并转到App Switcher时,他们会看到合理的快照图像.

即使我暂时改变我的代码以通过创建OpenGL表面和绘图(这与Apple dox相反,不会崩溃)完全实现layoutSubviewsafter applicationDidEnterBackground,然后我双击home并以不同方向查看快照,仅我之前所处方向的快照是正确的.另一个是另一个快照的超级丑陋的重新缩放.Apple似乎正在经历拍摄快照的动作,但实际上没有拍摄它们.

我在iPad Mini上看到iOS 9.3.2上的这种行为.大多数/所有iPhone设备都没有显示该行为,因为它们不支持横向App切换器.

更新:问题也发生了,并且更糟糕的是,当使用新的iOS 9"幻灯片"多任务处理功能并在正常的全屏应用程序与在另一个应用程序上滑动的应用程序之间切换相同的应用程序时.iOS似乎只捕获最后一个应用程序大小的快照,所以在使用640px宽的应用程序然后尝试使用App Switcher进入应用程序全屏后,我们在应用程序中看到一个奇怪的像素超出比例的快照切换器也在发射的第一秒.必须有一些方法来解决这个问题!

更新2:我见过几个iOS应用程序,我知道这些应用程序是OpenGL专用的应用程序,如果你以纵向方式使用它们,那么回到Home并旋转到横向,然后双击Home,你会看到纵向启动图像而不是像我所看到的那种可怕的,扭曲的,不对称的图像.虽然我更喜欢渲染快照图像,但我甚至很乐意看到启动图像.但选择大家提到了,ignoreSnapshotOnNextApplicationLaunch,不工作,因为它不仅影响你在实际的应用程序启动时间看,没有什么是在应用程序切换时看到您双击主页,并为许多在计算器上,它实际上甚至没有工作完全(甚至在发射时).

我们如何绕过这个Catch-22?

这个StackOverflow线程(与我不同,OP在这里使用GLKit,但症状是相同的):

iOS OpenGL ES屏幕旋转,而后台应用栏可见

确认iOS 上的一些OpenGL应用程序能够在Home双按应用切换器中为两个方向都拥有正确的预览图像.他们是如何做到的呢?

如何在App Switcher中以两个方向显示正确的快照?

这是一个来自iOS 的AppDelegate(appdel),ViewController(eaglc)和View(eaglv)调用的日志,当我单击Home按钮一次退出应用程序时.您可以在以下情况下看到快照的尝试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.