Android原生以AAR形式集成Flutter混合開發

開發集成環境
[✓] Flutter (Channel stable, v1.12.13+hotfix.9, on Mac OS X 10.14.6 18G103, locale zh-Hans-CN)

談到目前跨平臺框架的應用,無非兩種,一種使用純跨平臺技術開發的項目,一種是與原生進行混編的項目,當然這裏所講的是後者,後者相對前者稍微複雜些,而且目前大多數都是在原有項目中逐步插入跨平臺技術,當然一些新項目除外。
一、簡述Flutter集成到Android原生項目
二、Android原生以AAR形式集成Flutter項目
三、Flutter與原生(Android/IOS)的消息通信
四、Flutter中如何使用原生控件/組件
五、Flutter狀態管理Provider與Redux
六、Flutter升級及開發中遇到的問題彙總

其實在Flutter官網上 Add Flutter to existing app 就提供了兩種將Flutter引入的方式。

  • 方式一:
    以Android Archive (AAR)形式引入Flutter依賴。
  • 方式二:
    一種方式是將Flutter作爲module,然後native主工程將其引入進來。
    這種方式適合參與人數比較少的項目,如果有多人協作開發的大型項目就不合適了,因爲其他人首先要配置Flutter開發環境,而且團隊裏面其他人還要配置module的依賴,都要熟悉flutter,成本相對較高點。

這裏主要介紹方式一通過以Android Archive (AAR)形式引入Flutter依賴,步驟如下:

  1. .android目錄下的build.gradle目錄下添加依賴:

    buildscript {
        repositories {
            google()
            jcenter()
        }
    
        dependencies {
            classpath 'com.android.tools.build:gradle:3.5.0'
            classpath "com.kezong:fat-aar:1.2.8"  //新增這行 
        }
    }
    
    allprojects {
        repositories {
            google()
            jcenter()
            ...
        }
    }
    
    task clean(type: Delete) {
        delete rootProject.buildDir
    }
    
  2. .android/settings.gradle 文件中添加如下代碼:

    // Generated file. Do not edit.
    include ':app'
    
    rootProject.name = 'android_generated'
    setBinding(new Binding([gradle: this]))
    evaluate(new File(settingsDir, 'include_flutter.groovy'))
    
    //新增以下部分
    def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
    
    def plugins = new Properties()
    def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
    if (pluginsFile.exists()) {
        pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) }
    }
    
    plugins.each { name, path ->
        def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
        include ":$name"
        project(":$name").projectDir = pluginDirectory
    }
    
  3. .android/Flutter/build.gradle 文件中添加如下代碼:

    dependencies {
        testImplementation 'junit:junit:4.12'
        //新增以下部分
        def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
        def plugins = new Properties()
        def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
        if (pluginsFile.exists()) {
            pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) }
        }
        plugins.each { name, _ ->
            println name
            embed project(path: ":$name", configuration: 'default')
        }
    }
    
    apply plugin: "com.kezong.fat-aar"
    apply plugin: 'maven'
    
    final def localMaven = true // true:發佈到本地maven倉庫, false: 發佈到maven私服
    
    final def artGroupId = "com.cc.flutter"
    final def artVersion = "1.0.1"
    final def artifactId = "test-flutter"
    
    final def mavenUrl = "http://10.181.xx.xx:8083/repository/repo/"
    final def mavenAccountName = "admin"
    final def mavenAccountPwd = "admin123"
    final def localRepo = "../../repo-local" //在根目錄創建repo-local文件夾
    
    uploadArchives {
        repositories {
            mavenDeployer {
                println "==maven url: ${artGroupId}:${artifactId}:${artVersion}"
                println "==localMaven : ${localMaven}:${localRepo}"
                if(localMaven) {
                    repository(url: uri(localRepo))
                } else {
                    repository(url: mavenUrl) {
                        authentication(userName: mavenAccountName, password: mavenAccountPwd)
                    }
                }
    
                pom.groupId = artGroupId
                pom.artifactId = artifactId
                pom.version = artVersion
    
                pom.project {
                    licenses {
                        license {
                            name 'The Apache Software License, artVersion 2.0'
                            url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
                        }
                    }
                }
            }
        }
    }
    
  4. 在項目根目錄下創建打包腳本aar.sh,內容如下:

    #!/bin/bash
    
    # 初始化記錄項目pwd
    projectDir=`pwd`
    
    # step 1 clean
    echo 'clean old build'
    find . -depth -name "build" | xargs rm -rf
    cd ${projectDir} # 回到項目
    rm -rf .android/Flutter/build
    #flutter clean
    
    # step 2 package get
    echo 'packages get'
    cd ${projectDir} # 回到項目
    flutter packages get
    
    # step 3 build aar,生成aar,然後上傳到對應maven倉庫
    echo 'build aar'
    cd ${projectDir}
    flutter build apk
    if [ $? -eq 0 ]; then
        echo '打包成aar 成功!'
    else
        echo '打包成aar 失敗!'
        exit 1
    fi
    
    cd ${projectDir}/.android
    ./gradlew flutter:uploadArchives
    
    if [ $? -eq 0 ]; then
        echo 'uploadArchives 成功!'
    else
        echo 'uploadArchives 失敗!'
        exit 1
    fi
    
    echo '<<<<<<<<<<<<<<<<<<<<<<<<<< 打包成功,aar上傳成功 >>>>>>>>>>>>>>>>>>>>>>>>>'
    echo "打包成功 : flutter-release.aar, 本地倉庫:${projectDir}/repo-local"
    exit
    
  5. 在根目錄下打開命令行,執行打包腳本即可:

    $ ./aar.sh
    

    打包成功後可自動將打包的aar上傳至對應的maven倉庫,此處放在本地倉庫根目錄下的repo-local文件夾下。

  6. 將對應倉庫中的aar文件引入原生項目中

  • 在宿主項目根目錄下的build文件中添加如下

    allprojects {
        repositories {
            ... 
            maven {
                url 'http://download.flutter.io'
            }
            flatDir {
                dirs 'libs'
            }
            maven { url "../repo-local" }  //此處是本地倉庫,如是遠程私服換成對應遠程地址即可
        }
    }
    
  • 在app目錄下的build.gradle 中添加遠程依賴

    implementation 'com.cc.flutter:test-flutter:1.0.1'
    

上述步驟即可對Flutter以AAR方式引入到原生Android中進行混合開發,後面會逐漸對打包流程進行優化,以下的優化迭代並不是最終方案(一步步來)。現在你可以進行創建一個demo然後集成到自己的項目中進行試手,體驗以下Flutter。後期會逐步完善Dart語法相關筆記與Flutter相關筆記。


上述打包流程稍微有點繁瑣,如果現有項目比較多,需要重複配置同樣的信息,所以進行打包步驟優化通用配置:

  1. 在項目根目錄下創建configs文件夾,裏面分別創建dependencies_gradle_plugin.gradlesetting_gradle_plugin.gradleuploadArchives.gradle 三個文件

    • dependencies_gradle_plugin.gradle 文件內容如下:
      dependencies {
          def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
          def plugins = new Properties()
          def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
          if (pluginsFile.exists()) {
              pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) }
          }
          plugins.each { name, _ ->
              println name
              embed project(path: ":$name", configuration: 'default')
          }
      }
      
    • setting_gradle_plugin.gradle文件內容如下:
      def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
      
      def plugins = new Properties()
      def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
      if (pluginsFile.exists()) {
          pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) }
      }
      
      plugins.each { name, path ->
          def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
          include ":$name"
          project(":$name").projectDir = pluginDirectory
      }
      
    • uploadArchives.gradle 文件內容如下:
      apply plugin: 'maven'
      
      final def localMaven = true //true: 發佈到本地maven倉庫, false: 發佈到maven私服
      
      final def artGroupId = "com.cc.flutter"
      final def artVersion = "1.0.1"
      final def artifactId = "test-flutter"
      
      final def mavenUrl = "http://10.181.xx.xx:8083/repository/repo/"
      final def mavenAccountName = "admin"
      final def mavenAccountPwd = "admin123"
      final def localRepo = "../../repo-local"
      
      uploadArchives {
          repositories {
              mavenDeployer {
                  println "==maven url: ${artGroupId}:${artifactId}:${artVersion}"
                  println "==localMaven : ${localMaven}:${localRepo}"
                  if(localMaven) {
                      repository(url: uri(localRepo))
                  } else {
                      repository(url: mavenUrl) {
                          authentication(userName: mavenAccountName, password: mavenAccountPwd)
                      }
                  }
      
                  pom.groupId = artGroupId
                  pom.artifactId = artifactId
                  pom.version = artVersion
      
                  pom.project {
                      licenses {
                          license {
                              name 'The Apache Software License, artVersion 2.0'
                              url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
                          }
                      }
                  }
              }
          }
      }
      
  2. .android目錄下的build.gradle目錄下添加依賴:
    classpath "com.kezong:fat-aar:1.2.8" //新增這行

  3. 在.android/settings.gradle文件中添加如下代碼:

    apply from: "../configs/setting_gradle_plugin.gradle"
    
  4. 在.android/Flutter/build.gradle中添加如下代碼:

    apply from: "../../configs/uploadArchives.gradle"
    ...
    //下面放在尾部
    apply plugin: "com.kezong.fat-aar"
    apply from: "../../configs/dependencies_gradle_plugin.gradle"
    

稍後的利用打包腳本執行打包上傳相應倉庫的步驟和引入到原生項目中的流程和上述一致。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章