1. 如何理解Gradle?Gradle在Android的构建过程中有什么作用?
Gradle 是基于 Groovy 的 DSL(domain specific language),即领域专用语言。可以理解为用于在某个特定领域下解决问题的小语言。DSL 分为外部 DSL 和内部 DSL。像 Android 中使用 xml 描述布局文件,使用 json 描述数据信息,sql 语句操作数据库,都属于外部 DSL。而 Gradle 属于内部 DSL,基于 Groovy 语言,定义了各种语义来构建。
Gradle 是一种构建工具。
在 Android 中的作用:
- 差异化管理。我们每天都在 build,clean,签名,打包,发布, 这些过程都可以被代码描述出来,关键是可以被我们复用。在 Android 中,通常面对国内 N 个市场需要多渠道打包,或者针对不同手机品牌,不同手机尺寸做定制化的处理。通过 gradle 的 productFlavor 与 buildtype 可以是实现这种差异管理。
- 方便的依赖管理。只需要一个具体的坐标地址就可以加载各种库。库的版本也很方便,直接指定就可以,不同工程重复依赖最终只有一份。
- 项目部署。通过插件自动将项目上传到指定仓库。
2. 实践如下问题。
问题:我们都知道,Android中时常需要发布渠道包,需要将渠道信息附加到apk中,然后在程序启动的时候读取渠道信息。
动态指定一个渠道号(比如1001),那么构建的apk中,请在它的AndroidManifest.xml文件里面的application节点下面添加如下meta-data,请写一段Gradle脚本来自动完成:
<application android:allowBackup="false" android:supportsRtl="true">
<meta-data android:name=“channel" android:value=“1001" />
</application>
要求:当通过如下命令来构建渠道包的时候,将渠道号自动添加到apk的manifest中。
./gradlew clean assembleRelease -P channel=1001
实践
基本思路是通过在 AndroidManifest.xml
中定义 meta
,meta
中的 channel
值使用 ${name}
形式的占位符动态设置渠道号的值。
占位符使用 manifestPlaceholders
指定:
manifestPlaceholders = [CHANNEL: channel]
指定的时候需要指定一个变量 channel。这个变量 channel 的值我们接下来在 -P 命令中设置。此时直接编译通不过,因为 channel 是没有被定义过的。
在 gradle.properies 文件中定义 channel:
通过 gradle 的 -P 命令可以为某个属性设置值,哪怕这个属性没有定义。gradle -P channel=10001
就是给 channel 属性设置了一个 10001 值。
最终通过获取 meta 的值获取动态设置的渠道号。
android {
compileSdkVersion 27
defaultConfig {
applicationId "me.luwenjie.gradledemo"
minSdkVersion 21
targetSdkVersion 27
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
manifestPlaceholders = [CHANNEL: channel]
}
signingConfigs {
release {
storeFile file("key.jks")
storePassword "123456"
keyAlias "demo"
keyPassword "123456"
v1SigningEnabled true
v2SigningEnabled true
}
}
buildTypes {
release {
signingConfig signingConfigs.release
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
在 AndroidManifest.xml
设置占位符:
<application>
<meta-data
android:name="channel"
android:value="${CHANNEL}"/>
</application>
在 MainActivity 中获取渠道号。
public class MainActivity extends AppCompatActivity {
@SuppressLint("SetTextI18n") @Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView textView = findViewById(R.id.text);
textView.setText("渠道号 = " + getChannel(this));
}
public static String getChannel(Context context) {
try {
return context.getPackageManager()
.getApplicationInfo(context.getPackageName(),
PackageManager.GET_META_DATA).metaData.getInt("channel", 0) + "";
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
return "0";
}
}
}
最后运行 ./gradlew clean assembleRelease -P channel=1001
给 channel
设置值。就可以打出不同的渠道号包。