天天看點

安卓元件化架構實踐

元件化架構

元件化和插件化的目的都是為了解決項目越來越複雜,耦合性高,牽一發而動全身,一個小的改動也要編譯十幾分鐘等問題,兩者的差別簡單來說元件化是在編譯期分子產品,插件化是在運作期。一般插件化用于動态修複bug或者動态更新子產品,相對來說黑科技更多一些,而相對于插件化,元件化的架構更容易操作,效率高,基于安卓自有特性和gradle的功能,沒有插件化那麼多的坑,對于大多數應用而言,其優勢還是相當明顯的。

先看下我們的架構圖:

安卓元件化架構實踐

App控制中心主要負責元件的添加和删除,路由規則的定義。

module是我們單獨開發的子產品,如個人中心,詳情頁,專題頁等等

common主要功能就是集合第三方的library,統一引入到項目中

原理與思路:

為每一個module設定library和application兩種屬性,通過配置檔案控制,當集合一起編譯時作為library依賴到app控制中心,當獨立開發時切換到application屬性變成一個普通的module,common作為一個公共的三方庫集合,頁面跳轉基于ARouter路由架構,消息傳遞用可以用EventBus,當然也可以用Arouter内部的API。

架構概覽:

其中main、modulefirst和modulesecond是三個獨立的子產品,應用的首頁在main裡,當然也可以指定到其他元件,隻需要配一個注解就可以,修改起來非常友善。

當為集合編譯時項目是這樣的:

安卓元件化架構實踐

當為獨立開發時項目是這樣的:

安卓元件化架構實踐

開始搭建

1.建立完工程後,配置可切換library和application屬性的檔案。

在project根節點下在gradle.properties檔案添加以下代碼:
           
# 每次更改“isModule”的值後,需要點選 "Sync Project" 按鈕
isModule=false
           

然後在每個元件的build.gradle根節點裡添加代碼:

if (isModule.toBoolean()) {
    apply plugin: 'com.android.application'
} else {
    apply plugin: 'com.android.library'
}
           

2.清單檔案的處理

由于每一個元件都是一個獨立的APP,都有自己的清單檔案,都有自己的Application屬性和MainActivity,當合并一起編譯時勢必會和其他元件的清單檔案産生沖突,而我們自己的子產品又需要自己開發時用到清單檔案,為此,我們的解決方法是:分别建立一個debug檔案夾,一個release檔案夾,分别放置一個清單檔案,不同的工程屬性時啟用對應的清單檔案即可解決,兩個清單檔案的差別如圖所示:

安卓元件化架構實踐

然後再build.gradle裡添加如下代碼:

android {
   /……/
    //這裡是我們添加的代碼
    sourceSets {
        main {
            if (isModule.toBoolean()) {
                manifest.srcFile 'src/main/debug/AndroidManifest.xml'
            } else {
                manifest.srcFile 'src/main/release/AndroidManifest.xml'
                //release模式下排除debug檔案夾中的所有Java檔案
                java {
                    exclude 'debug/**'
                }
            }
        }
    }
}
           

3.解決全局Application群組件自己的Application的沖突問題

應用啟動時,系統會為每一個應用建立唯一一個Application對象,其生命周期最長一直到應用結束,我們開發時往往會自己定義一個Application,做一些初始化的操作,這時就要去告訴系統要執行個體化自己定義的,也就是我們在清單檔案的Application節點配置的name屬性,那麼我們的元件本就是獨立的APP,肯定會有自己的Application,如何合并編譯,肯定又有問題了,對此,我們的的解決方法是,先建立一個Common庫,這個庫包含了各種公共的類,如BaseActivity,BaseApplication,Utils等等,每一個元件的Application都繼承自Common的BaseApplication,這樣元件就可以用自己的Application了,記得在自己的清單檔案中做相應修改。為了保證合并編譯時隻有一個BaseApplication,我們可以這樣修改

安卓元件化架構實踐

然後在build.gradle裡的這一行代碼就起作用了:

安卓元件化架構實踐

4.對編譯版本統一配置,依賴庫也統一配置

這樣做的目的是為了統一元件的工作環境,避免API版本參差不齊帶來的問題,同時也符合規範化管理的要求,而且便于維護,預設情況下,如果是 aar 依賴,gradle 會自動幫我們找出新版本的庫而抛棄舊版本的重複依賴。但是如果你使用的是 project 依賴,gradle 并不會去去重,最後打包就會出現代碼中有重複的類了。為了避免同一個庫依賴兩次,我們把所有第三方依賴放到Common庫中管理,元件的build.gradle裡隻需要這樣寫:

安卓元件化架構實踐

5.對App控制中心子產品的處理

App子產品在項目裡負責路由規則定義群組件注冊,沒有界面,雖然看起來和普通module一樣,但是千萬不要搞混了,它除了管理功能,還有就是作為整個項目合并編譯的端口,通常我們debug編譯都是習慣這樣

安卓元件化架構實踐

這裡app就是這樣一個作用,輕按兩下即可合并所有元件一起編譯,在此雄偉的壯舉成功之前,我們一定要注意先修改App子產品的build.gradle檔案如下:

安卓元件化架構實踐

代碼貼出來

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    if (!isModule.toBoolean()) {
        compile project(':main')
        compile project(':modelfirst')
        compile project(':modelsecond')
    } else {
        compile project(':common')
    }

}
           

順便也把全局編譯版本統一配置:

在project的build.gradle裡這樣寫

ext{
    // Sdk and tools
    buildToolsVersion = localBuildToolsVersion
    compileSdkVersion = 
    minSdkVersion = 
    targetSdkVersion = 
    versionCode = 
    versionName = "1.0"
    javaVersion = JavaVersion.VERSION_1_8
    aptCompilerVersion = "1.1.7"
    routerVersion = "1.2.2"
    loggerVersion = "1.15"
}
           

元件的build.gradle裡這樣寫

android {
    compileSdkVersion rootProject.ext.compileSdkVersion
    buildToolsVersion rootProject.ext.buildToolsVersion
    defaultConfig {
        minSdkVersion rootProject.ext.minSdkVersion
        targetSdkVersion rootProject.ext.targetSdkVersion
        versionCode rootProject.ext.versionCode
        versionName rootProject.ext.versionName
    }

   /……/
}
           

6.最後就是各個元件之間的跳轉問題也是最關心的問題。

這一部分,對于不熟悉Router的我真是踩了不少坑,其實總結起來卻是非常簡單,隻是一些小的細節沒有注意,你的APP就總是無法跳轉成功。先說項目如何配置:

本文章用的是github一個開源路由架構:ActivityRouter裡面有詳細的說明,另外阿裡也開源了一個路由架構:ARouter,有時間的化可以拿過來研究一下,使用起來都比較容易上手的,如果你想自己實作一個路由,可以參考這篇文章:Android路由實作

在project的build.gradle添加代碼:

dependencies {
        classpath 'com.android.tools.build:gradle:2.2.3'
        //這是我們要添加的
        classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
           

然後在每一個元件的build.gradle裡添加:

dependencies {
    compile fileTree(include: ['*.jar'], dir: 'libs')
    apt 'com.github.mzule.activityrouter:compiler:1.1.7'
    compile project(':common')
}
           

如圖所示:

安卓元件化架構實踐

sync工程一下後,開始處理路由配置

首先是App子產品,這個是編譯入口,需要管理所有元件,

建立一個類檔案

安卓元件化架構實踐

注意圖中的注解,是@Module,不是@Modules,

然後給MainApplication添加注解,這裡注意是@Modules了,如圖:

安卓元件化架構實踐

接下來處理應用入口的元件,注意APP隻是編譯控制元件,應用的首頁是由另一個元件控制的,這裡我定義為main元件,這個地方需要注意,和其他子產品略有不同,如圖:

安卓元件化架構實踐

注意看,這個Activity是沒有注解的,同時,其清單檔案要添加Launcher屬性。

安卓元件化架構實踐

對應的定義一個Main類,如圖

安卓元件化架構實踐

和入口元件不同的是,其他元件的Activity上要加注解:

安卓元件化架構實踐

這裡注意,注解裡的字段一定是群組件module的名稱是一緻的!

接下來就可以開始跳轉了,随意定義幾個按鈕,然後添加監聽裡的方法

安卓元件化架構實踐

當然路由協定有多種跳轉規則,後期我會将其他示例逐漸加到架構裡。

關于元件間的通信

元件内跳轉建議還是采用startActivity,組建間跳轉,可以用ActivityRouter的路由協定:

例如:

元件2定義了兩個Activity:

@Router("modelsecond")
public class ModelSecondActivity extends BaseActivity{……}
……
……
@Router("modelsecond/:demo")//注意這裡“/:demo”即作為此Activity的定位符,路由可以據此找到對應Activity
public class ActivityDemo extends BaseActivity{……}
           

元件1中有一個Activity:

@Router("modelfirst")
public class ModelFirstActivity extends BaseActivity{}
           

現在如果想從元件1的ModelFirstActivity 跳轉到元件2的ActivityDemo ,那麼點選事件裡隻需要這樣寫:

如果需要傳遞intent參數,那麼隻需要這麼寫:

在需要擷取參數的地方這麼寫:

getIntent().getStringExtra("sign");
getIntent().getStringExtra("name");
           

更多細節可以參考這裡:【ActivityRouter】

如果單純的傳遞消息可以用EventBus

注意事項

  1. 每一個元件,要給自己的所有資源檔案制定命名規則,避免和其他元件資源重名,切記
  2. 注意入口元件和其他元件的差別是入口Activity是沒有注解的
  3. App控制中心元件也就是編譯元件裡,@Module和@Modules切記不要記混了
  4. 總之就是細心,再細心,一定要自己動手搞一遍

最後貼出demo位址:【傳送門】

參考文章:

  1. http://blog.csdn.net/guiying712/article/details/55213884