支援新的 Android 的 API
如果您並非親自開發或維護一個 Flutter 的 Android 外掛,您可以跳過本頁面。
自 1.12 版本釋出後,
Android 平台已可以使用新的 Android 外掛 API 。基於 PluginRegistry.Registrar
的 API 不會立刻廢棄,但我們鼓勵您向基於 FlutterPlugin
的 API 進行遷移。
相較舊的 API 而言,新版 API 的優點是為生命週期的相關元件提供了更簡潔清晰的存取方式。例如,在使用舊的 PluginRegistry.Registrar.activity()
時,如果 Flutter 尚未附加到任何 activites,可能會返回 null 。
換句話說,在使用舊的 API 進行 Flutter 嵌入 Android 應用時,可能會產生意外的行為。 Flutter 開發團隊提供的大部分 Flutter 外掛 已經完成了遷移。(瞭解如何成為 認證的釋出者)作為參考, battery plus package 已經遷移到新版 API 。
升級步驟
以下的步驟簡要說明了如何支援新版 API :
-
在外掛的主類檔案中 (
*Plugin.java
) 實現FlutterPlugin
介面。對於稍微複雜的外掛,您可以將FlutterPlugin
與MethodCallHandler
拆分到不同的類中。如需更多關於如何使用新版 API 獲取資源的內容,請參考下一節 基礎外掛 。
同時需要注意的是,外掛仍需保留靜態的registerWith()
方法,從而適配不相容 v2 版本嵌入的應用。 (檢視 Upgrading pre 1.12 Android projects 獲取更多資訊)
此外,所有不可覆蓋的公開成員都應該使用文件標註。在嵌入開發的場景下,這些可見內容通常需要包含文件。 -
(可選)如果您的外掛需要
Activity
的參考,請同時實現ActivityAware
介面。 -
(可選)如果您的外掛需要隨時保持一個後臺 Service ,請實現
ServiceAware
介面。 -
使用
FlutterActivity
將範例應用中的MainActivity.java
遷移到 v2 版本嵌入。更多資訊請檢視 Upgrading pre 1.12 Android projects 。如果您的外掛類尚不存在,則必須新增一個公有建構函式。例如:package 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
。例如:<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.java
同級目錄下建立一個EmbeddingV1Activity.java
檔案,使用 v1 版本嵌入以持續測試您的專案對 v1 版本嵌入的相容性。例如:package 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
檔案。例如:<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
:defaultConfig { ... testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" ... }
dependencies { ... 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
的測試檔案,並且您需要建立該目錄。例如:package 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); }
package 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); }
-
在
<plugin_name>/pubspec.yaml
和<plugin_name>/example/pubspec.yaml
中的 dev_dependencies 下新增e2e
和flutter_driver
。integration_test: sdk: flutter flutter_driver: sdk: flutter
-
更新
<plugin_name>/pubspec.yaml
中 Flutter 版本的最低限制。所有已遷移的外掛都將會設定最低版本為我們保證支援的最低版本 1.12.13+hotfix.6。例如:environment: sdk: ">=2.16.1 <3.0.0" flutter: ">=1.17.0"
-
在
<plugin_name>/test/<plugin_name>_e2e.dart
中建立一個簡單的測試。為了測試添加了 v2 版本嵌入支援的 PR,我們將嘗試測試一些外掛的基礎功能。這是一個確保外掛正確註冊到新的嵌入器的煙霧測試。例如:import '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); }); }
-
本地執行 e2e 測試。在終端中執行以下內容:
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()
返回當前執行的安卓應用的 Application 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
及一些回呼(Callback)。
由於 Activity
有可能在配置變化時被銷燬,您必須在
onDetachedFromActivityForConfigChanges()
方法中清理所有與 Activity
有關的參考,接著在
onReattachedToActivityForConfigChanges()
中重新建立它們。
最後,在 onDetachedFromActivity()
中清理所有與 Activity
有關的參考並返回與 UI 無關的配置。