Разные названия приложений для разных сборок?

94

У меня есть 2 вкуса, скажем, аромат1 и аромат2 .

Я бы хотел, чтобы мое приложение называлось, скажем, « AppFlavor1 », когда я создаю для варианта 2, и « AppFlavor2 », когда я создаю для варианта 2.

Я хочу изменить не название занятий. Я хочу изменить имя приложения, как оно отображается в меню телефона и в другом месте.

Из build.gradleя могу установить различные параметры для своих вкусов, но, похоже, не ярлык приложения. И я не могу программно изменить метку приложения на основе какой-то переменной.

Итак, как люди справляются с этим?

Александр Куляхтин
источник

Ответы:

24

Вместо того, чтобы изменять ваш основной strings.xml с помощью сценария и рисковать испортить систему управления версиями, почему бы не полагаться на стандартное поведение слияния сборки Android Gradle?

Мой build.gradleсодержит

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

Итак, теперь я могу определить свою app_nameстроку в файле variants/[release|debug]/res/strings.xml. И еще все, что я хочу изменить!

Пьер-Люк Паур
источник
Отредактировано: используйте res.srcDir для добавления в массив вместо его полного переопределения.
Пьер-Люк Паур
Да, я тоже уже понял это. Большое спасибо
Александр Куляхтин
1
Куда добавить sourceSetsблок? Это под android{...}блоком?
Abel Callejo
@AbelMelquiadesCallejo androidдействительно внутри блока.
Пьер-Люк Паур, 01
262

Удалить app_nameиз strings.xml(иначе gradle будет жаловаться на повторяющиеся ресурсы). Затем измените файл сборки следующим образом:

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

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

Также убедитесь, что атрибуту в манифесте @string/app_nameприсвоено значение android:label.

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

Это менее деструктивно, чем создание новых в strings.xmlрамках других построенных наборов или написание пользовательских сценариев.

Ганеш Кришнан
источник
9
Это работает как шарм, но вопрос: как добавить локализованные строки для других языков при добавлении такого строкового ресурса?
AndroidMechanic - Viral Patel,
разместил вопрос по этому поводу здесь: stackoverflow.com/questions/36105494/… Не могли бы вы взглянуть, пожалуйста?
AndroidMechanic - Viral Patel,
3
А как насчет использования нескольких параметров аромата? Как я могу назвать его по-разному для каждой комбинации вкуса / вкуса?
Zocket
1
Все в порядке, но имя приложения, отображаемое под значком запуска, не меняется в соответствии с настройками продукта Gradle. Я удалил "app_name" из strings.xml и установил вкус продукта. Если я вижу имя приложения на странице информации о приложении для Android, показывающее имя приложения, установленное в зависимости от продукта, но под значком запуска, показывающим мое предыдущее имя приложения.
iamcrypticcoder
2
@ mahbub.kuet вы используете @string/app_nameв качестве activityярлыка для лаунчера ? Имейте в виду, что вместо отображаемого имени приложения используется labelиз основного модуля запуска . activityapplication label
user650881
13

Если вы хотите сохранить локализацию имени приложения в разных вариантах, вы можете добиться этого следующим образом:

1) Укажите android:labelв <application>наличии AndroidManifest.xml:

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

2) Укажите значение по умолчанию fo appLabelна уровне приложения build.gradle:

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

3) Отмените значение аромата продукта следующим образом:

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

}

4) Добавьте строковые ресурсы для каждой из строк (defaultName, Flavour1, Flavour2) в ваш strings.xml. Это позволит вам их локализовать.

Сагар
источник
Шаг № 2 должен находиться на уровне «defaultConfig» build.gradle НЕ на уровне «android», иначе вы получите ошибку неизвестного свойства, связанную с именем manifestPlaceholder.
Брендон Уэйтли
8

Вы можете добавить файл ресурсов строки к каждому варианту, а затем использовать эти файлы ресурсов для изменения имени вашего приложения. Например, в одном из моих приложений есть бесплатная и платная версии. Чтобы переименовать их в «Lite» и «Pro», я создал meta_data.xmlфайл, добавил свое app_nameзначение к этому XML и удалил его из strings.xml. Затем app/srcсоздайте папку для каждого аромата (см. Пример структуры ниже). Внутри этих каталогов добавьте res/values/<string resource file name>. Теперь, когда вы строите, этот файл будет скопирован в вашу сборку, а ваше приложение будет переименовано.

Файловая структура:

app/src
   /pro/res/values/meta_data.xml
   /lite/res/values/meta_data.xml
Джеймс
источник
1
Это лучше, чем объявление в файле gradle. Работает как шарм. Спасибо.
Филип Лучианенко
7

Другой вариант, который я действительно использую, - это изменение манифеста для каждого приложения. Вместо копирования папки ресурсов вы можете создать манифест для каждого варианта.

sourceSets {
  main {
 }

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

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

У вас должен быть основной AndroidManifest в вашем src main, который будет основным. Затем вы можете определить манифест только с некоторыми параметрами для каждого аромата, например (src / release / AndroidManifest.xml):

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

Для отладки AndroidManifest (src / debug / AndroidManifest.xml):

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

Компилятор выполнит слияние манифеста, и у вас может быть значок для каждого варианта.

Хуанма Хурадо
источник
4

Это легко сделать с помощью 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
    }
}

Просто не забудьте удалить app_name из strings.xml

Дроид Крис
источник
2

Прежде всего, ответьте на вопрос: «Может ли пользователь установить обе разновидности вашего приложения на одном устройстве?»

Я использую скрипт Python, который исправляет исходный код. Он содержит несколько функций многократного использования и, конечно же, информацию о том, что нужно исправить в этом конкретном проекте. Таким образом, сценарий зависит от приложения.

Исправлений много, данные для исправлений хранятся в словаре Python (включая имена пакетов приложений, они, кстати, отличаются от имени пакета Java), по одному словарю на каждый вид.

Что касается l10n, строки могут указывать на другие строки, например, в моем коде у меня есть:

<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
источник
Это своего рода версии Light vs Pro, я думаю, у пользователя могут быть обе
версии
Затем вам нужно будет изменить имя пакета приложения, например com.example.mysoft.pro vs com.example.mysoft.light , иначе пользователь сможет установить только один из них на одном устройстве.
18446744073709551615 08
Я сделал это, но как мне получить «Мое приложение» или «Мое приложение Pro» в меню телефона? Теперь у меня есть 2 приложения (легкое и профессиональное), но оба имеют одно и то же имя. Для этого мне нужно два разных названия приложения, и это, как вы говорите, не так просто?
Александр Куляхтин 08
Как упоминается в другом (отрицательном) ответе, в AndroidManifest.xml есть <application android:icon="@drawable/ic_launcher" android:label="@string/app_name" >. После того, как вы очистите и перестроите все (два раза, по одному разу для каждой разновидности), вы должны получить два apk-файла с разными именами пакетов Android и разными метками запуска. Кстати, Eclipse часто не обнаруживает изменений в ресурсах, поэтому вам нужно попросить его очистить.
18446744073709551615 08
Как мне сделать строку / app_name разными для разных вкусов? Извините, я все еще не могу этого понять.
Александр Куляхтин 08
0

Как мне сделать строку / app_name разными для разных вкусов?

Я хотел написать обновление, но понял, что оно больше, чем исходный ответ, в котором говорится, что я использую скрипт Python, который исправляет источник.

У скрипта Python есть параметр - имя каталога. Этот каталог содержит ресурсы для каждого аромата, ресурсы, такие как значки запуска, и файл properties.txt со словарем Python.

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

Скрипт Python загружает словарь из этого файла и заменяет значение между <string name="app_name">и </string>на значение properties['appTitle'].

Приведенный ниже код предоставляется как есть / как было и т. Д.

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_/@\- ]+")

для чтения свойств из одного или нескольких таких файлов:

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

а функция fileReplace:

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+"'")

Первые строчки сценария:

#!/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
источник
-4

В файле AndroidManifest в теге приложения есть такая строка:

android:label

И там вы можете сказать, как метка приложения будет отображаться в меню приложений на устройстве.

Hitman
источник
Да, я прочитал вопрос ... Вы можете установить 2 ветки и для каждой (одну для аромата1 и одну для аромата2) установить другую метку android: в вашем файле AndroidManifest.
Hitman
6
Ах, я этого не знал. Как мне разместить эти 2 файла манифеста? Я хотя это невозможно
Александр Куляхтин