Unterschiedliche App-Namen für unterschiedliche Build-Varianten?

90

Ich habe 2 Geschmacksrichtungen, z. B. Flavour1 und Flavour2 .

Ich möchte, dass meine Anwendung beispielsweise " AppFlavor1 " heißt, wenn ich für Flavour1 erstelle, und " AppFlavor2 ", wenn ich für Flavour 2 erstelle.

Es ist nicht der Titel von Aktivitäten, die ich ändern möchte. Ich möchte den App-Namen so ändern, wie er im Telefonmenü und anderswo angezeigt wird.

Ab build.gradlekann ich verschiedene Parameter für meine Geschmacksrichtungen einstellen, aber anscheinend nicht das App-Label. Und ich kann das App-Label auch nicht programmgesteuert basierend auf einer Variablen ändern.

Wie gehen die Leute damit um?

Alexander Kulyakhtin
quelle

Antworten:

24

Anstatt Ihre Hauptzeichenfolge.xml mit einem Skript zu ändern und die Quellcodeverwaltung durcheinander zu bringen, sollten Sie sich auf das Standard-Zusammenführungsverhalten des Android Gradle-Builds verlassen.

Mein build.gradleenthält

sourceSets {
    main {
        manifest.srcFile 'AndroidManifest.xml'
        java.srcDirs = ['src']
        resources.srcDirs = ['src']
        aidl.srcDirs = ['src']
        renderscript.srcDirs = ['src']
        res.srcDirs = ['res']
        assets.srcDirs = ['assets']
    }

    release {
        res.srcDir 'variants/release/res'
    }

    debug {
        res.srcDir 'variants/debug/res'
    }
}

Jetzt kann ich meine app_nameZeichenfolge in der definieren variants/[release|debug]/res/strings.xml. Und alles andere möchte ich noch ändern!

Pierre-Luc Paour
quelle
Bearbeitet: Verwenden Sie res.srcDir, um das Array hinzuzufügen, anstatt es insgesamt neu zu definieren.
Pierre-Luc Paour
Ja, das habe ich inzwischen auch herausgefunden. Vielen Dank
Alexander Kulyakhtin
1
Wo soll man den sourceSetsBlock hinzufügen ? Ist es unter dem android{...}Block?
Abel Callejo
@AbelMelquiadesCallejo in der androidTat im Block.
Pierre-Luc Paour
252

Entfernen app_namevon strings.xml(sonst beschwert sich gradle über doppelte Ressourcen). Ändern Sie dann die Build-Datei wie folgt:

productFlavors {
    flavor1{
        resValue "string", "app_name", "AppNameFlavor1"
    }

    flavor2{
        resValue "string", "app_name", "AppNameFlavor2"
    }
   } 

Stellen Sie außerdem sicher, dass @string/app_namedem android:labelAttribut im Manifest ein Wert zugewiesen ist .

<application
        ...
        android:label="@string/app_name"
        ...

Dies ist weniger störend als das Erstellen neuer strings.xmlunter verschiedenen erstellten Sets oder das Schreiben von benutzerdefinierten Skripten.

Ganesh Krishnan
quelle
9
Dies funktioniert wie ein Zauber, aber die Frage: Wie fügen wir lokalisierte Zeichenfolgen für andere Gebietsschemas hinzu, wenn wir die Zeichenfolgenressource wie folgt hinzufügen?
AndroidMechanic - Viral Patel
hat hier eine Frage dazu gestellt: stackoverflow.com/questions/36105494/… Stört es Sie bitte, einen Blick darauf zu werfen?
AndroidMechanic - Viral Patel
3
Was ist mit der Verwendung mehrerer Geschmacksdimensionen? Wie kann ich es für jede Geschmacks- / Geschmackskombination unterschiedlich benennen?
Zocket
1
Alles ist in Ordnung, aber der App-Name, der unter dem Startsymbol angezeigt wird, ändert sich nicht gemäß dem Gradle-Produktgeschmack. Ich habe "app_name" aus strings.xml entfernt und die Produktvariante eingestellt. Wenn ich den App-Namen auf der App-Info-Seite von Android sehe, wird der App-Name nach Produktvariante festgelegt, aber unter dem Startsymbol wird mein vorheriger App-Name angezeigt.
iamcrypticcoder
2
@ mahbub.kuet verwenden Sie @string/app_namefür Ihr Launcher- activityLabel? Beachten Sie, dass der labelvom Hauptstarter activityverwendete application labelfür den App-Anzeigenamen bevorzugt verwendet wird .
user650881
13

Wenn Sie die Lokalisierung für den App-Namen in verschiedenen Varianten beibehalten möchten, können Sie dies wie folgt erreichen:

1) Angabe android:labelin <application>erhältlich , AndroidManifest.xmlwie folgt:

<application
    ...
    android:label="${appLabel}"
    ...
>

2) Geben Sie den Standardwert für appLabelin der App-Ebene an build.gradle:

manifestPlaceholders = [appLabel:"@string/defaultName"]

3) Überschreiben Sie den Wert für Produktaromen wie folgt:

productFlavors {
    AppFlavor1 {
        manifestPlaceholders = [appLabel:"@string/flavor1"]
    }
    AppFlavor2 {
        manifestPlaceholders = [appLabel:"@string/flavor2"]
    }

}

4) Fügen Sie Zeichenfolgenressourcen für jede Zeichenfolge (Standardname, Flavour1, Flavour2) in Ihrem hinzu strings.xml. Auf diese Weise können Sie sie lokalisieren.

Sagar
quelle
Schritt 2 muss sich in der Ebene 'defaultConfig' des build.gradle befinden, NICHT in der Ebene 'android'. Andernfalls wird ein unbekannter Eigenschaftsfehler in Bezug auf den Namen manifestPlaceholders angezeigt.
Brendon Whateley
8

Sie können jeder Variante eine String-Ressourcendatei hinzufügen und diese Ressourcendateien dann verwenden, um Ihren App-Namen zu ändern. Zum Beispiel habe ich in einer meiner Apps eine kostenlose und kostenpflichtige Version. Um sie in "Lite" und "Pro" umzubenennen, habe ich eine meta_data.xmlDatei erstellt, app_namediesem XML meinen Wert hinzugefügt und sie entfernt strings.xml. Als nächstes app/srcerstellen Sie einen Ordner für jede Geschmacksrichtung (siehe unten für die Beispielstruktur). Fügen Sie in diesen Verzeichnissen hinzu res/values/<string resource file name>. Wenn Sie jetzt erstellen, wird diese Datei in Ihren Build kopiert und Ihre App wird umbenannt.

Dateistruktur:

app/src
   /pro/res/values/meta_data.xml
   /lite/res/values/meta_data.xml
James
quelle
1
Dies ist besser als das Deklarieren in einer Gradle-Datei. Klappt wunderbar. Danke dir.
Filip Luchianenco
7

Eine andere Option, die ich tatsächlich verwende, ist das Ändern des Manifests für jede Anwendung. Anstatt den Ressourcenordner zu kopieren, können Sie für jede Variante ein Manifest erstellen.

sourceSets {
  main {
 }

  release {
    manifest.srcFile 'src/release/AndroidManifest.xml'
 }

  debug {
    manifest.srcFile 'src/debug/AndroidManifest.xml'
 }
}

Sie müssen ein Haupt-AndroidManifest in Ihrem src-Hauptfach haben, das das Hauptprinzip sein wird. Anschließend können Sie ein Manifest mit nur einigen Optionen für jede Variante definieren, z. B. (src / release / AndroidManifest.xml):

<manifest package="com.application.yourapp">
  <application android:icon="@drawable/ic_launcher">
  </application>
</manifest>

Zum Debuggen AndroidManifest (src / debug / AndroidManifest.xml):

<manifest package="com.application.yourapp">
  <application android:icon="@drawable/ic_launcher2">
  </application>
</manifest>

Der Compiler führt eine Zusammenführung des Manifests durch und Sie können für jede Variante ein Symbol festlegen.

Juanma Jurado
quelle
4

Dies kann leicht unter buildTypes erreicht werden

buildTypes {
    debug {
        buildConfigField("String", "server_type", "\"TEST\"")
        resValue "string", "app_name", "Eventful-Test"
        debuggable true
        signingConfig signingConfigs.debug_key_sign
    }

    stage {
        buildConfigField("String", "server_type", "\"STAGE\"")
        resValue "string", "app_name", "Eventful-Stage"
        debuggable true
        signingConfig signingConfigs.debug_key_sign
    }

    release {
        buildConfigField("String", "server_type", "\"PROD\"")
        resValue "string", "app_name", "Eventful"
        minifyEnabled false
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        //TODO - add release signing
    }
}

Stellen Sie einfach sicher, dass Sie app_name aus strings.xml entfernen

Droide Chris
quelle
2

Beantworten Sie zunächst diese Frage: "Kann der Benutzer beide Varianten Ihrer Anwendung auf demselben Gerät installieren?"

Ich verwende ein Python-Skript, das die Quelle patcht. Es enthält einige wiederverwendbare Funktionen und natürlich das Wissen, was in diesem speziellen Projekt gepatcht werden muss. Das Skript ist also anwendungsspezifisch.

Es gibt viele Patches, die Daten für das Patchen werden in einem Python-Wörterbuch gespeichert (einschließlich der Namen der Anwendungspakete, sie unterscheiden sich übrigens vom Namen des Java-Pakets), ein Wörterbuch pro Version.

In Bezug auf l10n können Zeichenfolgen auf andere Zeichenfolgen verweisen, z. B. in meinem Code:

<string name="app_name">@string/x_app_name_xyz</string>

<string name="x_app_name_default">My Application</string>
<string name="x_app_name_xyz">My App</string>
18446744073709551615
quelle
Es ist eine Art Light vs Pro-Version. Ich denke, der Benutzer hat möglicherweise beide
Alexander Kulyakhtin,
Dann müssen Sie den Namen des App-Pakets ändern, z. B. com.example.mysoft.pro vs com.example.mysoft.light , andernfalls kann der Benutzer nur eines davon auf demselben Gerät installieren.
18446744073709551615
Ich habe das getan, aber wie bekomme ich "Meine App" gegen "Meine App Pro" im Telefonmenü? Ich habe jetzt 2 Apps (Light und Pro), aber beide haben den gleichen Namen. Ich brauche dafür 2 verschiedene App-Namen und das ist, wie Sie sagen, nicht so einfach?
Alexander Kulyakhtin
Wie die andere (herabgestimmte) Antwort erwähnt, gibt es in AndroidManifest.xml <application android:icon="@drawable/ic_launcher" android:label="@string/app_name" >. Nachdem Sie alles gereinigt und neu erstellt haben (zweimal, einmal pro Geschmacksrichtung), sollten Sie zwei apk-s mit unterschiedlichen Android-Paketnamen und unterschiedlichen Launcher-Labels erhalten. Übrigens erkennt Eclipse häufig keine Änderungen an Ressourcen, daher müssen Sie sie zur Bereinigung auffordern.
18446744073709551615
Wie kann ich string / app_name je nach Geschmack unterscheiden? Es tut mir leid, dass ich es immer noch nicht bekommen kann.
Alexander Kulyakhtin
0

Wie kann ich string / app_name je nach Geschmack unterscheiden?

Ich wollte ein Update schreiben, stellte jedoch fest, dass es größer ist als die ursprüngliche Antwort, dass ich ein Python-Skript verwende, das die Quelle patcht.

Das Python-Skript hat einen Parameter, einen Verzeichnisnamen. Dieses Verzeichnis enthält Assets nach Geschmack, Ressourcen wie Startsymbole und die Datei properties.txt mit einem Python-Wörterbuch.

{ 'someBoolean' : True
, 'someParam' : 'none'
, 'appTitle' : '@string/x_app_name_xyz'
}

Das Python-Skript lädt das Wörterbuch aus dieser Datei und ersetzt den Wert zwischen <string name="app_name">und </string>durch den Wert von properties['appTitle'].

Der folgende Code wird wie besehen / wie besehen usw. bereitgestellt.

for strings_xml in glob.glob("res/values*/strings.xml"):
    fileReplace(strings_xml,'<string name="app_name">',properties['appTitle'],'</string>',oldtextpattern=r"[a-zA-Z0-9_/@\- ]+")

So lesen Sie Eigenschaften aus einer oder mehreren solchen Dateien:

with open(filename1) as f:
    properties = eval(f.read())
with open(filename2) as f:
    properties.update(eval(f.read()))

und die fileReplace-Funktion lautet:

really = True
#False for debugging

# In the file 'fname',
# find the text matching "before oldtext after" (all occurrences) and
# replace 'oldtext' with 'newtext' (all occurrences).
# If 'mandatory' is true, raise an exception if no replacements were made.
def fileReplace(fname,before,newtext,after,oldtextpattern=r"[\w.]+",mandatory=True):
    with open(fname, 'r+') as f:
        read_data = f.read()
        pattern = r"("+re.escape(before)+r")"+oldtextpattern+"("+re.escape(after)+r")"
        replacement = r"\g<1>"+newtext+r"\g<2>"
        new_data,replacements_made = re.subn(pattern,replacement,read_data,flags=re.MULTILINE)
        if replacements_made and really:
            f.seek(0)
            f.truncate()
            f.write(new_data)
            if verbose:
                print "patching ",fname," (",replacements_made," occurrence" + ("s" if 1!=replacements_made else ""),")",newtext,("-- no changes" if new_data==read_data else "-- ***CHANGED***")
        elif replacements_made:
            print fname,":"
            print new_data
        elif mandatory:
            raise Exception("cannot patch the file: "+fname+" with ["+newtext+"] instead of '"+before+"{"+oldtextpattern+"}"+after+"'")

Die ersten Zeilen des Skripts sind:

#!/usr/bin/python
# coding: utf-8

import sys
import os
import re
import os.path
import shutil
import argparse
import string
import glob
from myutils import copytreeover
18446744073709551615
quelle
-4

In der AndroidManifest-Datei haben Sie im Anwendungs-Tag folgende Zeile:

android:label

Dort können Sie festlegen, wie das Anwendungsetikett im Anwendungsmenü des Geräts angezeigt wird

Hitman
quelle
Ja, ich habe die Frage gelesen ... Sie können 2 Zweige festlegen und für jeden (einen für Flavour1 und einen für Flavour2) ein anderes Android: Label in Ihrer AndroidManifest-Datei festlegen.
Hitman
6
Ah, das wusste ich nicht. Wie platziere ich diese 2 Manifestdateien? Ich
dachte,