Flutter学习分享-齐绪东

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

2020-05-17  本文已影响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 提供了

创建完 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个方法:

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

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

通过 FlutterPluginBinding 可以得到

等常用对象。

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

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

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

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

Federated plugins

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

见另一篇 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文档:

上一篇下一篇

猜你喜欢

热点阅读