<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    Jack Jiang

    我的最新工程MobileIMSDK:http://git.oschina.net/jackjiang/MobileIMSDK
    posts - 494, comments - 13, trackbacks - 0, articles - 1

    本文由鞏鵬軍分享,原題“IM兼容性基建”,本文有修訂。

    1、引言

    一個成熟的IM成品,在運營過程中隨著時間的推移,會發布不同的版本,但為了用戶體驗并不能強制要求用戶必須升級到最新版本,而服務端此時已經是最新版本了,所以為了讓這些不同客戶端版本的用戶都能正常使用(尤其IM這種產品,不同版本可能通信協議都會有變動,這就更要命了),則必須要針對不同客戶端版本的兼容處理。

    本文將基于筆者的IM產品開發和運營實踐,為你分享如何實現不同APP客戶端版本與服務端通信的兼容性處理方案。

     

    學習交流:

    (本文已同步發布于:http://www.52im.net/thread-4202-1-1.html

    2、關于作者

    鞏鵬軍:專注移動開發十多年,熱愛即時通訊技術。個人微信公眾號:“鞏鵬軍”。

    作者在即時通訊網分享的另一篇《知識科普:IM聊天應用是如何將消息發送給對方的?(非技術篇)》,感興趣的讀者也可以看看。

    3、一個App時怎么辦?

    提示:“一個App”指的是同一個IM服務端,只服務于一個特定的IM產品。

    首先想到的就是直接使用App版本號判斷新老版本并進行兼容處理。

    如下圖所示:

    一般來說,不同的IM客戶端(如iOS、Android、Windows、Mac)都是同步迭代,多端發版時間一致,App版本號也一樣。

    所以用跨多端的App版本號可以很容易地讓服務端只用寫一遍判斷和兼容邏輯。

    示例:假設從V2.1.0開始應用紅包消息,那么判斷客戶端是否支持紅包的邏輯就很簡單。

    偽代碼如下:

    booleanisSupportRedEnvelop(String appVersion) {

     returngte(appVersion, "2.1.0");

    }

    附:版本號比對邏輯(未充分考慮異常情況):

    List<Integer> toNums(String version) {

      Matcher matcher = Pattern

     

        .compile("/[0-9]+\\.[0-9]+\\.[0-9]+")

     

        .matcher(version);

     

      String versionString = matcher.find()

     

        ? matcher.group(0).substring(1)

     

        : "1.0.0";

     

      List<Integer> verNums = Arrays

     

        .stream(versionString.split("\\."))

     

        .map(Integer::valueOf)

         .collect(Collectors.toList());

      returnverNums;

    }

     

    booleangte(String version, String target) {

     

      List<Integer> appVerNums = toNums(version);

      Integer appMajor = appVerNums.get(0);

      Integer appMinor = appVerNums.get(1);

      Integer appPatch = appVerNums.get(2);

      List<Integer> targetNums = toNums(target);

      Integer targetMajor = targetNums.get(0);

      Integer targetMinor = targetNums.get(1);

      Integer targetPatch = targetNums.get(2);

      return(appMajor >= targetMajor) ||

             (appMinor >= targetMinor) ||

             (appPatch >= targetPatch);

    }

    4、多個App時怎么辦?

    4.1概述

    提示:“多個App”指的是同一個IM服務端,可能作為通用服務,作為多個不同APP產品中的聊天模塊使用的場景。

    只有一個App時肯定是比較簡單的。但現實情況是一套IM系統通常會用于多個業務場景,這是很普遍的現象。業界的知名IM產品,比如釘釘、飛書、企業微信、美團大象等都是這樣。

    底層邏輯大概是:IM系統比較復雜,功能繁多而且難以實現、更難以穩定,所以一個IM團隊維護一套IM系統,然后應用在多個業務場景就是最具性價比的選擇了。

    4.2使用App版本

    每個業務場景都會有自己的客戶端App,每個App都有自己的版本號,那么根據App版本號判斷新老版本的邏輯就不適用了(如下圖所示)。

    一個App時可以這樣做兼容性判斷:

    booleanisSupportRedEnvelop(String appVersion) {

     returngte(appVersion, "2.1.0");

    }

    多個App時的兼容性判斷:

    booleanisSupportRedEnvelop(String version) {

        return

        (app.equals("App1")&>e(version,"2.1.0"))||

        (app.equals("App2")&>e(version,"2.2.3"))||

        (app.equals("App3")&>e(version,"6.1"));

    }

    4.3使用App版本號的麻煩

    隨著App的增多,需要的判斷也越多,這會很麻煩,也很容易出錯。

    每個App推出新版本后,用戶不可能瞬間就升級到最新版本,根據經驗,每個App往往都會同時存在十個以上的不同版本。

    這就會形成如下圖所示的局面:

    5、多個App時,可將IM能力提煉為一套公用代碼

    多個App時的問題總結起來就是:一套服務端代碼如何適應集成了不同IM能力的不同App客戶端?

    我們來具體舉例分析一下,假設一個IM團隊維護的IM相關的客戶端模塊有IM Client SDK、聯系人、長連接、朋友圈等四個模塊(如下圖所示)。

    如上圖所示:

    • 1)App 1:集成了全部四個模塊;
    • 2)App 2:只集成了三個模塊;
    • 3)App 3:只集成了三個模塊。

    因為三個App面向的客戶群不同,發版節奏不同,所以各自集成的IM的能力也不同。

    比如下面這樣:

    • 1)App 1:面向內部員工辦公溝通使用的App 1需要功能豐富,對于穩定性和Bug有一定的包容性,也容易溝通和修復再發版;
    • 2)App 2:面向客服場景,用于企業的客服專員和企業的C端用戶溝通解決客訴問題,對于穩定性要求高,C端用戶升級率不好控制,發版節奏慢,最快只能和主業務App一致;
    • 3)App 3:面向企業和B端供應商,比如美團和美團上的商戶,京東和京東平臺上的第三方商家,對于穩定性要求也比較高,B端商家的升級率好控制一點,發版節奏也可以快一些。

    從上圖可以看出,因為IM核心能力是同一個團隊維護,所以Core包含的多個模塊的代碼必然是只有一套源代碼。不同App只是Core集成打包出來的產物,或者說不同App只是Core外面套了不同的殼而已,只要Core一樣,則App的IM能力就一樣(這就是本節標題所述的“多個App時,可將IM能力提煉為一套公用的代碼”這個意思)。

    6、給每個App中使用的公用代碼(Core)一個版本號

    如上節所述,我們將IM能力提煉為一套公用代碼(以下內容簡稱“Core”)。

    那么,我們能不能給Core一個版本標識呢?

    答案是肯定的:

    站在App的角度,每個App相當于打上了Core版本標簽:

    7、如何正確地解讀Core版呢?

    7.1拋開App看Core版本

    如果不看App版本,只看Core版本標簽:

    7.2從一套服務端代碼看Core版本

    同一個IM團隊,其IM Servers必然也是同一套代碼集,不考慮部署的區別。

    那么上圖邏輯上等價于下圖:

    7.3使用Core版本的兼容性判斷

    站在Core的視角,多個App就像單個App類似,只是使用的版本標識不同。

    具體如下:

    • 1)單個App時,IM服務端要區分不同App版本;
    • 2)多個App時,IM服務端要區分不同Core版本。

    還拿是否支持紅包的判斷舉例。

    一個App時:

    booleanisSupportRedEnvelop(String appVersion){

     

    returngte(appVersion, "2.1.0");

    }

    多個App時:

    booleanisSupportRedEnvelop(Integer coreVersion){

     

     returncoreVersion >= 2;

    }

    通過Core版本號,我們可以把兼容邏輯判斷簡化到和單個App一樣的簡單。

    8、關于Core版本的命名和取值

    關于Core版本號的取值,有下列可能的選項:

    • 選項一:語義版本號 1.2.0;
    • 選項二:整數 自然數 1 2 3;
    • 選項三:整數 迭代日期 20220819 或 220819。

    因為Core版本號不用給最終用戶看的,無需遵循常見的語義版本號規范。而且Core版本號只用于版本對比,所以整數會是一個比較好的選擇,方便比較,準確可靠。

    用自然數 1、 2、 3作為Core版本號是可以的,每個迭代發布新的Core版本時遞增一下就可以了。

    但是考慮到有多個終端平臺iOS、Android、Windows、Mac,如果某個平臺的Core發布后發現小Bug需要HotFix,那么要遞增版本號,就會擠占其它端的下一個自然數。究其原因,在于自然數是連續的,沒辦法在兩個常規的版本間插入一個HotFix版本。

    選項三就可以解決這個問題:因為Core的迭代發布日期是稀疏的,若干天后才會發布一個Core版本,那么當某個端需要一個HotFix版本時,選擇HotFix當天的日期作為版本號即可。

    總體上:多個端的主要版本號都是約定的統一的發布日期,多端一致,同時允許某個端臨時HotFix插入一個新的版本號,保留彈性。

    參考 Google 對Android SDK API版本的實踐,我們可以把Core版本號命名為core_level,取值為Core的發布日期的整數表示。

    9、多個App情況下的其它版本標識

    1)platform:

    一套Core,不同端在實際開發中,可能存在差異,為了針對具體端進行特定的兼容,需要知道當前是哪個端,可以約定platform字段表示端。取值可以是:ios、android、win、mac、linux等。

    2)App版本號:

    在IM相關邏輯的兼容性判斷中,只需使用跨App的多端一致的core_level了。但是為了和最終用戶、產品經理等溝通方便,保留App版本號app_version用于人和人之間溝通交流。core_level主要用于研發工程師之間,還有工程師和程序之間的溝通。兩者各取所長。

    10、版本標識的傳輸方式

    每個API和每條長連接數據包都攜帶Core版本,這樣服務端可以無狀態得處理每一個請求。如果需要在服務端主動推送時區分目標端的版本,可以在App登錄時將其攜帶的Core版本落庫存儲,然后推送時查詢使用。

    10.1短連接(HTTP)

    HTTP短連接通過新增Header字段方式傳輸:

    curl "https://{domain}/api/v1/xxx"\

      -H "platform: ios"\

      -H "app_version: 8.0.25"\

      -H "core_level: 220819"

    10.2長連接(Socket)

    長連接SDK通過類似HTTP Header的方式傳輸:

    {

      "platform":"ios",

      "app_version":"8.0.25",

      "core_level":"220819"

     

    }

    10.3短轉長

    短轉長時HTTP Header會轉換為長連接數據body里的header通過長鏈傳遞。

    這樣就同時存在長連接header和長連接body.header兩套字段,最終以長連接body.header為準即可。

    10.4其它

    IM系統里的瀏覽器和小程序,如果可以新增HTTP Header則新增Header傳輸,實在沒有辦法可以通過User-Agent傳輸該信息,服務端優先解析Header,沒有找到時再解析User-Agent。

    服務端解析UA的正則表達式:

    / platform\/(ios|android|mac|win|linux) app_version\/([0-9]\.[0-9]+\.[0-9]+) core_level\/([1-9][0-9]+)( |$)/

    以上正則表達式在線運行效果:點此查看

    11、本文小結

    至此,我們找到了一個適用于多個App、多個子模塊、多個功能點、臨時BugFix的版本標識:Core版本號,這樣就可以很好地解決多App的IM能力兼容性問題。

    以下是版本兼容性判斷偽碼:

    booleanisSupportRedEnvelop(Integer coreLevel) {

      returncoreLevel >= 220819;

    }

    12、參考資料

    [1] Browser vs Engine Version

    [2] Node.js ABI version number

    [3] Android SDK API Level

    [4] 零基礎IM開發入門(一):什么是IM系統?

    [5] 一套海量在線用戶的移動端IM架構設計實踐分享(含詳細圖文)

    [6] 一套原創分布式即時通訊(IM)系統理論架構方案

    [7] 從零到卓越:京東客服即時通訊系統的技術架構演進歷程

    [8] 一套億級用戶的IM架構技術干貨(上篇):整體架構、服務拆分等

    [9] 基于實踐:一套百萬消息量小規模IM系統技術要點總結

    [10] 一套十萬級TPS的IM綜合消息系統的架構實踐與思考

    [11] 從新手到專家:如何設計一套億級消息量的分布式IM系統

    [12] 閑魚億級IM消息系統的架構演進之路

    [13] 深度解密釘釘即時消息服務DTIM的技術設計

    [14] 一套高可用、易伸縮、高并發的IM群聊、單聊架構方案設計實踐

    [15] 企業微信的IM架構設計揭秘:消息模型、萬人群、已讀回執、消息撤回等

    (本文已同步發布于:http://www.52im.net/thread-4202-1-1.html



    作者:Jack Jiang (點擊作者姓名進入Github)
    出處:http://www.52im.net/space-uid-1.html
    交流:歡迎加入即時通訊開發交流群 215891622
    討論:http://www.52im.net/
    Jack Jiang同時是【原創Java Swing外觀工程BeautyEye】【輕量級移動端即時通訊框架MobileIMSDK】的作者,可前往下載交流。
    本博文 歡迎轉載,轉載請注明出處(也可前往 我的52im.net 找到我)。


    只有注冊用戶登錄后才能發表評論。


    網站導航:
     
    Jack Jiang的 Mail: jb2011@163.com, 聯系QQ: 413980957, 微信: hellojackjiang
    主站蜘蛛池模板: 亚洲中文字幕无码一区二区三区| 久久亚洲精品无码VA大香大香| 成人免费福利视频| 无码精品人妻一区二区三区免费| 亚洲三级在线免费观看| 国产亚洲精品影视在线产品| 免费的涩涩视频在线播放| 亚洲网站在线免费观看| 黄色网址在线免费| 免费VA在线观看无码| 精品亚洲456在线播放| 亚洲欧洲国产经精品香蕉网| 亚洲AV午夜成人影院老师机影院| 亚洲男人在线无码视频| 在线不卡免费视频| 国产无遮挡无码视频免费软件| 无码人妻一区二区三区免费视频| 亚洲日韩精品国产3区| 亚洲成a人片在线看| 亚洲欧洲日产国码在线观看| 亚洲丝袜美腿视频| 亚洲高清视频在线观看| 久久久久国色AV免费观看性色| 最好看最新的中文字幕免费| 黄网站免费在线观看| 国产性生大片免费观看性| 一个人看的www免费在线视频| 日韩一区二区三区免费播放| 成人精品国产亚洲欧洲| 日韩色视频一区二区三区亚洲| 亚洲第一se情网站| 国产精品国产亚洲区艳妇糸列短篇 | 抽搐一进一出gif免费视频| 老外毛片免费视频播放| 亚洲爆乳少妇无码激情| 久久亚洲AV成人无码国产最大| 日韩欧美亚洲中文乱码| 另类图片亚洲校园小说区| 特级毛片A级毛片100免费播放| 又黄又大的激情视频在线观看免费视频社区在线 | 亚洲国产精品尤物YW在线观看 |