活用productFlavors,实现意想不到的功能
Posted 夏雨_
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了活用productFlavors,实现意想不到的功能相关的知识,希望对你有一定的参考价值。
前言:
在我们平时做项目时,总会遇到一些奇葩的要求,多渠道打包算是比较简单和常见的了,例如同时安装测试版和发布版,以及一套代码维护十几个不同的APP,这种需求也不少人遇到过,如果你不懂一些技巧,那么这些需求实现起来一定非常痛苦,所以我们接下来就介绍一下如何活用productFlavors,实现这些奇葩的需求
1. 简单使用
productFlavors直译过来就是特色的产品,所以他的主要作用就是让你同一套代码生产出不同的特色产品
productFlavors是build.gradle里面配置的,主要就是通过gradle打包时可以有多种配置供选择,类似buildTypes,并且可以和buildTypes共存
使用时在android 里面增加即可,我们下面简单的定义两个产品,一个是general,一个是vip,我们在里面给这两个产品定义不同的applicationId,这样就能同时安装了
(android Studio里面,真正区分APP的是applicationId)
android
productFlavors
general
applicationId "com.xiayu.flavorsdemo.general"
vip
applicationId "com.xiayu.flavorsdemo.vip"
这个时候我们就可以产生两个不同的产品了,接下来就要介绍怎么打包这两个产品了
(注意!每次修改了build.gradle,都必须同步(sync)一下,不然是不会生效的,这一点不少新人经常会忽略)
首先如果你不去选择的话默认是会打包最上面的产品,通过左下角的Build Variants可以自己选择打包的类型
我们可以看见上图是有四种产品供我们打包选择,这是因为与buildTypes共存时相互组合的结果
2. 特色图标
我们目前只是实现了同时安装,但是既然是特色产品,总会需要一些自己的特色,比如图标不一样
我们需要先在src目录下创建两个与产品同名的文件夹(下面简称产品文件夹)
把各自产品的特色图标放在各自的目录下,需要与main里面是相同目录结构,这里的效果就是各产品会先去从自己的目录下面读代码或者资源,如果没有的话就去main里面读
(注意!如果在main里面是放在哪个目录下,那么在自己产品文件夹下也要放在同样的目录下,比如图标之前是在mipmap-hdpi和mipmap-xhdpi都有,那么自己产品文件夹下也都需要有)
3. 清单文件
有时候我们的特色产品的清单文件里面需要一些自己的特色值,比如需要广播接收者需要不同的action,比如百度推送需要不同的API Key,这些同样可以用productFlavors来实现
我们常用的多渠道打包大部分也是这个原理,我们这里就以一个简单的多渠道打包为例
首先创建相应的productFlavors,这里因为不需要同时安装,所以就不用设置特色的applicationId
productFlavors
xiaomi
huawei
在清单文件的application节点中加入meta-data并在修改了application的label(label属性是修改应用名的)
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="$APP_NAME"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<meta-data android:name="CHANNEL" android:value="$CHANNEL_VALUE" />
</application>
接着我们修改productFlavors,设置特色的manifestPlaceholders
productFlavors
xiaomi
manifestPlaceholders = [CHANNEL_VALUE: "xiaomi",APP_NAME:"xiaomi版"]
huawei
manifestPlaceholders = [CHANNEL_VALUE: "huawei",APP_NAME:"huawei版"]
接着我们打包不同的产品后,应用名是不同的,并且可以在Activity里面读取当前渠道
public class MainActivity extends AppCompatActivity
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView tv= (TextView)findViewById(R.id.tv);
tv.setText(getChannelName(this));
//获取当前渠道
public static String getChannelName(Context context)
if (context == null)
return null;
String channelName = null;
try
PackageManager packageManager = context.getPackageManager();
if (packageManager != null)
//注意此处为ApplicationInfo 而不是 ActivityInfo,因为设置的meta-data是在application标签中,而不是某activity标签中,所以用ApplicationInfo
ApplicationInfo applicationInfo = packageManager.
getApplicationInfo(context.getPackageName(), PackageManager.GET_META_DATA);
if (applicationInfo != null)
if (applicationInfo.metaData != null)
channelName = String.valueOf(applicationInfo.metaData.get("CHANNEL"));
catch (PackageManager.NameNotFoundException e)
e.printStackTrace();
return channelName;
这里我们就可以看出来,清单文件中定义定义特色的值可以通过$VALUE来占位,然后通过manifestPlaceholders在打包的时候赋予不同的值
manifestPlaceholders是键值对的形式,key要与清单文件中的占位一样,value就是设置的值.键值对可以设置多个的,中间用逗号隔开
通过简单的设置,我们就完成了多渠道打包,并且每个渠道的应用名都是不一样的
4. buildConfigField
前面我们介绍了如何通过特色清单文件,读取当前渠道,虽然设置很简单,但是读取的时候代码还是比较多的,那么我们有没有比较简单的方式能在代码中直接读取productFlavors里面设置的特色值呢?我们可以通过buildConfigField.
设置:
productFlavors
xiaomi
buildConfigField "int", "APP_TYPE", "1"
huawei
buildConfigField "int", "APP_TYPE", "2"
读取:
int type = BuildConfig.APP_TYPE;
(这里要注意的就是BuildConfig的导包,要导入当前项目的非test包)
这样就可以很简单的读取产品的特色值,然后根据特色值做不同的处理了.
5. 应用场景
除了我们刚才举例的多渠道打包,以及同时安装线上线下两个版本的应用,我们还会遇到更加复杂的场景,需要同时应用上面的多种方法,下面以我之前做的某个应用为例,简单介绍一下如何综合应用上述几种方法
首先我们的项目除了正常版本,还有两个定制版,需求是这三个应用需要可以同时安装在一台手机上,并且主要功能是要同步的,那么我们就需要通过一套代码代码来维护三个应用.
如果每次打包不同的应用时,手动做一系列的修改,或者是通过代码中某个静态值来控制具体的效果,都容易出错,不仅麻烦,而且有很多局限性,比如代码中要加入很多if,else.比如清单文件就不能设置特色值,所以这个时候productFlavors就派上用场了
首先在productFlavors中设置特色applicationId,用于实现可以同时安装的功能
接着清单文件中设置一些特色值,比如不同应用的广播接收者的action设为不同的值
当一些图片文字不同或者布局差别特别大时,放在特色产品同名的文件夹
当一些逻辑差别比较小时,通过读取BuildConfig在代码中来做不同的处理
这样综合应用刚才介绍的几种方法,就可以很简单的完成我们的需求了
热门文章
- onTouch事件传递
- 那些年我们解决滑动冲突时遇过的坑
- 进程间通信–AIDL
- 序列化–Serializable与Parcelable
- 如何解决内存溢出以及内存泄漏
- Okhttputils终极封装
- FaceBook推出的调试神器
- Android代码优化工具
- Glide-入门教程
- Glide-图片预处理(圆角,高斯模糊等)
- Glide-图片的压缩
- Glide-内存缓存与磁盘缓存
- Glide-自定义缓存
以上是关于活用productFlavors,实现意想不到的功能的主要内容,如果未能解决你的问题,请参考以下文章
Android Gradle 插件ProductFlavor 配置 ( ProductFlavor 引入 | ProductFlavor 参考文档地址 )
Android Gradle中的productFlavors
Android Gradle 插件ProductFlavor 配置 ( ProductFlavor#resValue 方法 | ProductFlavor#dimension 维度属性 )