Android Studio 一个工程打包多个不同包
Android Studio 一个工程打包多个不同包
转: https://blog.csdn.net/kdsde/article/details/88639194
AS主要是利用gradle来实现这个需求的,具体做法如下:
修改app的build.gradle文件
假设我们同一套代码编译2个app:app1和app2
android {
…
productFlavors {
// app1
app1 {
// 设置applicationId(这里很重要,两个相同applicationId的apk不同同时安装在同一台Android手机中)
applicationId “com.johan.demo”
// 自动生成@string/app_name为demo
resValue “string”,“app_name”,“demo”
// 定义app_icon字段,在AndroidManifest.xml文件中用到
manifestPlaceholders = [app_icon : “@mipmap/ic_launcher”]
}
// app2
app2 {
// 解释同app1
applicationId “com.johan.demo1”
resValue “string”,“app_name”,“demo1”
manifestPlaceholders = [app_icon : “@mipmap/ic_launcher1”]
}
}
lintOptions {
checkReleaseBuilds false
abortOnError false
}
}
注意啦,这里有个坑,我们上面写了
?
1
resValue “string”,“app_name”,“demo”
运行之后,AS会自动生成@string/app_name,内容是这样的
?
1
demo
那么问题来了,如果你在app的strings.xml文件也定义了
?
1
demo
编译的时候就会出现问题,因为有2个app_name,所以我们要把app的strings.xml去掉,编译就会正常了。
再注意啦,我们 只能在app的build.gradle文件配置各个版本的值 ,如
?
1
2
3
4
5
6
app1 {
buildConfigField “int”, “TYPE”, “1”
}
app2 {
buildConfigField “int”, “TYPE”, “2”
}
如果你在其他子模块配置的话,编译时出现乱七八糟的错误!!
如果子模块需要配置的值,可以在公共模块定义静态变量,在app模块取出配置值后,设置到公共模块定义的静态变量中,这样的话各个模块都可以取到!!
修改AndroidManifest.xml文件
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<manifest xmlns:android=“http://schemas.android.com/apk/res/android”
package=“com.johan.demo”>
<application
android:allowBackup=“true”
// 注意啦,这里改为${app_icon}
android:icon="${app_icon}"
android:label="@string/app_name"
android:supportsRtl=“true”
android:theme="@style/AppTheme">
<action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" />
注意啦,icon属性的值是${app_icon},虽然为红色,但是不要紧,我们在build.gradle文件中加入了这么一段代码:
?
1
2
3
4
5
6
7
android {
…
lintOptions {
checkReleaseBuilds false
abortOnError false
}
}
这里的作用就是即使项目中报错也不会停止打包 。
打包并签名APK
我们打包时,就会出现2个app:
我们选择2个app,AS就会帮我们打包2个不同的APK了,就这么简单!!
填坑
今天按照以上步骤在开发项目尝试了一下,虽然可以打包不同版本的apk,但是不能同时安装到同一台设备,提示:xx有相同组件之类的。然后查看两个apk的包名是否一样,结果两个apk的包名是不同的。就这个问题查了一整天,果然皇天不负有心人,被我找到了,原因是我在AndroidManifest文件定义了一个provider:
记住,provider标签的authorities属性的值一定要是唯一的,如果两个app的authorities属性值一样,就会提示安装失败,一定要记住!!
查看包名的方法:
因为我们此时的apk不能安装的手机上,所以只有apk这个包,这时,我们使用aapt命令(aapt是sdk自带的一个工具,在sdk\builds-tools\目录下):
?
1
aapt dump badging D:\apk\xxx.apk | findstr package
由于已经集成在gradle中,所以能直接在gradle中使用,在app的build.gradle中创建productFlavors结构
android{
#…
productFlavors{
productA{
#这里定义产品A的特性
}
productB{#这里定义产品B的特性}#更多产品 ...
}
进行编译,在Build Variants版块里面我们能看到生成出来的不同Build Variant
这里切换不同的product能够切换到不同的产品上面去。
那么怎么样才能在不同产品上体现出差异化呢??
肯定是在对应的product括号下添加对应的属性,我们看下写法…
productA{
buildConfigField ‘String’, ‘HOST’, ‘”http://192.168.0.208:7001/“’
}
productB{
buildConfigField ‘String’, ‘HOST’, ‘”http://192.168.0.30:7001/“’
}
首先我们添加一个名为HOST的字符串对象,实现编译, 然后我们在app的build/generated/buildConfig/productA(由于当前选的是productA项目)/包名/下有个BuildConfig.java的文件,打开看下
首先我们可以看到这个文件是自动生成的且无法修改的,可以看到文件里面有DEBUG,AOOLICATION_ID这些参数,这些都是默认有的,我们看重点
这不就是我们在productA里面声明的HOST参数吗,系统帮我们声明了一个名为HOST的String对象,那么在Activity里面怎么使用它呢,很简单,只要BuildConfig.HOST就可以拿到HOST对象了。
由于我们现在是在productA项目下,我们在Build Variants里面将现场切换成ProductB试一下。然后我们在刚才Activity声明的HOST变量 点进去看一下,发现跳到了ProductB的BuildConfig.java文件来了
很显然,HOST的对象已经变了,变成了productB的对象值。
此外,除了String对象,我们还可以定义其他不同的对象,比如boolean,Class对象等等,
buildConfigField ‘boolean’, ‘displayFamilyName’, ‘true’ //列表Item前面是显示姓还是名
buildConfigField ‘Class’, ‘scheduleAddr’, ‘cn.com.minstone.httplogic.schedule.addr.PASys.class’
都是能够生成出来的。
替换manifest字段
在mainfest里按照一定格式自定义个可变的字段,在gradle里根据不同版本赋予不同的值.
注意:自定义mainfest字段的格式为:
YOURNAME;例如{ YOURNAME };例如YOURNAME;例如{APP_NAME}
具体写法是
productA{
manifestPlaceholders = [“APP_KEY”: “123456789”,]
}
在manifest文件里面可以这么引用
<meta-data
android:name = “APP_KEY”
android:value = “${APP_KEY}”
定义res对象
我们还可以定义资源对象,具体用法
productA{
resValue “string”, “appName”, ‘“柳州数字质监移动办公”’
}
然后在strings.xml文件里面使用
@string/appName`
此外,我们还可以定义像versionCode,versionName这样的字段,这里我就不一一类出来了。
假如所有现场都有一个统一的变量,这时候我总不能每个product里面都申明一模一样的变量吧??放心,这个问题productFlavors也帮我们考虑了,我们可以定义一个叫跟productX同级的defaultConfig的标签,标签里面可以放所有现场共用的属性和变量,具体操作是
android{
defaultConfig{
//存放公共变量
buildConfigField ‘String’, ‘COMMON’, ‘“admin”’
}
productA{
…
}
productB{
…
}
}
这样的话在productA和productB项目里都可以用到COMMON变量,假如productA的COMMON变量跟其他现场不一样怎么办?可以在productA标签下重写该变量进行差异化区分。
productA{
buildConfigField ‘String’, ‘COMMON’, ‘“aaaa”’
}
通过productFlavors,我们可以很方便地对每个现场的变量进行控制,只需要鼠标点击只能切换到对应的项目,并且变量的值也能够对应切换,这样我们就能够去掉恶心的if else语句,可维护性更高。
最后,我说下我根据自己项目特点使用productFlavors的一些小技巧。
首先,随着项目的增大,你会发现每个标签下的变量越来越多,这样的话会导致app的build.gradle文件的行数会越来越多,影响可阅读性。所以,我将不同现场的标签抽取出来,分成个个文件,然后在app的build.gradle引用这些文件
这样的话显得更加的直观 结构更加清晰,并且减少了build.gradle的代码量
2.假如我一个现场的主页面要导航页的5个功能,另外一个现场只要其中的4个功能,导致功能性的差异,这时候使用productFlavors怎么做?
这里我提供一种解决思路,也是使用String变量来存,但是存放的值是Json字符串
buildConfigField 'String', 'workBenchMenu', '"[{\\"title\\": \\"所有公文\\",\\"icon\\": \\"workbench_review\\"},{\\"title\\": \\"消息\\",\\"icon\\": \\"workben_message\\"},{\\"title\\": \\"任务\\",\\"icon\\": \\"workben_task\\" },{\\"title\\": \\"联系人\\",\\"icon\\": \\"workben_contact\\"},{\\"title\\": \\"单位动态\\",\\"icon\\": \\"workbench_dynamic\\"},{\\"title\\": \\"行程\\",\\"icon\\": \\"workben_schedule\\"},{\\"title\\": \\"公文分类\\",\\"icon\\": \\"workbench_documentrank\\"}]"'
然后Activity里面通过解析该json去生成布局,实现功能性差异。
1.创建productFlavors
在APP的gradle中添加:
android {
…
//创建productFlavors
productFlavors {
ceshi{//配置测试版包名和应用名
applicationId “ceshi.yb.com.wanandroid”
manifestPlaceholders = [APP_NAME: “@string/app_name_ceshi”]
}
shengchan{//配置生产版包名和应用名
applicationId “shengchan.yb.com.wanandroid”
manifestPlaceholders = [APP_NAME: “@string/app_name_shengchan”]
}
}
}
此时应该报以下错误:
Error:All flavors must now belong to a named flavor dimension. Learn more at https://d.android.com/r/tools/flavorDimensions-missing-error-message.html
在defaultConfig 中加上:
defaultConfig {
…
flavorDimensions “versionCode”
}
再重新编译下就OK了.
2.创建统一文件夹
切换到Project模式的目录:
在src目录下新建ceshi(/shengchan)包:
再新建以下包和文件:
资源文件同:
调试时点击 Build Variant 选择自己需要的版本即可正常引用
3.配置不同的应用名或其他属性
首先strings.xml中添加:
<string name="app_name_ceshi">测试版WanAndroid</string>
<string name="app_name_shengchan">生产版WanAndroid</string>
然后manifest中改下lable:
<application
android:name=".base.BaseApp"
android:allowBackup=“true”
android:icon="@mipmap/ic_launcher"
android:label="${APP_NAME}"//引用gradle中定义的变量
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl=“true”
android:theme="@style/AppTheme">
通过配置Flavors和自定义buildConfigField进行多个服务器地址打包
productFlavors{ } 是配置多渠道打包的.1).productFlavors{ } 与 buildTypes{ }里面的配置是多对多的关系。2).productFlavors{ } 其实是defaultConfig{ }的子集defaultConfig {}中的属性在productFlavors{}中都可以单独设置,若重复会以productFlavors{}中的属性为最终属性.a.可以对单独的productFlavors{ } 设置applicationId进而达到多个相同应用安装到同一台设备(现applicationId为唯一标识,区别于packageName)b.对单独的productFlavors{ }进行一些单独的配置或者操作
其中需要关注的是三部分:
defaultConfig {},buildTypes {},productFlavors {}
这三部分均可以对applicationId,图标及appname进行设置,但是优先级不同。优先级如下:
buildTypes > productFlavors > defaultConfig
设置AndroidManifest.xml中的属性可以通过manifestPlaceholders 进行设置,不同场景下的常量可以通过buildConfigField进行设置,资源的引用通过resValue 进行设置
eg:单独对company的flavors进行了applicationId、minSdk、和JUnit测试限制操作,这样打出的包只会对company的有影响,其他的flavors无影响defaultConfig的相关设置属性可直接在ProjectStructure中查看并设置
buildConfigField是用于解决Beta版本服务和Release版本服务地址不同
或者一些Log打印需求控制的.
形式:buildConfigField “boolean”, “LOG_DEBUG”, “true”
三个字段分别表示为: 自定义字段类型 自定义字段名 自定义字段值
将buildConfigField写入到Flavors中在打包编译时就会单独的编入进去(PS.请注意单双引号的使用,对于链接需要额外的单引号buildConfigField的放置位置很灵活,如果Flavors的buildConfigField是一样的话,直接放入到debug{}和release{}中即可.)
eg:查看时请注意路径,另外如果创建了多个Flavors时同步后可能只出现了第一个Flavors的文件夹.手动针对其他Flavors编译即可.
设置buildConfigField的IS_PUBLIC无用
一个app,两个module,一个是application module,另外一个是library module;
在library中设置buildConfigField,如下
release {
minifyEnabled false
proguardFiles getDefaultProguardFile(‘proguard-android.txt’), ‘proguard-rules.pro’
buildConfigField(“boolean”, “IS_PUBLIC”, “true”)
}
debug{
buildConfigField(“boolean”, “IS_PUBLIC”, “false”)
}
用来控制http及debug在测试环境,和正式环境的不同;
然而,无论如何都只能得到IS_PUBLIC为false;
最后子stackoverflow上得到了解决
http://stackoverflow.com/questions/20176284/buildconfig-debug-always-false-when-building-library-projects-with-gradle
解决方法如下
With Android Studio 1.1 and having also the gradle version at 1.1 it is possible:
Library
android {
publishNonDefault true
}
App
dependencies {
releaseCompile project(path: ‘:library’, configuration: ‘release’)
debugCompile project(path: ‘:library’, configuration: ‘debug’)
}
致谢:
https://www.jianshu.com/p/533240d222d3
https://blog.csdn.net/u010818425/article/details/52335844
https://blog.csdn.net/reancool/article/details/50673762
https://blog.csdn.net/xx326664162/article/details/49247815
https://blog.csdn.net/u010818425/article/details/52319382
https://developer.android.com/studio/publish/app-signing
————————————————
版权声明:本文为CSDN博主「快乐的飞鱼」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/kdsde/article/details/88639194
Android Studio 一个工程打包多个不同包相关推荐
- Android studio 多渠道版本打包方法 flavor dimension
Android studio 多渠道版本打包方法 flavor dimension 前言 开始 新建项目 修改build.gradle 创建差异化文件 创建图标 修改APP配色 修改APP名字 APP ...
- android项目打包apk,Android Studio将程序打包成APK的步骤详解
第一步:先点击Build选择GenerateSigned APK 第二步:如果之前有编译成APK的话,就直接选择Choose existing已经存在的key:如果没有编译成APK那就选择Create ...
- Uniapp中使用高德地图,并在android studio中离线打包
Uniapp中使用高德地图,并在android studio中离线打包 带高德地图功能的Uniapp的android离线打包 1. Uniapp中使用高德地图的方式 2. 高德地图中申请key 3. ...
- android studio一个好看的字体设置
android studio一个好看的字体设置 用了很多字体,觉得这个字体,大小和款式都很好看 如下 as 版本 Android Studio Electric Eel | 2022.1.1 RC 1 ...
- Android导入一个工程时提示 Invalid project description的解决方法
今天在网上下了个源码,导入的时候发现出现Invalid project description的提示,翻译成中文就是"无效的项目描述"的意思,搞不明白遂百度找到了解决办法,现记录并 ...
- Android Studio 单工程、多工程级联依赖下的aar的引用
Android Studio 多工程级联依赖下的aar的引用 背景: application A 依赖 library B library B 依赖 library C library C 引用aar ...
- Android Studio删除工程、项目的操作步骤
Android Studio删除工程.项目的操作步骤. 移除工程 主要用于从最近打开的项目列表中移除.硬盘中还是存在这个项目的. File--Close Project 注意:不要点击项目.(点击项目 ...
- android studio gradle 添加jar,android studio学习----通过gradle来导入jar包
转载地址:http://www.th7.cn/Program/Android/201507/495477.shtml File->Project Structure 可以打开下面的图: 1.通过 ...
- android 删除一个工程,Android Studio该怎样删除项目?
Android Studio该怎样删除项目?当你想在Android Studio中删除某个module时,大家习惯性的做法都是选中要删除的module,右键去找delete.但是在android St ...
最新文章
- 算法与数据结构重点归纳
- 绿色版Tomcat 启动 + 停止 + 随系统自动启动 - - 博客频道 - CSDN.NET
- 矩阵分析相关证明(一) —— 正交与投影
- Mysql 自动增长 重置
- 一篇文章让你彻底了解Java内部类
- 日常笔记-snownlp情感分析计算情感得分
- 六爻预测,前沿科学?伪科学?
- rtthread学习之(2)——STM32 系列外设驱动添加指南
- 人工智能导论(3)——确定性推理(Certainty Reasoning)
- 六州歌头 本周(1216-1220)部分GAN论文
- 七公江湖烤翅防骗子—常见网络骗子骗术防御要点
- IDEA 添加插件后启动闪退问题
- mysql数据迁移不停机_数据迁移还需要停机?不停机上线的正确姿势你能get到吗?...
- 华为手机怎么使用读卡器_手机nfc功能怎么打开(华为手机nfc功能使用步骤)
- im4java+GraphicsMagick 的问题
- 时间观——《天行九歌》第51集《一叶知秋》台词与典故
- eof() 和fail()
- float与double的MAX-MIN
- 数字营销公司HubSpot成功的9个经验
- video 标签 禁止下载 亲测有效 隐藏按钮 三个点 亲测有效