Repository navigation
Conversation
|
I've looked into this some more and it seems like this behaviour was changed in an attempt to fix some bug by this pr: #7450 Looking at the apple documentation linked in #7450 it seems that it might be a little outdated, also it contradicts itself somewhat by saying you should again enable rendering in @xster @gaaclarke @cbracken do you have any additional comments and/or thoughts on this? |
|
As background, #7450 fixed a very real crasher that affected a ton of devices. I should probably have been more explicit in my commit message as to which devices were affected, but IIRC it was iPhone 6, iPhone 6S devices in particular. If I'm not mistaken, this was a fix to a previous change that had paused animation in
Can you give a bit of detail as to what part of it is incorrect? If you've got a link to up-to-date documentation, that would be very useful. It's important that this cover all iOS devices back to the iPhone 4S and all OS levels back to iOS 8.4.1.
Can you provide details on what this contradicts? Is your suggestion that it's inconsistent, and animation should be re-enabled in |
Interesting, weird that it would only affect older devices, especially the 6s since that isn't even that old. Btw @cbracken, does
Well there is a big banner saying that it's deprecated and you should use metal (which has been out since iOS 8 I believe)
Yes I would expect it to be consistent between the enable and disable because if you follow apple's guidelines then (like you explain in the PR) it would pause the ui on inactive and never enable it again since it never got backgrounded and thus doesnt enter the foreground again. This is also kind of what's happening now, the ui pauses when it goes to the inactive state (which happens for instance when a native popup shows for permissions or you go to the app switcher). So either disable in inactivate and re-enable in becomeActive or inactivate in didEnterBackground and re-enable in didEnterForeground. Also, here Apple explicitly states:
Which is also in contradiction with the other documentation that suggests to complete stop the OpenGL rendering. |
|
Here is also som new documentation (for metal) So would it be a good approach to keep the current behaviour when using openGL and move to the disabling in |
|
@Kavantix When will this be merged, i face the same issue now. And do you have any work around ways? |
|
@cbracken @chinmaygarde do you have any update whether this is anywhere on the current roadmap and/or how I could help get it there With the idea from my last comment it seems possible to fix this without breaking on older devices that cannot use metal. This fix would greatly improve the ‘native’ feel of flutter apps on iOS |
| [center addObserver:self | ||
| selector:@selector(applicationBecameActive:) | ||
| name:UIApplicationDidBecomeActiveNotification | ||
| selector:@selector(applicationWillEnterForeground:) |
There was a problem hiding this comment.
I'm not sure how these notifications match access to the GPU. The problem is the wording "Will Enter Foreground", which means it isn't currently in the foreground, which means it's in the background. If it's in the background does it have access to the GPU? Typically no, but the wording on the notification might just be awkward.
Unfortunately it's hard to prove this is correct because even with setIsGpuDisabled removed, the crash doesn't manifest 100% of the time. It's a race condition.
If we could provide instructions that could reproduce the crash 100% of the time with the setIsGpuDisabled removed, we could have more confidence in the change. I'll try playing around with it.
There was a problem hiding this comment.
From apples docs on didEnterBackground:
Use this method to release shared resources, invalidate timers, and store enough app state information to restore your app to its current state in case it's terminated later. Disable updates to your app’s user interface, and avoid using some types of shared system resources (such as the user’s contacts database). Don’t use OpenGL ES in the background.
From willEnterForeground:
In iOS 4.0 and later, UIKit calls this method as part of the transition from the background to the active state. You can use this method to undo many of the changes you made to your app upon entering the background.
In the background you should not access the gpu indeed but before didEnterBackground is called we’re not in the background. And when willEnterForeground we are also no longer in the background.
Also the metal documentation I linked before has this:
When UIKit calls your app delegate's applicationDidEnterBackground(_:) method, make sure Metal has scheduled all command buffers you've already committed before your app returns control to the system. On each command queue, if the last command buffer you queued isn't already scheduled or complete, call waitUntilScheduled() to force it to be scheduled.
Also the crash is only when using openGL ES
When using metal any commands in the background will simply return an error instead of crashing the app:
After your app moves into the background, if Metal sees a new command buffer from your app, it returns an error, rather than scheduling the command buffer. You can test for this error by adding a completion handler (addCompletedHandler(_:)). Inside your completion handler, check the status and error properties.
There was a problem hiding this comment.
The problem is the wording "Will Enter Foreground", which means it isn't currently in the foreground, which means it's in the background.
This is not correct, the app has more than 2 states.
When willEnterForeground is called it’s no longer in the background but in the inactive state, it might not be visible to the user yet though but that’s independent of the state
There was a problem hiding this comment.
Finally from willResignActive which we’re currently using to stop rendering:
Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. An app in the inactive state should do minimal work while it waits to transition to either the active or background state.
So in this method the app should not stop rendering just try to use less resources
Hopefully these points help you figure this out 🙂
I’m glad it’s finally being looked at again!
|
Btw as a general note, feel free to push to this PR I don’t mind |
|
Ugh, I accidentally closed this with a bungled rebase. @Kavantix can you please force push your version or a rebased version, here's what it looks like rebased: commit 52fdfe6617bde17a7f633cd30530ed365add74cd
Author: Pieter van Loon <[email protected]>
Date: Mon Mar 30 15:57:31 2020 +0200
Fixed flutter not rendering in inactive state
Move setIsGpuDisabled to the correct notifications
diff --git a/shell/platform/darwin/ios/framework/Source/FlutterEngine.mm b/shell/platform/darwin/ios/framework/Source/FlutterEngine.mm
index 23e56fdc4..cf23c1f0a 100644
--- a/shell/platform/darwin/ios/framework/Source/FlutterEngine.mm
+++ b/shell/platform/darwin/ios/framework/Source/FlutterEngine.mm
@@ -155,18 +155,13 @@ static constexpr int kNumProfilerSamplesPerSec = 5;
object:nil];
[center addObserver:self
- selector:@selector(applicationDidEnterBackground:)
- name:UIApplicationDidEnterBackgroundNotification
- object:nil];
-
- [center addObserver:self
- selector:@selector(applicationBecameActive:)
- name:UIApplicationDidBecomeActiveNotification
+ selector:@selector(applicationWillEnterForeground:)
+ name:UIApplicationWillEnterForegroundNotification
object:nil];
[center addObserver:self
- selector:@selector(applicationWillResignActive:)
- name:UIApplicationWillResignActiveNotification
+ selector:@selector(applicationDidEnterBackground:)
+ name:UIApplicationDidEnterBackgroundNotification
object:nil];
[center addObserver:self
@@ -887,11 +882,11 @@ static void SetEntryPoint(flutter::Settings* settings, NSString* entrypoint, NSS
#pragma mark - Notifications
-- (void)applicationBecameActive:(NSNotification*)notification {
+- (void)applicationWillEnterForeground:(NSNotification*)notification {
[self setIsGpuDisabled:NO];
}
-- (void)applicationWillResignActive:(NSNotification*)notification {
+- (void)applicationDidEnterBackground:(NSNotification*)notification {
[self setIsGpuDisabled:YES];
}
diff --git a/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm b/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm
index 91c73b0b3..49733a54b 100644
--- a/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm
+++ b/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm
@@ -736,24 +736,24 @@ static void sendFakeTouchEvent(FlutterEngine* engine,
- (void)applicationBecameActive:(NSNotification*)notification {
TRACE_EVENT0("flutter", "applicationBecameActive");
- if (_viewportMetrics.physical_width)
- [self surfaceUpdated:YES];
[self goToApplicationLifecycle:@"AppLifecycleState.resumed"];
}
- (void)applicationWillResignActive:(NSNotification*)notification {
TRACE_EVENT0("flutter", "applicationWillResignActive");
- [self surfaceUpdated:NO];
[self goToApplicationLifecycle:@"AppLifecycleState.inactive"];
}
- (void)applicationDidEnterBackground:(NSNotification*)notification {
TRACE_EVENT0("flutter", "applicationDidEnterBackground");
+ [self surfaceUpdated:NO];
[self goToApplicationLifecycle:@"AppLifecycleState.paused"];
}
- (void)applicationWillEnterForeground:(NSNotification*)notification {
TRACE_EVENT0("flutter", "applicationWillEnterForeground");
+ if (_viewportMetrics.physical_width)
+ [self surfaceUpdated:YES];
[self goToApplicationLifecycle:@"AppLifecycleState.inactive"];
} |
|
(in the future, it's easier to work with branches if they aren't named |
Yeah I know, did that by accident |
|
I opened a new PR which is also rebased on master #25196 |
Moved to #25196
Flutter currently does not render on ios in the inactive state
This is because it is using the wrong lifecycle events to turn rendering on/off
Relates to flutter/flutter#50732 and flutter/flutter#33236
I'm not sure what other impact this has on the engine though so need some help.
I noticed that in the application delegate there is also an
setIsGpuDisabledmethod which is also called on the wrong events.