Flutter Android 1.12 迁移指南

7,046 阅读6分钟

翻译自 github.com/flutter/flu…

如果您在版本 1.12 之前是通过 flutter create 创建项目,则这可能适用于您的项目

背景

为了更好地支持将 Flutter 添加到现有项目的执行环境,托管 Flutter 运行时的旧版 Android 平台端包装器位于 io.flutter.app.FlutterActivity 及其关联的类现在已弃用。新的包装器 io.flutter.embedding.android.FlutterActivity 及相关类替代了他们。

这些类能更好地支持实际使用情况,如 FlutterActivity 可能不是应用程序中的第一个也不是唯一的 Android Activity。

Motivation

您现有的 Full-Flutter 项目不会立即受到影响,并且在可预见的将来将继续像以前一样工作。

但是,新的 Android 包装器还引入了一组新的 Android 插件开发 API。 仅在新插件 API 上开发的插件不适用于较早的 1.12 版 Android 项目。使用 1.12 之后创建的插件来构建 1.12 之前的 Android 项目,会产生构建时错误,除非该插件开发人员明确选择创建第二个向后兼容的实现。

旧版 Android API 尚未正式支持“Add-to-app”。 如果您在 1.12 之前遵循 Wiki 中关于“Add-to-app”的实验性说明,则应遵循下面 Add-to-app 部分 下的迁移步骤。

Full-Flutter 应用迁移

本指南假定您尚未手动为 Flutter 项目修改 Android host 项目。 如果您这样做了,请查阅下面的“add-to-app”迁移指南。

如果您选择迁移标准的 flutter create 项目,请遵循以下步骤:

  1. 删除 android/app/src/main/java/[your/package/name]/MainActivity.java。如果你没有添加过代码,那么可以直接删掉 [your/package/name]整个包结构,因为里面只有MainActivity.java
  2. 打开 android/app/src/main/AndroidManifest.xml.
  3. 从 application 标签中删除 FlutterApplication 的引用

修改前:

<application
  name="io.flutter.FlutterApplication"
  >
  <!-- code omitted -->
</application>

修改后:

<application
  >
  <!-- code omitted -->
</application>
  1. 修改 MainActivityFlutterActivity.

修改前:

<activity android:name=".MainActivity"
  android:launchMode="singleTop"
  android:theme="@android:style/Theme.Black.NoTitleBar"
 android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
  android:hardwareAccelerated="true"
  android:windowSoftInputMode="adjustResize"
  >
  <intent-filter>
    <action android:name="android.intent.action.MAIN"/>
    <category android:name="android.intent.category.LAUNCHER"/>
  </intent-filter>
</activity>

修改后(只改了前 3 行):

<activity android:name="io.flutter.embedding.android.FlutterActivity"
  android:theme="@android:style/Theme.Black.NoTitleBar" 
 android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
  android:hardwareAccelerated="true"
  android:windowSoftInputMode="adjustResize"
  >
  <intent-filter>
    <action android:name="android.intent.action.MAIN"/>
    <category android:name="android.intent.category.LAUNCHER"/>
  </intent-filter>
</activity>
  1. 更新 Splash 页(如果需要初始行为)。

删除所有键为 android:name="io.flutter.app.android.SplashScreenUntilFirstFrame"<meta-data> 标签。

styles.xml 中添加一个启动主题,将所需的启动屏幕配置为背景`Drawable':

<!-- You can name this style whatever you'd like -->
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
    <item name="android:windowBackground">@drawable/[your_launch_drawable_here]</item>
</style>

如果使用 Flutter create 创建 Flutter 项目,则可能已经定义了 LaunchTheme 以及一个名为 Launch_background 的可绘制对象。 您可以重新使用该配置并根据需要进行调整。

styles.xml 中添加一个普通主题,当 Android 进程完全初始化时,该主题会替换启动屏幕:

<!-- You can name this style whatever you'd like -->
<style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
    <item name="android:windowBackground">@drawable/[your_normal_background_drawable]</item>
</style>

"normal theme" 为您的 Flutter 体验提供了背景。 通常会在第一个 Flutter 帧渲染之前的短暂时间内看到该背景。 在您的 Flutter 体验期间,"normal theme" 还控制 Android 的状态栏和导航栏的视觉属性。

配置 FlutterActivity 以 launch theme 启动,然后再切换到 normal theme。 还指定您希望启动屏幕继续显示,直到 Flutter 渲染其第一帧为止:

<activity android:name="io.flutter.embedding.android.FlutterActivity"
  android:theme="@style/LaunchTheme"
  // some code omitted
  >
  <!-- Specify that the launch screen should continue being displayed -->
  <!-- until Flutter renders its first frame. -->
  <meta-data
    android:name="io.flutter.embedding.android.SplashScreenDrawable"
    android:resource="@drawable/launch_background" />

  <!-- Theme to apply as soon as Flutter begins rendering frames -->
  <meta-data
    android:name="io.flutter.embedding.android.NormalTheme"
    android:resource="@style/NormalTheme"
    />

  <!-- some code omitted -->
</activity>
  1. <application> 下添加 <meta-data> 标签。
<meta-data
    android:name="flutterEmbedding"
    android:value="2" />

您的应用仍应正常构建(例如通过 flutter build apk 构建),但是您现在正在使用新的 Android 类。

Add-to-app 迁移

本节详细介绍如何使用 Flutter 实验性嵌入构建的 add-to-app 场景,以及如何将该代码转换为 Flutter 新的稳定嵌入。

和 full-Flutter 一样的步骤

上面 Full-Flutter 应用迁移部分中的某些说明仍然适用。 请按照上述步骤操作:

3. 从 application 标签中删除 FlutterApplication 的引用
5. 更新 Splash 页(如果需要初始行为)。
6. 在 <application> 下添加 <meta-data> 标签。

特定于 add-to-app 的更改

如果你调用了 FlutterMain.startInitialization(...) or FlutterMain.ensureInitializationComplete(...),应当删除。Flutter 现在会在适当的时间进行初始化。

迁移 FlutterActivity 使用

Add-to-app 场景通常涉及对 FlutterActivity 子类的修改。 例如,这种情况下可能会引入新的MethodChannel,自定义 FlutterEngine 实例,自定义启动屏幕行为或其他要求覆盖现有方法的行为。 因此,尽管全 Flutter 应用程序可以删除其 MainActivity 并将其替换为标准FlutterActivity,但您将需要保留子类,以便保留行为覆盖。

如果您未修改 FlutterActivity 中的行为,则应删除您的子类,并按照上一节中的描述将其替换为标准的 FlutterActivity

如果你需要修改 FlutterActivity 中的行为,你需要将代码从旧的 io.flutter.app.FlutterActivity 迁移到新的 io.flutter.embedding.android.FlutterActivity

From:

package [your.package.name];

import android.os.Bundle;
import io.flutter.app.FlutterActivity;
import io.flutter.plugins.GeneratedPluginRegistrant;

public class MainActivity extends FlutterActivity {
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    GeneratedPluginRegistrant.registerWith(this);
  }

  // ...some amount of custom code for your app is here.
}

To:

package [your.package.name];

import io.flutter.embedding.android.FlutterActivity;

public class MainActivity extends FlutterActivity {
  // 不再需要重写  onCreate 来调用 GeneratedPluginRegistrant
  // You do not need to override onCreate() in order to invoke
  // GeneratedPluginRegistrant. Flutter now does that on your behalf.

  // ...retain whatever custom code you had from before (if any).
}

一些应用可能需要预热 Flutter 体验,现在建议在初次呈现 Flutter UI 时,所有 add-to-app 的用例都应使 Flutter 预热,以达到最佳视觉效果。参考 Flutter guide for pre-warming a FlutterEngine (TODO: mattcarroll,还没写…) 更新你的代码来预热 Flutter。

您的 FlutterActivity 子类现在已使用最新的、稳定的 Android embedding 了

迁移 FlutterFragment 使用

实验性嵌入提供了一个名为 io.flutter.facade.FlutterFragment 的类,以及io.flutter.facade 包中的其他类。 整个 io.flutter.facade 软件包已被弃用,您不应使用其中的任何类。

实验性的 io.flutter.facade.FlutterFragmentio.flutter.embedding.android.FlutterFragment 所取代,它被设计用于比原始的FlutterFragment 更广泛的用例集合。

如果使用了 Flutter.createFragment(...) 实例化 io.flutter.facade.FlutterFragment,则应删除这样的调用,并通过以下任一方法实例化新的io.flutter.embedding.android.FlutterFragment:

  • FlutterFragment.createDefault()
  • FlutterFragment.withNewEngine()
  • FlutterFragment.withCachedEngine(...)

这些工厂方法的使用已在以下网站的网站指南中进行了深入讨论: flutter.dev.

迁移 FlutterView 使用

已弃用的 io.flutter.facade.Flutter 类具有一个名为 createView(...)的工厂方法,也已弃用,以及 io.flutter.facade 软件包中的所有其他代码。

Flutter目前不提供在View级别使用Flutter的便捷API,因此如果可能,应避免使用 FlutterView。 但是如果需要的话,显示 FlutterView 在技术上是可行的。 确保使用io.flutter.embedding.android.FlutterView 而不是 io.flutter.view.FlutterView。 您可以像其他任何Android View 一样实例化新的 FlutterView。 然后,按照相关Javadocs中的说明通过 FlutterView 显示Flutter。