随着 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;

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
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
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; |
... |
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)
在 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"
}
小擴充
小菜在适配 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 基本完成,下一步是兩者之間的互動;更新适配是一個艱難複雜的過程,可能會有很多意想不到的問題,希望可以沉下心來慢慢解決;如有問題請多多指導!
來源: 阿策小和尚