Android 产品定制之资源定制(同一应用程序使用不同资源)
前言
前两天面试一家公司(当然我没去),他们那边的工作要求是把一个软件发布多个不同的版本,每个稍微修改一些UI。就类似于同一软件发布多个不同名的版本,本质代码还是一样的,不过可能有些文字或者图片的变化。面试官跟我说你来的话任务很简单,就是不停地复制粘贴和改名。虽然我没去那家公司入职,但我也想了想那边任务的实现方式。复制粘贴?No!我们有更好的方法!下面我们来介绍如何创建多个不同版本的相同的应用程序。
基础版本
首先我们做一个基础版本的app,很简单,从第一个页面点击按钮到第二个页面,从第二个页面点击按钮到第三个页面。整体如图:
项目目录如下:
只是三个很简单的Activity。
进行定制
接下来,我们进行项目的定制。制作一个在第二个页面(SecondActivity)展示不同文字的定制版本。
首先,使用Android闭包的productFlavors块来声明一个产品定制。代码如下:
android {
compileSdkVersion 27
defaultConfig {
flavorDimensions(versionName)
}
productFlavors{
customone{
applicationId "learn.song.com.customone"
}
customtwo{
applicationId "learn.song.com.customtwo"
}
customthree{
applicationId "learn.song.com.customthree"
}
}
}
注意,新的Gradle版本要求在defaultConfig里声明flavorDimensions
本项目中,我们有customone,customtwo,customthree三种定制版本,每个定制拥有一个略微不同的applicationId,所以这三个定制版本可以被安装到同一个设备上。
每个产品定制可以拥有其自己的值,如下面的属性,还有一些其他的基于默认的defaultConfig的相同属性。
- applicationId
- minSdkVersion
- targetSdkVersion
- versionCode
- versionName
- sigingConfig
接下来,我们开始着手定制customone。打开工程视图,在app/src下建立customone文件夹,与main文件夹同级。项目结构如下:
下一步,我们定制customone,在SecondActivity里显示不同的文字,下面我们看SecondActivity的xml文件代码:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".SecondActivity">
<TextView
android:layout_marginTop="40dp"
android:layout_gravity="center_horizontal"
android:id="@+id/tv_second_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/secondpage"
/>
<TextView
android:id="@+id/tv_second_next"
android:padding="10dp"
android:background="#cf1414"
android:layout_marginTop="40dp"
android:layout_gravity="center_horizontal"
android:text="Go To Thrid Page"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
可见,我们第一个Textview显示的文字来自资源文件strings.xmlandroid:text="@string/secondpage"
,我们看我们基础版本的strings.xml:
<resources>
<string name="app_name">My Application</string>
<string name="title_activity_thrid">ThridActivity</string>
<string name="title_home">Home</string>
<string name="title_dashboard">Dashboard</string>
<string name="title_notifications">Notifications</string>
<string name="secondpage">Hello SecondPage From Main!</string>
</resources>
secondpage对应的文字是Hello SecondPage From Main!。好,接下来我们在customone对其定制,让我们customone版本显示的文字为Hello SecondPage From CustomOne!。怎么做呢?跟随我一步一步来。
1. 在customone文件夹下建立res文件夹,其就相当于main文件夹下的res,现在它是我们定制的res文件。我们要定制secondpage的值,那么我们要新建res/values/strings.xml,新的项目结构如下:
重写strings.xml,修改secondpage的值。我所定制的customone下strings.xml具体代码如下:
<resources>
<string name="app_name">My CustomOne</string>
<string name="title_activity_thrid">ThridActivity</string>
<string name="title_home">Home</string>
<string name="title_dashboard">Dashboard</string>
<string name="title_notifications">Notifications</string>
<string name="secondpage">Hello SecondPage From CustomOne!</string>
</resources>
主要就是修改了secondpage的值。接下来我们运行一下。要运行不同的定制,Android Studio提供了一个Build Variant视图。从下拉框中选择合适的变种,并像平常一样部署。 如图:
我们可以看到三个不同定制的Debug版本和Release版本。我们运行customoneDebug,效果如下:
看第二个页面(SecondActivity),上面的文字已经改变,但是我们并没有重新copy一套代码,而是直接在原代码上进行了定制。
通过合并项目定制和构建类型的res文件夹以及主要的目录树来合并资源。优先级是:构建类型覆盖产品定制,其覆盖main代码集。
为了更好的理解,接下来我们继续定制SecondActivity,在红色按钮下面显示一张妹子的图片。如何定制呢?跟之前思路一样,在customone/res下建立layout文件夹,重写activity_second.xml,重写之后的activity_second.xml如下:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".SecondActivity">
<TextView
android:layout_marginTop="40dp"
android:layout_gravity="center_horizontal"
android:id="@+id/tv_second_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/secondpage"
/>
<TextView
android:id="@+id/tv_second_next"
android:padding="10dp"
android:background="#cf1414"
android:layout_marginTop="40dp"
android:layout_gravity="center_horizontal"
android:text="Go To Thrid Page"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<ImageView
android:layout_gravity="center_horizontal"
android:src="@mipmap/img_meizi"
android:layout_marginTop="10dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
项目结构如下:
再看看我们customone定制版本的运行效果:
此时,第二个页面多出了我们刚刚添加的妹子的图片。与此同时,我们没有动过手脚的customtwo和customthree版本仍旧与基础版本一样,仍然保留着我们最初的效果。
结尾
刚刚我们对原始的项目进行了定制,产生了新的变种,展示了不同的页面效果。但是如果我们需要该某些activity的java代码应该怎么做呢?copy吗?当然不是,如果需要定制java代码,请看我的下一篇文章Android 产品定制之java代码定制(同一应用程序某个Activity使用不同java代码)。