參考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工程中,不過坑依舊很多,踩吧