如何为通过 gradle 构建变体生成的两个版本的 GPS 应用程序获取不同的图标?

How do I get different icons for the two versions of my GPS app generated via gradle build variants?

我想要一个 Android Studio (AS) 1.1.0 项目创建两个 APK 文件:一个用于付费版本,一个免费版本 Google Play 商店 (GPS) 应用程序。使用 gradle 构建变体 ("flavors")。 我非常接近。我已经从一个 AS 项目上传了两个版本——免费和付费。

唯一的 relatively-minor 问题:我不能让两个版本有不同的图标,我不能让操作栏为不同的应用程序显示不同的标题。

由于我们处理的是风味,所以有三个 AndroidManifest.xml 文件:一个我可以编辑,两个 gradle 生成,每个风味一个。如果我编辑这些,编辑内容将在下一个版本中丢失。

这里是 "my" AndroidManifest.xml:

package="com.dslomer64.kakurocombosbuildvariants" >

<application


    android:icon="@drawable/kc_icon_free">


    android:label="@string/app_name"



    android:allowBackup="true"
>
    <activity
        android:screenOrientation="portrait"




        android:icon="@drawable/kc_icon_free"




        android:name=".MyActivity"
    >
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
</application>
</manifest>

除了包名,生成的 AndroidManifest.xml 个文件是相同的(这里是一个):

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.dslomer64.kakurocombosbuildvariants.pro"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="15"
        android:targetSdkVersion="21" />

    <application
        android:allowBackup="true"
        android:label="KC" >
        <activity
            android:name="com.dslomer64.kakurocombosbuildvariants.MyActivity"
            android:icon="@drawable/kc_icon_free"
            android:screenOrientation="portrait" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

我的工作基于 build.gradle 列出的 here 文件,其中内容已过时,标记为 //////////:

    buildscript {
        repositories {
            mavenCentral()
        }
        dependencies {
            classpath 'com.android.tools.build:gradle:0.5.+'  /////////(wrong version)
        }
    }
    apply plugin: 'android'

    repositories {
        mavenCentral()
    }

    android {
        compileSdkVersion 18
        buildToolsVersion "18.0.1"

        defaultConfig {
            minSdkVersion 15
            targetSdkVersion 18
        }

        productFlavors {
            production {
                packageName "be.tamere.gradlebuildtypesexample"   ////// packageName should be applicationId
            }

            staging {
                packageName "be.tamere.gradlebuildtypesexample.staging"
            }
        }
    }

    dependencies {
        compile 'com.android.support:appcompat-v7:18.0.0'
    }

我的工作也基于相关文件结构的草图:

    +-- main
    ¦   +-- AndroidManifest.xml
    ¦   +-- ic_launcher-web.png
    ¦   +-- java
    ¦   ¦   +-- be
    ¦   ¦       +-- tamere
    ¦   ¦           +-- gradlebuildtypesexample
    ¦   ¦               +-- MainActivity.java
    ¦   +-- res
    ¦       +-- drawable-hdpi
    ¦       ¦   +-- ic_launcher.png
    ¦       +-- drawable-mdpi
    ¦       ¦   +-- ic_launcher.png
    ¦       +-- drawable-xhdpi
    ¦       ¦   +-- ic_launcher.png
    ¦       +-- drawable-xxhdpi
    ¦       ¦   +-- ic_launcher.png
    ¦       +-- layout
    ¦       ¦   +-- activity_main.xml
    ¦       +-- menu
    ¦       ¦   +-- main.xml
    ¦       +-- values
    ¦       ¦   +-- dimens.xml
    ¦       ¦   +-- strings.xml
    ¦       ¦   +-- styles.xml
    ¦       +-- values-v11
    ¦       ¦   +-- styles.xml
    ¦       +-- values-v14
    ¦           +-- styles.xml
    +-- production
    ¦   +-- java
    ¦       +-- be
    ¦           +-- tamere
    ¦               +-- gradlebuildtypesexample
    ¦                   +-- Constants.java
    +-- staging
        +-- java
        ¦   +-- be
        ¦       +-- tamere
        ¦           +-- gradlebuildtypesexample
        ¦               +-- Constants.java
        +-- res
            +-- drawable-hdpi
            ¦   +-- ic_launcher.png
            +-- drawable-mdpi
            ¦   +-- ic_launcher.png
            +-- drawable-xhdpi
            ¦   +-- ic_launcher.png
            +-- drawable-xxhdpi
            ¦   +-- ic_launcher.png
            +-- values
                +-- string.xml

不知道是不是少了"|"从上到下的标志意义重大。如果是这样,那可能是我发散的地方。

当我尝试创建这两个 APK 时,我最终看到了这个屏幕,这是个好消息:

在 AS 内部,我看到了这个,这是个好消息:

在 Windows 7 Explorer 中我看到:

这是我在 AS 中的结构:

这对应于link中显示的结构。特别注意 free 版本中没有 res 文件夹。 main 中的 res 文件夹包含 free 版本的图标。 pro 中的 res 文件夹包含 pro 版本的图标。

如何为两个不同的 APK 获取不同的图标?

为什么两个版本的操作栏中的标题都显示为 fully-qualified 包名称?

有没有办法编辑生成的 AndroidManifest.xml 文件?或者让每种口味都有自己的可编辑 AndroidManifest.xml?

I can't make the two versions have different icons and I can't make the action bar display different titles for the different apps.

第 1 步:选择一个(免费或付费)作为您在 main/ 源集中拥有的那个。出于此答案的目的,我假设免费的进入 main/.

第 2 步:编辑 main/res/values/strings.xml 以获得您想要的 app_name 资源免费版本,因为您在清单中使用 app_name 字符串资源。

第 3 步:使用 app_name 的定义创建一个 paid/res/values/strings.xml,其中包含您想要的 paid 应用显示名称的值。

第 4 步:决定是否要为启动器图标使用 mipmap 或可绘制对象。您似乎有 mipmap 目录,但您的清单引用了可绘制资源。出于此答案的目的,我假设您将使用 mipmap。

第 5 步:决定您要给启动器图标起什么名字。你的应用程序目前没有构建,它会出现,因为你的清单引用了一个 kc_icon_free 可绘制对象,但你的目录列表显示 ic_launcher。特别是,您希望名称 而不是 引用 "free" 或 "paid"。我在这里假设你选择 ic_launcher.

第 6 步:使用 main 源集中的免费图标,按照上述方法重新组织您的图标和清单。

第 7 步:创建 paid/res/mipmap-*/ 目录并将 ic_launcher 图标的付费版本放在那里。

Since we're dealing with flavors, there are three AndroidManifest.xml files: one I CAN edit and two that gradle generates, one for each flavor. If I edit those, the edits are lost with the next build.

当然欢迎您在 freepaid 源集中拥有 AndroidManifest.xml 文件。它们将与 main 中的那个、Gradle 设置合并,并从任何依赖项中体现出来。

话虽如此,您在这里不需要它。有一个清单,指向一组标签和图标资源。在 main 源集中拥有一个版本的标签和图标;在产品风味的源集中有另一个(例如,paid 按照我上面的步骤)。

Why does the title in the action bar for both versions show as a fully-qualified package name?

据推测,这就是您对 app_name 字符串资源值的看法。如果你不喜欢它,请更改字符串资源。

Is there a way to edit the generated AndroidManifest.xml files?

不是合并的。

Or to make each flavor have its own editable AndroidManifest.xml?

见上文。同样,这不是您问题的正确解决方案。

这是一张我被困在@CommonsWare 上的图片,非常清楚:

各有不同 app_name:

Gradle 通过 ProductFlavors 块声明消除歧义:

apply plugin: 'com.android.application'

android
{
    compileSdkVersion 21
    buildToolsVersion "21.1.2"

    defaultConfig
    {
        applicationId "com.dslomer64.kakurocombosbuildvariants"
        minSdkVersion 15
        targetSdkVersion 21
        versionCode 1
        versionName "1.0"
    }
    buildTypes
    {
        release
        {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }


    productFlavors
    {
        pro
        {
            applicationId "com.dslomer64.kakurocombosbuildvariants.pro"
        }
        free
        {
            applicationId "com.dslomer64.kakurocombosbuildvariants.free"
        }
    }
}

dependencies
{
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:22.0.0'
}

这里是对两个变体的 MyActivity.java 引用:

public class MyActivity extends Activity {

  boolean FREE = Free.FREE;

根据每个变量中 FREE 值的设置方式,变量为 "free" (FREE = true) 或 "pro" (FREE = false)。这是这两个变体 类,它们在各自的文件中都命名为 Free

KakuroCombosBuildVariants\app\src\free\java\com\dslomer64\kakurocombosbuildvariants\Free.java中:

package com.dslomer64.kakurocombosbuildvariants;

public class Free
{
  public static final boolean FREE = true;
}

KakuroCombosBuildVariants\app\src\pro\java\com\dslomer64\kakurocombosbuildvariants\Free.java中:

package com.dslomer64.kakurocombosbuildvariants;

public class Free
{
  public static final boolean FREE = false;
}

我用过 FUJI Goro 写的''Ribbonizer plugin for Android''。

这是一个 ribbonizer,作为 Android 的 Gradle 插件,它会自动将功能区添加到启动器图标。

https://github.com/gfx/gradle-android-ribbonizer-plugin