前言
之前我們把ARouter的原理分析了一遍,如果你是剛啓動的新項目,建議立刻使用,哪天運營有這個需求了,你就可以牛逼的對他說,我早就已經做好了。
但是老項目就會有一丟丟的尷尬,所以我們要在ARouter的基礎上,獨立深度鏈接的功能,然後打造出加強版的深度鏈接庫,我起名爲DeepLinkSo。
正文
回顧一下ARouter的源碼,我們記得他使用的是自定義註解,完成路由的註冊和綁定。註解看上去高大上,但是在這裏我認爲存在一個致命的短板,那就是不夠靈活。
註解的侷限性
註解的解析是在編譯期間完成並生成源碼,也就是說版本一經發布,註冊的路由地址就無法發生改變,例如
- 開啓新的路由。例如個人信息頁我們並沒有配置路由,我們就無法通過深度鏈接打開這個網頁,只能修改代碼,然後重新發布版本解決這個問題。
- 關閉某個路由,因爲某些原因某個頁面要停止外部訪問,也只能修改代碼,然後重新發布版本。
所以幾經思考,如果路由的配置文件能夠從網上下載更新的話,是不是就能讓深度鏈接更佳靈活呢?
於是我選擇了使用XML。
使用註解可以在編譯期間生成源碼,節省了啓動時間,但是犧牲了靈活性。
使用XML恰恰相反,沒有增加編譯時間,而是增加了啓動時間,但是我們的XML還是很小的,經過測試也就10毫秒左右,還在可以接受的範圍內。
自定義XML協議
XML協議無論在前端後端都被廣泛的使用,而且Android對XML解析的有很好的支持,複習一下XML解析的三種方式:
1、SAX解析
2、Pull解析(推薦)
3、Dom解析
Android推薦使用Pull解析,輕量快速,所以我們也選擇使用Pull解析。
首先制定好我們的XML格式:
<?xml version="1.0" encoding="utf-8"?>
<DeepLinkSo>
<!-- 版本號 -->
<version value="1" />
<!-- 攔截器會按照配置的順序依次執行 -->
<common-interceptors>
<common-interceptor>com.lzp.deeplinkso.demo.interceptor.TestInterceptor</common-interceptor>
</common-interceptors>
<!-- 所有需要支持DeepLink的文件列表 -->
<list>
<!-- 跳轉的頁面 -->
<Activity>
<class>com.lzp.deeplinkso.demo.MainActivity</class>
<page>main</page>
</Activity>
<!-- 跳轉的頁面 -->
<Activity>
<class>com.lzp.deeplinkso.demo.TestActivity</class>
<page>test</page>
<!-- 需要的參數 -->
<params>
<key type="Long" value="userId" />
<key value="userName" />
</params>
<!-- 是否跳過公共Interceptor -->
<skipCommonInterceptor>true</skipCommonInterceptor>
<!-- 私有攔截器 -->
<!--<interceptors>-->
<!--<interceptor>com.lzp.deeplinkso.demo.interceptor.TestInterceptor</interceptor>-->
<!--</interceptors>-->
</Activity>
<!-- 自定義事件 -->
<Event>
<class>com.lzp.deeplinkso.demo.handler.TestEventHandler</class>
<page>event</page>
<params>
<key value="eventId" />
</params>
</Event>
</list>
</DeepLinkSo>
我們在XML制定了以下內容:
1、版本號。可以根據降級和升級做一些操作。
2、全局攔截器。所有的跳轉都會經過攔截處理,我們可以在跳轉中設置跳過全局攔截器。
3、跳轉的頁面。可以設置對應的路由地址,跳轉的參數,私有攔截器等。
4、自定義事件。設置和頁面是一樣的,只是不跳轉頁面。
這樣我們的功能已經算是很全面了,接下來我們可以通過解析XML,保存所有的配置信息:
class DeepLinkSoConfig {
/**
* 當前版本號
*
* 無實際作用,僅僅是爲了區別xml的版本
* */
private var version = "0"
internal var listener: IDeepLinkSoListener? = null
/**
* 保存跳轉Activity配置項
* */
private val activityOptionMap = HashMap<String, DeepLinkSoActivityOption>()
/**
* 保存自定義事件配置項
* */
private val eventOptionMap = HashMap<String, DeepLinkSoEventOption>()
/**
* 自定義攔截器
* */
internal var interceptors: ArrayList<IDeepLinkSoInterceptor>? = null
internal fun setVersionCode(version: String) {
this.version = version
}
fun getVersionCode() = this.version
/**
* 添加配置項
* */
internal fun addOption(key: String, option: DeepLinkSoOption) {
when (option) {
is DeepLinkSoActivityOption -> activityOptionMap[key] = option
is DeepLinkSoEventOption -> eventOptionMap[key] = option
}
}
/**
* 添加配置項
* */
internal fun getOption(key: String): DeepLinkSoOption? {
return activityOptionMap[key] ?: eventOptionMap[key]
}
/**
* 獲取Activity配置項
* */
internal fun getActivityOption(key: String) = activityOptionMap[key]
/**
* 獲取Event配置項
* */
internal fun getEventOption(key: String) = eventOptionMap[key]
/**
* 清除配置項
* */
internal fun reset() {
activityOptionMap.clear()
eventOptionMap.clear()
interceptors?.clear()
}
}
解析的過程就不貼了,到此爲止,我們已經爲具體的開發做好了準備。
總結
今天我們分析了並制定了深度鏈接庫的XML協議,思考了使用註解和XML的優劣點,爲之後的功能開發做好準備。