Post

已有项目接入Flutter第二次不展示的问题

已有项目接入Flutter第二次不展示的问题

问题

在已有iOS项目里接入flutter模块后,第一次presentpush一个FlutterViewController后,通过手势或调用方法关闭flutter页面后,再次presentpush时展示不了flutter页面了

原因:

flutter页面关闭后,flutterEngine.viewController还是持有FlutterViewController,导致FlutterViewController不销毁,下次调用presentpush时就展示不了

解决方案

自定义一个FlutterViewController并在viewDidDisappear(:)里判断如果是销毁则将flutterEngine.viewController设置为nil,具体代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
class MyFlutterViewController: FlutterViewController {
    deinit {
        print("deinit--\(self)")
    }
    
    override func viewDidLoad() {
        print("viewDidLoad--\(self)")
        self.view.backgroundColor = .white
        super.viewDidLoad()
        
    }
    
    override func viewDidDisappear(_ animated: Bool) {
        print("viewDidDisappear--isBeingDismissed:\(self.isBeingDismissed)--isMovingFromParent:\(self.isMovingFromParent)--\(self)")
        super.viewDidDisappear(animated)
        // 判断是否是被销毁
        if self.isBeingDismissed || self.isMovingFromParent {
            // isBeingDismissed: present展示的,拖拽到底部、或调用dismiss关闭时,值为true
            // isMovingFromParent:push展示的,侧滑、或者调用pop返回关闭时,值为true
            // 执行销毁或清理操作
            if let engine = (UIApplication.shared.delegate as? AppDelegate)?.engine,
               engine.viewController == self {
                engine.viewController = nil
                engine.destroyContext()
                (UIApplication.shared.delegate as? AppDelegate)?.engine = nil
            }
            print("FlutterViewController 被销毁")
        } else {
            // 只是暂时隐藏,不执行销毁操作
            print("FlutterViewController 被隐藏")
        }
    }
    
    
    override func dismiss(animated flag: Bool, completion: (() -> Void)? = nil) {
        print("dismiss(animated:completion:)--\(self)")
        super.dismiss(animated: flag, completion: completion)
    }
}

完整代码: AppDelegate.swift

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import UIKit

import Flutter
import FlutterPluginRegistrant

@main
class AppDelegate: UIResponder, UIApplicationDelegate {

    private var flutterEngine : FlutterEngine?
    var engine: FlutterEngine? {
        get {
            if let engine = flutterEngine {
                return engine
            }
            let engine = FlutterEngine(name: "xxxx", project: nil)
            self.flutterEngine = engine
            self.flutterEngine?.run(withEntrypoint: nil)
            GeneratedPluginRegistrant.register(with: engine)
            return engine
        } set {
            if newValue == nil {
                // 清空
                flutterEngine = nil
            } else {
                flutterEngine = newValue
            }
        }
    }

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.
        return true
    }
}

完整的MyViewController + MyFlutterViewController

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
import UIKit
import Flutter

class MyViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        let btn = UIButton(type: .custom)
        btn.frame = CGRect(x: 50, y: 100, width: 200, height: 50)
        btn.backgroundColor = .blue
        btn.setTitle("present 进入flutter页面", for: .normal)
        btn.addTarget(self, action: #selector(enterFlutterPage(btn:)), for: .touchUpInside)
        self.view.addSubview(btn)
        
        let btn2 = UIButton(type: .custom)
        btn2.frame = CGRect(x: 50, y: 200, width: 200, height: 50)
        btn2.backgroundColor = .blue
        btn2.setTitle("push 进入flutter页面", for: .normal)
        btn2.tag = 2
        btn2.addTarget(self, action: #selector(enterFlutterPage(btn:)), for: .touchUpInside)
        self.view.addSubview(btn2)
        
    }

    // MARK: App进入flutter页面
    @objc func enterFlutterPage(btn: UIButton) {
        if let engine = (UIApplication.shared.delegate as? AppDelegate)?.engine {
            let flutterViewController = MyFlutterViewController(engine: engine, nibName: nil, bundle: nil)
            // 全屏展示
            if btn.tag == 2 {
                self.navigationController?.pushViewController(flutterViewController, animated: false)
            } else {
                //            flutterViewController.modalPresentationStyle = .fullScreen
                self.present(flutterViewController, animated: false, completion: nil)
            }
        }
    }
}

class MyFlutterViewController: FlutterViewController {
    deinit {
        print("deinit--\(self)")
    }
    
    override func viewDidLoad() {
        print("viewDidLoad--\(self)")
        self.view.backgroundColor = .white
        super.viewDidLoad()
        
    }
    
    override func viewDidDisappear(_ animated: Bool) {
        print("viewDidDisappear--isBeingDismissed:\(self.isBeingDismissed)--isMovingFromParent:\(self.isMovingFromParent)--\(self)")
        super.viewDidDisappear(animated)
        // 判断是否是被销毁
        if self.isBeingDismissed || self.isMovingFromParent {
            // isBeingDismissed: present展示的,拖拽到底部、或调用dismiss关闭时,值为true
            // isMovingFromParent:push展示的,侧滑、或者调用pop返回关闭时,值为true
            // 执行销毁或清理操作
            if let engine = (UIApplication.shared.delegate as? AppDelegate)?.engine,
               engine.viewController == self {
                engine.viewController = nil
                engine.destroyContext()
                (UIApplication.shared.delegate as? AppDelegate)?.engine = nil
            }
            print("FlutterViewController 被销毁")
        } else {
            // 只是暂时隐藏,不执行销毁操作
            print("FlutterViewController 被隐藏")
        }
    }
    
    
    override func dismiss(animated flag: Bool, completion: (() -> Void)? = nil) {
        print("dismiss(animated:completion:)--\(self)")
        super.dismiss(animated: flag, completion: completion)
    }
}
This post is licensed under CC BY 4.0 by the author.