美文网首页Flutter学习分享-齐绪东
Flutter 插件 从启动到插件开始执行

Flutter 插件 从启动到插件开始执行

作者: 外星间谍 | 来源:发表于2020-05-17 15:14 被阅读0次

    2020-05-14 0:00:26
    Flutter 插件,FlutterPlugin,FlutterEngine

    Android Plugin API 2.0

    在 Flutter 1.12 ,插件 API 升 级到了 2.0 。
    API 2.0 之前。
    开发者通常要在 MainActivityonCreate() 方法中手动调用 GeneratedPluginRegistrant.registerWith() 来执行插件类中的一个静态方法初始化插件。

    API 2.0 之后,出现了 FlutterPlugin 接口。
    开发者只要让创建的插件类实现它,并把初始化代码放到一个重写的方法中就好了。
    甚至都不需要创建 MainActivity

    从 Flutter 启动到开始执行插件

    随 FlutterPlugin 一同出现的还有新的 FlutterActivity 和 FlutterEngine 。

    FlutterActivity 是什么

    启动一个 Android 应用,启动的通常是一个 Activity 。
    如果这个应用是 Flutter 应用,那么这个 Activity 是 FlutterActivity

    Activity 创建后会先执行 onCreate() 方法。
    在 FlutterActivity 的 onCreate() 方法中,创建了一个 FlutterEngine

    FlutterEngine 是什么

    官方文档对 FlutterEngine 的解释:

    A single Flutter execution environment.
    The FlutterEngine is the container through which Dart code can be run in an Android application.

    是一个单独的 Flutter 执行环境,通过它,可以让一个 Android 应用运行 Dart 代码。

    FlutterEngine 提供了

    • FlutterRenderer 负责渲染视图。

    • DartExecutor 作为 BinaryMessenger 用来和 Flutter 端通信。我们创建 MethodChannel 就要用到这个。

    • FlutterEnginePluginRegistry 作为 PluginRegistry 来登记开发者创建的 FlutterPlugin 。当我们在项目的 pubspec.yaml 文件中添加了插件,运行 flutter pub get 后,会在安卓平台生成一个 GeneratedPluginRegistrant 类,该类中就用到了 PluginRegistry 来注册 FlutterPlugin 。

    • PlatformViewsController 用来管理提供给 Flutter 端的原生平台视图。当我们想让 Flutter 应用中显示安卓原生视图的时候,例如百度地图,就会用到。

    创建完 FlutterEngine ,FlutterActivity 的 onCreate() 方法还没有结束。

    登记插件

    接下来会执行 FlutterActivity 中的 configureFlutterEngine() 方法。
    并把 FlutterEngine 作为参数传递给它。

    @Override
    public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {
      registerPlugins(flutterEngine);
    }
    
      private static void registerPlugins(@NonNull FlutterEngine flutterEngine) {
        try {
          Class<?> generatedPluginRegistrant =
              Class.forName("io.flutter.plugins.GeneratedPluginRegistrant");
          Method registrationMethod =
              generatedPluginRegistrant.getDeclaredMethod("registerWith", FlutterEngine.class);
          registrationMethod.invoke(null, flutterEngine);
        } catch (Exception e) {
          Log.w(
              TAG,
              "Tried to automatically register plugins with FlutterEngine ("
                  + flutterEngine
                  + ") but could not find and invoke the GeneratedPluginRegistrant.");
        }
      }
    

    这里调用了 GeneratedPluginRegistrant 中的 registerWith() 来登记插件。
    并且给了 FlutterEngine 作为参数。
    下面的内容就和我们写的插件相关了。

    GeneratedPluginRegistrant

    这个类是根据 pubspec.yaml 中的依赖生成的。
    新建一个插件后,示例中的 pubspec.yaml

    # <plugin_name>/example/pubspec.yaml
    dependencies:
      flutter:
        sdk: flutter
    
      flutter_plugin_demo: # 示例依赖了新建的插件
        path: ../
    

    插件的 pubspec.yaml

    # <plugin_name>/pubspec.yaml
    name: flutter_plugin_demo
    flutter:
      plugin:
        platforms:
          android:
            package: xyz.waixingjiandie.flutter_plugin_demo
            pluginClass: FlutterPluginDemoPlugin # 指定了 Android 插件的类名字
          ios:
            pluginClass: FlutterPluginDemoPlugin
    

    自动生成的 GeneratedPluginRegistrant :

    package io.flutter.plugins;
    
    import androidx.annotation.Keep;
    import androidx.annotation.NonNull;
    
    import io.flutter.embedding.engine.FlutterEngine;
    
    /**
     * Generated file. Do not edit.
     * This file is generated by the Flutter tool based on the
     * plugins that support the Android platform.
     */
    @Keep
    public final class GeneratedPluginRegistrant {
      public static void registerWith(@NonNull FlutterEngine flutterEngine) {
        flutterEngine.getPlugins().add(new xyz.waixingjiandie.flutter_plugin_demo.FlutterPluginDemoPlugin());
      }
    }
    

    通过 FlutterEngine 的 getPlugins() 方法返回一个 PluginRegistry
    这个 PluginRegistry 是新版,没有 hasPlugin() 方法。
    通过它的 add() 方法登记插件,会自动检查是否已经登记过。
    插件的登记,其实就是把插件添加到一个 Map 里。
    这样就算把 FlutterPlugin 附加到了 FlutterEngine 。

    插件登记后,会执行插件的 onAttachedToEngine() 方法。
    并传递一个 FlutterPluginBinding 作为参数。

    然后程序的运行就进入了 FlutterPlugin 。

    FlutterPlugin

    插件的代码位于 <plugin_name>/android/ 目录下。

    插件有2个方法:

    • onAttachedToEngine()
    • onDetachedFromEngine()

    根据名字就能看出来,
    一个是插件被关联到 FlutterEngine 时调用,可以做一些初始化工作。
    另一个是插件从 FlutterEngine 移除时调用,可以在这里做一些清理工作。

    他们都接收一个 FlutterPluginBinding 作为参数。
    这个 FlutterPluginBinding 是 FlutterEngine 创建 PluginRegistry 时,
    由 PluginRegistry 的实现 FlutterEnginePluginRegistry 创建的。

    通过 FlutterPluginBinding 可以得到

    • Application context
    • BinaryMessenger
    • PlatformViewRegistry

    等常用对象。

    自带的示例在这里创建了一个 MethodChannel 用来和 Flutter 通信。
    创建 MethodChannel 就要用到 BinaryMessenger 。
    可以通过 FlutterPluginBinding 的 getBinaryMessenger() 方法得到。

    如果插件需要用到 Activity ,可以让插件再实现一个 ActivityAware 接口。
    如果涉及后台服务,还有个 ServiceAware 接口。

    用法可以参考官方插件
    目前我只写了一个百度地图插件,参考了谷歌地图,需要用到 ActivityAware 。

    以上就是从 app 启动到插件开始执行的过程了。
    新的 API 还提出了 Federated plugins 的概念。

    Federated plugins

    将一个插件包,分离成了3类。

    • 插件原生平台端提供的功能声明成接口放在一个包中
    • 特定平台实现接口的包,可以有多个
    • 插件为 app 提供各种功能的包,插件使用者调用这个包中的方法。
      接口为这个包提供一个平台的实现,这个包调用实现中的方法。

    见另一篇 Federated plugins

    可以简化的东西

    这是新建项目后示例的清单文件(有省略):

    <!-- <plugin_name>/example/android/app/src/main/AndroidManifest.xml -->
    
    <application
        android:name="io.flutter.app.FlutterApplication"
        <activity
            android:name=".MainActivity"
        </activity>
    </application>
    

    MainActivity.java

    public class MainActivity extends FlutterActivity {
    }
    

    MainActivity 我并没有省略,就是空的。

    参考官方的升级指南

    我们可以在清单文件中把 .MainActivity 改成 io.flutter.embedding.android.FlutterActivity
    然后删掉 MainActivity.java 文件。
    清单文件中的 FlutterApplication 也可以去掉。于是变成了这样子:

    <application
        <activity
            android:name="io.flutter.embedding.android.FlutterActivity"
        </activity>
    </application>
    

    相关文章

    参考资料

    源代码

    文章:

    API文档:

    相关文章

      网友评论

        本文标题:Flutter 插件 从启动到插件开始执行

        本文链接:https://www.haomeiwen.com/subject/ptlsohtx.html