項目背景
1、開屏廣告,是商業用戶端維護的最重要子產品,有,,,,,等特點。
2、商業早期開屏廣告功能單一,實作随意,多處違背基本設計原則,更沒有系統的進行架構設計,80%的代碼堆砌在少數幾個類中。
3、随着,,,人力無法滿足業務deadline時的,,。目前開屏子產品已接近無法維護,煙囪化嚴重,研發測試成本翻倍,品質瀕臨失控,性能肉眼可見的日益劣化。
重構目标
核心意圖:管理複雜度,建設為獨立商業能力,角色由面向頁面的,轉向面向接口的。
重構收益:
1、提供開屏服務,獨立元件、可獨立運作。
2、可插拔式UI插件庫設計。
3、調試速度大幅提升,從運作一次應用10分鐘左右,提升至30秒左右,提升95%。
4、無用、過期代碼下線,包體積縮小100k左右。
5、去煙囪化,多套開屏邏輯統一,獨立元件高速調試,開屏開發周期縮短30%以上,故障率減少50%以上,QA測試周期縮減50%以上。
6、優化開屏耗時200ms,開屏展示率提升3%。
7、獨立商業能力之一,可為任何業務,任何知乎app,直接提供插屏廣告能力。
開屏子產品現狀
現有問題&代碼性能評估
重構前梳理:Android 開屏廣告梳理
對梳理過程中,代碼現存具體問題進行歸類,總結,進而進一步評估代碼性能現狀。
結論:現有開屏架構不能滿足商業日漸複雜的開屏場景,與日俱增的開屏收入。重構時需重點關注可讀性、可維護性、可複用性。
可讀性
可拓展性
可維護性
可複用性
代碼性能
設計原則比對
結合代碼性能現狀,評估設計原則比對度,找出重構側重點及方向。
結論:重構設計中,重點關注SRP、LKP、OCP、DIP四個指導性原則上的優化。
代碼結構
核心類 LaunchAdFragmentDelegation 現狀,70%功能堆疊在一個類中,20%功能與該類有關
現有架構
頁面級開發,即每個頁面有自己的一套開屏邏輯,一個需求點,多倍工作量,且難以保持一緻性。
縱向與橫向(架構與切面)
縱向:
如上面簡易架構圖,目前縱向縱深不夠,整體是一個拍平的狀态。基本的UI層、資料層、邏輯層、核心層結構都不具備。UI層和邏輯層在一處,且或多或少包含資料層及核心層邏輯。
橫向:
目前關鍵節點間途徑若幹方法或回調,其間散落了大量各方面邏輯,不成體系,難以了解,且任何一處出錯都會打斷開屏邏輯,沒統一管理。
架構設計
理念
1、核心思想為将開屏廣告子系統「SDK化」,抽象為一種商業能力,面向API開發、維護。
2、SDK内部隻包含通用功能,高穩定性,高可拓展性,不關注具體業務場景。
3、縱向架構層級上講究「動靜分級」。
4、橫向切面分割上講究「統一精準」。
5、于使用方而言,内部實作黑盒,高度可配置,可插拔,可自定義。
商業整體架構圖
開屏子產品架構圖
SDK 層:
抽象出和業務完全無關的 SDK 層,面向接口設計,可為知乎App,來鴨App,知乎日報App或外公司App提供開屏廣告接入支援。
基建層:
基礎能力,日常開發時無需修改。
架構層:
将通用業務、共性代碼等低頻率修改代碼獨立出來,形成架構層,這層代碼是可由專人維護,其他業務線同學無法修改。
拓展層(Api):
處于元件api中間件之中,對外提供兩套接口,一套為指令式,控制開屏廣告;一套為響應式,接收開屏廣告各類回調。
接口設計:
ZHSplashAd:
- 構造方法:ZHSplashAd(Activity activity, String posId, ZHSplashAdListener adListener)
- fetchAd() 拉取廣告,配合showAd使用,實作和fetchAndShowIn相同的功能。
- showAd(ViewGroup container) 展示廣告,配合fetchAdOnly使用
- addViewPlugin(SplashPlugin plugin),添加自定義插件
- removeViewPlugin(),删除任意開屏插件
- isLaunchAdShow() 開屏廣告展示條件是否滿足
ZHSplashAdListener:
- onNoAD(AdError error) 廣告加載失敗,error 對象包含了錯誤碼和錯誤資訊,錯誤碼的詳細内容可以參考文檔第5章
- onADDismissed() 廣告關閉時調用,可能是使用者關閉或者展示時間到。此時一般需要跳過開屏的 Activity,進入應用内容頁面
- onTimeOut()熔斷時間内,開屏廣告未就緒
- onADClicked() 廣告被點選時調用,不代表滿足計費條件(如點選時網絡異常)
- onADExposure() 廣告曝光時調用
- onADTick(long millis) 倒計時回調,傳回廣告還将被展示的剩餘時間,機關是 ms
- onADLoaded(long expireTimestamp) 廣告加載成功的回調,在此方法中調用SplashAD.showAd(ViewGroup container) 方法,即可展示廣告。
業務層:
SDK層的使用者。如超級首映,冷啟動開屏,熱啟動開屏,端内開屏等,知乎創新産品App等。
元件化設計
重構前開屏代碼并不獨立,處于ad元件中,,,其他業務線元件直接調用,,且。
重構前元件圖:
重構後新增launch元件,并伴生luanch-api中間件,面向接口程式設計,與其他業務線解耦,可獨立編譯(開發現狀:跑一次主工程10分鐘。可獨立編譯後,開屏需求跑一次隻需要1分鐘,大幅提升人效)
重構後元件圖:
具體實作
響應式程式設計
重構前,由于開屏場景,多線程,阻塞,等待,資料轉化場景複雜且豐富,皆采用回調的方式實作,造成了現在的“回調地獄”,代碼可讀性,可維護性很差。
重構後,采用rxjava,響應式程式設計方案。基于觀察者的實作原理,豐富的操作符支援,使得開屏邏輯主幹流程在100行代碼以内實作,一目了然。
主流程時序圖
開屏展示條件
重構前:
跳過方式:實作接口的方式跳過開屏
重構後:
跳過方式:采用apt注解處理器的方式,利用編譯期來标記不展示開屏的Activity,實作跳過開屏
資料流、資料結構設計
重構前:
多套資料結構來回轉換,重複指派,容易造成記憶體洩漏,可讀性差,浪費性能。
重構後:
單資料結構Advert一以貫之
圖層插件設計
開屏插件庫:
開屏廣告所需UI元素,皆以自定義view形式建構,并加入插件庫,随時插拔。
預設渲染流程圖:
預設渲染的插件:
自定義插件預設處于最上層,可設定事件是否透傳。
發射井設計
下發的多個開屏廣告同時并發執行,抽象為發射井模型,設計上關注比對、優先級、發射、傳回隊列、時限等。
流程圖
等待隊列設計
類圖
作者:知乎商業移動端團隊-于铠瑞
出處:https://zhuanlan.zhihu.com/p/593000564