关于Flutter和Android混合开发maven方式打包引用调用-有更新,见底部

 

参考Flutter:https://www.jianshu.com/p/cf7cf1b640ee,https://blog.csdn.net/u010479969/article/details/90671463

参考Nexus:https://blog.csdn.net/Michael_HM/article/details/78207279,https://www.cnblogs.com/yjmyzz/p/auto-upload-artifact-to-nexus.html

Flutter 工程通常有以下 4 种类型:

1. Flutter Application

标准的 Flutter App 工程,包含标准的 Dart 层与 Native 平台层,如果新项目基于flutter开发的话使用

2. Flutter Module

Flutter 组件工程,仅包含 Dart 层实现,Native 平台层子工程为通过 Flutter 自动生成的隐藏工程(.ios  / .android),可以集成到Native中

3. Flutter Plugin

Flutter 平台插件工程,包含 Dart 层与 Native 平台层的实现,一些公共插件

4. Flutter Package

Flutter 纯 Dart 插件工程,仅包含 Dart 层的实现,往往定义一些公共 Widget。

官方提供的一种混编方案(https://github.com/flutter/flutter/wiki/Add-Flutter-to-existing-apps ),即在现有Native工程下创建 Flutter Module 工程,以本地依赖的方式集成到现有的 Native 工程中。

但是这种方式Flutter和Native耦合性太高,需要解耦,应该是阿里咸鱼团队最初提出的方案,将Flutter工程Native的依赖抽取出来在Native中引用。

看了一下阿里、美团还有马蜂窝的抽取文章要么比较早要么一些细节没注明,最后参考https://blog.csdn.net/u010479969/article/details/90671463完成了Flutter Module工程Android包的抽取

先声明一下名词:

Flutter Module工程:自己新建的Flutter Module工程

Android Native工程:已有的Android Native项目或者新建一个

Flutter Module工程下的Android工程:Flutter Module工程下的Native平台子工程目录为根目录下的.android

1、需要一个Android Native工程,可以使已有的Android Native工程,或者新建一个

2、新建Flutter Module工程(我觉得这里新建Flutter Module工程或者Flutter Application工程都可以,我是用的Flutter Module工程,有用Flutter Application工程成功集成的话可以反馈下),和Android Native工程是独立的,两者没有关联,最后build的Flutter aar包才会依赖到Android Native工程。(官方提供的混编方案是推荐放到Android Native同级目录)

flutter create -t module  -a kotlin flutter_module 因为Android Native工程是kotlin写的这里加上了kotlin支持,如下project视图

 

3、在Flutter Module项目根目录的.android/app/build.gradle文件加入编译配置,不然Flutter Module项目起不来

compileOptions {
sourceCompatibility 1.8
targetCompatibility 1.8
}

 

4、接下来需要将Flutter Module工程下的Android工程打包aar上传到Maven供Android Native工程使用,用Nexus在本地建了一个Maven库并将aar上传,有Maven库的话这步就不用了

参考https://blog.csdn.net/Michael_HM/article/details/78207279,https://www.cnblogs.com/yjmyzz/p/auto-upload-artifact-to-nexus.html

一个需要注意的问题就是admin默认密码不是admin123了,默认会在nexus同级资源目录sonatype-work\nexus3\admin.password 文件,登录修改admin密码后文件会消失

5、将https://blog.csdn.net/u010479969/article/details/90671463博主提供的两个文件cp到Flutter Module根目录下的.android/Flutter中,在这个目录下的build.gradle文件中引入flutter_maven.gradle

apply from: "flutter_maven.gradle"

upload_maven.gradle里有一些变量需要配置,可以放到Flutter Module根目录下的gradle.properties中,或者gradle用户配置文件/Users/xxx/.gradle/gradle.properties中

我直接放到工程文件里了

MAVEN_USERNAME=maven库账号
MAVEN_PASSWORD=maven库密码
RELEASE_REPOSITORY_URL=maven库release url
SNAPSHOT_REPOSITORY_URL=maven库snapshot url
GROUP=工程group
ARTIFACT_ID=flutter
VERSION_NAME=工程版本号,这里如果带SNAPSHOT的话flutter_maven.gradle里会有一些逻辑

 

6、Flutter Module根目录下的.android目录执行编译命令,上传工程,至此Flutter Module这边的工作已经完成了,在maven库里能看到生成的aar包

gradlew clean assembleRelease

gradlew uploadArchives

 

7、到Android Native工程引入,先需要修改下Android Native工程根目录下的app/build.gradle文件,不然flutter引入进去也会build失败

1)、增加编译选项

compileOptions {
sourceCompatibility 1.8
targetCompatibility 1.8
}

2)、修改minSdkVersion为16

3)、解决debug包 Failure [INSTALL_FAILED_NO_MATCHING_ABIS: Failed to extract native libraries, res=-113] 问题,增加splits配置

splits {
abi {
enable true
reset()
include 'armeabi-v7a', "x86"
universalApk true
}
}

4)增加maven库配置

repositories {
maven {
url "maven库url"
credentials {
username 'maven库用户名'
password 'maven库密码'
}
}
}

5)引入aar,dependencies增加implementation GROUP,ARTIFACT_ID,VERSION_NAME是你自己打包时gradle.properties里的配置

dependencies {

// 引入flutter maven依赖包
implementation 'GROUP:ARTIFACT_ID:VERSION_NAME@aar'
}

 8、build下工程没问题的话就可以参考https://www.jianshu.com/p/cf7cf1b640ee写原生和Flutter的胶水代码了,在原生的首页写了一个jumpButton,点击后跳转的Flutter首页,

这里是kotlin的代码,java代码也差不多的调用。还有个问题就是build的出来的x86包没有libflutter.so库在模拟器运行失败,直接在真机运行没问题,这个谁解决了告我下

9、问题:.android 和 .ios目录是Flutter Module工程的临时目录,随时都有可能重新生成,参考https://github.com/flutter/flutter/issues/32989,https://github.com/flutter/flutter/issues/28135。怎么才能不重新生成呢?因为build.gradle和gradle.properties修改了东西,flutter_maven.gradle和upload_maven.gradle是新增的文件,每次重新build或者增加插件执行flutter pub get的时候.android目录都会重新生成被覆盖掉。

找到了一个解决方案https://github.com/flutter/flutter/issues/23123,但他这个只是把Android代码抽取出去了,只适合修改原生代码的情况,Flutter还是在.andorid下,这样的话只能每次build upload的时候重新把这四个文件复制到.android下了。。

 手动复制也比较麻烦,直接把四个文件放到properties目录下,写个cmd批处理复制然后build upload

1 ::copy file
2 copy /y properties\gradle.properties .android
3 copy /y properties\build.gradle .android\Flutter
4 copy /y properties\flutter_maven.gradle .android\Flutter
5 copy /y properties\upload_maven.gradle .android\Flutter
6 
7 cd .android
8 ::build and upload
9 gradlew clean assembleRelease && gradlew uploadArchives

 10、果然还是要改gradle配置文件了,上面博主提供的两个gradle文件用起来都有些问题,一个是build时task不能overwrite问题‘Cannot add task 'flutterSourcesJar' as a task with that name already exists’,一个是windows下'\f'这样的路径识别成表情符号导致plugin打包失败,改了下两个配置文件

flutter_maven.gradle

 1 apply plugin: MavenPlugin
 2 apply from:'upload_maven.gradle'
 3 class MavenPlugin implements Plugin<Project> {
 4 
 5 
 6     @Override
 7     void apply(Project target) {
 8         target.afterEvaluate {
 9             def scriptFile = target.rootDir
10             def FlutterFile = new File(target.rootDir,"Flutter")
11             def uploadFile = new File(FlutterFile,"upload_maven.gradle")
12             def flutterProjectRoot = scriptFile.parentFile
13             def plugins = new Properties()
14             def pluginsFile = new File(flutterProjectRoot, '.flutter-plugins')
15             if (pluginsFile.exists()) {
16                 pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) }
17             }
18 
19             plugins.each { name, path ->
20 
21                 def version = "1.0-SNAPSHOT"
22                 def folderName = new File(path).getName()
23                 if(folderName.contains("-")){
24                     version = folderName.split("-")[1]+"-SNAPSHOT"  //每次更新flutter 插件都更新snapshot版本
25 //                    version = folderName.split("-")[1]
26                 }
27 
28                 def properties = new Properties()
29 
30                 def pluginDirectory = flutterProjectRoot.toPath().resolve(path).resolve('android').toFile()
31                 def propertiesFile = new File(pluginDirectory,'gradle.properties')
32                 def buildFile = new File(pluginDirectory,'build.gradle')
33 
34                 def list = []
35                 buildFile.withReader('UTF-8') { reader ->
36                     reader.eachLine {
37                         if (it.contains('group ')) {
38                             it = "group \'com.flutter.plugin\'"
39                         } else if (it.contains('version ')) {
40                             it = "version "+"\'"+version+"\'"
41                         } else if (it.contains('apply plugin: \'com.android.library\'')) {
42                             list.add('apply from:' + '\''+uploadFile.getPath().replace('\\','\\\\') + '\'' + "\n")
43                         } else if(it.contains('apply from:' + '\''+uploadFile.getPath().replace('\\','\\\\')+ '\'')){
44                             it = ""
45                         }
46                         list.add(it + "\n")
47                     }
48                 }
49 
50                 buildFile.withWriter('UTF-8') { writer ->
51                     list.each {
52                         writer.write(it)
53                     }
54                 }
55 
56                 if (propertiesFile.exists()) {
57                     propertiesFile.withReader('UTF-8') { reader -> properties.load(reader) }
58                 }
59 
60 
61                 properties.setProperty("GROUP","com.flutter.plugin")
62                 properties.setProperty("ARTIFACT_ID",name)
63                 properties.setProperty("VERSION_NAME",version)
64                 properties.store(new FileOutputStream(propertiesFile),"maven configuration");
65 
66             }
67         }
68 
69 
70     }
71 }

upload_maven.gradle

 1 apply plugin: 'maven'
 2 
 3 def getRepositoryUsername() {
 4     return hasProperty('MAVEN_USERNAME') ? MAVEN_USERNAME : ""
 5 }
 6 def getRepositoryPassword() {
 7     return hasProperty('MAVEN_PASSWORD') ? MAVEN_PASSWORD : ""
 8 }
 9 def getRepositoryUrl() {
10     return !VERSION_NAME.toUpperCase().contains("SNAPSHOT") ? RELEASE_REPOSITORY_URL : SNAPSHOT_REPOSITORY_URL
11 }
12 
13 afterEvaluate { project ->
14     uploadArchives {
15         repositories {
16             mavenDeployer {
17                 pom.groupId = GROUP
18                 pom.artifactId = ARTIFACT_ID
19                 pom.version = VERSION_NAME
20                 repository(url: getRepositoryUrl()) {
21                     authentication(userName: getRepositoryUsername(), password: getRepositoryPassword())
22                 }
23             }
24         }
25     }
26 
27     if (project.hasProperty("android")) { // Android libraries
28         task flutterSourcesJar(type: Jar, overwrite: true) {
29             classifier = 'sources'
30             from android.sourceSets.main.java.srcDirs
31         }
32 
33     } else { // Java libraries
34         task flutterSourcesJar(type: Jar, dependsOn: classes, overwrite: true) {
35             classifier = 'sources'
36             from sourceSets.main.allSource
37         }
38     }
39 
40 
41     artifacts {
42         archives flutterSourcesJar
43     }
44 
45     //解决 JavaDoc 中文注释生成失败的问题
46     tasks.withType(Javadoc) {
47         options.addStringOption('Xdoclint:none', '-quiet')
48         options.addStringOption('encoding', 'UTF-8')
49         options.addStringOption('charSet', 'UTF-8')
50     }
51 }

 ------------------------------------更新线---------------------------------

真正合到native项目的时候发现问题了,这个博主的文章还是有问题的,只是初步实现了整合,而且对每个插件的build.gradle侵入也比较厉害,打包的配置文件还是有些问题。不过还是有所帮助。评论里提了问题也一直没回。当插件增多的时候,每个插件都单独打了aar包,显然是不行的,然后找到一篇blog 见https://www.jianshu.com/p/2258760e9540,最终将所有插件打成一个fat-aar包导入到native工程中,不过坑依旧很多,踩吧

posted @ 2019-08-07 11:17  nightfallsad  阅读(1229)  评论(0编辑  收藏  举报