FlutterSDK升级后与原生交互-android

前言:简书菜鸟一枚,主要用于记录。如有侵权,望告知,我会下架文章。

Flutter发展快速现在的稳定版已经是1.20.2了。而且我前同事跳槽去做flutter专职了,这是一个有钱景的技术。之前我们公司APP接入FlutterModule还是在他主导的,技术着实厉害,是我入坑引导人。不过我们当时接入Flutter时,SDK才1.9.1.现在都好几个大版本更新了。所以我最近想要升级一下SDK,我现在的是1.17.5。

一、升级SDK常用方式:

1.命令:执行 flutter upgrade 常用:
在已配置好Flutter环境的情况下在终端、编辑器都可执行命令;
也可以执行git 命令先拉去stable分支,然后选定回滚到指定版本[在GitHub找]。
2.下载最新或者对应版本的压缩包解压替换。[我最近买了未拆封2018款Mac,这也是我想要升级SDK的原因之一,新电脑还用旧的SDK ? 不!,所以我新下载了SDK,也简单说一下我的Mac配置环境过程,Mac新手也记录了一下基础Mac使用]。

二、Mac 配置Flutter

参考:https://flutter.dev/docs/development/tools/sdk/releases?tab=macos#macos
https://zhuanlan.zhihu.com/p/71854245等等
1.下载SDK:git clone -b stable https://github.com/flutter/flutter.git
GitHub不稳定,经常clone失败【受阻】。
后来发现打开SDK官网https://flutter.dev/docs/development/tools/sdk/releases?tab=macos#macos。直接下载zip还更好一些。
在GitHub搜索flutter,去到flutter项目详情页,Documentation 目录下的 Install Flutter->macOS->Get the Flutter SDK 目录【有一个zip,就是stable分支最新的SDK,也可以选择 SDK archive(档案),去查看更多的SDK 版本与分支,选择自己想要的然后下载,注:下载有时也不稳定,不需翻墙,过一会再试即可。】下载好zip后放到自定义的文件夹,如SDK_FLutter。进入到该文件夹,Mac中打开(双击)zip即解压。
2.配置环境:
终端(window中我习惯叫控制台,// 代表注释,用于记录)
cd ~ // 回到Mac用户root目录
vim ~/.bash_profile // 在终端打开并编辑.bash_profile文件,输入文件开始几个字母就可以按tab键"->|"自动拼全。
英文输入下按 i ,进入编辑模式;

flutter_pzhj@2x.png

添加好后点击esc退出编辑模式,然后输入:wq退出文件编辑返回终端命令,
执行 source ~/.bash_profile 使刚配置的环境生效。
执行flutter --help 试试。有多行命令样例出来就是配置好环境了。类似command not found 就代表配置失败。配好后执行flutter doctor 检查flutter开发条件,会有对应编辑器的提示。就不再说了。

三、SDK升级后

参考:注:参考地址容易打不开timeout,不是需要翻墙。经实验:打开失败后切换网络再次打开容易成功打开。
activity:https://flutter.dev/docs/development/add-to-app/android/add-flutter-screen
fragment:https://flutter.dev/docs/development/add-to-app/android/add-flutter-fragment?tab=add-fragment-kotlin-tab
重大改动:以前的Flutter.CreateView()在SDK1.12开始已弃用,不再建议使用FlutterView。所以使用了Flutter module的Android项目需要对应整理代码适配。其实弄完这个交互模块后给我的感觉就是:
Native与Flutter的对接桥梁变了,以前是用Flutter.CreateView()的FlutterView,将该FlutterView,add到布局后,原生就可以通过这个桥梁打开Flutter的lib下的main.dart的main()方法【这个方法是flutter项目/内容的入口】从而将flutter代码用到了项目中。现在的SDK改变了内部封装,将桥梁换成FlutterActivity和FlutterFragment,在使用上多了个划分、解耦、更便捷了。对与跳转到纯Flutter页面可以使用FlutterActivity即可,对相应的生命周期回调处理也相对方便直接,甚至不需更多交互的页面可以一个语句几行代码搞定。对应的FlutterFragment的使用场景与之前的FlutterView比较像。其实最赞的应该是FlutterEngine的变化,现在版本使用FlutterEngine能有秒启动页面的效果速度几近原生。以下是一些较具体的说明及使用样例,其实也是按照上述两个参考地址摘录出来的[/大写的尴尬]。

1.FlutterActivity

步骤1.将FlutterActivity在Manifest.xml清单文件中注册,就像我们的MainActivity一样,至于其中的theme、softInputMode等属性根据需求自己去增添就好。参考资料的代码:

<activity
  android:name="io.flutter.embedding.android.FlutterActivity"
  android:theme="@style/自己的Theme"
  android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
  android:hardwareAccelerated="true"
  android:windowSoftInputMode="adjustResize"
  />

步骤2.启动Flutter页面。
(1) 直接启动默认路由“/”的页面:

context.startActivity(FlutterActivity.createDefaultIntent(currentActivity))

(2) 启动指定路由“page00”的页面:

startActivity( FlutterActivity.withNewEngine().initialRoute("page00").build(context))

(3) 使用FlutterEngine,神器,推荐使用,
注意:提前创建好FlutterEngine并设置对应路由,不设置默认“/”,然后放到FlutterEngineCache中。一般在自己程序入口即自定义的XXApplication【记得在manifest.xml中引用一下】的onCreate中;本着减少APP启动初始好消耗,优化加速启动过程的想法,我试了一下在子线程中创建,但报错了,报错信息明确了要在main线程中初始化。这本来也是很轻量级的,那就继续放在application了。代码如下:

override fun onCreate() {
        super.onCreate()
        // 初始化Engine
        var flutterEngine = FlutterEngine(this)
        // + 配置一个初始路由:
        flutterEngine.navigationChannel.setInitialRoute("/")
        // 预执行dart入口代码,其实这时已经在执行了dart的部分初始化流程了。所以引用CacheEngine不能动态更改路由,改用NewEngine。
        flutterEngine.dartExecutor.executeDartEntrypoint(DartExecutor.DartEntrypoint.createDefault())
        // 存入FlutterEngineCache【类似一个全局Map】便于管理
        FlutterEngineCache.getInstance().put("自定义key1",,flutterEngine)
        // 通过 key-value的方式理论上可以添加多个CacheEngine 经验证有效
        var flutterEngine2 = FlutterEngine(this)
        flutterEngine2.navigationChannel.setInitialRoute("page01")
        flutterEngine2.dartExecutor.executeDartEntrypoint(DartExecutor.DartEntrypoint.createDefault())
        FlutterEngineCache.getInstance().put("自定义一个key2",flutterEngine2)

    }

使用:

startActivity(FlutterActivity.withCachedEngine("自定义key1").build(currentActivity));

(4) 背景主题,有时候Activity间跳转切换需要过渡动画可能用上。或者能视觉穿透的Activity层叠【公司项目中旧代码有出现过一个独立软键盘输入Activity上半部分全透明的层叠在一个有输入框的Activity上】。
· 在style.xml资源文件中增加对应的主题如:

<style name="MyTheme" parent="@style/MyParentTheme">
  <item name="android:windowIsTranslucent">true</item>
</style>

然后在mainfest.xml中注册FlutterActivity时使用该theme。即加属性:android:theme="@style/MyTheme"
· FlutterActivity构建(build)intent时使用.backgroundMode(FlutterActivity.BackgroundMode.transparent) 。如:

startActivity(FlutterActivity
    //.withNewEngine() // 新Engine
    .withCachedEngine("自定义key1") // 缓存Engine
    .backgroundMode(FlutterActivity.BackgroundMode.transparent) // 透明模式
    .build(context)
);

贼坑,昨晚补充的两个点不见了。。。20200901。仅有的创造(记录)激情也没有了!!!!
看了一下浏览器记录这是个大坑。。。我是昨晚凌晨1点左右完成的,然后居然没有简书的浏览记录!!!估计是我没关电脑、浏览器的原因。。。。
当然这也让我意识到记录的重要性。我已经记不清我昨晚具体写的内容量了。所以笔记记录是非常必要的!!!!

2.Fragment

FlutterFragment,我们先来看看应用场景,与普通Fragment、WebView应用场景一样。我一直对Fragment的使用有着一个主观认知:是一个带有生命周期的View,有初始化过程和销毁过程,能更合理、高效配置数据与资源回收。类比一下WebView,我发现其实他们也是有着共同点的,一个承载Web页面、一个承载Flutter页面,他们都是原生与第三方页面的通信桥梁。其中webview会设置WebViewClient、WebChromeClient等界定一定的基础通信,还可以使用addJavascriptInterface(mBaseWebDecorator, "Android")来拓展交互。而FlutterFragment则是由现在版本封装在底层的NativeChannel、和之前版本创建FlutterView时传入的Lifecycle,来界定一些生命周期同信,当然也有其他界定同信,也可以自定义Channel来拓展交互【这个稍晚一些抽时间也弄个文章记录一下】。以下来点简单事例:
(1)路由等设置为默认的方式:

 // 默认方式,直接打开flutter module中的main的runapp()且默认路由"/"
 // flutterFragment 全局变量,R.id.flutter02_flContent布局中承载fragment的FrameLayout,
 // TAG_FRAGMENTFragment知识用于复用Fragment
  flutterFragment = FlutterFragment.createDefault()
  supportFragmentManager.beginTransaction()
      .add(R.id.flutter02_flContent, flutterFragment!!, TAG_FRAGMENT)
      .commit()

(2)使用FlutterEngineCache、(3)使用newEngine、主题等于FlutterActivity的基本一样就不再一一举例了,可参考项目源码。这里说一下我在事例中发现的一个奇怪点:TransparencyMode 透明模式。[Demo中的Flutter02Activity.kt、DefaultPage.dart]
布局:

 <View
        android:layout_width="match_parent"
        android:layout_height="150dp"
        android:background="#F40B0B"
        app:layout_constraintTop_toTopOf="parent"
        android:layout_marginTop="50dp"/>
    <FrameLayout
        android:id="@+id/flutter02_flContent"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:background="#00D8D8D8"
        android:padding="50dp"
        app:layout_constraintTop_toBottomOf="@id/flutter02_tvTitle"
        app:layout_constraintBottom_toBottomOf="parent"
        />
    <Button
        android:layout_width="match_parent"
        android:layout_height="75dp"
        app:layout_constraintBottom_toBottomOf="parent"
        android:layout_marginBottom="50dp"
        android:text="底部按钮"
        />

现象:图1.TransparencyMode.transparent:
7A0C7ABBD3BD8BB1FE662A9BC8F3499E.jpg

图2:TransparencyMode.opaque


4697D1389340318D31976236850FF0BD.jpg
lutterFragment = FlutterFragment.withNewEngine()
                   // opaque 会根据布局的层叠次序,但是Flutter内容的透明无效。transparent 不安层叠次序,Flutter透明有效。
               .transparencyMode(TransparencyMode.transparent) // // 我目前的SDK版本已经不需要设置了。没有不同。
               .shouldAttachEngineToActivity(false)
               // 是否把引擎绑定到宿主Activity,即通过引擎是否可以交互,默认是true。如何交互,继续学习
               .build()
           supportFragmentManager.beginTransaction()
               .add(R.id.flutter02_flContent,flutterFragment!!, TAG_FRAGMENT)
               .commit()

即:opaque 会根据布局的层叠次序,但是Flutter内容的透明无效。transparent 不安层叠次序,默认在最上层,Flutter内容透明有效。

3.对应依赖(插件)的升级。

SDK升级后再跑一下之前的项目可能会遇到这样的bug:

The plugin `fluttertoast` is built using an older version of the Android plugin API 

这是执行一下:flutter pub upgrade 可以看到有多少插件需要升级,可以选择去插件库https://pub.flutter-io.cn/packages/ 【能搜索】查看对应的合适版本,或者再执行一下:flutter pub outdated 看到对应的版本状态。然后修改pubspec.yaml文件中的依赖就好。

父目录:first_module walke$ flutter pub outdated
Dependencies         Current   Upgradable  Resolvable  Latest   
fluttertoast         *3.1.3    *3.1.3      7.0.4       7.0.4  
...
最后:附上源码地址:

Android:Learning/KtPractice/app/src/main/java/com/walke/ktpractice/with_flutter/
Flutter:Learning/Flutter/Module/first_module/lib/

最近才开始写文章,如有相同,纯属意外,无意侵权,望告知。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,222评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,455评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,720评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,568评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,696评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,879评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,028评论 3 409
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,773评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,220评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,550评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,697评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,360评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,002评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,782评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,010评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,433评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,587评论 2 350