支援新的 Android 外掛 API
如果您不編寫或維護 Android Flutter 外掛,可以跳過此頁面。
從 1.12 版本開始,Android 平臺提供了新的外掛 API。基於 PluginRegistry.Registrar 的舊 API 不會立即棄用,但我們鼓勵您遷移到基於 FlutterPlugin 的新 API。
與舊 API 相比,新 API 的優勢在於為依賴於生命週期的元件提供了一組更清晰的訪問器。例如,如果 Flutter 未連線到任何 Activity,PluginRegistry.Registrar.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>(可選)建立一個
EmbeddingV1Activity.java檔案,該檔案在MainActivity相同的資料夾中使用 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")); } }在
<plugin_name>/example/android/app/src/main/AndroidManifest.xml中新增<meta-data android:name="flutterEmbedding" android:value="2"/>。這將設定示例應用使用 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.testbuild.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_driverdev_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 chrome,那麼您需要採取額外的步驟來定義您的外掛。您必須實現 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 配置。