Flutter-Android返回事件分发源码分析

551 阅读3分钟

一.Activity中点击返回键

1、Activity响应返回事件,由onBackPressed方法处理

   @Override
   public void onBackPressed() {
     if (stillAttachedForEvent("onBackPressed")) {
       //delegate为FlutterActivityAndFragmentDelegate实例,实际负责与Flutter交互的类
       delegate.onBackPressed();
     }
   }

delegateFlutterActivityAndFragmentDelegate的实例,代理Android与Flutter交互的所有事件。

2、FlutterActivityAndFragmentDelegate.onBackPressed()

   void onBackPressed() {
     ...
     if (flutterEngine != null) {
       ...
       //getNavigationChannel为NavigationChannel的实例,把事件传递到Flutter端
       flutterEngine.getNavigationChannel().popRoute();
     } else {
      ...
     }
   }
 ​

3、NavigationChannel.popRoute()

   public NavigationChannel(@NonNull DartExecutor dartExecutor) {
     this.channel = new MethodChannel(dartExecutor, "flutter/navigation", JSONMethodCodec.INSTANCE);
   }
 ​
   public void popRoute() {
     ...
     //将返回事件分发到Flutter
     channel.invokeMethod("popRoute", null);
   }

二.Flutter注册Channel

FlutterApp在启动时会注册与Native交互的Channel

 //Flutter App的启动入口
 void runApp(Widget app) {
   WidgetsFlutterBinding.ensureInitialized()
     ..scheduleAttachRootWidget(app)
     ..scheduleWarmUpFrame();
 }
 ​
 class WidgetsFlutterBinding extends BindingBase with GestureBinding, SchedulerBinding, ServicesBinding, PaintingBinding, SemanticsBinding, RendererBinding, WidgetsBinding {}
 ​
 mixin WidgetsBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureBinding, RendererBinding, SemanticsBinding {
   @override
   void initInstances() {
     super.initInstances();
     ...
     //加载Native NavigationChannel,并处理Navtive传递过来的事件
     SystemChannels.navigation.setMethodCallHandler(_handleNavigationInvocation);
     ...
   }
 }  

Flutter返回键处理,这里popRoute对应Native上点击返回按钮

   Future<dynamic> _handleNavigationInvocation(MethodCall methodCall) {
     switch (methodCall.method) {
       case 'popRoute':
         //处理返回事件
         return handlePopRoute();
       case 'pushRoute':
         return handlePushRoute(methodCall.arguments as String);
       case 'pushRouteInformation':
         return _handlePushRouteInformation(methodCall.arguments as Map<dynamic, dynamic>);
     }
     return Future<dynamic>.value();
   }

三.Flutter事件分发

事件优先有Flutter消耗,如果Flutter没有消耗,最终把事件传回Native。

 Future<void> handlePopRoute() async {
   //Flutter内部分发返回事件
   for (final WidgetsBindingObserver observer in List<WidgetsBindingObserver>.from(_observers)) {
     if (await observer.didPopRoute())
       return;
   }
   //如果Flutter不处理,交由Native处理
   SystemNavigator.pop();
 }

四.Flutter内部事件分发

   for (final WidgetsBindingObserver observer in List<WidgetsBindingObserver>.from(_observers)) {
     if (await observer.didPopRoute())
       return;
   }

1、_observers是一个List<WidgetsBindingObserver>类型的对象

WidgetsBindingObserver代码如下:

 abstract class WidgetsBindingObserver {
  
   //在Android中点击返回键时会触发这个函数
   //如果返回true表示消费这个事件
   Future<bool> didPopRoute() => Future<bool>.value(false);
   ...
 }

2、WidgetsBindingObserver子类:_WidgetsAppState - WidgetsApp

 class WidgetsApp extends StatefulWidget {
 ​
   //一个好多参数的构造方法
   WidgetsApp({
   ...,
   backButtonDispatcher = null,
   })
   
   //一个命名构造函数
   WidgetsApp.router({
   ...,
   backButtonDispatcher = backButtonDispatcher ?? RootBackButtonDispatcher(),
   })
   
   State<WidgetsApp> createState() => _WidgetsAppState();
 }
 ​
 class _WidgetsAppState extends State<WidgetsApp> with WidgetsBindingObserver {
   @override
   void initState() {
     ...
     //把自身注册到_observers
     WidgetsBinding.instance!.addObserver(this);
   }  
  
   // On Android: the user has pressed the back button.
   //每个页面的返回事件由这边处理
   @override
   Future<bool> didPopRoute() async {
     // The back button dispatcher should handle the pop route if we use a router.
     //使用MaterialApp.router这个方法才会走到这里
     if (_usesRouter)
       return false;
     //大部分情况下都会走到这~
     final NavigatorState? navigator = _navigator?.currentState;
     if (navigator == null)
       return false;
     return navigator.maybePop();
   }
 }

3、WidgetsApp被使用的时机

在使用MaterialApp时,内部会创建WidgetsApp对象来处理返回事件,并注册到_observers

 class MaterialApp extends StatefulWidget {
 ​
   const MaterialApp({...})
   
   const MaterialApp.router({...})
   ...
   @override
   State<MaterialApp> createState() => _MaterialAppState();  
 }
 ​
 class _MaterialAppState extends State<MaterialApp> {
   ...
   @override
   Widget build(BuildContext context) {
     Widget result = _buildWidgetApp(context);
     ...
     return ScrollConfiguration(
       ...
       child: HeroControllerScope(
        ...
         child: result,
       ),
     );
   }  
   
   Widget _buildWidgetApp(BuildContext context) {
     ...
     if (_usesRouter) {
       return WidgetsApp.router(...);
     }  
     return WidgetsApp(...);
   }  
 }

4、NavigatorState.maybePop()处理返回事件,WillPopScope也会在这个方法进行处理

   Future<bool> maybePop<T extends Object?>([ T? result ]) async {
     final _RouteEntry? lastEntry = _history.cast<_RouteEntry?>().lastWhere(
       (_RouteEntry? e) => e != null && _RouteEntry.isPresentPredicate(e),
       orElse: () => null,
     );
     if (lastEntry == null)
       return false;
     //WillPopScope会被注册到这个地方处理
     final RoutePopDisposition disposition = await lastEntry.route.willPop(); // this is asynchronous
     if (!mounted)
       return true; // forget about this pop, we were disposed in the meantime
     final _RouteEntry? newLastEntry = _history.cast<_RouteEntry?>().lastWhere(
       (_RouteEntry? e) => e != null && _RouteEntry.isPresentPredicate(e),
       orElse: () => null,
     );
     if (lastEntry != newLastEntry)
       return true; // forget about this pop, something happened to our history in the meantime
     switch (disposition) {
       case RoutePopDisposition.bubble:
         return false;
       case RoutePopDisposition.pop:
         pop(result);
         return true;
       case RoutePopDisposition.doNotPop:
         return true;
     }
   }

五.事件交由Native处理

   //如果Flutter不处理,交由Native处理
   SystemNavigator.pop();
   
   //把事件分发到Native
   static Future<void> pop({bool? animated}) async {
     await SystemChannels.platform.invokeMethod<void>('SystemNavigator.pop', animated);
   }

Native接收到Flutter发送的SystemNavigator.pop

   //最终由Android-PlatformPlugin处理
   private void popSystemNavigator() {
     //FlutterActivity中platformPluginDelegate=null,所以不会走到此处
     if (platformPluginDelegate != null && platformPluginDelegate.popSystemNavigator()) {
       // A custom behavior was executed by the delegate. Don't execute default behavior.
       return;
     }
     //最后看到的现象就是Activity退出了~
     if (activity instanceof OnBackPressedDispatcherOwner) {
       ((OnBackPressedDispatcherOwner) activity).getOnBackPressedDispatcher().onBackPressed();
     } else {
       activity.finish();
     }
   }

\