Android 产品定制之资源定制(同一应用程序使用不同资源)

前言

前两天面试一家公司(当然我没去),他们那边的工作要求是把一个软件发布多个不同的版本,每个稍微修改一些UI。就类似于同一软件发布多个不同名的版本,本质代码还是一样的,不过可能有些文字或者图片的变化。面试官跟我说你来的话任务很简单,就是不停地复制粘贴和改名。虽然我没去那家公司入职,但我也想了想那边任务的实现方式。复制粘贴?No!我们有更好的方法!下面我们来介绍如何创建多个不同版本的相同的应用程序。

基础版本

首先我们做一个基础版本的app,很简单,从第一个页面点击按钮到第二个页面,从第二个页面点击按钮到第三个页面。整体如图:
Android 产品定制之资源定制(同一应用程序使用不同资源)_第1张图片
项目目录如下:
Android 产品定制之资源定制(同一应用程序使用不同资源)_第2张图片
只是三个很简单的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文件夹同级。项目结构如下:
Android 产品定制之资源定制(同一应用程序使用不同资源)_第3张图片
下一步,我们定制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:


    <string name="app_name">My Applicationstring>
    <string name="title_activity_thrid">ThridActivitystring>
    <string name="title_home">Homestring>
    <string name="title_dashboard">Dashboardstring>
    <string name="title_notifications">Notificationsstring>
    <string name="secondpage">Hello SecondPage From Main!string>

secondpage对应的文字是Hello SecondPage From Main!。好,接下来我们在customone对其定制,让我们customone版本显示的文字为Hello SecondPage From CustomOne!。怎么做呢?跟随我一步一步来。
1. 在customone文件夹下建立res文件夹,其就相当于main文件夹下的res,现在它是我们定制的res文件。我们要定制secondpage的值,那么我们要新建res/values/strings.xml,新的项目结构如下:
Android 产品定制之资源定制(同一应用程序使用不同资源)_第4张图片
重写strings.xml,修改secondpage的值。我所定制的customone下strings.xml具体代码如下:


    <string name="app_name">My CustomOnestring>
    <string name="title_activity_thrid">ThridActivitystring>
    <string name="title_home">Homestring>
    <string name="title_dashboard">Dashboardstring>
    <string name="title_notifications">Notificationsstring>
    <string name="secondpage">Hello SecondPage From CustomOne!string>

主要就是修改了secondpage的值。接下来我们运行一下。要运行不同的定制,Android Studio提供了一个Build Variant视图。从下拉框中选择合适的变种,并像平常一样部署。 如图:
Android 产品定制之资源定制(同一应用程序使用不同资源)_第5张图片
我们可以看到三个不同定制的Debug版本和Release版本。我们运行customoneDebug,效果如下:
Android 产品定制之资源定制(同一应用程序使用不同资源)_第6张图片
看第二个页面(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>

项目结构如下:
Android 产品定制之资源定制(同一应用程序使用不同资源)_第7张图片
再看看我们customone定制版本的运行效果:
Android 产品定制之资源定制(同一应用程序使用不同资源)_第8张图片
此时,第二个页面多出了我们刚刚添加的妹子的图片。与此同时,我们没有动过手脚的customtwo和customthree版本仍旧与基础版本一样,仍然保留着我们最初的效果。

结尾

刚刚我们对原始的项目进行了定制,产生了新的变种,展示了不同的页面效果。但是如果我们需要该某些activity的java代码应该怎么做呢?copy吗?当然不是,如果需要定制java代码,请看我的下一篇文章Android 产品定制之java代码定制(同一应用程序某个Activity使用不同java代码)。

你可能感兴趣的:(android开发)