flutter build aar時"Android property not found."問題

android端在執(zhí)行flutter build aar命令時棉钧,有時候會遇到如下錯誤(問題版本1.17.1屿脐,目前最新的flutter版本1.22.4已不存在此問題)

FAILURE: Build failed with an exception.

  • Where:

    Initialization script '....\packages\flutter_tools\gradle\aar_init_script.gradle' line: 15

    aar_init_script.gradle中修改相關代碼如下
void configureProject(Project project, String outputDir) {
    if (!project.hasProperty("android")) {
        throw new GradleException(project.toString())
        // throw new GradleException("Android property not found.")
    }
    ...
}

再次執(zhí)行flutter build aar掰盘,可定位到具體出錯插件項目。如:
引入path_provider:1.6.8的項目愧捕,執(zhí)行以上命令時會有如下錯誤信息提示

  • What went wrong:

    project ':path_provider_macos'

    由此猜測可能是某些插件依賴了macos相關申钩,查看path_provider-1.6.8中的pubspec.yaml,可發(fā)現(xiàn)其依賴了path_provider_macos
dependencies:
  flutter:
    sdk: flutter
  path_provider_platform_interface: ^1.0.1
  path_provider_macos: ^0.0.4

目前我們的項目中這三個插件path_provider:1.6.8撒遣、shared_preferences: 0.5.7+2、webview_flutter: 0.3.22+1
都會有同樣的"Android property not found."問題义黎。

在網(wǎng)上搜了一下,大部分解決辦法都是說臨時刪除掉.pub-cache/hosted/pub.flutter-io.cn下出錯的相關包泻云,
這個的確可以解決狐蜕,但下次執(zhí)行flutter clean, flutter pub get后,再次執(zhí)行flutter build aar時還會有同樣的問題层释,
于是想看能否看下源碼了解下有沒有好的解決辦法。

在flutter的packages/flutter_tools/gradle/flutter.gradle中廉白,看到如下項目配置的代碼

/**
 * Configures the Flutter plugin dependencies.
 *
 * The plugins are added to pubspec.yaml. Then, upon running `flutter pub get`,
 * the tool generates a `.flutter-plugins` file, which contains a 1:1 map to each plugin location.
 * Finally, the project's `settings.gradle` loads each plugin's android directory as a subproject.
 */
private void configurePlugins() {
    if (!buildPluginAsAar()) {
        getPluginList().each this.&configurePluginProject
        getPluginDependencies().each this.&configurePluginDependencies
        return
    }
    project.repositories {
        maven {
            url "${getPluginBuildDir()}/outputs/repo"
        }
    }
    getPluginList().each { pluginName, pluginPath ->
        configurePluginAar(pluginName, pluginPath, project)
    }
}

配置插件依賴部分的代碼如下猴蹂,其會過濾掉不支持android platform的依賴插件

// Add the dependencies on other plugin projects to the plugin project.
// A plugin A can depend on plugin B. As a result, this dependency must be surfaced by
// making the Gradle plugin project A depend on the Gradle plugin project B.
private void configurePluginDependencies(Object dependencyObject) {
    ...
    dependencyObject.dependencies.each { pluginDependencyName ->
        ...
        Project dependencyProject = project.rootProject.findProject(":$pluginDependencyName")
        if (dependencyProject == null ||
            !doesSupportAndroidPlatform(dependencyProject.projectDir.parentFile.path)) {
            return
        }
        // Wait for the Android plugin to load and add the dependency to the plugin project.
        pluginProject.afterEvaluate {
            pluginProject.dependencies {
                implementation dependencyProject
            }
        }
    }
}

關鍵代碼doesSupportAndroidPlatform如下晕讲,主要是判斷插件項目中是否有android目錄和android/build.gradle文件

// Returns `true` if the given path contains an `android/build.gradle` file.
//
// TODO(egarciad): Fix https://github.com/flutter/flutter/issues/39657.
// Android Studio may create empty android directories due to the logic in <app>/android/settings.gradle,
// which imports all plugins regardless of whether they support the android platform.
private Boolean doesSupportAndroidPlatform(String path) {
    File editableAndroidProject = new File(path, 'android' + File.separator + 'build.gradle')
    return editableAndroidProject.exists()
}

根據(jù)之前代碼configurePlugins中的注釋,我們大概了解項目中插件配置流程如下

1.首先在pubspec.yaml中添加相關插件

2.執(zhí)行flutter pub get命令生成.flutter-plugins文件

3.項目的settings.gradle加載每一個插件的android目錄作為子項目

在.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'))

再查看生成的文件include_flutter.groovy勤婚,部分代碼如下

def plugins = new Properties()
def pluginsFile = new File(flutterProjectRoot, '.flutter-plugins')
if (pluginsFile.exists()) {
    pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) }
}

plugins.each { name, path ->
    def pluginDirectory = flutterProjectRoot.toPath().resolve(path).resolve('android').toFile()
    gradle.include ":$name"
    gradle.project(":$name").projectDir = pluginDirectory
}

其先從.flutter-plugins文件中加載插件,然后配置插件項目作為subproject
其中可以看到缨称,在添加插件的android目錄作為子目錄時祝迂,并未判斷插件是否含有android目錄,
這樣上面的path_provider_macos就會被添加到子項目中作為依賴項目当凡,然后在構建時校驗失敗纠俭。

projectsEvaluated {
    ...
    // Gets the plugin subprojects.
    Set<Project> modulePlugins = rootProject.subprojects.findAll {
        it.name != "flutter" && it.name != "app"
    }
    // When a module is built as a Maven artifacts, plugins must also be built this way
    // because the module POM's file will include a dependency on the plugin Maven artifact.
    // This is due to the Android Gradle Plugin expecting all library subprojects to be published
    // as Maven artifacts.
    modulePlugins.each { pluginProject ->
        configureProject(pluginProject, moduleProject.property("output-dir"))
        moduleProject.android.libraryVariants.all { variant ->
            // Configure the `assembleAar<variantName>` task for each plugin's projects and make
            // the module's equivalent task depend on the plugin's task.
            String variantName = variant.name.capitalize()
            moduleProject.tasks.findByPath("assembleAar$variantName")
                .dependsOn(pluginProject.tasks.findByPath("assembleAar$variantName"))
        }
    }
}

大概了解依賴配置流程后冤荆,我們可以想到如下解決辦法

1.修改include_flutter.groovy中的插件項目配置規(guī)則,加上android目錄的校驗

2.修改aar_init_script.gradle中的配置規(guī)則

具體修改如下:

1.include_flutter.groovy是通過模版生成的乌妒,修改的話可修改flutter下packages/flutter_tools/templates/module/android/library_new_embedding/include_flutter.groovy.copy.tmpl

plugins.each { name, path ->
    def pluginDirectory = flutterProjectRoot.toPath().resolve(path).resolve('android').toFile()
    if (pluginDirectory.exists()) {
        gradle.include ":$name"
        gradle.project(":$name").projectDir = pluginDirectory
    } else {
        println("plugins " + name + " pluginDirectory : " + pluginDirectory + " does not exist")
    }
}

2.修改flutter下文件packages/flutter_tools/gradle/aar_init_script.gradle中projectsEvaluated配置部分代碼:

    Set<Project> modulePlugins = rootProject.subprojects.findAll {
        it.name != "flutter" && it.name != "app" && it.hasProperty("android")
    }

以上兩個方式都需要修改flutter中的代碼涌庭,暫時沒找到更好的解決方法,有了解其他解決辦法的拴魄,也希望分享下。

追記:
flutter 1.22.4版本生成的include_flutter.groovy中代碼變更

gradle.apply from: "$flutterSdkPath/packages/flutter_tools/gradle/module_plugin_loader.gradle"

查看module_plugin_loader.gradle代碼可見其中添加插件依賴時夏漱,檢查了是否支持android

def pluginsFile = new File(moduleProjectRoot, '.flutter-plugins-dependencies')
if (pluginsFile.exists()) {
    def object = new JsonSlurper().parseText(pluginsFile.text)
    assert object instanceof Map
    assert object.plugins instanceof Map
    assert object.plugins.android instanceof List
    // Includes the Flutter plugins that support the Android platform.
    object.plugins.android.each { androidPlugin ->
        assert androidPlugin.name instanceof String
        assert androidPlugin.path instanceof String
        def pluginDirectory = new File(androidPlugin.path, 'android')
        assert pluginDirectory.exists()
        include ":${androidPlugin.name}"
        project(":${androidPlugin.name}").projectDir = pluginDirectory
    }
}
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末挂绰,一起剝皮案震驚了整個濱河市服赎,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌重虑,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,681評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件永高,死亡現(xiàn)場離奇詭異提针,居然都是意外死亡辐脖,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,205評論 3 399
  • 文/潘曉璐 我一進店門落萎,熙熙樓的掌柜王于貴愁眉苦臉地迎上來炭剪,“玉大人翔脱,你說我怎么就攤上這事〗煊酰” “怎么了?”我有些...
    開封第一講書人閱讀 169,421評論 0 362
  • 文/不壞的土叔 我叫張陵暂氯,是天一觀的道長亮蛔。 經(jīng)常有香客問我,道長辣吃,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 60,114評論 1 300
  • 正文 為了忘掉前任厘惦,我火速辦了婚禮哩簿,結果婚禮上,老公的妹妹穿的比我還像新娘羡玛。我一直安慰自己全跨,他們只是感情好,可當我...
    茶點故事閱讀 69,116評論 6 398
  • 文/花漫 我一把揭開白布渺杉。 她就那樣靜靜地躺著挪钓,像睡著了一般。 火紅的嫁衣襯著肌膚如雪倚评。 梳的紋絲不亂的頭發(fā)上馏予,一...
    開封第一講書人閱讀 52,713評論 1 312
  • 那天,我揣著相機與錄音呢岗,去河邊找鬼蛹尝。 笑死,一個胖子當著我的面吹牛突那,可吹牛的內容都是我干的。 我是一名探鬼主播早龟,決...
    沈念sama閱讀 41,170評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼它褪!你這毒婦竟也來了翘悉?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 40,116評論 0 277
  • 序言:老撾萬榮一對情侶失蹤老赤,失蹤者是張志新(化名)和其女友劉穎制市,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體开财,經(jīng)...
    沈念sama閱讀 46,651評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡误褪,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,714評論 3 342
  • 正文 我和宋清朗相戀三年兽间,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片嘀略。...
    茶點故事閱讀 40,865評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡帜羊,死狀恐怖,靈堂內的尸體忽然破棺而出讼育,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 36,527評論 5 351
  • 正文 年R本政府宣布忧饭,位于F島的核電站筷畦,受9級特大地震影響刺洒,放射性物質發(fā)生泄漏吼砂。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 42,211評論 3 336
  • 文/蒙蒙 一因俐、第九天 我趴在偏房一處隱蔽的房頂上張望周偎。 院中可真熱鬧,春花似錦蓉坎、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,699評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至罐监,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間沟堡,已是汗流浹背矢空。 一陣腳步聲響...
    開封第一講書人閱讀 33,814評論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留粥血,地道東北人酿箭。 一個月前我還...
    沈念sama閱讀 49,299評論 3 379
  • 正文 我出身青樓,卻偏偏與公主長得像缔御,于是被迫代替她去往敵國和親妇蛀。 傳聞我的和親對象是個殘疾皇子笤成,可洞房花燭夜當晚...
    茶點故事閱讀 45,870評論 2 361

推薦閱讀更多精彩內容