参考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工程中,不过坑依旧很多,踩吧