flutter / flutter/flutter

[ios] Flutter view can't refresh in Pip when app in background.

Open
#158,913 8 comments 3 reactions 0 assignees View on GitHub
a: platform-views engine found in release: 3.24 found in release: 3.27 has reproducible steps P2 platform-ios team-ios triaged-ios
Dominant language
Dart
Stars
179k
Forks
31.1k
PR merge metrics
PR metrics pending

Description

### Steps to reproduce

use the project
https://github.com/ahyangnb/flutter_pip

running in ios and click the `Open` button to displaying PIP, and then go back to home page in ios system,

### Expected results

refresh the pip content as new flutter widget.

### Actual results

print error
```
Execution of the command buffer was aborted due to an error during execution. Insufficient Permission (to submit GPU work from background) (00000006:kIOGPUCommandBufferCallbackErrorBackgroundExecutionNotPermitted)
```
all the time in xcode.

### Code sample

```swift
@objc public func setDisplayText(name: String, msg: String) {
let conContent = name + ":" + msg
print("setDisplayText::receive::" + conContent)

let oldContent = delegate!.flutterController!.view
// Remove the existing flutterController view from its superview
delegate!.flutterController!.view = nil

/// Tested adding it as a new Label and it worked perfectly [even if it was changed midway through the background]
let nativeLabel = UILabel()
nativeLabel.text = "New Content"
nativeLabel.textColor = UIColor.red
nativeLabel.textAlignment = .center
nativeLabel.frame = CGRect(x: 0, y: 0, width: 180, height: 48.0)
delegate!.flutterController!.view = nativeLabel
/// Trying to reassign to the old version of the content results in: Execution of the command buffer was aborted due to an error during execution. Insufficient Permission (to submit GPU work from background) (00000006:kIOGPUCommandBufferCallbackErrorBackgroundExecutionNotPermitted)
delegate!.flutterController!.view = oldContent

// The final add operation.
firstWindow?.addSubview(delegate!.flutterController!.view)
}
```

`delegate!.flutterController!.view = nativeLabel `
will be totally normal, and the
`delegate!.flutterController!.view = oldContent` error.

i've been ask to chat gpt and the anwser is
```
The issue here appears to be related to restrictions that iOS imposes on rendering in the background. When your app is in the background, iOS limits GPU work (such as rendering and managing views) to save resources, and this impacts `FlutterViewController` because Flutter heavily relies on GPU resources for rendering. Here’s what’s happening in detail:

1. **Native `UILabel` works in the background**: The line `delegate!.flutterController!.view = nativeLabel` succeeds because `UILabel` is a lightweight, UIKit-native component that does not require GPU resources for basic rendering. iOS allows UIKit components like `UILabel` to refresh even in the background, as these are handled by the CPU.

2. **Flutter’s `FlutterViewController` fails in the background**: The line `delegate!.flutterController!.view = oldContent` fails because reassigning a `FlutterViewController`'s view involves a GPU-rendered context that iOS does not permit in the background. When your app is in the background, the system throws an error (kIOGPUCommandBufferCallbackErrorBackgroundExecutionNotPermitted) because the app does not have permission to submit GPU work, which is required for Flutter views.

3. **Flutter views and background limitations**: Flutter views are managed by a Metal or OpenGL context in iOS, both of which cannot render when the app is not in the foreground. Attempting to reassign the `FlutterViewController`'s view while in the background causes an `EXC_BAD_ACCESS` error because the GPU resources needed for Flutter views are restricted.

### Potential Workarounds
If you need to update a Flutter view while the app is in the background, consider these strategies:

1. **Avoid assigning Flutter views in the background**: Instead, defer any Flutter view updates until the app returns to the foreground. You can listen for `UIApplication.didBecomeActiveNotification` to detect when the app returns to the foreground and safely reassign the view at that point.

2. **Send background data updates to Flutter when it becomes active**: If you only need to pass data (not a view) to Flutter, you can save data in a shared state or UserDefaults and notify Flutter to reload this data when the app is active again.

3. **Use a Flutter plugin or platform channel**: Send necessary updates to Flutter through a plugin or platform channel while the app is in the background, and let Flutter update its view when it is in the foreground.

These approaches should help avoid GPU-related crashes and allow your app to handle background updates more effectively.
```
link https://chatgpt.com/share/6735b595-17e4-8002-a807-c7ad68f73f9a.

relate apple bbs link https://forums.developer.apple.com/forums/thread/76818

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

### Screenshots or Video

_No response_

### Logs

_No response_

### Flutter Doctor output

```
zengyang@zengyangdeMac-mini ~ % flutter doctor -v
[✓] Flutter (Channel stable, 3.24.3, on macOS 14.0 23A344 darwin-arm64, locale
en-CN)
• Flutter version 3.24.3 on channel stable at
/Users/zengyang/fvm/versions/3.24.3
• Upstream repository https://github.com/flutter/flutter.git
• Framework revision 2663184aa7 (9 weeks ago), 2024-09-11 16:27:48 -0500
• Engine revision 36335019a8
• Dart version 3.5.3
• DevTools version 2.37.3
• Flutter download mirror https://storage.flutter-io.cn

[✓] Android toolchain - develop for Android devices (Android SDK version 34.0.0)
• Android SDK at /Users/zengyang/Library/Android/sdk
• Platform android-34, build-tools 34.0.0
• ANDROID_HOME = /Users/zengyang/Library/Android/sdk
• Java binary at: /Applications/Android
Studio.app/Contents/jbr/Contents/Home/bin/java
• Java version OpenJDK Runtime Environment (build
17.0.10+0-17.0.10b1087.21-11609105)
• All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 15.3)
• Xcode at /Applications/Xcode.app/Contents/Developer
• Build 15E204a
• CocoaPods version 1.15.2

[✓] Chrome - develop for the web
• Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Android Studio (version 2024.1)
• Android Studio at /Applications/Android Studio.app/Contents
• Flutter plugin can be installed from:
🔨 https://plugins.jetbrains.com/plugin/9212-flutter
• Dart plugin can be installed from:
🔨 https://plugins.jetbrains.com/plugin/6351-dart
• Java version OpenJDK Runtime Environment (build
17.0.10+0-17.0.10b1087.21-11609105)

[✓] VS Code (version 1.93.1)
• VS Code at /Applications/Visual Studio Code.app/Contents
• Flutter extension version 3.96.0

[✓] Connected device (5 available)
• 苹果11啊 (mobile) • 00008030-0019082236E2802E • ios
• iOS 17.6.1 21G93
• qqqqqqq1iPhone (mobile) • 00008030-000171CE1168802E • ios
• iOS 17.6.1 21G93
• macOS (desktop) • macos • darwin-arm64
• macOS 14.0 23A344 darwin-arm64
• Mac Designed for iPad (desktop) • mac-designed-for-ipad • darwin
• macOS 14.0 23A344 darwin-arm64
• Chrome (web) • chrome •
web-javascript • Google Chrome 130.0.6723.117
! Error: Browsing on the local area network for iPhone 11 Pro Max. Ensure
the device is unlocked and attached with a cable or associated with the
same local area network as this Mac.
The device must be opted into Developer Mode to connect wirelessly. (code
-27)

[✓] Network resources
• All expected network resources are available.

• No issues found!
```

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.