Mam 2 smaki kompilacji, powiedzmy smak1 i smak2 .
Chciałbym, aby moja aplikacja nosiła nazwę, na przykład „ AppFlavor1 ”, gdy tworzę dla smaku 1 i „ AppFlavor2 ”, gdy tworzę dla smaku 2.
To nie jest tytuł działań, które chcę zmienić. Chcę zmienić nazwę aplikacji wyświetlaną w menu telefonu i w innych miejscach.
Od build.gradle
mogę ustawić różne parametry dla moich smaków, ale wydaje się, że nie etykieta aplikacji. Nie mogę też programowo zmienić etykiety aplikacji na podstawie jakiejś zmiennej.
Jak więc ludzie sobie z tym radzą?
sourceSets
blok? Czy to podandroid{...}
blokiem?android
rzeczywiście wewnątrz bloku.Usuń
app_name
zstrings.xml
(w przeciwnym razie gradle będzie narzekać na zduplikowane zasoby). Następnie zmodyfikuj plik kompilacji w następujący sposób:productFlavors { flavor1{ resValue "string", "app_name", "AppNameFlavor1" } flavor2{ resValue "string", "app_name", "AppNameFlavor2" } }
Upewnij się również, że
@string/app_name
wartość jest przypisana doandroid:label
atrybutu w manifeście.<application ... android:label="@string/app_name" ...
Jest to mniej uciążliwe niż tworzenie nowych
strings.xml
w innych zestawach zbudowanych lub pisanie niestandardowych skryptów.źródło
@string/app_name
jakoactivity
etykiety programu uruchamiającego ? Należy pamiętać, że zamiast nazwy wyświetlanej aplikacji jest używanylabel
z głównego programu uruchamiającego .activity
application
label
Jeśli chcesz zachować lokalizację nazwy aplikacji w różnych smakach, możesz to osiągnąć w następujący sposób:
1) Określ
android:label
w<application>
dostępne wAndroidManifest.xml
sposób następujący:<application ... android:label="${appLabel}" ... >
2) Określ domyślną wartość fo
appLabel
na poziomie aplikacjibuild.gradle
:manifestPlaceholders = [appLabel:"@string/defaultName"]
3) Zastąp wartość smaków produktu w następujący sposób:
productFlavors { AppFlavor1 { manifestPlaceholders = [appLabel:"@string/flavor1"] } AppFlavor2 { manifestPlaceholders = [appLabel:"@string/flavor2"] } }
4) Dodaj zasoby ciągów dla każdego z ciągów (defaultName, smak1, smak2) w pliku
strings.xml
. To pozwoli ci je zlokalizować.źródło
Możesz dodać plik zasobów ciągów do każdego smaku, a następnie użyć tych plików zasobów, aby zmienić nazwę aplikacji. Na przykład w jednej z moich aplikacji mam darmową i płatną wersję. Aby zmienić ich nazwy na „Lite” i „Pro”, utworzyłem
meta_data.xml
plik, dodałem swojąapp_name
wartość do tego XML i usunąłem go zstrings.xml
. Następnieapp/src
utwórz folder dla każdego smaku (zobacz poniżej przykładową strukturę). W tych katalogach dodajres/values/<string resource file name>
. Teraz podczas kompilacji ten plik zostanie skopiowany do Twojej kompilacji, a nazwa aplikacji zostanie zmieniona.Struktura plików:
app/src /pro/res/values/meta_data.xml /lite/res/values/meta_data.xml
źródło
Inną opcją, której faktycznie używam, jest zmiana manifestu dla każdej aplikacji. Zamiast kopiować folder zasobów, możesz utworzyć manifest dla każdego smaku.
sourceSets { main { } release { manifest.srcFile 'src/release/AndroidManifest.xml' } debug { manifest.srcFile 'src/debug/AndroidManifest.xml' } }
Musisz mieć główny plik AndroidManifest w pliku głównym src, który będzie głównym. Następnie możesz zdefiniować manifest z tylko niektórymi opcjami dla każdego smaku, takimi jak (src / release / AndroidManifest.xml):
<manifest package="com.application.yourapp"> <application android:icon="@drawable/ic_launcher"> </application> </manifest>
Do debugowania, AndroidManifest (src / debug / AndroidManifest.xml):
<manifest package="com.application.yourapp"> <application android:icon="@drawable/ic_launcher2"> </application> </manifest>
Kompilator połączy manifest i możesz mieć ikonę dla każdego smaku.
źródło
Można to łatwo osiągnąć w buildTypes
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 } }
Po prostu upewnij się, że usunąłeś app_name z strings.xml
źródło
Przede wszystkim odpowiedz na pytanie: „Czy użytkownik może zainstalować obie wersje aplikacji na tym samym urządzeniu?”
Używam skryptu w Pythonie, który łata źródło. Zawiera kilka funkcji wielokrotnego użytku i oczywiście wiedzę, co należy załatać w tym konkretnym projekcie. Tak więc skrypt jest specyficzny dla aplikacji.
Jest dużo łatania, dane do łatania są przechowywane w słowniku Pythona (w tym nazwy pakietów aplikacji, przy okazji różnią się od nazwy pakietu Java), po jednym słowniku na smak.
Co do l10n, stringi mogą wskazywać na inne stringi, np. W moim kodzie mam:
<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>
źródło
<application android:icon="@drawable/ic_launcher" android:label="@string/app_name" >
. Po wyczyszczeniu i ponownym skompilowaniu wszystkiego (dwa razy, raz na smak), powinieneś otrzymać dwa pliki APK z różnymi nazwami pakietów Androida i różnymi etykietami programu uruchamiającego. BTW, Eclipse często nie wykrywa zmian w zasobach, więc musisz poprosić go o wyczyszczenie.Jak jednak zmienić ciąg / nazwa_aplikacji w zależności od smaku?
Chciałem napisać aktualizację, ale zdałem sobie sprawę, że jest ona większa niż oryginalna odpowiedź mówiąca, że używam skryptu Pythona, który łata źródło.
Skrypt w Pythonie ma parametr, nazwę katalogu. Ten katalog zawiera zasoby według smaku, zasoby, takie jak ikony programu uruchamiającego oraz plik properties.txt ze słownikiem Pythona.
{ 'someBoolean' : True , 'someParam' : 'none' , 'appTitle' : '@string/x_app_name_xyz' }
Skrypt w języku Python ładuje słownik z tego pliku i zastępuje wartość między
<string name="app_name">
i</string>
wartościąproperties['appTitle']
.Poniższy kod jest dostarczany na zasadzie „tak jak jest / jak było” itp.
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_/@\- ]+")
aby odczytać właściwości z jednego lub więcej takich plików:
with open(filename1) as f: properties = eval(f.read()) with open(filename2) as f: properties.update(eval(f.read()))
a funkcja fileReplace to:
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+"'")
Pierwsze wiersze skryptu to:
#!/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
źródło
W pliku AndroidManifest w tagu aplikacji znajduje się następujący wiersz:
android:label
I tam możesz powiedzieć, jak etykieta aplikacji pojawi się w menu aplikacji na urządzeniu
źródło