1. 程式人生 > >iOS客戶端React-Native增量更新實踐

iOS客戶端React-Native增量更新實踐

市場上現存方案:微軟的 CodePush 以及React-Native中文網的Pushy,大家可根據公司實際情況酌情選擇。
處於安全性的考慮,公司禁止向第三方平臺上傳原始碼相關檔案,所以要自己動手實現。

增量更新主要實現流程
1.使用react-native bundle 命令打包,壓縮打包檔案
2.使用bsdiff生成新舊RN版本壓縮檔案的差異化檔案patchFile
3.客戶端舊RN版本壓縮檔案合併下載的patchFile檔案,校驗檔案MD5值,解壓合併後的檔案,重新載入jsbundle,完成更新
4.增加版本控制,指令碼化1、2過程

$ cd bsdiff-4.3

2.修改makefile檔案格式如下,原檔案後三行縮排格式不對:

CFLAGS        +=    -O3 -lbz2

PREFIX        ?=    /usr/local
INSTALL_PROGRAM    ?=    ${INSTALL} -c -s -m 555
INSTALL_MAN    ?=    ${INSTALL} -c -m 444

all:        bsdiff bspatch
bsdiff:        bsdiff.c
bspatch:    bspatch.c

install:
    ${INSTALL_PROGRAM} bsdiff bspatch ${PREFIX}/bin
    .ifndef WITHOUT_MAN
    ${INSTALL_MAN} bsdiff.1
bspatch.1 ${PREFIX}/man/man1 .endif

3.在bspatch.c檔案中加入標頭檔案

#include<sys/types.h>

4.終端執行make命令,生成bsdiff、bspatch檔案

$ make

5.將bsdiff、bspatch檔案拷貝到usr/local/bin 目錄下
6.使用方式:

//生成差異檔案
$ bsdiff oldFilePath newFilePath patchFilePath
//合併檔案
$ bspatch oldFilePath newFilePath patchFilePath

二、客戶端合併檔案,工程需要新增libbz2.tbd


1.bsdiff.h

#ifndef bsdiff_h
#define bsdiff_h

#define LBD_OK 0

#define LBD_ERR_OPEN 1000
#define LBD_ERR_CLOSE 1005
#define LBD_ERR_MALLOC 1010
#define LBD_ERR_SEEK 1015
#define LBD_ERR_TELL 1020
#define LBD_ERR_READ 1025
#define LBD_ERR_WRITE 1030
#define LBD_ERR_CORRUPT 1035

#define LBD_ERR_BZ 2000

#include <stdio.h>

int ff_patch(const char *oldf, const char *patchf, const char *newf);

#endif /* bsdiff_h */

2.bsdiff.c

#include "bsdiff.h"
#include <stdio.h>
#include <stdint.h>
#include <bzlib.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include<sys/types.h>

#define MIN(x,y) (((x)<(y)) ? (x) : (y))

static off_t offtin(u_char *buf) {
    off_t y;

    y=buf[7]&0x7F;
    y=y*256;y+=buf[6];
    y=y*256;y+=buf[5];
    y=y*256;y+=buf[4];
    y=y*256;y+=buf[3];
    y=y*256;y+=buf[2];
    y=y*256;y+=buf[1];
    y=y*256;y+=buf[0];

    if(buf[7]&0x80) y=-y;

    return y;
}

#pragma mark - Public

int ff_patch(const char *oldf, const char *patchf, const char *newf) {
    FILE *f, *cpf, *dpf, *epf;
    BZFILE *cpfbz2, *dpfbz2, *epfbz2;
    int cbz2err, dbz2err, ebz2err;
    int fd;
    ssize_t oldsize, newsize;
    ssize_t bzctrllen, bzdatalen;
    uint8_t header[32], buf[8];
    uint8_t *old, *new;
    off_t oldpos, newpos;
    off_t ctrl[3];
    off_t lenread;
    off_t i;

    if ((f = fopen(patchf, "r")) == NULL)
    {
        return LBD_ERR_OPEN;
    }

    /* Read header */
    if (fread(header, 1, 32, f) < 32)
    {
        if (feof(f))
        {
            return LBD_ERR_CORRUPT;
        }

        return LBD_ERR_READ;
    }

    /* Check for appropriate magic */

    // had to change this to use patches created with command line bsdiff
    //    if (memcmp(header, "LBDIFFXX", 8) != 0)
    if (memcmp(header, "BSDIFF40", 8) != 0)
    {
        return LBD_ERR_CORRUPT;
    }

    /* Read lengths from header */
    bzctrllen = offtin(header + 8);
    bzdatalen = offtin(header + 16);
    newsize = offtin(header + 24);
    if ((bzctrllen < 0) || (bzdatalen < 0) || (newsize < 0))
    {
        return LBD_ERR_CORRUPT;
    }

    /* Close patch file and re-open it via libbzip2 at the right places */
    if (fclose(f))
    {
        return LBD_ERR_CLOSE;
    }

    if ((cpf = fopen(patchf, "r")) == NULL)
    {
        return LBD_ERR_OPEN;
    }

    if (fseeko(cpf, 32, SEEK_SET))
    {
        return LBD_ERR_SEEK;
    }

    if ((cpfbz2 = BZ2_bzReadOpen(&cbz2err, cpf, 0, 0, NULL, 0)) == NULL)
    {
        return LBD_ERR_BZ;
    }

    if ((dpf = fopen(patchf, "r")) == NULL)
    {
        return LBD_ERR_OPEN;
    }

    if (fseeko(dpf, 32 + bzctrllen, SEEK_SET))
    {
        return LBD_ERR_SEEK;
    }

    if ((dpfbz2 = BZ2_bzReadOpen(&dbz2err, dpf, 0, 0, NULL, 0)) == NULL)
    {
        return LBD_ERR_BZ;
    }

    if ((epf = fopen(patchf, "r")) == NULL)
    {
        return LBD_ERR_OPEN;
    }

    if (fseeko(epf, 32 + bzctrllen + bzdatalen, SEEK_SET))
    {
        return LBD_ERR_SEEK;
    }

    if ((epfbz2 = BZ2_bzReadOpen(&ebz2err, epf, 0, 0, NULL, 0)) == NULL)
    {
        return LBD_ERR_BZ;
    }

    if (((fd = open(oldf, O_RDONLY, 0)) < 0) ||
        ((oldsize = lseek(fd, 0, SEEK_END)) == -1) ||
        ((old = malloc(oldsize + 1)) == NULL) ||
        (lseek(fd, 0, SEEK_SET) != 0) ||
        (read(fd, old, oldsize) != oldsize) ||
        (close(fd) == -1))
    {
        return LBD_ERR_OPEN;
    }

    if ((new = malloc(newsize + 1)) == NULL)
        return LBD_ERR_MALLOC;

    oldpos = 0;
    newpos = 0;
    while (newpos < newsize)
    {
        /* Read control data */
        for (i = 0;i <= 2; i++)
        {
            lenread = BZ2_bzRead(&cbz2err, cpfbz2, buf, 8);

            if ((lenread < 8) || ((cbz2err != BZ_OK) &&
                                  (cbz2err != BZ_STREAM_END)))
            {
                return LBD_ERR_CORRUPT;
            }

            ctrl[i] = offtin(buf);
        }

        /* Sanity-check */
        if (newpos + ctrl[0] > newsize)
        {
            return LBD_ERR_CORRUPT;
        }

        /* Read diff string */
        lenread = BZ2_bzRead(&dbz2err, dpfbz2, new + newpos, ctrl[0]);
        if ((lenread < ctrl[0]) ||
            ((dbz2err != BZ_OK) && (dbz2err != BZ_STREAM_END)))
        {
            return LBD_ERR_CORRUPT;
        }

        /* Add old data to diff string */
        for (i=0; i < ctrl[0]; i++)
            if ((oldpos + i >= 0) && (oldpos + i < oldsize))
                new[newpos + i] += old[oldpos + i];

        /* Adjust pointers */
        newpos += ctrl[0];
        oldpos += ctrl[0];

        /* Sanity-check */
        if (newpos + ctrl[1] > newsize)
        {
            return LBD_ERR_CORRUPT;
        }

        /* Read extra string */
        lenread = BZ2_bzRead(&ebz2err, epfbz2, new + newpos, ctrl[1]);
        if ((lenread < ctrl[1]) ||
            ((ebz2err != BZ_OK) && (ebz2err != BZ_STREAM_END)))
        {
            return LBD_ERR_CORRUPT;
        }

        /* Adjust pointers */
        newpos += ctrl[1];
        oldpos += ctrl[2];
    }

    /* Clean up the bzip2 reads */
    BZ2_bzReadClose(&cbz2err, cpfbz2);
    BZ2_bzReadClose(&dbz2err, dpfbz2);
    BZ2_bzReadClose(&ebz2err, epfbz2);
    if (fclose(cpf) || fclose(dpf) || fclose(epf))
    {
        return LBD_ERR_CLOSE;
    }

    /* Write the new file */
    if (((fd = open(newf, O_CREAT|O_TRUNC|O_WRONLY, 0666)) < 0) ||
        (write(fd, new, newsize) != newsize) || (close(fd) == -1))
    {
        return LBD_ERR_OPEN;
    }

    free(new);
    free(old);

    return LBD_OK;
}

五、版本管理指令碼化 待更新

相關推薦

iOS客戶React-Native增量更新實踐

市場上現存方案:微軟的 CodePush 以及React-Native中文網的Pushy,大家可根據公司實際情況酌情選擇。 處於安全性的考慮,公司禁止向第三方平臺上傳原始碼相關檔案,所以要自己動手實現。 增量更新主要實現流程 1.使用react-nativ

基於React Native封裝的資訊頻道TopBar,常見於新聞客戶react-native-scrollable-topbar

react-native-scrollable-topbar 基於React Native封裝的資訊頻道TopBar,常見於新聞客戶端,具體實現功能如下: TopBar區域可手動滑動(Underline 聯動) 點選頻道實現內容區切換 根據內容區(this.p

58 同城 iOS 客戶搜尋模組元件化實踐

【編者按】58 同城 App 自從 1.0 版本開始,便已經提供了搜尋功能。隨著版本的迭代、業務的複雜,搜尋框架也在不斷受到挑戰。諸如程式碼不能複用、耦合度高、業務功能接入成本高等問題日積月累,成為需要迫切解決的問題。本文從具體實際問題入手,詳述了利用元件

React Native入門——佈局實踐:開發京東客戶首頁(二)TabBar的構建

上篇文章講到構建京東客戶端首頁的搜尋欄,本篇我們一起來學習TabBar的構建。根據之前的調研,在構建TabBar的方式上,我推薦使用國外大神James Ide(https://github.com/ide)釋出在Exponent上的react-native-tab-navig

React-Native更新以及增量更新

不是增量更新,Rn的熱更新,流程是下載伺服器端上的一個解壓包到本地 解壓到應用的檔案目錄 這是一個打包後的apk檔案,在Rn中我們的js程式碼都是打包後存放在assets目錄中,其中index.android.bundle,可以理解我們js寫後打包

react native增量更新生成合並補丁檔案

這是一個node命令,有兩個命令可用,一是用於生成補丁檔案,一個是合併補丁生成新的檔案. 很多情況下我們需要生成補丁檔案,例如 react native 的熱更新,自建伺服器進行熱更新,不用codepush和pushy,需要生成bundle的補丁檔案,然後從伺服器下載下

[深入剖析React Native]熱更新react-native-pushy使用指南(IOS)

本文使用RN版本:0.33.0 準備工作 首先你應該有一個基於React Native開發的應用,我們把具有package.json的目錄叫做你的”應用根目錄”。 如果你還沒有初始化應用,請參閱開始使用React Native。 所以我們也假

iOS 客戶獲取七牛上傳token

生成 edi signed 解析 ring request self 在線 err 一、官方參考文檔: 1.上傳策略http://developer.qiniu.com/article/developer/security/put-policy.html 2.上傳憑證(即u

js判斷安卓客戶或者是ios客戶

終端 use navigator 判斷 com oca topic fun and 代碼:   function xaizai() {   var u = navigator.userAgent, app = navigator.appVersion;   var isA

iOS客戶節日換膚方案探究

named 普通模式 ani chang theme 1.5 static 解析 .json 轉自:https://www.ianisme.com的博客 一、前言: tip: 本來這篇文章在聖誕節就已經準備好了,但是由於種種原因一直沒有寫完,今天將它寫出來,也算是2018

要開始做博客園iOS客戶

2個 wid 原始的 註冊 網易 博客 可能 技術 內容 去年心血來潮做了一個dribbble客戶端,但是因為太忙又沒有發布,直到今年這時候準備回頭去整理一下然後上架,居然發現dribbble官方早在今年3月就把API權限收緊了,現在仍然開放的API和沒有差不多,真是欲

iOS客戶的微信支付接入

對於一個iOS的APP,如果有一些虛擬的商品或者服務需要通過線上支付來收費的話,一般有幾種主流的選擇。 如果是通過APP呼叫支付平臺APP的思路的話,一個是調起支付寶客戶端,一個則是調起微信支付。 實際上,從程式碼的角度,調起支付APP就是把一些關鍵的引數通過一定方式打包成為一個訂單,

React Native更新(CodePush使用)

dfa epush nodejs 管理 push alpha 輸入 進制 通過                                      React Native熱更新(CodePush使用)   在移動應用開發過程中,應用的發布上線一直是個耗時且長時間沒有

一個資深iOS開發者對於React Native的看法

本文轉自:http://blog.csdn.net/zhe13/article/details/48439967?hmsr=toutiao.io&utm_medium=toutiao.io&utm_source=toutiao.io 當我第一次嘗試ReactNative的時候,我

react-native更新

一、全域性安裝 code-push-cli $ npm i -g code-push-cli 二、註冊 App Center 執行以下命令 $ code-push register 或直接開啟 https://appcenter.ms/ 註冊 三、登入

支付寶客戶架構解析:iOS 客戶啟動效能優化初探

前言 《支付寶客戶端架構解析》系列將從支付寶客戶端的架構設計方案入手,細分拆解客戶端在“容器化框架設計”、“網路優化”、“效能啟動優化”、“自動化日誌收集”、“RPC 元件設計”、“移動應用監控、診斷、定位”等具體實現,帶領大家進一步瞭解支付寶在客戶端架構上的迭代與優化歷程。 啟動應用是使用者使用任何一款

AJAX+Servlet實現客戶無重新整理請求伺服器實踐

   最近需要做一個在網頁中要不斷檢測伺服器端資料程式,當然最簡單的方法是在html頁面頭部加以下標籤 <META http-equiv=V="REFRESH" content="5;URL=本頁面url">  實現將網頁設成每隔5秒鐘將自身頁面重新整理一次

react native更新與程式簡單除錯

1.如何開啟Developer Menu          模擬器:ctrl+m          真機:搖一搖手機即可 2.除錯及熱更新準備工作:當真機使用資料線或者模擬器時可以忽略,建議

IOS客戶app線上安裝ipa包,

在github上建立安裝需要的plist檔案 <?xml version="1.0" encoding="UTF-8"?><!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN""http://www.app

58 同城 iOS 客戶元件化演變思路整理

1、 http://geek.csdn.net/news/detail/193435 2、標題:58 同城 iOS 客戶端元件化演變歷程 3、第一版App架構:功能比較簡單,出發點是為了快速搶佔市場,採取“短平快”的方式開發。 4、第二版架構: