How do I get different icons for the two versions

2019-09-06 18:22发布

问题:

I want to have ONE Android Studio (AS) 1.1.0 project create TWO APK files: one for pay version and one for free version of my Google Play Store (GPS) app. Using gradle build variants ("flavors"). I'm VERY close. I have uploaded from one AS project both versions--free and pay.

The only relatively-minor problems: 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.

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.

Here's "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>

Except for package name, the generated AndroidManifest.xml files are identical (here's one):

<?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>

I'm basing what I'm doing on this build.gradle file listed here, which has outdated content, flagged with ///////////:

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

Also basing my effort on this sketch of the associated file structure:

    +-- 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

I don't know if lack of "|" symbols from staging on down is significant. If so, that could be where I'm diverging.

When I try to create both APKs, I eventually get this screen, which is great news:

Inside AS, I see this, which is great news:

And in Windows 7 Explorer I see:

Here's my structure inside AS:

This corresponds to the structure shown in the link. Note especially NO res folder in the free version. The res folder in main contains the icon for free version. The res folder in pro contains the icon for pro version.

How can I get different icons for the two different APKs?

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

Is there a way to edit the generated AndroidManifest.xml files? Or to make each flavor have its own editable AndroidManifest.xml?

回答1:

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.

Step #1: Choose one (free or paid) to be the one you have in the main/ sourceset. For the purposes of this answer, I'll assume that the free one goes in main/.

Step #2: Edit main/res/values/strings.xml to have your desired free edition of the app_name resource, as you are using the app_name string resource in your manifest.

Step #3: Create a paid/res/values/strings.xml with a definition of app_name that contains your desired value for the paid app's display name.

Step #4: Decide whether you are going to use mipmaps or drawables for your launcher icon. You seem to have mipmap directories, but your manifest references a drawable resource. For the purposes of this answer, I will assume that you will go with mipmaps.

Step #5: Decide what you are going to call the launcher icon. Your app presently does not build, it would appear, as your manifest refers to a kc_icon_free drawable, but your directory listing shows ic_launcher. In particular, you want the name to NOT refer to "free" or "paid". I will assume here that you go with ic_launcher.

Step #6: Get your icons and manifest reorganized per the above, with your free edition of the icons in the main sourceset.

Step #7: Create paid/res/mipmap-*/ directories and put the paid edition of ic_launcher icons in there.

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.

You are certainly welcome to have AndroidManifest.xml files in the free and paid sourcesets. They will get merged with the one in main, the Gradle settings, and manifests from any dependencies.

That being said, you don't need that here. Have one manifest, pointing to one set of resources for labels and icons. Have one edition of the labels and icons in the main sourceset; have the other in a product flavor's sourceset (e.g., paid per my steps above).

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

Presumably, that is what you have for the app_name string resource value. If you do not like it, change the string resource.

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

Not the merged ones.

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

See above. Again, that's not the right solution for your problem.



回答2:

Here's a picture of what I had been stuck on that @CommonsWare so completely clarified:

Each with different app_name:

Gradle disambiguates both via ProductFlavors block declarations:

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

And here is the MyActivity.java reference to BOTH variants:

public class MyActivity extends Activity {

  boolean FREE = Free.FREE;

Depending on how the value of FREE is set in each variant, the variant is either "free" (FREE = true) or "pro" (FREE = false). Here are those two variant classes, both named Free in their respective files:

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

package com.dslomer64.kakurocombosbuildvariants;

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

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

package com.dslomer64.kakurocombosbuildvariants;

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


回答3:

I've used the ''Ribbonizer plugin for Android'', written by FUJI Goro.

This is a ribbonizer as a Gradle plugin for Android, which adds a ribbon to launcher icons automatically.

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