Repository: flutter
Issue: Refactoring FlutterViewController to support addToExistingApp better
Labels: platform-ios,engine,customer: alibaba,a: existing-apps,c: proposal,P3,team-ios,triaged-ios

<!-- Thank you for using Flutter!

     If you are looking for support, please check out our documentation
     or consider asking a question on Stack Overflow:
      * https://flutter.dev/
      * https://api.flutter.dev/
      * https://stackoverflow.com/questions/tagged/flutter?sort=frequent

     If you have found a bug or if our documentation doesn't have an answer
     to what you're looking for, then fill our the template below. Please read
     our guide to filing a bug first: https://flutter.dev/docs/resources/bug-reports
-->

## Use case
As we know, flutter was designed to  only support one flutter view container in the whole app at the very beginning. As a result, the life cycle of FlutterViewController is as same as the whole app. The FlutterViewController will start, resume and pause the app life cycle state according to the view appear/disappear events. What is more, it handle the surface update process and not allowed the sub class to override.
And now, we try to support adding it to existing app, and support multiple flutter view controller sometimes.
However,  due to the first design, we met a lot of problems, as following:
1. the app's life cycle is not as same as one FlutterViewController, because we have more Flutter VC.
2. The sequence of multiple views' life cycle have side effect on the surface updates. for example:
I start a FlutterVC#1 to render flutter page#2, then I push a second FlutterVC#2 to render flutter page#2. The FlutterVC#2 will cover the FlutterVC#1. Note that we have only one FlutterEngine which hold only one surface, so when I started the FlutterVC#2, the FlutterVC#2 view will appear and surfaceUpdate:YES, then for a while, the FlutterVC#1 will view disappear, and surfaceUpdate:NO, which will let the FlutterEngine hold a nulled surface, and introduce failure of FlutterVC#2.
<!--
     Please tell us the problem you are running into that led to you wanting
     a new feature.

     Is your feature request related to a problem? Please give a clear and
     concise description of what the problem is.

     Describe alternative solutions you've considered. Is there a package
     on pub.dev/flutter that already solves this?
-->

## Proposal
I suggest that:
1. refactoring the FlutterViewController to extract the sub functions occurred in  view's appear and disappear event, and let those sub function public accessed by sub class. 
Take the viewWillAppear as an example:
```objc
- (void)viewWillAppear:(BOOL)animated {
  TRACE_EVENT0("flutter", "viewWillAppear");

  if (_engineNeedsLaunch) {
    [_engine.get() launchEngine:nil libraryURI:nil];
    [_engine.get() setViewController:self];
    _engineNeedsLaunch = NO;
  }

  // Send platform settings to Flutter, e.g., platform brightness.
  [self onUserSettingsChanged:nil];

  // Only recreate surface on subsequent appearances when viewport metrics are known.
  // First time surface creation is done on viewDidLayoutSubviews.
  if (_viewportMetrics.physical_width) {
    [self surfaceUpdated:YES];
  }
  [[_engine.get() lifecycleChannel] sendMessage:@"AppLifecycleState.inactive"];

  [super viewWillAppear:animated];
}
``` 
We can refactor it to following sub functions:
```objc
- (void)onEngineNeedsLaunch{....}//this function should be public to access by sub class
- (void)deactivateEngine{...}//public function to sub class
- (void)surfaceUpdated:(BOOL)appeared {...}//make this function public to sub class
- (int)physical_width{...}//just an example
- (void)viewWillAppear:(BOOL)animated {
  TRACE_EVENT0("flutter", "viewWillAppear");

  [self onEngineNeedsLaunch];

  // Only recreate surface on subsequent appearances when viewport metrics are known.
  // First time surface creation is done on viewDidLayoutSubviews.
  if ([self physical_width]) {
    [self surfaceUpdated:YES];
  }
  [self deactivateEngine:YES];

  [super viewWillAppear:animated];
}
```
Then in my MyFlutterViewController which inherit from FlutterViewController, I can decide when I need to call surfaceUpdated function during view's life cycle, and avoid to introduce the problem mentioned in problem#2.
```objc
@implementaton MYFlutterViewController : public FlutterViewController
- (void)viewWillAppear:(BOOL)animated {
  TRACE_EVENT0("myflutter", "viewWillAppear");

  [self onEngineNeedsLaunch];

  // Only recreate surface on subsequent appearances when viewport metrics are known.
  // First time surface creation is done on viewDidLayoutSubviews.
  if ([self physical_width]) {
    [self surfaceUpdated:YES];
  }
  [self deactivateEngine:YES];

// here I am able to not call super's implementation, and avoid surfaceUpdate:YES, and move this call to viewAppear handler
 // [super viewWillAppear:animated];
}

```
<!--
     Briefly but precisely describe what you would like Flutter to be able to do.

     Consider attaching images showing what you are imagining.

     Does this have to be provided by Flutter directly, or can it be provided
     by a package on pub.dev/flutter? If so, maybe consider implementing and
     publishing such a package rather than filing a bug.
-->