標籤:
從友盟微社區看Android第三方SDK架構實踐【轉載】
“先寫在前面吧,本來想通過連結來轉載這篇文章,發現沒找到有相關的按鈕。上網查了一下,都說部落格園沒有這功能。我在部落格園也有一段時間了,鼓勵原創是必須的,不過適當的轉載也算是一種將有價值的文章進行分享的方式,不知道以後會不會支援呢!”
原文連結:http://www.csdn.net/article/2015-05-08/2824648-micro-community
摘要:第三方SDK的開發需要考慮很多因素,比如穩定性、靈活性等,並且還要做到能讓開發人員能自由定製UI層、替換子系統。本文以友盟微社區為例,詳細講解了在開發SDK時架構方面的設計理念。
開發Android第三方SDK說難不難,但說簡單也不簡單,要開發一個給很多人使用的第三方SDK,如何在保證穩定性的同時,增強SDK的靈活性,讓開發人員能自由定製UI層、替換子系統,這是一個值得思考的問題。為瞭解決這個問題,開發第三方SDK必須要有良好的應用架構。本文就分享一下我在開發友盟微社區SDK時在架構方面的一些想法。
友盟的微社區是一款協助開發人員在應用中快速搭建一個社區(類似於新浪微博、朋友圈),目前正在內測當中。
技術架構
從項目結構上來說,友盟微社區SDK可以簡單分為如下三層。
- UI層(開源)。UI層對外開放,目的是讓使用者能夠定製微社區的UI效果,使微社區SDK能夠很自然的融入到使用者的App中。
- 商務邏輯層。商務邏輯層會通過一個統一的介面向UI層提供資料請求等功能,比如擷取緩衝的feed、好友名單等,因此商務邏輯層對於使用者來說是一個資料操作介面,通過這個介面使用者能夠與SDK核心層進行一些資料方面的操作。
- 核心層。核心層則包含了友盟SDK的核心系統抽象,比如賬戶系統、推送、資料庫、網路操作等,這一層對外封閉,使用者可以通過一些介面與核心層進行互動。而核心層定義的抽象使得使用者可以很方便的實現定製化,即自己實現抽象介面,然後將具體的實現注入到微社區中,從而使自己的子系統替換掉微社區中的預設實現。
1所示,SDK層次非常分明,通過這三個層次的隔離,使得使用者既可以自訂最外層的UI效果,也對外隱藏了商務邏輯層、核心層的實現細節。而核心層定義的子系統抽象,使得使用者可以注入自己的實現,保證了整個微社區SDK的靈活性、擴充性。
圖1 洋蔥結構圖
簡單來說,就是使用者在UI層通過邏輯層暴露的通用介面來操作SDK,從封閉的核心系統中擷取、儲存資料以及其他的相關操作。階層2所示。
圖2 階層圖
圖1、圖2都顯示了SDK是通過不同的層次來分離職責,是一個較為典型的架構形式。對於使用者來說,最關心的莫過於可定製化。UI層開放源碼,自然可以通過修改代碼來實現。其他的定製化使用者就需要依賴注入來實現。微社區SDK內部依賴於抽象,而不依賴於具體實現,並且使用者可以注入具體實現。也就是說使用者可以根據我們的抽象介面實現自己的子系統,然後注入到SDK內部,SDK此時就會使用使用者注入的實現,這樣就達到了子系統替換的效果,也就是我們說的定製化。
友盟微社區的定製化如何滿足定製化?
那麼如何來實現定製化呢?友盟微社區SDK內部定義了一些抽象,比如Loginable、Pushable、ImageLoader來分別代表登入系統介面、推送介面、圖片載入介面,每種介面都有一個SDKManager來進行管理。比如管理登入子系統的就是LoginSDKManager,使用者可以往這個Manager裡面添加、移除具體的登入系統實現,然後通過useThis函數來指定使用某個具體的實現(SDK Manager裡面可能有多個實現)。結構圖3所示。
圖3 LoginSDKManager功能
SDK Manager是一個泛型類,類型T就代表了介面類型,比如上述的Loginable等。通過泛型我們就可以將這些通用的添加、移除實現等操作抽象化,避免重複代碼。代碼如下所示:
public abstract class SDKManager<T> {
// 泛型Map
private Map<String, T> mImplMap = new HashMap<String, T>();
// 要使用的實現的key
private String mCurrentKey = "";
public void addImpl(String key, T impl) {
mImplMap.put(mCurrentKey, impl);
}
public void removeImpl(String key) {
mImplMap.remove(mCurrentKey);
}
public void useThis(String key) {
mCurrentKey = key;
}
public T getCurrentImpl() {
return mImplMap.get(mCurrentKey);
}
}
代碼很簡單,就是在SDK Manager內部維護了一個Map,key是使用者為這個實現指定的一個字串值,value就是具體的實現。使用者可以通過這個key來移除實現,更常用的是我們需要調用useThis(String key)介面來指定使用某個具體的實現。
我們並沒有直接使用SDKManager,因為它是一個抽象泛型類,因此我們定義了一些子類來對不同的實現進行管理,這些子類都是單例類,例如LoginSDKManager,代碼如下所示。
public final class LoginSDKManager extends SDKManager<Loginable> {
// 單例對象
static LoginSDKManager sInstance = new LoginSDKManager();
private LoginSDKManager() {
}
// 擷取單例對象
public static LoginSDKManager getInstance() {
return sInstance;
}
}
在使用者需要對登入系統進行管理時,通過LoginSDKManager.getInstance()就可以擷取到負責管理登入系統的SDK Manager,此時使用者可以通過addImpl(String key, T impl)、useThis(String key)等介面對登入系統進行管理,這就可以靈活使用使用者自訂的子系統。
樣本
下面還是以一個樣本來說明問題吧。在與使用者溝通的過程中,我們發現登入模組是使用者自訂機率最高的子系統。通常情況下,使用者可能有自己的賬戶系統或者使用了第三方登入,此時使用者就不需要友盟微社區SDK中附帶的登入實現,完全依賴自己的賬戶系統或者其他第三方登入SDK來實現一個登入系統。下面我們就以實現登入系統(其他子系統的自訂原理一樣)來示範自訂過程。在開始之前,我們需要對登入的抽象介面Loginable進行瞭解。代碼如下所示:
public interface Loginable {
public void login();
public void logout();
public boolean isLogined();
}
- login():登入函數,使用者需要在登入成功後將使用者資訊回調給友盟微社區SDK(具體過程可以參考友微社區整合文檔 http://dev.umeng.com/wsq/android/detail-integration#1);
- logout():登出函數,登出使用者的登入即可;
- isLogined():使用者是否登入,返回true表示已登入,否則為未登入。
微社區SDK內部通過抽象了幾個簡單介面來定義登入模組的功能,使用者通過實現這幾個函數即可定製自己的登入系統,最後將實現注入到SDK即可。例如,如果你的應用中已經有了自己的賬戶系統邏輯,你可以在Loginable的幾個函數中通過調用你的賬戶系統邏輯實現這幾個功能;如果你使用了友盟社會化組件那麼你可以通過該社會化組件的登入、登出功能實現對應的功能,例如你可以在login()函數中調用UMSocialService對象的doOauthVerify(Context context、SHARE_MEDIA platform、UMAuthListener listener)介面來實現登入。
一句話概括就是:自訂一個實現了Loginable介面的類,在這個類的各個函數中調用你原有的登入、登出、判斷是否已登入的函數來實現對應的功能。實現了登入類之後,通過LoginSDKManager的addImpl(String key, Loginable impl)來將該實現注入到SDK中,最後通過LoginSDKManager的useThis(String key)函數來指定要使用的登入實現,這個key就是addImpl(String key、Loginable impl)中設定的key。
自訂登入類範例程式碼如下:
/**
* 友盟社會化組件的登入實現,這裡可以替換成自己的賬戶系統、第三方登入等,實現幾個介面函數即可。
*/
public class SocialLoginImpl implements Loginable {
@Override
public void login() {
// 登入的具體實現,可以調用你自己的登入代碼或者第三方SDK的登入函數
}
@Override
public void logout() {
// 登出的具體實現,可以調用你自己的登入代碼或者第三方SDK的登入函數
}
@Override
public boolean isLogined() {
// 檢測是否登入
return true /* 代碼省略 */;
}
}
**注入登入實現 :**
// 登入系統管理器
LoginSDKManager loginMgr = LoginSDKManager.getInstance() ;
// key
String clzKey = SocialLoginImpl.class.getName() ;
// 注入實現
loginMgr.addImpl(clzKey, new SocialLoginImpl());
// 指定使用的具體實現
loginMgr.useThis(clzKey);
為了更簡單,這個過程被我們封裝到一個函數中,使用的代碼最後簡化為 :
// 一行代碼搞定!這個函數封裝了上述所有的代碼。
LoginSDKManager.getInstance().addAndUse(new SocialLoginImpl()) ;
通過這幾步,登入系統就被替換掉了。當微社區需要登入時,微社區SDK就會通過LoginSDKManager擷取當前使用的登入實現,然後觸發login()函數,此時就會執行你的登入代碼了。登入成功之後,通過login()函數的回調listener(這個簡單樣本中沒有給出該listener,具體可參考友盟微社區使用已有賬戶系統)將使用者資訊傳回給友盟SDK,就完成了整個登入過程。
目前友盟微社區SDK還處在內測階段(內測申請地址:http://wsq.umeng.com/),不過已經可以投入使用。已經有一部分整合了友盟微社區的App上線,並且運行良好。希望本文能有開發第三方Android SDK的同學一些協助,讓開發中的坑更少一些。
從友盟微社區看Android第三方SDK架構實踐【轉載】