日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Flutter升级到1.12填坑指南

發布時間:2024/1/23 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Flutter升级到1.12填坑指南 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

最近由于項目需要,需要把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填坑指南的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。