如何在 Android Studio (AS) 1.1.0 中使用此项目结构来生成两个 APK?

How do I get this project structure in Android Studio (AS) 1.1.0 to work to produce two APKs?

编辑#3——由于建议错误而更改目录结构。

基于 this link 我遵循了一个 SO 问题,我需要我的文件结构在 Android Studio (AS) 1.1 中显示为这样。 0 以便获得我的 GPS(Google Play 商店)应用程序的免费和付费版本:

+-- main
¦   +-- AndroidManifest.xml
¦   +-- java
¦   ¦   +-- com
¦   ¦       +-- whatever
¦   ¦           +-- kakurocombos
¦   ¦               +-- MyActivity.java 

¦   +-- res        
¦       +-- layout
¦       ¦   +-- activity_main.xml        
+-- FreeVersion
¦   +-- java
¦       +-- com
¦           +-- whatever
¦               +-- kakurocombos
¦                   +-- Free.java (where FREE = true;)
+-- Pro
    +-- java
    ¦   +-- com
    ¦       +-- whatever
    ¦           +-- kakurocombos
    ¦               +-- Free.java (where FREE = false;)
    +-- res
        +-- values
            +-- string.xml

编辑-- 正如下面评论中指出的那样,上述所有结构都必须在 src 下。

我选择那个结构是因为 link(上图)是这样显示它的结构的:

├── 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

请注意 production 下的 res 缺失 因为它将使用 main 下的 res

请注意 stagingres 存在 因为它使用不同的资源,因为它是第二个 APK/package。

下面是目录结构在 Windows 7 Explorer 中的样子:

这是它在 AS 中的样子:(EDITED!)(TWICE)

这是build.gradle

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
    {
        paid
        {
            applicationId "com.dslomer64.kakurocombos.paid"
        }
        free
        {
            applicationId "com.dslomer.kakurocombos.free"
        }
    }
}

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

post 开头提到的 link 有一些错误,包括未能将 .paid 附加到 productFlavors 块中的第一个包。

与您的口味相关的所有内容都应该在 src 文件夹中,例如

src/main/...
src/free/...
src/pro/...

现在您的 src 文件夹与 flavor 文件夹处于同一级别,这是不正确的。

请参阅 this documentation 以确认上述内容。

这就是最终对我有用的方法。它基于@CommonsWare 的帮助。简短回答:构建变体。假定这两个变体仅略有不同。在此示例中,一个需要声明为免费,而另一个必须声明为不免费。

本例中的两个构建变体被命名为 profree。它们不完全是 main 的变体,我们为其定义了通常的资源,但是非常短的 classes 封装了变体之间的唯一差异。不要为两个构建变体之一定义任何资源,这样它将 "inherit" main 的资源。

我选择free是为了拥有main的资源。为了使其他构建变体 pro 具有不同的名称和图标(以及其他内容),必须定义足够的资源以提供与正在构建的其他 APK 的差异。

使用类似于下面 build.gradle 中所示的语法,我们将 profree 声明为 productFlavors 块内的构建变体。

build.gradle:

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'
    }

请注意,这两个构建变体从 com.dslomer64.kakurocombosbuildvariants 扩展包名称,附加 .pro.free 以获得唯一名称。这些必然唯一的名称最终会上传到 GPS。

AndroidManifest.xmlmainfree):

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"

    package="com.dslomer64.kakurocombosbuildvariants" >

    <application

        android:icon="@mipmap/ic_launcher">

        android:allowBackup="true"
    >
    <activity
            android:screenOrientation="portrait"
            android:label="@string/app_name"

            android:icon="@mipmap/ic_launcher"

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

我们将为这两个变体定义不同的 app_name 和不同的 ic_launcher

MyActivity.java 包含这两个略有不同的应用程序的几乎所有代码。其他源应用程序中包含的唯一代码是将一个与另一个区分开来的代码。在这种情况下,class 中的每一行在两个 APK 源中都被命名为 Free。并且 MyActivity.java 指的是 class 和变量,这似乎是一种模棱两可的方式,除了 gradle 在制作两个构建时会注意这一点。

参考文献在 MyActivity.java 中的样子如下:

`boolean FREE = Free.FREE;`

(我选择在所有 3 个 .java 文件中使用相同的字段名称 FREE,并将两个 classes 命名为 Free。可能不是一个很好的举动。但它奏效了。)

下面是名为 Free 的相同 classes 的样子:

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;
}

如果您不关心不同的图标和应用程序名称,您就完成了。 只需点击构建 |生成签名的 APKs ...你会看到这个:

这是两个 APK: C:\Users\Dov\AndroidStudioProjects\KakuroCombosBuildVariants\app

在 AS 内部,您会看到:

您已准备好将应用程序的两个版本上传到 GPS。一次一个。

但是,如果您需要为两个应用程序使用不同的图标或名称,请遵循相同的理念:让 free 的资源由 main 定义,并为 [=16] 定义不同的资源=] 在其目录节点下。注意 free 下没有 res 文件夹;它使用 main:

中的 res 文件夹信息

大图:

现在请注意 pro 下的复杂 res 文件夹,它定义了不同的名称和图标,以及与免费版本不同的 "java difference"。

请注意,不同版本的 mipmap 图标具有相同的名称--ic_launcher--但该名称在 strings.xml 文件中的定义不同,用于 main(对于 free)和在 strings.xml 文件中对于 pro.

同样适用于 app_names,在 main 中为 free 定义,在 pro 中为它自己定义。

对于pro:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="app_name">Kakuro Combos Pro </string>
</resources>

对于free

现在是将这两个 APK 上传到 GPS 的另一个机会。