天天看點

Flutter 77: 圖解曆史 Android Native 項目接入 Flutter Module

      随着 Flutter 的逐漸發展與完善,與 Native 結合使用的場景越來越多;小菜今天嘗試将一個曆史的 Android Native 項目接入 Flutter Module;

AndroidX

      Flutter 的發展很迅速,大部分插件均适配 AndroidX,為了今後開發的便利性,小菜優先由如下版本更新适配 AndroidX;

minSdkVersion 17
targetSdkVersion 26

compileSdkVersion 28
buildToolsVersion "28.0.3"           

      小菜以前嘗試過

Flutter 更新适配 AndroidX

,Android 的處理類似,小菜以實際項目嘗試适配;

1. 添加 AndroidX 配置

      在 android/gradle.properties 檔案中添加如下配置:

android.useAndroidX=true
android.enableJetifier=true           
2. Migrate to AndroidX

      小菜通過 Android Studio 中的 Migrate to AndroidX 來配合更新(純手動更新需要修改巨多的檔案),選擇本工程 -> Refactor -> Migrate to Androidx;但小菜目前 Gradle 版本是 3.0.0,此時提示 Gradle 需 >= 3.2.0,故小菜需要先更新 Gradle;

Flutter 77: 圖解曆史 Android Native 項目接入 Flutter Module
3. Gradle 更新

      更新 android/build.gradle 檔案中 Gradle 版本;此時 Sync 同步時會由如下兩個提示;

classpath 'com.android.tools.build:gradle:3.2.0'           

3.1 compile 已經不建議使用,小菜把各個 Module 中 compile 替換為 api / implementation;

Configuration 'compile' is obsolete and has been replaced with 'implementation' and 'api'.
It will be removed at the end of 2018. For more information see: http://d.android.com/r/tools/update-dependency-configurations.html           
Flutter 77: 圖解曆史 Android Native 項目接入 Flutter Module

3.2 小菜的項目中在之前通過 retrolambda 支援 Java8,在 Gradle > 3.0.0 之後預設支援 Java8,小菜将引入去掉即可;

One of the plugins you are using supports Java 8 language features. To try the support built into the Android plugin, remove the following from your build.gradle:
    apply plugin: 'me.tatarka.retrolambda'
To learn more, go to https://d.android.com/r/tools/java-8-support-message.html           
Flutter 77: 圖解曆史 Android Native 項目接入 Flutter Module
4. 重複第二步驟,Migrate to AndroidX

      注意要選擇底部 Do Refactor,會幫我們節省巨大的工作量,隻需要個别的檔案引入或 xml 需要更改,否則需要我們手動修改大量的檔案引入等;

android.support androidx
android.support.annotation.NonNull; androidx.annotation.NonNull;
android.support.annotation.Nullable; androidx.annotation.Nullable;
android.support.annotation.IntRange; androidx.annotation.IntRange;
android.support.design.widget.CoordinatorLayout; androidx.coordinatorlayout.widget.CoordinatorLayout;
android.support.v4.content.ContextCompat; androidx.core.content.ContextCompat;
android.support.v4.widget.DrawerLayout; androidx.drawerlayout.widget.DrawerLayout;
android.support.v4.app.Fragment; androidx.fragment.app.Fragment;
android.support.v4.graphics.drawable.RoundedBitmapDrawable; androidx.core.graphics.drawable.RoundedBitmapDrawable;
android.support.v4.graphics.drawable.RoundedBitmapDrawableFactory; androidx.core.graphics.drawable.RoundedBitmapDrawableFactory;
android.support.v7.widget.RecyclerView; androidx.recyclerview.widget.RecyclerView;
android.support.v7.app.AlertDialog; androidx.appcompat.app.AlertDialog;
...
Flutter 77: 圖解曆史 Android Native 項目接入 Flutter Module
5. Sync 同步打包檢驗

      若有個别 xml 檔案需要調整,按照提示微調即可;debug / release 均需要打包檢驗;到此更新适配 AndroidX 工作基本完成;

Flutter Module

      小菜之前也嘗試過

Android 原生內建 Flutter Module

,小菜組内已有相關的 Flutter 工程,是以不再建立,內建方法很簡單;

1. setting.gradle 中引入 Flutter Module 路徑
setBinding(new Binding([gradle: this]))
evaluate(new File(
        '/Users/user/Documents/workspace/flutter_module02/.android/include_flutter.groovy'
))           
2. app/build.project 中引入 Flutter 依賴
implementation project(':flutter')           
3. Sync 同步後檢驗

      小菜以前整理過

Flutter 與 Android 原生互動

,但為了驗證友善小菜僅提供一個 FlutterActivity 供頁面跳轉即可;

public class FlutterMainActivity extends FlutterActivity {
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }
}           

      小菜未使用 FlutterApplication,此時提示如下問題;

Caused by: java.lang.IllegalStateException: ensureInitializationComplete must be called after startInitialization
    at io.flutter.embedding.engine.loader.FlutterLoader.ensureInitializationComplete(FlutterLoader.java:153)
    at io.flutter.view.FlutterMain.ensureInitializationComplete(FlutterMain.java:80)
    at io.flutter.app.FlutterActivityDelegate.onCreate(FlutterActivityDelegate.java:144)
    at io.flutter.app.FlutterActivity.onCreate(FlutterActivity.java:89)
    at com.test.FlutterMainActivity.onCreate(FlutterMainActivity.java:13)
    at android.app.Activity.performCreate(Activity.java:6367)
    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1110)
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2397)           
Flutter 77: 圖解曆史 Android Native 項目接入 Flutter Module

      在 FlutterMainActivity 中提前初始化後,又提示新的問題;

protected void onCreate(@Nullable Bundle savedInstanceState) {
    FlutterMain.startInitialization(this);
    super.onCreate(savedInstanceState);
}

UncaughtException detected: java.lang.UnsatisfiedLinkError: dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/com.test-2/base.apk", zip file "/data/app/com.test-2/split_lib_dependencies_apk.apk", zip file "/data/app/com.test-2/split_lib_slice_0_apk.apk", zip file "/data/app/com.test-2/split_lib_slice_1_apk.apk"],nativeLibraryDirectories=[/data/app/com.test-2/lib/arm, /data/app/com.test-2/base.apk!/lib/armeabi, /data/app/com.test-2/split_lib_dependencies_apk.apk!/lib/armeabi, .../split_lib_slice_8_apk.apk!/lib/armeabi, /data/app/com.test-2/split_lib_slice_9_apk.apk!/lib/armeabi, /vendor/lib, /system/lib]]] couldn't find "libflutter.so"
    at java.lang.Runtime.loadLibrary(Runtime.java:379)
    at java.lang.System.loadLibrary(System.java:1086)
    at io.flutter.embedding.engine.loader.FlutterLoader.startInitialization(FlutterLoader.java:122)
    at io.flutter.embedding.engine.loader.FlutterLoader.startInitialization(FlutterLoader.java:93)
    at io.flutter.view.FlutterMain.startInitialization(FlutterMain.java:45)
    at com.test.FlutterMainActivity.onCreate(FlutterMainActivity.java:14)           

      小菜查詢後發現目前項目 NDK 隻支援 armeabi 架構,而 Flutter 支援的時 armeabi-v7a,加入之後檢驗;若項目有特殊要求 NDK 必須是 armeabi 時,可考慮将 armeabi-v7a 的 flutter.so 拷貝到項目中;

ndk {
    abiFilters "armeabi", "armeabi-v7a", "x86"
}           
Flutter 77: 圖解曆史 Android Native 項目接入 Flutter Module

小擴充

      小菜在适配 AndroidX 過程中還遇到如下問題,并非所有項目涉及,記錄僅供參考;

Q1:All flavors must now belong to a named flavor dimension.

      小菜更新 Gradle 之後進行多管道打包時會提示如下錯誤;

FAILURE: Build failed with an exception.
* What went wrong:
A problem occurred configuring project ':app'.
> All flavors must now belong to a named flavor dimension. Learn more at https://d.android.com/r/tools/flavorDimensions-missing-error-message.html
* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.
* Get more help at https://help.gradle.org
BUILD FAILED in 0s           
A1:

      Gradle > 3.0 時多管道打包需要指定一種 flavor dimensions;其中建議不要直接使用 main 的名稱,否則容易出現新的重複鍵問題;com.android.build.gradle.internal.api.artifact.BuildableArtifactImpl

// 修改前
productFlavors {
  test1 {}
  test2 {}
  main {}
}
// 修改後
flavorDimensions "main"
productFlavors {
  test1 { dimension "main" }
  test2 { dimension "main" }
  main0 { dimension "main" }
}           
Q2:com.android.builder.dexing.DexArchiveBuilderException

      小菜在運作過程中還提示 DexArchiveBuilderException 錯誤;

com.android.builder.dexing.DexArchiveBuilderException           
A2:

      小菜查閱是未指定 Java8 的問題,添加指定 1.8 即可;

compileOptions {
    sourceCompatibility 1.8
    targetCompatibility 1.8
}           
Q3:Unable to find method '...getOutputs()Ljava/util/List'
Error:Unable to find method 'com.android.build.gradle.api.BaseVariant.getOutputs()Ljava/util/List;'.
Possible causes for this unexpected error include:<ul><li>Gradle's dependency cache may be corrupt (this sometimes occurs after a network connection timeout.)
<a href="syncProject">Re-download dependencies and sync project (requires network)</a></li><li>The state of a Gradle build process (daemon) may be corrupt. Stopping all Gradle daemons may solve this problem.           
A3:

      小菜幾經查證後發現是 ButterKinfe 版本較低,是以更新至支援 AndroidX 的 10.2.1 的最新版本即可;注意,此時需要 Java8 環境;

dependencies {
  implementation 'com.jakewharton:butterknife:10.2.1'
  annotationProcessor 'com.jakewharton:butterknife-compiler:10.2.1'
}           

      至此,小菜的曆史項目更新适配 AndroidX 并接入 Flutter Module 基本完成,下一步是兩者之間的互動;更新适配是一個艱難複雜的過程,可能會有很多意想不到的問題,希望可以沉下心來慢慢解決;如有問題請多多指導!

來源: 阿策小和尚

繼續閱讀