支持新的 Android 插件 API
如果你不编写或维护 Android Flutter 插件,则可以跳过此页面。
从 1.12 版本开始,Android 平台提供了新的插件 API。基于 PluginRegistry.Registrar
的旧版 API 不会立即弃用,但我们鼓励你迁移到基于 FlutterPlugin
的新版 API。
与旧版 API 相比,新版 API 的优势在于提供了一组更清晰的生命周期相关组件访问器。例如,PluginRegistry.Registrar.activity()
在 Flutter 未附加到任何 Activity 时可能会返回 null。
换句话说,使用旧版 API 的插件在将 Flutter 嵌入到 Android 应用时可能会产生未定义的行为。flutter.dev 团队提供的大多数 Flutter 插件 已经迁移了。(了解如何在 pub.dev 上成为 已验证的发行商!)有关使用新版 API 的插件示例,请参阅 battery plus 软件包。
升级步骤
#以下说明支持新版 API 的步骤
更新主插件类(
*Plugin.java
)以实现FlutterPlugin
接口。对于更复杂的插件,你可以将FlutterPlugin
和MethodCallHandler
分离到两个类中。有关使用最新版本 (v2) 嵌入访问应用资源的更多详细信息,请参阅下一节 基础插件。
此外,请注意,插件仍应包含静态registerWith()
方法以保持与不使用 v2 Android 嵌入的应用的兼容性。(有关详细信息,请参阅 升级 1.12 之前的 Android 项目)。最简单的方法(如果可能)是将registerWith()
中的逻辑移动到一个私有方法中,registerWith()
和onAttachedToEngine()
都可以调用该方法。registerWith()
或onAttachedToEngine()
将会被调用,但不会同时调用两者。
此外,你应该记录插件中所有未重写公有成员。在添加到应用的场景中,这些类对开发人员是可访问的,需要文档。(可选)如果你的插件需要
Activity
引用,则还需要实现ActivityAware
接口。(可选)如果你的插件预计在任何时间点都将保存在后台服务中,则需要实现
ServiceAware
接口。更新示例应用的
MainActivity.java
以使用 v2 嵌入FlutterActivity
。有关详细信息,请参阅 升级 1.12 之前的 Android 项目。如果你的插件类还没有公有构造函数,你可能需要创建一个。例如MainActivity.javajavapackage io.flutter.plugins.firebasecoreexample; import io.flutter.embedding.android.FlutterActivity; import io.flutter.embedding.engine.FlutterEngine; import io.flutter.plugins.firebase.core.FirebaseCorePlugin; public class MainActivity extends FlutterActivity { // You can keep this empty class or remove it. Plugins on the new embedding // now automatically registers plugins. }
(可选)如果你删除了
MainActivity.java
,请更新<plugin_name>/example/android/app/src/main/AndroidManifest.xml
以使用io.flutter.embedding.android.FlutterActivity
。例如AndroidManifest.xmlxml<activity android:name="io.flutter.embedding.android.FlutterActivity" android:theme="@style/LaunchTheme" android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale" android:hardwareAccelerated="true" android:exported="true" android:windowSoftInputMode="adjustResize"> <meta-data android:name="io.flutter.app.android.SplashScreenUntilFirstFrame" android:value="true" /> <intent-filter> <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity>
(可选)在与
MainActivity
相同的文件夹中创建EmbeddingV1Activity.java
文件,该文件使用 v1 嵌入来为示例项目进行测试,以保持与你的插件的 v1 嵌入的兼容性。请注意,你必须手动注册所有插件,而不是使用GeneratedPluginRegistrant
。例如EmbeddingV1Activity.javajavapackage io.flutter.plugins.batteryexample; import android.os.Bundle; import io.flutter.app.FlutterActivity; import io.flutter.plugins.battery.BatteryPlugin; public class EmbeddingV1Activity extends FlutterActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); BatteryPlugin.registerWith(registrarFor("io.flutter.plugins.battery.BatteryPlugin")); } }
将
<meta-data android:name="flutterEmbedding" android:value="2"/>
添加到<plugin_name>/example/android/app/src/main/AndroidManifest.xml
。这将设置示例应用以使用 v2 嵌入。(可选)如果你在之前的步骤中创建了
EmbeddingV1Activity
,请将EmbeddingV1Activity
添加到<plugin_name>/example/android/app/src/main/AndroidManifest.xml
文件中。例如AndroidManifest.xmlxml<activity android:name=".EmbeddingV1Activity" android:theme="@style/LaunchTheme" android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale" android:hardwareAccelerated="true" android:exported="true" android:windowSoftInputMode="adjustResize"> </activity>
测试你的插件
#其余步骤将介绍测试你的插件,我们鼓励你进行测试,但不是必需的。
更新
<plugin_name>/example/android/app/build.gradle
以将对android.support.test
的引用替换为androidx.test
build.gradlegroovydefaultConfig { ... testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" ... }
build.gradlegroovydependencies { ... androidTestImplementation 'androidx.test:runner:1.2.0' androidTestImplementation 'androidx.test:rules:1.2.0' androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' ... }
在
<plugin_name>/example/android/app/src/androidTest/java/<plugin_path>/
中添加MainActivity
和EmbeddingV1Activity
的测试文件。你需要创建这些目录。例如MainActivityTest.javajavapackage io.flutter.plugins.firebase.core; import androidx.test.rule.ActivityTestRule; import io.flutter.plugins.firebasecoreexample.MainActivity; import org.junit.Rule; import org.junit.runner.RunWith; @RunWith(FlutterRunner.class) public class MainActivityTest { // Replace `MainActivity` with `io.flutter.embedding.android.FlutterActivity` if you removed `MainActivity`. @Rule public ActivityTestRule<MainActivity> rule = new ActivityTestRule<>(MainActivity.class); }
EmbeddingV1ActivityTest.javajavapackage io.flutter.plugins.firebase.core; import androidx.test.rule.ActivityTestRule; import io.flutter.plugins.firebasecoreexample.EmbeddingV1Activity; import org.junit.Rule; import org.junit.runner.RunWith; @RunWith(FlutterRunner.class) public class EmbeddingV1ActivityTest { @Rule public ActivityTestRule<EmbeddingV1Activity> rule = new ActivityTestRule<>(EmbeddingV1Activity.class); }
将
integration_test
和flutter_driver
dev_dependencies 添加到<plugin_name>/pubspec.yaml
和<plugin_name>/example/pubspec.yaml
。pubspec.yamlyamlintegration_test: sdk: flutter flutter_driver: sdk: flutter
更新
<plugin_name>/pubspec.yaml
中的环境的最低 Flutter 版本。所有未来的插件都将最低版本设置为 1.12.13+hotfix.6,这是我们能够保证支持的最低版本。例如pubspec.yamlyamlenvironment: sdk: ">=2.16.1 <3.0.0" flutter: ">=1.17.0"
在
<plugin_name>/test/<plugin_name>_test.dart
中创建一个简单的测试。为了测试添加 v2 嵌入支持的 PR,我们试图测试插件的一些非常基本的功能。这是一个冒烟测试,以确保插件正确地与新的嵌入器注册。例如dartimport 'package:flutter_test/flutter_test.dart'; import 'package:integration_test/integration_test.dart'; void main() { IntegrationTestWidgetsFlutterBinding.ensureInitialized(); testWidgets('Can get battery level', (tester) async { final Battery battery = Battery(); final int batteryLevel = await battery.batteryLevel; expect(batteryLevel, isNotNull); }); }
在本地运行
integration_test
测试。在终端中,执行以下操作flutter test integration_test/app_test.dart
基础插件
#要开始使用代码中的 Flutter Android 插件,请先实现 FlutterPlugin
。
public class MyPlugin implements FlutterPlugin {
@Override
public void onAttachedToEngine(@NonNull FlutterPluginBinding binding) {
// TODO: your plugin is now attached to a Flutter experience.
}
@Override
public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {
// TODO: your plugin is no longer attached to a Flutter experience.
}
}
如上所示,你的插件可能(也可能不)在任何给定时间点与给定的 Flutter 体验相关联。你应该注意在 onAttachedToEngine()
中初始化插件的行为,然后在 onDetachedFromEngine()
中清理插件的引用。
FlutterPluginBinding
为你的插件提供了一些重要的引用
- binding.getFlutterEngine()
- 返回你的插件附加到的
FlutterEngine
,提供对DartExecutor
、FlutterRenderer
等组件的访问。 - binding.getApplicationContext()
- 返回正在运行的应用的 Android 应用的
Context
。
UI/Activity 插件
#如果你的插件需要与 UI 交互,例如请求权限或更改 Android UI 界面,则需要采取其他步骤来定义你的插件。你必须实现 ActivityAware
接口。
public class MyPlugin implements FlutterPlugin, ActivityAware {
//...normal plugin behavior is hidden...
@Override
public void onAttachedToActivity(ActivityPluginBinding activityPluginBinding) {
// TODO: your plugin is now attached to an Activity
}
@Override
public void onDetachedFromActivityForConfigChanges() {
// TODO: the Activity your plugin was attached to was
// destroyed to change configuration.
// This call will be followed by onReattachedToActivityForConfigChanges().
}
@Override
public void onReattachedToActivityForConfigChanges(ActivityPluginBinding activityPluginBinding) {
// TODO: your plugin is now attached to a new Activity
// after a configuration change.
}
@Override
public void onDetachedFromActivity() {
// TODO: your plugin is no longer associated with an Activity.
// Clean up references.
}
}
要与 Activity
交互,你的 ActivityAware
插件必须在 4 个阶段实现适当的行为。首先,你的插件附加到一个 Activity
。你可以通过提供的 ActivityPluginBinding
访问该 Activity
及其许多回调。
由于 Activity
可以在配置更改期间被销毁,因此你必须在 onDetachedFromActivityForConfigChanges()
中清理对给定 Activity
的任何引用,然后在 onReattachedToActivityForConfigChanges()
中重新建立这些引用。
最后,在 onDetachedFromActivity()
中,你的插件应该清理与 Activity
行为相关的所有引用,并返回到非 UI 配置。
除非另有说明,否则本网站上的文档反映了 Flutter 的最新稳定版本。页面最后更新于 2024-06-24。 查看源代码 或 报告问题。