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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM