ชื่อแอปที่แตกต่างกันสำหรับรสชาติการสร้างที่แตกต่างกัน?


94

ฉันมี 2 รสชาติคือรส1และรส 2

ฉันต้องการให้แอปพลิเคชันของฉันตั้งชื่อโดยพูดว่า " AppFlavor1 " เมื่อฉันสร้างสำหรับรสชาติ 1 และ " AppFlavor2 " เมื่อฉันสร้างสำหรับรสชาติ 2

ไม่ใช่ชื่อของกิจกรรมที่ฉันต้องการเปลี่ยนแปลง ฉันต้องการเปลี่ยนชื่อแอพตามที่แสดงบนเมนูโทรศัพท์และที่อื่น ๆ

จากbuild.gradleฉันสามารถตั้งค่าพารามิเตอร์ต่างๆสำหรับรสชาติของฉัน แต่ดูเหมือนว่าไม่ใช่ป้ายกำกับแอป และฉันไม่สามารถเปลี่ยนป้ายกำกับแอปโดยใช้โปรแกรมตามตัวแปรบางตัวได้เช่นกัน

แล้วผู้คนจะจัดการกับเรื่องนี้อย่างไร?

คำตอบ:


24

แทนที่จะเปลี่ยน strings.xml หลักของคุณด้วยสคริปต์และความเสี่ยงที่จะทำให้การควบคุมซอร์สของคุณยุ่งเหยิงทำไมไม่พึ่งพาพฤติกรรมการรวมมาตรฐานของ Android Gradle build?

ของฉัน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 เพื่อเพิ่มลงในอาร์เรย์แทนการกำหนดใหม่ทั้งหมด
Pierre-Luc Paour

ใช่ฉันได้คิดออกแล้วในตอนนี้ ขอบคุณมาก
Alexander Kulyakhtin

1
ควรเพิ่มsourceSetsบล็อกที่ไหน อยู่ใต้android{...}บล็อคหรือไม่?
Abel Callejo

@AbelMelquiadesCallejo ในandroidบล็อกแน่นอน
Pierre-Luc Paour

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ตัวเรียกactivityใช้งานหลักจะถูกใช้ในการตั้งค่าapplication labelสำหรับชื่อที่แสดงของแอป
user650881

13

หากคุณต้องการรักษาการแปลเป็นภาษาท้องถิ่นสำหรับชื่อแอปในรสชาติที่แตกต่างกันคุณสามารถทำได้ดังนี้:

1) ระบุandroid:labelใน<application>ที่มีอยู่ในAndroidManifest.xmlดังนี้

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

2) ระบุค่าเริ่มต้นสำหรับappLabelระดับแอปbuild.gradle:

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

3) แทนที่ค่าสำหรับรสชาติของผลิตภัณฑ์ดังนี้:

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

}

4) เพิ่มทรัพยากรสตริงสำหรับแต่ละสตริง (defaultName, taste1, flavor2) ในstrings.xmlไฟล์. ซึ่งจะช่วยให้คุณสามารถแปลเป็นภาษาท้องถิ่นได้


ขั้นตอนที่ # 2 ต้องอยู่ในระดับ 'defaultConfig' ของ build.gradle NOT ในระดับ 'android' มิฉะนั้นคุณจะได้รับข้อผิดพลาดคุณสมบัติที่ไม่รู้จักซึ่งเกี่ยวข้องกับชื่อ manifestPlaceholders
Brendon Whateley

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 ใช้งานได้เหมือนมีเสน่ห์ ขอบคุณ.
Filip Luchianenco

7

อีกทางเลือกหนึ่งที่ฉันใช้จริงคือเปลี่ยนรายการสำหรับแต่ละแอปพลิเคชัน แทนที่จะคัดลอกโฟลเดอร์ทรัพยากรคุณสามารถสร้างรายการสำหรับแต่ละรสชาติได้

sourceSets {
  main {
 }

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

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

คุณต้องมี AndroidManifest หลักใน src หลักของคุณซึ่งจะเป็นตัวหลัก จากนั้นคุณสามารถกำหนดรายการที่มีเพียงบางตัวเลือกสำหรับแต่ละรสชาติเช่น (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 (รวมถึงชื่อแพ็กเกจแอปพลิเคชัน BTW ต่างจากชื่อแพ็กเกจ 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>

มันเป็นชนิดของแสงเทียบกับรุ่น Pro ผมคิดว่าผู้ใช้อาจจะมีพวกเขาทั้งสอง
อเล็กซานเด Kulyakhtin

จากนั้นคุณจะต้องเปลี่ยนชื่อแพ็กเกจแอปเช่นcom.example.mysoft.proเทียบกับcom.example.mysoft.lightมิฉะนั้นผู้ใช้จะสามารถติดตั้งได้เพียงรายการเดียวในอุปกรณ์เดียวกัน
18446744073709551615

ฉันทำอย่างนั้น แต่ฉันจะรับ "แอปของฉัน" กับ "แอปของฉัน Pro" ในเมนูโทรศัพท์ได้อย่างไร ตอนนี้ฉันมี 2 แอพ (เบาและโปร) แต่ทั้งสองมีชื่อเดียวกัน ฉันต้องการชื่อแอพที่แตกต่างกัน 2 ชื่อสำหรับสิ่งนั้นและนั่นคืออย่างที่คุณพูดไม่ใช่เรื่องง่ายอย่างนั้นเหรอ?
Alexander Kulyakhtin

ในฐานะที่เป็นอื่น ๆ (downvoted) คำตอบที่กล่าวถึงใน AndroidManifest.xml <application android:icon="@drawable/ic_launcher" android:label="@string/app_name" >มี หลังจากที่คุณทำความสะอาดและสร้างทุกอย่างใหม่ (สองครั้งครั้งละครั้งต่อรสชาติ) คุณควรได้รับ apk-s สองตัวพร้อมชื่อแพ็กเกจ Android ที่แตกต่างกันและป้ายกำกับตัวเรียกใช้งานที่แตกต่างกัน BTW, Eclipse มักตรวจไม่พบการเปลี่ยนแปลงในทรัพยากรดังนั้นคุณต้องขอให้ทำความสะอาด
18446744073709551615

ฉันจะทำให้ string / app_name แตกต่างกันตามรสชาติได้อย่างไร ฉันขอโทษที่ฉันยังรับไม่ได้
Alexander Kulyakhtin

0

ฉันจะทำให้ string / app_name แตกต่างกันตามรสชาติได้อย่างไร

ฉันต้องการเขียนอัปเดต แต่ตระหนักว่ามันใหญ่กว่าคำตอบเดิมที่บอกว่าฉันใช้สคริปต์ Python ที่แก้ไขซอร์ส

สคริปต์ Python มีพารามิเตอร์ชื่อไดเร็กทอรี ไดเร็กทอรีนั้นมีเนื้อหาตามรสชาติทรัพยากรเช่นไอคอนตัวเรียกใช้งานและคุณสมบัติของไฟล์ 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

-4

ในไฟล์ AndroidManifest ในแท็กแอปพลิเคชันคุณมีบรรทัดนี้:

android:label

และคุณสามารถพูดได้ว่าป้ายกำกับแอปพลิเคชันจะปรากฏในเมนูแอปพลิเคชันบนอุปกรณ์อย่างไร


ใช่ฉันอ่านคำถามแล้ว ... คุณสามารถตั้งค่า 2 สาขาและสำหรับแต่ละสาขา (หนึ่งสาขาสำหรับรสชาติ 1 และอีกหนึ่งสำหรับรสชาติ 2) เพื่อตั้งค่า android: label อื่นในไฟล์ AndroidManifest ของคุณ
Hitman

6
อาฉันไม่รู้เรื่องนั้น ฉันจะวางไฟล์ manifest 2 ไฟล์นั้นได้อย่างไร แม้ว่าจะเป็นไปไม่ได้
ก็ตาม
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.