Android应用-开发框架设计

目录

1.  简介

1.1 背景

1.2 专业术语

2.  总体设计思想

2.1 分层:组件化设计框架

2.2 分类:应用开发架构图

3. ⚛️ 框架详细设计

3.1 组件化框架外形

3.2 业务模块化

3.3 代码编程框架

4.  框架其他设计

4.1 版本统一控制

4.2 引入部分第三方框架

4.3 封装网络请求框架

4.4 统一应用签名


1.  简介

1.1 背景

        为减少应用开发重复造轮子,于是希望有一套统一的应用框架,可以让应用开发者快速上手开发需求,而无需过多关注应用框架相关内容。

        而且,基于同一套应用框架,有利于同事互相之间的代码Review与维护,也方便后期项目交接。不仅减少开发人员繁复的工作,而且提升整个团队的产研效率。

1.2 专业术语

术语名称

描述

AndroidStudio

简称AS,是Android开发者用来开发应用的一个工具

Retrofit/okhttp3

知名的网络请求框架

Glide

知名的图片加载框架

LiveEventBus

基于LiveData的应用开发事件总线,方便业务间消息通信,有取代EventBus的趋势

MVVM

基于MVC、MVP的一套代码开发框架

Kotlin

Android开发官方推荐语言

2.  总体设计思想

2.1 分层:组件化设计框架

        我们知道常见的应用开发框架主要有:模块化、组件化、插件化,那么随着各个应用不断的迭代升级,应用的开发框架也从最开始的单App模块到多模块化,再到组件化与插件化。那么对于一般的应用开发框架,应该遵循什么样的设计原则呢?

        首先,我想到的是不能过度设计,一口不能吃一个大胖子,一来就嚷着要做插件化是不太现实的,框架应该跟随应用需求一步步迭代或重构。其次,直接使用AS创建一个新项目,会缺少应用迭代升级的一些常见元素(如常见的Retrofit、Glide、LiveEventBus等三方开源SDK和一些工具类),在后期慢慢引入时很可能会没有必要的重复踩前人走过的坑。于是,依赖于组件化设计思想——无惧应用后期扩展迭代,再结合应用基本所需元素——搭一个轮子减少重复劳动,就设计出本文将要阐述的应用开发框架,具体思想请继续往下看。

2.2 分类:应用开发架构图

        总体方向是:首先建立一个组件化框架的外形架构,然后实现业务模块化,再搭建一套MVVM+Kotlin代码编程框架。

Android应用-开发框架设计_第1张图片

3. ⚛️ 框架详细设计

3.1 组件化框架外形

        以app模块为总入口,作为组件化中提到的壳工程。app模块不应包含相关业务代码,它的主要工作应该是进行Application初始化、依赖各个模块,和声明各模块manifest相关配置。

3.2 业务模块化

        app模块依赖portal业务模块,暂且我们可将所有业务写在portal模块,后期业务壮大后可朝组件化方向再拆分业务模块。

        middleware模块作为中间件层,放置一些模块间共用的元素,那么项目中除middleware模块之外的其他所有模块,如:app模块和portal模块,都应依赖middleware模块。但需注意,随着业务的增长middleware模块可预料的会不断膨胀,所以写业务时需注意解耦,切勿将非模块间公用的元素放进middleware模块。

        portal模块包括主要的业务代码,采用组件化分包方式搭建各业务模块,比如下面这样的包名结构:

  • com.xxx.xxx.portal.feature.home

  • com.xxx.xxx.portal.feature.bt

  • com.xxx.xxx.portal.feature.wifi

3.3 代码编程框架

        各业务模块采用MVVM框架,包结构为:data-model-view-viewmodel

Android应用-开发框架设计_第2张图片

        使用Kotlin语言,依赖于下沉到middleware模块的BaseActivity、BaseFragment,以及ViewBinding,建立起一套如下的代码编程框架:

Android应用-开发框架设计_第3张图片

4.  框架其他设计

4.1 版本统一控制

        根目录新建version.gradle文件,将各类版本号统一放置此处,在其他gradlle脚本通过 apply from: "${rootDir}/version.gradle" 导入使用。

Android应用-开发框架设计_第4张图片

4.2 引入部分第三方框架

        在middleware模块中引入一些应用开发必要的第三方库,主要包括blankj工具包合集、图片加载框架Glide、网络请求框架和相关配置Retrofit/okhttp3、动效加载工具lottie、以及应用开发事件总线LiveEventBus等。

    api "androidx.constraintlayout:constraintlayout:$CONSTRAINTLAYOUT"
    api "androidx.lifecycle:lifecycle-livedata-ktx:$LIVEDATA"
    api "androidx.lifecycle:lifecycle-viewmodel-ktx:$VIEWMODEL"
    api "androidx.viewpager2:viewpager2:$VIEWPAGER2"
    api "com.blankj:utilcodex:$COM_BLANKJ_UTILCODEX"
    api "com.github.bumptech.glide:glide:$GLIDE"
    api "com.squareup.retrofit2:retrofit:$RETROFIT"
    api "com.squareup.retrofit2:converter-gson:$RETROFIT_CONVERTER_GSON"
    api "com.squareup.retrofit2:adapter-rxjava:$RETROFIT_ADAPTER_RXJAVA"
    api "com.squareup.okhttp3:logging-interceptor:$OKHTTP_LOGGING_INTERCEPTOR"
    api "com.airbnb.android:lottie:$LOTTIE"
    api "io.github.jeremyliao:live-event-bus-x:$LIVE_EVENT_BUS_X"

4.3 封装网络请求框架

        基于Retrofit/okhttp3,封装出相应的ApiFactory以及BaseModel、BaseViewModel,方便基于MVVM项目访问网络,本应用开发框架中已包含整套网络请请求和处理的编程范式,具体可参考如下代码:

Model层:

interface MainApi {

    // 随机获取1张猫图(GET):https://api.thecatapi.com/v1/images/search?limit=1
    @GET("v1/images/search")
    suspend fun getCat(@QueryMap hashMap: HashMap): List
//    suspend fun getCat(@QueryMap hashMap: HashMap): BaseResponse

}

class MainModel : BaseModel() {

    override fun createApi(): Class = MainApi::class.java

    //    suspend fun getCat(hashMap: HashMap): BaseResponse =
    suspend fun getCat(hashMap: HashMap): List =
        withContext(Dispatchers.IO) {
            try {
                apiStores.getCat(hashMap)
            } catch (e: Exception) {
                mutableListOf()
            }
        }
}

abstract class BaseModel {

    protected var apiStores: T

    init {
        apiStores = ApiFactory.remoteService(createApi())
    }

    protected abstract fun createApi(): Class

}

网络请求工厂:

object ApiFactory {

    private val okHttpClient: OkHttpClient by lazy { setHttpClient() }

    private fun retrofit(): Retrofit {
        return Retrofit.Builder().baseUrl(Constants.BASE_URL)
            .addConverterFactory(GsonConverterFactory.create())
            .addCallAdapterFactory(RxJavaCallAdapterFactory.create()).client(okHttpClient).build()
    }

    private fun setHttpClient(): OkHttpClient = OkHttpClient.Builder().apply {
        addInterceptor(InterceptorManager.headerInterceptor()).addInterceptor(InterceptorManager.httpLoggingInterceptor())
        InterceptorManager.otherInterceptors.forEach { addInterceptor(it) }
    }.connectTimeout(NET_TIMEOUT, TimeUnit.SECONDS).readTimeout(NET_TIMEOUT, TimeUnit.SECONDS)
        .writeTimeout(NET_TIMEOUT, TimeUnit.SECONDS).build()

    @JvmStatic
    fun  remoteService(apiService: Class): T {
        return retrofit().create(apiService)
    }

}

 网络请求拦截器:

object InterceptorManager {

    /**
     * 返回头拦截器
     * @return
     */
    fun headerInterceptor(): Interceptor = Interceptor { chain: Interceptor.Chain ->
        chain.proceed(
            chain.request().newBuilder().addHeader(HeaderNames.TOKEN.headerName, "")
                .addHeader(HeaderNames.PLATFORM.headerName, "android")
                .addHeader(HeaderNames.UID.headerName, "")
                .addHeader(HeaderNames.VERSION.headerName, AppUtils.getAppVersionName()).build()
        )
    }

    /**
     * 返回http拦截器
     */
    fun httpLoggingInterceptor(): Interceptor = HttpLoggingInterceptor().apply {
        this.level =
            if (Constants.RELEASE) HttpLoggingInterceptor.Level.NONE else HttpLoggingInterceptor.Level.BODY
    }

    /**
     * 自定义http拦截器
     */
    var otherInterceptors: MutableList = mutableListOf()

    enum class HeaderNames(val headerName: String) {
        TOKEN("Token"), PLATFORM("Platform"), UID("UID"), VERSION("Version"),
    }

}

4.4 统一应用签名

        在app模块中新增signing.properties文件存储签名信息,xxx.jks签名文件放在同级目录,然后在app模块build.dradle文件中增加如下签名校验信息:

Properties signingProps = new Properties()
signingProps.load(new FileInputStream(file("signing.properties")))

android {
    signingConfigs {
        KeyStore {
            keyAlias signingProps['KEY_STORE_ALIAS']
            keyPassword signingProps['KEY_STORE_KEY_PASSWD']
            storeFile file(signingProps['KEY_STORE_FILE'])
            storePassword signingProps['KEY_STORE_PASSWD']
            v1SigningEnabled true
            v2SigningEnabled true
        }
    }
    buildTypes {
        release {
            minifyEnabled false
            signingConfig signingConfigs.KeyStore
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }

        debug {
            minifyEnabled false
            signingConfig signingConfigs.KeyStore
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
}

你可能感兴趣的:(Android:开发实践,android,kotlin,应用开发框架)