使用Gradle构建Android应用,替换每个产品口味中的字符串。

18

在我构建Android项目为两个不同的应用程序(付费版和免费版)之前,我更改了每个值和字符串,所以昨天犯了一个大错误。

因此,我正在学习如何使用gradle来构建我的应用程序。

我的应用程序有一些不同之处:

  1. 应用程序名称(只需添加后缀“-Free”) -> 值/strings.xml

  2. 更改 *.java 文件中的标志

// signingConfigs 被省略。

productFlavors{
    free{
        packageName "my.app.free"
        versionCode 20
        signingConfig signingConfigs.freeConfing

        copy{
            from('/res'){
                include '**/*.xml'
            }
            into 'build/res/'

            filter{
                String line -> line.replaceAll("android:label=\"@string/app_name\"", "android:label=\"@string/app_name_free\"")
            }
        }
        copy{
            from('/src'){
                include '**/*.java'
            }
            into 'build/src/'

            filter{
                String line -> line.replaceAll("public static final Boolean IS_FULL_VER = true;", "public static final Boolean IS_FULL_VER = false;")
            }
        }
    }
    paid{
        packageName "my.app.paid"
        versionCode 20
        signingConfig signingConfigs.paidConfing
    }
}

但是,制作的应用没有改变任何东西。

我错过了什么?

4个回答

54

请参阅关于产品风味的文档:

http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Product-flavors

在您的build.gradle文件中,对于每个风味,您都可以定义要在BuildConfig.java文件中生成的标记:

productFlavors {
    free {
        packageName "com.company.appfree"
        buildConfig  "public final static com.company.common.MonetizationType monetizationType = com.company.common.MonetizationType.FREE;"
    }

    paid {
        packageName "com.company.apppaid"
        buildConfig  "public final static com.company.common.MonetizationType monetizationType = com.company.common.MonetizationType.PAID;"
    }
}

这个例子使用了一个枚举类型(你需要在 Java 代码中定义):

public enum MonetizationType {
    PAID, FREE
}

现在您可以像这样在任何地方使用它:

if (BuildConfig.monetizationType == MonetizationType.FREE) { ... } 

对于覆盖资源,您可以为每个风味在源文件夹中创建不同的资源文件:

使用以下结构:

app/build.gradle
app/ [.. some other files...]
app/src/main/
app/src/main/java
app/src/main/res
app/src/main/assets
app/src/main/AndroidManifest.xml


app/src/free/res/values/apptitle.xml
app/src/paid/res/values/apptitle.xml

apptitle.xml是一个字符串资源文件(就像strings.xml一样),但只包含一个字符串:根据不同的flavor,您想要不同的那个字符串。 (您不需要在主/res目录中有一个apptitle.xml)。

<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools">
    <string name="app_title">App Title (or whatever you want)</string>
</resources>

你可能有不同的方法来覆盖字符串,但是为了清晰起见,我喜欢将被覆盖的字符串与其他部分分开。


谢谢!现在我可以使用不同的monetizationType构建。但是我无法更改我的应用程序名称。我的项目结构与那个不同。在我的项目中,**/src/my/app//*.java,/res/values/string.xml。那是Maven项目结构吗?我需要改变项目结构吗? - Flask_KR
我的项目结构是新的Android Studio / Gradle项目结构。请参阅文档http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Product-flavors。它应该解释一切。是的,您可能需要更改文件夹,但这并不难做到。为Android Studio创建一个新的示例项目,并查看那个build.gradle文件以及目录设置方式。然后更改您的项目以反映该结构。 - treesAreEverywhere
我该如何在AndroidManifest.xml中引用app_title?我尝试了@apptitle/app_title,但它无法解析。 - dannyroa
类似 android:label="@string/app_title" 的语句应该可以工作。 - treesAreEverywhere
2
Gradle 2.14不识别buildConfig函数,只识别buildConfigField - 4emodan
显示剩余3条评论

12

被接受的答案在新版本的Gradle中无法使用。 为了获得相同的结果,您需要将buildConfig替换为buildConfigField

答案不再适用于较新版本的Gradle。你需要用 buildConfigField 取代buildConfig来达到相同的结果:

productFlavors {
free {
    packageName "com.company.appfree"
    buildConfigField  "com.company.common.MonetizationType", "MONETIZATION_TYPE",  "company.common.MonetizationType.FREE"
}

paid {
    packageName "com.company.apppaid"
    buildConfigField  "com.company.common.MonetizationType", "MONETIZATION_TYPE",  "company.common.MonetizationType.PAID"
}

1
treesAreEverywhere的回答(以及用户名)是正确的。但是,了解到Android Studio将极大地简化创建构建风格或属性特定资源文件的过程也非常有价值。
在AS项目窗口中,右键单击res/values文件夹,选择New > Values resource file。然后命名它(例如,“strings”),如果不是默认值,则选择源集,并选择任何所需的限定符(例如,屏幕宽度=800)。这是确保将资源覆盖放置在编译器想要的位置的最简单方法。

0
这是我在项目中的做法。我创建了多个构建类型而不是口味。这个解决方案将根据您正在尝试组装的构建类型向您的包名称添加前缀。例如,对于dev,包名称将为com.sample.myapp.dev,类似地,对于beta,包名称将更改为com.sample.myapp.release。您可以调整它以获取免费和付费前缀。希望能有所帮助。
buildTypes {
    release {
        minifyEnabled false
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        signingConfig signingConfigs.production
        applicationIdSuffix '.release'
        versionNameSuffix '-RELEASE'
    }

    dev {
        signingConfig signingConfigs.debug
        applicationIdSuffix '.dev'
        versionNameSuffix '-DEV'
    }

    beta {
        signingConfig signingConfigs.debug
        applicationIdSuffix '.beta'
        versionNameSuffix '-BETA'
    }

    debug {
        signingConfig signingConfigs.debug
        applicationIdSuffix '.debug'
        versionNameSuffix '-DEBUG'
        debuggable true
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接