ChatGPT解决这个技术问题 Extra ChatGPT

基于 Android Gradle 中多风味库的多风味应用

我的应用程序针对多个市场的应用程序内计费系统具有多种风格。

我有一个库,它共享我所有项目的基本代码。所以我决定将这些支付系统作为产品风味添加到这个库中。

问题是android库可以有产品风味吗?

如果是这样,我如何在应用程序的各个风味中包含不同的风味?

我进行了很多搜索,但找不到有关此场景的任何信息。我在 http://tools.android.com/tech-docs/new-build-system/user-guide 中发现的唯一接近的东西是:

dependencies {
    flavor1Compile project(path: ':lib1', configuration: 'flavor1Release')
    flavor2Compile project(path: ':lib1', configuration: 'flavor2Release')
}

我将配置更改为不同的东西,但它不起作用!

我正在使用 android studio 0.8.2。

经过多次搜索,我发现没有办法实现这一点,即使我将 android 插件升级到最新的 3.4.2 版本并 gradle 到最新的 5.5.1,它仍然在编译时失败,或者 资源链接失败 在 aapt 中,或 找不到库模块中的符号

T
Top-Master

最后我发现了如何做到这一点,我将在这里为其他面临同样问题的人解释:

如果 App 和 Library 具有相同的 Flavor 名称

从 Gradle Plugin 3.0.0(及更高版本)开始可以执行以下操作:

库 build.gradle:

apply plugin: 'com.android.library'

// Change below's relative-path
// (as the `../` part is based on my project structure,
// and may not work for your project).
apply from: '../my-flavors.gradle'

dependencies {
    // ...
}

android {
    // ...
}

项目 build.gradle:

buildscript {
    // ...
}

apply plugin: 'com.android.application'
// Note that below can be put after `dependencies`
// (I just like to have all apply beside each other).
apply from: './my-flavors.gradle'

dependencies {
    api project(':lib')
}

android {
    productFlavors {
        // Optionally, configure each flavor.
        market1 {
            applicationIdSuffix '.my-market1-id'
        }
        market2 {
            applicationIdSuffix '.my-market2-id'
        }
    }
}

我的口味.gradle:

android {
    flavorDimensions 'my-dimension'
    productFlavors {
        market1 {
            dimension 'my-dimension'
        }
        market2 {
            dimension 'my-dimension'
        }
    }
}

如果 App 或 Library 有不同的 Flavor-name(旧答案)

关键部分是在库 build.gradle 中将 publishNonDefault 设置为 true,然后您必须按照用户指南的建议定义依赖项。

2022 年更新; publishNonDefault 现在默认为 true,将其设置为 false 将被忽略,因为不推荐使用该选项。

整个项目会是这样的:

库 build.gradle:

apply plugin: 'com.android.library'

android {        
    ....
    publishNonDefault true
    productFlavors {
        market1 {}
        market2 {}
        market3 {}
    }
}

项目 build.gradle:

apply plugin: 'com.android.application'

android {
    ....
    productFlavors {
        market1 {}
        market2 {}
        market3 {}
    }
}

dependencies {
    ....
    market1Compile project(path: ':lib', configuration: 'market1Release')
    market2Compile project(path: ':lib', configuration: 'market2Release')

    // Or with debug-build type support.
    android.buildTypes.each { type ->
        market3Compile project(path: ':lib', configuration: "market3${type.name}")
    }

}

现在您可以选择应用程序风格和构建变体面板,库将被相应地选择,所有构建和运行都将基于所选风格完成。

如果你有多个基于库的应用程序模块 Android Studio 会抱怨 Variant selection conflict ,没关系,忽略它。

https://i.stack.imgur.com/kC8tJ.jpg


感谢分享,现在我可以摆脱我的 defaultPublishConfig 解决方法了。
运行 AS 1.1.0,上述解决方案似乎仍然有效,但是 1) 调试/发布构建选择丢失,我似乎一直在遇到库中的 AIDL 问题,这些问题经常无法生成适当的代码。对此有什么想法吗?
@IgorGanapolsky buildTypes 与此无关。每种风格都有所有的构建类型(通常是调试和发布),并且它们都使用这种方法。
@An-droid 它定义了用于market1 风格的库!
为什么将其设置为“发布”构建类型?在调试构建期间是否选择了“发布”构建类型?
C
Community

Ali 答案有一个问题。我们在构建变体中失去了一个非常重要的维度。如果我们想拥有所有选项(在我的示例中低于 4 (2 x 2)),我们只需在 main module build.gradle 文件中添加 custom configurations 即可使用 Build Variants 中的所有多风格多构建类型。我们还必须在 library module build.gradle 文件中设置 publishNonDefault true

示例解决方案:

库构建.gradle

android {

    publishNonDefault true

    buildTypes {
        release {
        }
        debug {
        }
    }
    productFlavors {
        free {
        }
        paid {
        }
    }
}

应用程序构建.gradle

android {

    buildTypes {
        debug {
        }
        release {
        }
    }
    productFlavors {
        free {
        }
        paid {
        }
    }
}

configurations {
    freeDebugCompile
    paidDebugCompile
    freeReleaseCompile
    paidReleaseCompile
}

dependencies {

    freeDebugCompile project(path: ':lib', configuration: 'freeDebug')
    paidDebugCompile project(path: ':lib', configuration: 'paidDebug')
    freeReleaseCompile project(path: ':lib', configuration: 'freeRelease')
    paidReleaseCompile project(path: ':lib', configuration: 'paidRelease')

}

在我的应用程序中执行相同的操作后,发生 Error:java.lang.RuntimeException: Error: more than one library with package name
C
Community

Android 插件 3.0.0 及更高版本的更新

根据官方 Android 文档 - Migrate dependency configurations for local modules

通过变体感知依赖解析,您不再需要对本地模块依赖项使用特定于变体的配置,例如 freeDebugImplementation - 插件会为您处理这个您应该按如下方式配置您的依赖项:

dependencies {
    // This is the old method and no longer works for local
    // library modules:
    // debugImplementation project(path: ':library', configuration: 'debug')
    // releaseImplementation project(path: ':library', configuration: 'release')

    // Instead, simply use the following to take advantage of
    // variant-aware dependency resolution. You can learn more about
    // the 'implementation' configuration in the section about
    // new dependency configurations.
    implementation project(':library')

    // You can, however, keep using variant-specific configurations when
    // targeting external dependencies. The following line adds 'app-magic'
    // as a dependency to only the "debug" version of your module.

    debugImplementation 'com.example.android:app-magic:12.3'
}

所以在阿里的回答中,改变

dependencies {
    ....
    market1Compile project(path: ':lib', configuration: 'market1Release')
    market2Compile project(path: ':lib', configuration: 'market2Release')
}

implementation project(':lib')

插件将自动处理特定于变体的配置。希望它有助于其他人将 Android Studio 插件升级到 3.0.0 及更高版本。


仅当所有风味具有完全相同的名称(根应用程序和每个库)时,新功能才适用,因此即使单个库具有单独的风味名称,也应使用旧语法。
J
JiajiaGu

我的 Android 插件是 3.4.0,我发现它现在不需要配置。您只需确保应用程序中的 flavorDimensions 和 productFlavors 在库中包含一个相同的 flavorDimensions 和 productFlavors 的 productFlavor。例如:

在 mylibrary 的 build.gradle

apply plugin: 'com.android.library'

android {        
    ....
    flavorDimensions "mylibFlavor"

    productFlavors {
        market1
        market2
    }
}

应用程序的 build.gradle:

apply plugin: 'com.android.application'

android {
    ....
    flavorDimensions "mylibFlavor", "appFlavor"
    productFlavors {
        market1 {
            dimension "mylibFlavor"
        }
        market2 {
            dimension "mylibFlavor"
        }
        common1 {
            dimension "appFlavor"
        }
        common2 {
            dimension "appFlavor"
        }
    }
}

dependencies {
    ....
    implementation project(path: ':mylibrary')
}

https://i.stack.imgur.com/ncblI.png


但是,如果我不想在我的主应用程序模块中使用相同的风格怎么办?假设我有多个具有自己特定风格的应用程序模块和一个具有自己风格的通用模块,并且我想在我的应用程序中使用具有特定风格的库。你会怎么做?将我的 lib 风格复制到所有应用程序是没有意义的。
@Billda您不需要全部复制,只需在应用程序中保留一个相同的productFlavor,对于我的示例,我可以将market1 或market2 保留在应用程序的build.gradle 中。
D
David Lev

要让风格在 AAR 库上运行,您需要在 Android 库模块的 build.gradle 文件中定义 defaultPublishConfig。

有关详细信息,请参阅:Library Publication

库发布 默认情况下,库仅发布其发布变体。所有引用该库的项目都将使用此变体,无论它们自己构建哪个变体。由于我们正在努力消除 Gradle 限制,这是一个临时限制。您可以控制发布哪个变体: android { defaultPublishConfig "debug" } 请注意,此发布配置名称引用了完整的变体名称。发布和调试仅适用于没有风味的情况。如果您想在使用风味时更改默认发布的变体,您可以编写: android { defaultPublishConfig "flavor1Debug" }


S
Sergio

我还遇到了为各种选项编译模块的问题。

我发现了什么:

看起来我们不需要将 publishNonDefault true 添加到 lib 的 build.gradle 文件中,因为 Gradle 3.0.1

反编译类 BaseExtension 后发现:

public void setPublishNonDefault(boolean publishNonDefault) {
   this.logger.warn("publishNonDefault is deprecated and has no effect anymore. All variants are now published.");
}

而不是:

dependencies {
...
   Compile project(path: ':lib', configuration: 'config1Debug')
}

我们应该使用:

dependencies {
...
   implementation project(':lib')
}

唯一重要的是,将 configurations {...} 部分添加到 build.gradle

因此,应用的 build.gradle 文件的最终变体是:

buildTypes {
   debug {
      ...
   }

   release {
      ...
   }
}

flavorDimensions "productType", "serverType"
productFlavors {
   Free {
      dimension "productType"
      ...
   }
   Paid {
      dimension "productType"
      ...
   }
   Test {
      dimension "serverType"
      ...
   }
   Prod {
      dimension "serverType"
      ...
   }
}

configurations {
   FreeTestDebug
   FreeTestRelease
   FreeProdDebug
   FreeProdRelease
   PaidTestDebug
   PaidTestRelease
   PaidProdDebug
   PaidProdRelease
}

dependencies {
   implementation fileTree(dir: 'libs', include: ['*.jar'])
   implementation project(':lib')
   ...
}

此外,您可以使用 Filter variants 来限制构建变体。

ps 不要忘记在 settings.gradle 文件中包含模块,例如:

include ':app'
include ':lib'
project(':lib').projectDir = new File('app/libs/lib')

先生,您能解释一下脚本将如何确定天气以将库包含到某个配置中吗?我的意思是当我需要为某种风味使用一些库时,我有一个案例,但我不需要将它用于另一种风味
没有陷入这样的境地。但是谷歌教程developer.android.com/studio/build/dependencies建议在“依赖项{...}”块中的“实施”命令之前添加一个前缀。即依赖项{paidImplementation project(':lib')},或依赖项{debugImplementation project(':lib')},或任何多个变体组合依赖项{paidProdDebugImplementation project(':lib')}。检查出来并给我们反馈:)
嗨@Sergio,我们的应用程序中也有多个构建变体,我们可以在多种风格上运行应用程序,但无法为其创建 aar 文件。在为每种口味生成 .aar 文件时,我们遇到了错误。 * 出了什么问题:任务 ':sdk:explodeSample-sdkVariantPreprodDeviceDebug' 执行失败。 > 无法展开 ZIP 'xyz.aar',因为它不存在。
D
Delblanco

目前这是不可能的,尽管如果我没记错的话,这是他们想要添加的功能。 (编辑 2:linklink2

编辑:目前我使用 defaultPublishConfig 选项来声明发布了哪个库变体:

android {
    defaultPublishConfig fullRelease
    defaultPublishConfig demoRelease 
}

所以,每次我要编译应用程序时,我必须在库的 build.gradle 中更改它?
嗯,是的......每次你想用不同的风格编译应用程序。
实际上,当我为库模块定义风味时,在应用程序模块中找不到继承的 R 包。
你在AS中同步了gradle文件吗?
@Delblanco 这似乎是体力劳动,非常脆弱(开发人员很懒惰,忘记修改他们的 build.gradle 文件)。
A
AlexG

我知道这个主题已经关闭,但只是 gradle 3.0 的更新,请参阅:https://developer.android.com/studio/build/gradle-plugin-3-0-0-migration.html#variant_aware 和 grep matchingFallbacksmissingDimensionStrategy。现在声明模块风格之间的依赖关系变得更加简单。

...在 gradle3.0 的这种精确情况下,由于风味共享相同的名称,gradle 会神奇地映射它们,不需要配置。


对我来说,似乎跳过了运行时生成的东西。例如 simonvt-> 原理图生成不再适用于我的新方法。 :-/
M
Manoel Pereira Leno

在这个情况下。我如何导入特定构建的依赖项。例如:market1Common1Debug market1Common1DebugImplementation 'androidx.appcompat:1.2.0'

https://i.stack.imgur.com/hk2ya.png