如果您不編寫或維護 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 的步驟

  1. 更新主外掛類(*Plugin.java)以實現 FlutterPlugin 介面。對於更復雜的外掛,您可以將 FlutterPluginMethodCallHandler 分離到兩個類中。有關使用最新版本(v2)嵌入訪問應用資源的更多詳細資訊,請參閱下一節 基礎外掛

    另外,請注意,外掛仍應包含靜態 registerWith() 方法,以保持與不使用 v2 Android 嵌入的應用相容。(有關詳細資訊,請參閱 升級 1.12 之前的 Android 專案。)最簡單的方法(如果可能)是將 registerWith() 中的邏輯移到一個私有方法中,該方法可以由 registerWith()onAttachedToEngine() 呼叫。只會呼叫 registerWith()onAttachedToEngine() 中的一個,不會同時呼叫。

    此外,您應該記錄外掛中所有未重寫的公共成員。在“新增到應用”場景中,開發者可以訪問這些類,因此需要進行文件記錄。

  2. (可選)如果您的外掛需要 Activity 引用,還要實現 ActivityAware 介面。

  3. (可選)如果您的外掛預計在任何時候都駐留在後臺服務中,請實現 ServiceAware 介面。

  4. 更新示例應用的 MainActivity.java 以使用 v2 嵌入的 FlutterActivity。有關詳細資訊,請參閱 升級 1.12 之前的 Android 專案。您可能需要為您的外掛類建立一個公共建構函式(如果之前不存在)。例如:

    MainActivity.java
    java
     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.
     }
  5. (可選)如果您刪除了 MainActivity.java,請更新 <plugin_name>/example/android/app/src/main/AndroidManifest.xml 以使用 io.flutter.embedding.android.FlutterActivity。例如:

    AndroidManifest.xml
    xml
     <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>
  6. (可選)建立一個 EmbeddingV1Activity.java 檔案,該檔案在 MainActivity 相同的資料夾中使用 v1 嵌入,用於示例專案,以繼續測試 v1 嵌入與您的外掛的相容性。請注意,您必須手動註冊所有外掛,而不是使用 GeneratedPluginRegistrant。例如:

    EmbeddingV1Activity.java
    java
    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"));
      }
    }
  7. <plugin_name>/example/android/app/src/main/AndroidManifest.xml 中新增 <meta-data android:name="flutterEmbedding" android:value="2"/>。這將設定示例應用使用 v2 嵌入。

  8. (可選)如果您在上一步中建立了 EmbeddingV1Activity,請將 EmbeddingV1Activity 新增到 <plugin_name>/example/android/app/src/main/AndroidManifest.xml 檔案中。例如:

    AndroidManifest.xml
    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>

測試您的外掛

#

接下來的步驟將介紹測試您的外掛,我們鼓勵您這樣做,但並非必需。

  1. 更新 <plugin_name>/example/android/app/build.gradle 以將對 android.support.test 的引用替換為 androidx.test

    build.gradle
    groovy
    defaultConfig {
      ...
      testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
      ...
    }
    build.gradle
    groovy
    dependencies {
    ...
    androidTestImplementation 'androidx.test:runner:1.2.0'
    androidTestImplementation 'androidx.test:rules:1.2.0'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
    ...
    }
  2. <plugin_name>/example/android/app/src/androidTest/java/<plugin_path>/ 中為 MainActivityEmbeddingV1Activity 新增測試檔案。您需要建立這些目錄。例如:

    MainActivityTest.java
    java
    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);
    }
    EmbeddingV1ActivityTest.java
    java
    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);
    }
  3. integration_testflutter_driver dev_dependencies 新增到 <plugin_name>/pubspec.yaml<plugin_name>/example/pubspec.yaml 中。

    pubspec.yaml
    yaml
    integration_test:
      sdk: flutter
    flutter_driver:
      sdk: flutter
  4. 更新 <plugin_name>/pubspec.yaml 中的最低 Flutter 版本要求。所有未來的外掛都將設定最低版本為 1.12.13+hotfix.6,這是我們可以保證支援的最低版本。例如:

    pubspec.yaml
    yaml
    environment:
      sdk: ">=2.16.1 <3.0.0"
      flutter: ">=1.17.0"
  5. <plugin_name>/test/<plugin_name>_test.dart 中建立一個簡單的測試。為了測試新增 v2 嵌入支援的 PR,我們試圖測試外掛的一些非常基本的功能。這是一個冒煙測試,以確保外掛能夠正確地與新的嵌入器進行註冊。例如:

    dart
    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);
      });
    }
  6. 本地執行 integration_test 測試。在終端中,執行以下操作:

    flutter test integration_test/app_test.dart

基礎外掛

#

要開始使用程式碼中的 Flutter Android 外掛,請先實現 FlutterPlugin

java
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,提供對 DartExecutorFlutterRenderer 等元件的訪問。
binding.getApplicationContext()
返回正在執行的應用的 Android 應用的 Context

UI/Activity 外掛

#

如果您的外掛需要與 UI 互動,例如請求許可權或修改 Android UI chrome,那麼您需要採取額外的步驟來定義您的外掛。您必須實現 ActivityAware 介面。

java
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 配置。