专栏首页阿策小和尚【Flutter 专题】77 图解历史 Android Native 项目接入 Flutter Module

【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[1],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 已经不建议使用,和尚把各个 Modulecompile 替换为 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[2],和尚组内有相关的 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 同步后检验

和尚以前整理过 FlutterAndroid 原生交互[3],但为了验证方便和尚仅提供一个 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 版本较低,因此升级至支持 AndroidX10.2.1 的最新版本即可;注意,此时需要 Java8 环境;

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

至此,和尚的历史项目升级适配 AndroidX 并接入 Flutter Module 基本完成,下一步是两者之间的交互;升级适配是一个艰难复杂的过程,可能会有很多意想不到的问题,希望可以沉下心来慢慢解决;如有问题请多多指导!

来源:阿策小和尚

References

[1] Flutter 升级适配 AndroidX: https://www.jianshu.com/p/601eb858d507 [2] Android 原生集成 Flutter Module: https://www.jianshu.com/p/aab477e49ce4 [3] FlutterAndroid 原生交互: https://www.jianshu.com/p/22939eaa47b1

本文分享自微信公众号 - 阿策小和尚(gh_8297e718c166),作者:阿策小和尚

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-02-22

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 【Flutter 专题】75 图解基本 TabBar 标签导航栏 (一)

    分析源码可得,TabBar 与 TabBarView 是配对使用的,其对应的 Tab 数量必须相同;其中 TabBar 中提供了众多相关指示器属性,...

    阿策
  • Android 仅四步,实现更改包名,屡试不爽

    和尚我很久以前在简书上发表过一篇《Android 更改包名,屡试不爽》的文章,现在用的多了,发现步骤可以更简单,分享给大家。 虽然不是啥...

    阿策
  • Android Gradle 2.3.3 升级 3.0.1 小记录

    和尚因为种种原因需要升级 Android Gradle,Gradle > 3.0 时默认支持 Java 8;每次大版本升级都会涉及很多内容,和尚尽可...

    阿策
  • java.lang.reflect.InaccessibleObjectException: Unable to make

    java.lang.reflect.InaccessibleObjectException: Unable to make ...

    一个会写诗的程序员
  • java.sql.SQLException: connection holder is null

    java.sql.SQLException: connection holder is null

    一个会写诗的程序员
  • 【R语言进行数据挖掘】数据探索

    这一章我们将会用到‘iris’(鸢尾花)数据集,这个数据集属于R中自带的数据,因此不需要额外的加载。首先,查看数据的维度和结构,使用函数dim()和names(...

    统计学家
  • Android解决“java.lang.IllegalArgumentException: You cannot start a load for a destroyed activity”问题方案

    最近在友盟收集的错误列表中,发现有个问题使得蛮多用户闪退的。根据错误信息定位到,是由于图片轮播控件com.youth.banner使用Glide异步加载图片时发...

    SoullessCoder
  • java:如何让程序按要求自行重启?

    正文开始前的废话: 这里的程序即包括b/s的web application,也包括standalone的类c/s的java application。 为什么要自...

    菩提树下的杨过
  • linux学习第四十七篇:Nginx负载均衡,ssl原理,生产ssl密钥对,Nginx配置ssl

    Nginx负载均衡 负载均衡,将用户的所有HTTP请求均衡的分配到每一台机器上,充分发挥所有机器的性能,提高服务的质量和用户体验。 ? vim /usr/l...

    用户1215343
  • java:如何让程序按要求自行重启?

    正文开始前的废话: 这里的程序即包括b/s的web application,也包括standalone的类c/s的java application。 为什么要自...

    菩提树下的杨过

扫码关注云+社区

领取腾讯云代金券