最近由于项目需要,需要把flutter升级到stable版本,目前的stable版本是1.12.13的hotfix,而我们项目目前的版本是1.7.3。Google在发布flutter 1.12对Android做了不少改动,只能说官方的指南都是一些非常基础的,很多使用细节都不完整。这里总结一下我升级遇到的一些问题。


相关参考链接

  • 官方新版插件api介绍
  • 官方提供的升级1.12指南
  • 官方注册methodChannel方法
  • 其他作者升级1.12指南

1.去除FlutterApplication

1.12版本整个flutter的engine,已经不在FlutterApplication中去初始化了,所以只需要把项目的FlutterApplication改回原生的Application即可。

官方介绍:

If you invoke FlutterMain.startInitialization(...) or
FlutterMain.ensureInitializationComplete(...) anywhere in your code, you should
remove those calls. Flutter now initializes itself at the appropriate time.

也就是说如果你代码中有调用FlutterMain.startInitialization(...)方法,需要去除。FlutterApplication中的onCreate方法实际上也调了这个方法。

2. io.flutter.facade包已移除,flutterView不再建议使用

//官方介绍
The deprecated io.flutter.facade.Flutter class has a factory method called
createView(...). This method is deprecated, along with all other code in theio.flutter.facade package.Flutter does not currently provide convenient APIs for utilizing Flutter at the View
level, so the use of a FlutterView should be avoided, if possible. However, it is
technically feasible to display a FlutterView, if required. Be sure to use
io.flutter.embedding.android.FlutterView instead of io.flutter.view.FlutterView.
You can instantiate the new FlutterView just like any other Android View. Then,
follow instructions in the associated Javadocs to display Flutter via a
FlutterView.

大概意思就是说io.flutter.facade这个包没啦,要避免使用FlutterView。这个点倒是慢慢和ios靠近了。

3.FlutterActivity的相关修改

官方新版启动FlutterActivity文档

3.1 FlutterActivity包路径修改

//import io.flutter.app.FlutterActivity;
import io.flutter.embedding.android.FlutterActivity;

3.2 修改启动FlutterActivity方法

根据官方的介绍

startActivity(FlutterActivity.withNewEngine().initialRoute("/my_route").build(currentActivity));

如果你的项目没有继承FlutterActivity,那只需要按照官方新的启动方法启动即可。但是一般项目都需要埋点啥的,肯定会继承FlutterActivity。按照官方的方式,你永远启动的都是FlutterActiivty,而不是自己写的子类。咋办呢,只好从源码入手。

//FlutterActivity部分源码
.....@NonNullpublic static NewEngineIntentBuilder withNewEngine() {return new NewEngineIntentBuilder(FlutterActivity.class);}.....protected NewEngineIntentBuilder(@NonNull Class<? extends FlutterActivity> activityClass) {this.activityClass = activityClass;}.....@NonNullpublic Intent build(@NonNull Context context) {return new Intent(context, activityClass).putExtra(EXTRA_INITIAL_ROUTE, initialRoute).putExtra(EXTRA_BACKGROUND_MODE, backgroundMode).putExtra(EXTRA_DESTROY_ENGINE_WITH_ACTIVITY, true);}

可以看出这个withNewEngine方法传的一直都是FlutterActivity.class,然后new一个NewEngineIntentBuilder,那我自己new一个NewEngineIntentBuilder传入子类不就好了吗?
成功报错:

原因是NewEngineIntentBuilder的构造函数是protected,不是子类没法直接new。那只好继承NewEngineIntentBuilder这个类,重写它的构造函数了。最终代码如下:

public class MyFlutterActivity extends FlutterActivity {public static NewMyEngineIntentBuilder withNewEngine(Class<? extends FlutterActivity> activityClass) {return new NewMyEngineIntentBuilder(activityClass);}//重写创建引擎方法public static class NewMyEngineIntentBuilder extends NewEngineIntentBuilder{protected NewMyEngineIntentBuilder(Class<? extends FlutterActivity> activityClass) {super(activityClass);}

调用:

Intent intent = MyFlutterActivity.withNewEngine(MyFlutterActivity.class).initialRoute("/my_route").build(context);context.startActivity(intent);

3.3 启动transparency透明FlutterActivity的超级大坑

项目中之前有需求要把FlutterActivity弄成透明的,之前的做法是activity设置透明,再拿到flutterView设置透明。现在拿不到flutterView咋办,官方倒是贴心,有直接设置FlutterActivity。如下:

<!-- 设置activity透明属性  -->
<style name="MyTheme" parent="@style/MyParentTheme"><item name="android:windowIsTranslucent">true</item>
</style>
startActivity(FlutterActivity.withNewEngine().backgroundMode(FlutterActivity.BackgroundMode.transparent)//设置backgroundMode.build(context)
);

这也太方便了吧,可以一用发现FlutterActivity并没有这个属性,一用就报错。但是在FlutterActivityLaunchConfigs发现了这个属性,可惜类声明不是public,压根调不到啊,坑爹。

package io.flutter.embedding.android;class FlutterActivityLaunchConfigs {....../*** The mode of the background of a Flutter {@code Activity}, either opaque or transparent.*/public enum BackgroundMode {/** Indicates a FlutterActivity with an opaque background. This is the default. */opaque,/** Indicates a FlutterActivity with a transparent background. */transparent}private FlutterActivityLaunchConfigs() {}
}

查看官方的issue显示这个已经fix了,但是好像并没有合到stable分支上。官方提交
最后参考了issue下面的回答解决了这个问题。查看源码其实FlutterActivity会接受Intent中的参数background_mode,只需要传入一样的“ transparent”,也能达到效果。
最终代码:

Intent intent = MyFlutterActivity.withNewEngine(MyFlutterActivity.class).initialRoute("/my_route").build(context);//主要加入这句话intent.putExtra("background_mode","transparent");context.startActivity(intent);

3.4 新增启动FlutterActivity过渡的图片

这步是为了启动了FlutteActivity后加载flutter过程中显示的图片,没设置一般是白屏或者黑屏。
如果你之前设置了android:name="io.flutter.app.android.SplashScreenUntilFirstFrame".需要移除掉
新设置如下:

<!-- 在所在的activity中加入 -->
<meta-dataandroid:name="io.flutter.embedding.android.SplashScreenDrawable"android:resource="@mipmap/normal_background" />

4.MethodChannel注册改动

首先在application下加入:

<meta-dataandroid:name="flutterEmbedding"android:value="2" />

声明完后插件的注册就使用FlutterEngine而不是以前的PluginRegistry.Registrar。

4.1 注册第三方插件的修改

之前注册方式:

    protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);//升级后这句话会报错GeneratedPluginRegistrant.registerWith(this);}

升级后registerWith的入参已经改为FlutterEngine,只需要做如下修改即可:

    @Overridepublic void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {GeneratedPluginRegistrant.registerWith(flutterEngine);}

4.2 修改自定义的MethodChannel注册

官方介绍的写法:

@Overridepublic void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {GeneratedPluginRegistrant.registerWith(flutterEngine);new MethodChannel(flutterEngine.getDartExecutor().getBinaryMessenger(), CHANNEL).setMethodCallHandler((call, result) -> {// Note: this method is invoked on the main thread.// TODO});}

但是我的项目已经分了模块化,每个channel都写好了静态方法registerWith(PluginRegistry registry)。于是乎参考了GeneratedPluginRegistrant.registerWith(flutterEngine);里面的方法:

public final class GeneratedPluginRegistrant {public static void registerWith(@NonNull FlutterEngine flutterEngine) {//关键在这句,把flutterEngine,转为了shimPluginRegistry,而shimPluginRegistry是PluginRegistry的子类ShimPluginRegistry shimPluginRegistry = new ShimPluginRegistry(flutterEngine);com.example.flutterimagecompress.FlutterImageCompressPlugin.registerWith(shimPluginRegistry.registrarFor("com.example.flutterimagecompress.FlutterImageCompressPlugin"));com.example.flutterautotext.FlutterautotextPlugin.registerWith(shimPluginRegistry.registrarFor("com.example.flutterautotext.FlutterautotextPlugin"));com.github.adee42.keyboardvisibility.KeyboardVisibilityPlugin.registerWith(shimPluginRegistry.registrarFor("com.github.adee42.keyboardvisibility.KeyboardVisibilityPlugin"));io.flutter.plugins.localauth.LocalAuthPlugin.registerWith(shimPluginRegistry.registrarFor("io.flutter.plugins.localauth.LocalAuthPlugin"));io.flutter.plugins.packageinfo.PackageInfoPlugin.registerWith(shimPluginRegistry.registrarFor("io.flutter.plugins.packageinfo.PackageInfoPlugin"));io.flutter.plugins.pathprovider.PathProviderPlugin.registerWith(shimPluginRegistry.registrarFor("io.flutter.plugins.pathprovider.PathProviderPlugin"));io.flutter.plugins.sharedpreferences.SharedPreferencesPlugin.registerWith(shimPluginRegistry.registrarFor("io.flutter.plugins.sharedpreferences.SharedPreferencesPlugin"));com.tekartik.sqflite.SqflitePlugin.registerWith(shimPluginRegistry.registrarFor("com.tekartik.sqflite.SqflitePlugin"));io.flutter.plugins.urllauncher.UrlLauncherPlugin.registerWith(shimPluginRegistry.registrarFor("io.flutter.plugins.urllauncher.UrlLauncherPlugin"));}
}

所以也参考着生成一个ShimPluginRegistry,传到我的每个registerWith方法中,目前使用没啥问题,但感觉不是最佳方案。

4.3 FlutterPlugin和ActivityAware

按照官方这次更新的方法,新的插件除了需要继承MethodCallHandler接口,还是需要继承FlutterPlugin接口,而ActivityAware是用于 Activity 的生命周期管理和获取,这个优势在于为插件所依赖的生命周期提供了一套更解耦的使用方法,只有Flutter插件Attach到引擎时才初始化,所以需要实现下面两个方法:


public class MyPlugin implements FlutterPlugin {@Overridepublic void onAttachedToEngine(@NonNull FlutterPluginBinding binding) {// TODO: your plugin is now attached to a Flutter experience.}@Overridepublic void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {// TODO: your plugin is no longer attached to a Flutter experience.}
}

但是我研究了下,MyPlugin这个类在哪里初始化呢?怎么让这个插件和某个FlutterActivity关联呢?有知道的小伙伴麻烦告诉我一下~

5.FlutterFragment修改

官方新版添加FlutterFragment文档

5.1FlutterFragment包路径修改

我们项目混合了原生Fragment和FlutterFragment,首先要保证你的FlutterFragment包路径是对的:

import io.flutter.embedding.android.FlutterFragment;

5.2 如何创建FlutterFragment

官方使用:

FlutterFragment flutterFragment = FlutterFragment.withNewEngine().build();

依然很简单,但是不可能满足我们的需要,和FlutterActivity一样,我们还是会写一个子类去继承FlutterFragment,同样的直接调用withNewEngine()启动的永远都是FlutterFragment,继续查看源码:

 public NewEngineFragmentBuilder() {fragmentClass = FlutterFragment.class;}/*** Constructs a {@code NewEngineFragmentBuilder} that is configured to construct an instance of* {@code subclass}, which extends {@code FlutterFragment}.*/public NewEngineFragmentBuilder(@NonNull Class<? extends FlutterFragment> subclass) {fragmentClass = subclass;}

在FlutterFragment里面竟然是public的,真的是让人摸不着头脑,那这样就很好修改了,最终代码:

        NewEngineFragmentBuilder newEngineFragmentBuilder = new NewEngineFragmentBuilder(MyFlutterFragment.class);newEngineFragmentBuilder.initialRoute("/myRoute");MyFlutterFragment myFlutterFragment = newEngineFragmentBuilder.build();

5.3 FlutterFragment两种渲染模式

之前的FlutterView都是SurfaceView的子类,虽然说性能高,但是偶尔会出现一些视图层级的bug。升级后FlutterFragment支持另一种渲染方式,TextureView。FlutterFragment默认是创建SurfaceView,如果你想改为TextureView只需要如下操作:

FlutterFragment flutterFragment = FlutterFragment.withNewEngine().renderMode(FlutterView.RenderMode.texture).build();

5.4 FlutterFragment显示过渡图片

和FlutterActivity一样,FlutterFragment在加载flutter时也支持增加过渡图片显示

public class MyFlutterFragment extends FlutterFragment {@Overrideprotected SplashScreen provideSplashScreen() {// Load the splash Drawable.Drawable splash = getResources().getDrawable(R.drawable.my_splash);// Construct a DrawableSplashScreen with the loaded splash Drawable and// return it.return new DrawableSplashScreen(splash);}
}

6.flutter出现黑屏无法显示

如果改完之后发现flutter页面是黑屏,没有任何显示,则需要在flutter的main函数中,runApp前调用如下方法即可:

void main() {WidgetsFlutterBinding.ensureInitialized();runApp(MyApp());
}

7.其他坑

7.1建议升级到AndroidX

一开始没有升级androidX,升级到Flutter后编译出现support包冲突,咬咬牙把整个项目都升级到AndroidX,竟然解决了。而且官方也建议使用AndroidX,长痛不如短痛,建议都升到AndroidX,具体怎么升这里就不详细介绍了。

7.2 flutter中.android还是使用support包的问题

在升级完AndroidX后,发现flutter下的.android中GeneratedPluginRegistrant.java还是使用support包,这个文件是通过指令生成的,导致一开始需要修改包的引用为AndroidX:

//这个两个类需要修改为androidX
import androidx.annotation.Keep;
import androidx.annotation.NonNull;

其实官方文档有相关介绍,只需要在pubspec.yaml中增加:

module:...androidX: true // Add this line.

然后执行flutter clean,重新build一下就OK了

链接:https://www.jianshu.com/p/24b9b3e702a4

Flutter升级到1.12填坑指南相关推荐

  1. 开发工具总结(2)之全面总结Android Studio2.X的填坑指南

    前言:好多 Android 开发者都在说Android Studio太坑了,老是出错,导致开发进度变慢,出错了又不知道怎么办,网上去查各种解决方案五花八门,有些可以解决问题,有些就是转来转去的写的很粗 ...

  2. alert点击确定后跳转_公众号/h5 跳转到小程序填坑指南

    公众号/h5 跳转到小程序填坑指南 本文介绍的是使用微信开放标签 wx-open-launch-weapp 实现微信浏览器内网页跳转到任意合法合规的小程序里,官方要求微信版本为:7.0.12 及以上, ...

  3. Redmine3.3.3 搭建与不完全填坑指南

    为什么80%的码农都做不了架构师?>>>    Redmine3.3.3 搭建与不完全填坑指南 [TOC] 概要 Redmine3.3.3 搭建.不完全填坑指南.不联网安装.Wind ...

  4. 开发工具总结(4)之Android Studio3.0填坑指南

    序言 Android Studio 3.0 上篇讲了: 全面总结Android Studio2.X的填坑指南 这篇讲一下AS3.0的坑.. 作为这个世界上走在最前沿的生物"猿",怎 ...

  5. Android Studio 填坑指南

    前几天发布了一篇名为<Android Studio 安装.配置及第一个程序演示>的博文,有不少童鞋都认真阅读过并照步骤一步一步操作了一遍,有滴如期成功地装好了,然鹅有滴反映说这不对呀,为森 ...

  6. 第二篇:salt-api使用填坑指南

    前言 salt-api在使用时,有些坑欲哭无泪,一路趟雷过后,总结了一趟salt-pai使用填坑指南,保君一路畅通. salt-api 安装 #本文的安装版本 2018.3.2-1.el6 yum i ...

  7. KKBOX音乐——数据分析,用户研究与填坑指南

    KKBOX音乐--数据分析,用户研究与填坑指南 导语 1 数据来源 2 数据处理 2.1 录入数据 2.2 数据类型 3 探索性分析 3.1 MySQL+Excel 3.1.1 每年3月最先注册的前1 ...

  8. NW.JS填坑指南(解决Flash插件、视频播放等故障)

    目录 NW.JS填坑指南 NW.js是什么? NW.js 和 electron的选择 开发工具IDE 下载nwjs 版本信息 简单的实例 改图标 改合成exe的图标 改图标第二种方案是 播放不了视频 ...

  9. python find函数_Python 装饰器填坑指南 | 最常见的报错信息、原因和解决方案

    本文为霍格沃兹测试学院学员学习笔记,进阶学习文末加群. Python 装饰器简介 装饰器(Decorator)是 Python 非常实用的一个语法糖功能.装饰器本质是一种返回值也是函数的函数,可以称之 ...

最新文章

  1. 服务器上安装n点虚拟主机,N点虚拟主机管理系统之①-运行N点
  2. lollipods耳机蓝牙连接方法
  3. 【Android】人体图片、地图图片、热力图,如何实现点击不同的部位执行不同的操作?...
  4. .NET gRPC核心功能初体验
  5. Carrier Configuration in Android 6.0 文档翻译
  6. 144Hz和60Hz显示器差别很大吗?
  7. UE4之TextureSample
  8. Mysql联表查询(学生表、教师表、成绩表、课程表)
  9. tomcat连接mysql数据库_tomcat连接常用数据库的用法
  10. 关于软件注册问题的讨论
  11. Verilog 时钟分频
  12. jsp汽车销售系统带前端
  13. 信息系统项目管理知识--项目立项管理
  14. 名图怎么弄云服务器_“双车”战略,名图如何驱动新兴细分市场
  15. MG7780打印机喷嘴堵塞
  16. 游戏服务器之存档读档
  17. int、dev、uat、prod、pp、sit、ides、qas、pet、sim、zha环境是什么
  18. 转:openCV基础图像处理
  19. Android 内核加载fw通用方法分析
  20. mysql 查询分析工具下载_SQL分析工具下载-SQL查询工具(DB Solo)下载v5.2.5官方版-西西软件下载...

热门文章

  1. mem库系列函数合集(memset、memchr、memcmp、memcpy)
  2. linux-压缩和解压类
  3. 大话synchronize底层原理
  4. java pdfbox 解析报错_pdfbox 读取文件报错 java.io.IOException: Page tree root must be a dictionary...
  5. linux笔记之 搭建本地yum源,网卡的基本操作
  6. php转字,php汉字如何转数字
  7. git 只commit不push 会有影响吗_规范化团队 git 提交信息
  8. android.process.media+sd,android P系统WRITE_MEDIA_STORAGE添加读写SD卡权限
  9. 7月5日服务器临时维护更新公告,7月7日临时维护公告
  10. python web为什么不火_如何用纯 Python 写交互式 Web 应用?