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

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

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

    HSF:High-speed Service Framework

    主要做了以下方面:服務方式的遠程調用;軟負載體系;服務可用性保障

    spring-hessian

    序列化方式一:Hessian 是由 caucho 提供的一個基于 binary-RPC 實現的遠程通訊 library 。

       1 、是基于什么協議實現的 ?

                基于 Binary-RPC 協議實現。

       2 、怎么發起請求 ?

                需通過 Hessian 本身提供的 API 來發起請求。

       3 、怎么將請求轉化為符合協議的格式的 ?

                Hessian 通過其自定義的串行化機制將請求信息進行序列化,產生二進制流。

       4 、使用什么傳輸協議傳輸 ?

                Hessian 基于 Http 協議進行傳輸。

       5 、響應端基于什么機制來接收請求 ?

                響應端根據 Hessian 提供的 API 來接收請求。

       6 、怎么將流還原為傳輸格式的 ?

                Hessian 根據其私有的串行化機制來將請求信息進行反序列化,傳遞給使用者時已是相應的請求信息對象了。

       7 、處理完畢后怎么回應 ?

                處理完畢后直接返回, hessian 將結果對象進行序列化,傳輸至調用端。

     

    序列化方式二: Protocol buffer,Protocol buffers are a flexible, efficient, automated mechanism for serializing structured data – think XML, but smaller, faster, and simpler. You define how you want your data to be structured once, then you can use special generated source code to easily write and read your structured data to and from a variety of data streams and using a variety of languages. You can even update your data structure without breaking deployed programs that are compiled against the "old" format.

     

     

    遠程調用:同步、單向異步、Future異步、Callback異步、可靠異步

     

    負載均衡 : failover,隨機尋址,第七層路由,路由規則,權重規則

     

    failover(故障轉移):In computing , failover is the capability to switch over automatically to a redundant or standbycomputer server , system , or network upon the failure or abnormal termination of the previously activeapplication ,[ 1] server, system, or network. Failover happens without human intervention and generally without warning, unlike switchover .

     

    隨機尋址:

    負載均衡策略

    選擇合適的負載均衡策略,使多個設備能很好的共同完成任務,消除或避免現有網絡負載分布不均、數據流量擁擠反應時間長的瓶頸。在各負載均衡方式中,針對不同的應用需求,在 OSI 參考模型的第二、三、四、七層的負載均衡都有相應的負載均衡策略。 
    負載均衡策略的優劣及其實現的難易程度有兩個關鍵因素:一、負載均衡算法,二、對網絡系統狀況的檢測方式和能力。 
    輪循均衡( Round Robin ): 每一次來自網絡的請求輪流分配給內部中的服務器,從 1 至 N 然后重新開始。此種均衡算法適合于服務器組中的所有服務器都有相同的軟硬件配置并且平均服務請求相對均衡的情況。  
    權重輪循均衡( Weighted Round Robin ): 根據服務器的不同處理能力,給每個服務器分配不同的權值,使其能夠接受相應權值數的服務請求。例如:服務器 A 的權值被設計成 1 , B 的權值是 3 , C 的權值是 6 ,則服務器 A 、 B、 C 將分別接受到 10% 、 30 %、 60 %的服務請求。此種均衡算法能確保高性能的服務器得到更多的使用率,避免低性能的服務器負載過重。  
    隨機均衡( Random ): 把來自網絡的請求隨機分配給內部中的多個服務器。  
    權重隨機均衡( Weighted Random ): 此種均衡算法類似于權重輪循算法,不過在處理請求分擔時是個隨機選擇的過程。  
    響應速度均衡( Response Time ): 負載均衡設備對內部各服務器發出一個探測請求(例如 Ping ),然后根據內部中各服務器對探測請求的最快響應時間來決定哪一臺服務器來響應客戶端的服務請求。此種均衡算法能較好的反映服務器的當前運行狀態,但這最快響應時間僅僅指的是負載均衡設備與服務器間的最快響應時間,而不是客戶端與服務器間的最快響應時間。 
    最少連接數均衡( Least Connection ): 客 戶端的每一次請求服務在服務器停留的時間可能會有較大的差異,隨著工作時間加長,如果采用簡單的輪循或隨機均衡算法,每一臺服務器上的連接進程可能會產生 極大的不同,并沒有達到真正的負載均衡。最少連接數均衡算法對內部中需負載的每一臺服務器都有一個數據記錄,記錄當前該服務器正在處理的連接數量,當有新 的服務連接請求時,將把當前請求分配給連接數最少的服務器,使均衡更加符合實際情況,負載更加均衡。此種均衡算法適合長時處理的請求服務,如 FTP 。 
    處理能力均衡: 此種均衡算法將把服務請求分配給內部中處理負荷(根據服務器 CPU 型號、 CPU 數量、內存大小及當前連接數等換算而成)最輕的服務器,由于考慮到了內部服務器的處理能力及當前網絡運行狀況,所以此種均衡算法相對來說更加精確,尤其適合運用到第七層(應用層)負載均衡的情況下。 
    DNS 
    響應均衡( Flash DNS ): 在 Internet 上,無論是 HTTP 、 FTP 或是其它的服務請求,客戶端一般都是通過域名解析來找到服務器確切的 IP 地址的。在此均衡算法下,分處在不同地理位置的負載均衡設備收到同一個客戶端的域名解析請求,并在同一時間內把此域名解析成各自相對應服務器的 IP 地址(即與此負載均衡設備在同一位地理位置的服務器的 IP 地址)并返回給客戶端,則客戶端將以最先收到的域名解析 IP 地址來繼續請求服務,而忽略其它的 IP 地址響應。在種均衡策略適合應用在全局負載均衡的情況下,對本地負載均衡是沒有意義的。 

     

    HSF 框架:OSGI,動態部署;Core+Plugins 模式;動態線程池

     

     

    動態線程池:Jini中的TaskManager

     

    服務方式的遠程調用:遠程通信框架Mina,消息中間件Notify,序列化協議Hessian;跨語言協議XFire

    Equinox

     

    Mina通信

     

    心跳機制

     

    分享到:  
    posted @ 2014-12-01 19:42 小馬歌 閱讀(379) | 評論 (0)編輯 收藏
     
         摘要: pt-table-checksum測試庫一致的情況下./pt-table-checksum h='127.0.0.1',u='root',p='dh123',P=5331 -d db1 --recursion-method=processlist --no-check-binlog-format --replicate=test.checksumsSELECT db, tbl,lower_boun...  閱讀全文
    posted @ 2014-11-21 16:08 小馬歌 閱讀(1478) | 評論 (0)編輯 收藏
     


    以前statement復制下做表結構變更時,一般是一臺一臺的從庫依次去做,最后做主庫。

    今天在一臺從庫上進行表結構變更時卻遇到一個復制報錯,
    Last_Errno: 1677
    Last_Error: Column 7 of table ‘user_0.user_00′ cannot be converted from type ‘varchar(10)’ to type ‘varbinary(30)’

    原變更語句為
    alter table user_00 modify `column7` varbinary(30) NOT NULL DEFAULT ”;

    原表中此字段類型為
    `column7` varbinary(10) NOT NULL DEFAULT ”

    s 命令顯示此從庫為5.5格式,并且復制是row格式。

    官網查詢后,發現這并不是一個bug,

    http://bugs.mysql.com/bug.php?id=59424

    在5.5的row格式復制中,有參數
    slave_type_conversions來控制復制中主從結構不一致的處理

    取值見下表:

    默認為”,即不支持主從字段類型不一致,
    其它3種類型為:
    all_lossy 支持有損轉換,如int–>tinyint
    all_non_lossy 支持無損轉換,如char(20)–>varchar(25)
    all_lossy,all_non_lossy 支持所有轉換

    此時手工在從庫上執行:
    stop slave;
    set global slave_type_conversions=ALL_LOSSY;
    start slave;

    復制恢復正常

    posted @ 2014-11-21 14:19 小馬歌 閱讀(2528) | 評論 (0)編輯 收藏
     


    客戶端在測試服務器上上傳大的圖片,報“413 Request Entity Too Large”的錯誤,從網上搜索解決辦法如下:

    解決方法:打開nginx主配置文件nginx.conf,找到http{}段,添加
    client_max_body_size 20m;
    Centos下 vi /usr/local/nginx/conf/nginx.conf

    重啟NGINX
    kill -HUP `cat /usr/local/nginx/nginx.pid `
    恢復正常

    posted @ 2014-11-14 14:08 小馬歌 閱讀(426) | 評論 (0)編輯 收藏
     
    本文由 ImportNew - xiafei 翻譯自 anturis。歡迎加入翻譯小組。轉載請參見文章末尾的要求。

    簡介

    Java虛擬機(JVM)是Java應用的運行環境,從一般意義上來講,JVM是通過規范來定義的一個虛擬的計算機,被設計用來解釋執行從Java源碼編譯而來的字節碼。更通俗地說,JVM是指對這個規范的具體實現。這種實現基于嚴格的指令集和全面的內存模型。另外,JVM也通常被形容為對軟件運行時環境的實現。通常JVM實現主要指的是HotSpot。

    JVM規范保證任何的實現都能夠以同樣的方式解釋執行字節碼。其實現可以多樣化,包括進程、獨立的Java操作系統或者直接執行字節碼的處理器芯片。我們了解最多的JVM是作為軟件實現,運行在流行的操作系統平臺上(包括Windows、OS X、Linux和Solaris等)。

    JVM的結構允許對一個Java應用進行更細微的控制。這些應用運行在沙箱(Sandbox)環境中。確保在沒有恰當的許可時,無法訪問到本地文件系統、處理器和網絡連接。遠程執行時,代碼還需要進行證書認證。

    除了解釋執行Java字節碼,大多數的JVM實現還包含一個JIT(just-in-time 即時)編譯器,用于為常用的方法生成機器碼。機器碼使用的是CPU的本地語言,相比字節碼有著更快的運行速度。

    雖然理解JVM不是開發或運行Java程序的必要條件,但是如果多了解一些JVM知識,那么就有機會避免很多性能上的問題。理解了JVM,實際上這些問題會變得簡單明了。

    體系結構

    JVM規范定義了一系列子系統以及它們的外部行為。JVM主要有以下子系統:

    • Class Loader 類加載器。 用于讀入Java源代碼并將類加載到數據區。
    • Execution Engine 執行引擎。 執行來自數據區的指令。

    數據區使用的是底層操作系統分配給JVM的內存。

    類加載器(Class Loader)

    JVM在下面幾種不同的層面使用不同的類加載器:

    • bootstrap class loader(引導類加載器):是其他類加載器的父類,它用于加載Java核心庫,并且是唯一一個用本地代碼編寫的類加載器。
    • extension class loader(擴展類加載器):是bootstrap class loader加載器的子類,用于加載擴展庫。
    • system class loader(系統類加載器):是extension class loader加載器的子類,用于加載在classpath中的應用程序的類文件。
    • user-defined class loader(用戶定義的類加載器):是系統類加載器或其他用戶定義的類加載器的子類。

    當一個類加載器收到一個加載類的請求,首先它會檢查緩存,確認該類是否已經被加載,然后把請求代理給它的父類。如果父類沒能成功的加載類,那么子類就會自己去嘗試加載該類。子類可檢查父類加載器的緩存,但父類不能看到子類所加載的類。之所類加載體系會這樣設計,是認為一個子類不應該重復加載已經被父類加載過的類。

    執行引擎(Execution Engine)

    執行引擎一個接一個地執行被加載到數據區的字節碼。為了保證字節碼指令對于機器來說是可讀的,執行引擎使用下面兩個方法:

    • 解釋執行:執行引擎把它遇到的每一條指令解釋為機器語言。
    • 即時編譯:如果一條指令經常被使用,執行引擎會把它編譯為本地代碼并存儲在緩存中。這樣,所有和這個方法相關的代碼都會直接執行,從而避免重復解釋。

    盡管即時編譯比解釋執行要占用更多的時間,但是對于需要使用成千上萬次的方法,只需要處理一次。相比每次都解釋執行,以本地代碼的方式運行會節約很多執行時間。

    JVM規范中并不規定一定要使用即時編譯。即時編譯也不是用于提高JVM性能的唯一的手段。規范僅僅規定了每條字節碼對應的本地代碼,至于執行引擎如何實現這一對應過程的,完全由JVM的具體實現來決定。

    內存模型(Memory Model)

    Java內存模型建立在自動內存管理的概念之上。當一個對象不再被一個應用所引用,垃圾回收器就會回收它,從而釋放相應的內存。這一點和其他很多需要自行釋放內存的語言有很大不同。

    JVM從底層操作系統中分配內存,并將它們分為以下幾個區域:

    • 堆空間(Heap Space):這是共享的內存區域,用于存儲可以被垃圾回收器回收的對象。
    • 方法區(Method Area):這塊區域以前被稱作“永生代”(permanent generation),用于存儲被加載的類。這塊區域最近被JVM取消了。現在,被加載的類作為元數據加載到底層操作系統的本地內存區。
    • 本地區(Native Area):這個區域用于存儲基本類型的引用和變量。

    一個有效的管理內存方法是把對空間劃分為不同代,這樣垃圾回收器就不用掃描整個堆區。大多數的對象的生命周期都很段短暫,那些生命周期較長的對象往往直到應用退出才需要被清除。

    當一個Java應用創建了一個對象,這個對象是被存儲到“初生池”(eden pool)。一旦初生池存儲滿了,就會在新生代觸發一次minor gc(小范圍的垃圾回收)。首先,垃圾回收器會標記出那些“死對象”(不再被應用所引用的對象),同時延長所有保留對象的生命周期(這個生命周期長度是用數字來描述,代表了期所經歷過的垃圾回收的次數)。然后,垃圾回收器會回收這些死對象,并把剩余的活著的對象移動到“幸存池”(survivor pool),從而清空初生池。

    當一個對象存活達到一定的周期后,它就會被移動到堆中的老生代:“終身代”(tenured pool)。最后,當終身代被填滿時,就會觸發一次full gc或major gc(完全的垃圾回收),以清理終身代。

    (譯者注:一般我們把初生池和幸存池所在的區域合并成為新生代,把終身代所在的區域成為老生代。對應的,在新生代上產生的gc稱為minor gc,在老生代上產生的gc稱為full gc。希望這樣大家在其他地方看到對應的術語時能更好理解)

    當垃圾回收(gc)執行的時候,所有應用線程都要被停止,系統產生一次暫停。minor gc非常頻繁,所以被優化的能夠快速的回收死對象,是新生代的內存的主要的回收方式。major gc運行起來就相對慢得多,因為要掃描非常多的活著的對象。垃圾回收器本身也有多種實現,有些垃圾回收器在一定情況下能更快的執行major gc。

    堆的大小是動態的,只有堆需要擴張的時候才會從內存中分配。當堆被填滿時,JVM會重新給堆分配更多的內存,直到達到堆大小的上限,這種重新分配同樣會導致應用的短暫停止。

    線程

    JVM是運行在一個獨立的進程中的,但它可以并發執行多個線程,每個線程都運行自己的方法,這是Java必備的一個部分。以即時消息客戶端這樣一個應用為例,它至少運行兩個線程。一個線程用于等待用戶輸入,另一個檢查服務端是否有新的消息傳輸。再以服務端應用為例,有時一個請求可能要涉及多個線程并發執行,所以需要多線程來處理請求。

    在JVM的進程中,所有的線程共享內存和其他可用的資源。每一個JVM進程在進入點(main方法)處都要啟動一個主線程,其他線程都從主線程啟動,成為執行過程中的一個獨立部分。線程可以再不同的處理器上并行執行,同樣也可以共享一個處理器,線程調度器負責處理多個線程共享一個處理器的情況。

    很多應用(特別是服務端應用)會處理很多任務,需要并行運行。這些任務中有些是非常重要的,需要實時執行的。而另外一些是后臺任務,可以在CPU空閑時執行。任務是在不同的線程中運行的。舉例子來說,服務端可能有一些低優先級的線程,它們會根據一些數據來計算統計信息。同時也會啟動一些高優先級的進程用于處理傳入的數據,響應對這些統計信息的請求。這里可能有很多的源數據,很多來自客戶端的數據請求,每個請求都會使服務端短暫的停止后臺計算的線程以響應這個請求。所以,你必須監控在運行的線程數目并且保證有足夠的CPU時間來執行必要的計算。

    (譯者注:這一段在原文中是在性能優化的章節,譯者認為這可能是作者的不小心,似乎放在線程的章節更合適。)

    性能優化

    JVM的性能取決于其配置是否與應用的功能相匹配。盡管垃圾回收器和內存回收進程是自動管理內存的,但是你必須掌管它們的頻率。通常來說,你的應用可使用的內存越多,那么這些會導致應用暫停的內存管理進程需要起作用的就越少。

    如果垃圾回收發生的頻率比你想的要多很多,那么可以在啟動JVM的時候為其配置更大的最大堆大小值。堆被填滿的時間越久,就越能降低垃圾回收發生的頻率。最大堆大小值可以在啟動JVM的時候,用-Xmx參數來設定。默認的最大堆大小是被設置為可用的操作系統內存的四分之一,或者最小1GB。

    如果問題出在經常重新分配內存,那么你可以把初始化堆大小設置為和最大堆大小一樣。這就意味著JVM永遠不需要為堆重新分配內存。但這樣做就會失去動態堆大小適配的優化,堆的大小從一開始就被固定下來。配置初始化對大小是在啟動JVM,用-Xms來設定。默認初始化堆大小會被設定為操作系統可用的物理內存的六十四分之一,或者設置一個最小值。這個值是根據不同的平臺來確定的。

    如果你清楚是哪種垃圾回收(minor gc或major gc)導致了性能問題,可以在不改變整個堆大小的情況下設定新生代和老生代的大小比例。對于需要產生大量臨時對象的應用,需要增大新生代的比例(當然,后果是減小了老生代的大?。τ陂L生命周期對象較多的應用,則需增大老生代的比例(自然需要減少新生代的大?。?。以下幾種方法可以用來設定新生代和老生代的大?。?/p>

    • 在啟動JVM時,使用-XX:NewRatio參數來具體指定新生代和老生代的大小比例。比如,如果想讓老生代的大小是新生代的五倍,則設置參數為-XX:NewRatio=5,默認這個參數設定為2(即老生代占用堆空間的三分之二,新生代占用三分之一)。
    • 在啟動JVM時,直接使用-Xmn參數設定初始化和最大新生代大小,那么堆中的剩余大小即是老生代的大小。
    • 在啟動JVM時,直接使用-XX:NewSize-XX:MaxNewSize參數設定初始化和最大新生代大小,那么堆中的剩余大小即是老生代的大小。

    每一個線程都有一個棧,用于保存函數調用、返回地址等等,這些棧有著對應的內存分配。如果線程過多,就會導致OutOfMemory錯誤。即使你有足夠的空間的堆來存放對象,你的應用也可能會因為創建一個新的線程而崩潰。這種情況下,需要考慮限制線程中的棧大小的最大值。線程棧大小可以在JVM啟動的時候,通過-Xss參數來設置,默認這個值被設定為320KB至1024KB之間,這和平臺相關。

    性能監控

    當開發或運行一個Java應用的時候,對JVM的性能進行監控是很重要的。配置JVM不是一次配置就萬事大吉的,特別是你要應對的是Java服務器應用的情況。你必須持續的檢查堆內存和非堆內存的分配和使用情況,線程數的創建情況和內存中加載的類的數據情況等。這些都是核心參數。

    使用Anturis控制臺,你可以為任何的硬件組件上運行的JVM配置監控(例如,在一臺電腦上運行的一個Tomcat網頁服務器)。

    JVM監控可以使用以下衡量標準:

    • 總內存使用情況(MB):即JVM使用的總內存。如果JVM使用了所有可用內存,這項指標可以衡量底層操作系統的整體性能。
    • 堆內存使用(MB):即JVM為運行的Java應用所使用的對象分配的所有內存。不使用的對象通常會被垃圾回收器從堆中移除。所以,如果這個指數增大,表示你的應用沒有把不使用的對象移除或者你需要更好的配置垃圾回收器的參數。
    • 非堆內存的使用(MB):即為方法區和代碼緩存分配的所有內存。方法區是用于存儲被加載的類的引用,如果這些引用沒有被適當的清理,永生代池會在每次應用被重新部署的時候都會增大,導致非堆的內存泄露。這個指標也可能指示了線程創建的泄露。
    • 池內總內存(MB):即JVM所分配的所有變量內存池的內存和(即除了代碼緩存區外的所有內存和)。這個指標能夠讓你明確你的應用在JVM過載前所能使用的總內存。
    • 線程:即所有有效線程數。舉個例子,在Tomcat服務器中每個請求都是一個獨立的線程來處理,所以這個衡量指標可以表示當前有多少個請求數,是否影響到了后臺低權限的線程的運行。
    • 類:即所有被加載的類的總數。如果你的應用動態的創建很多類,這可能是服務器內存泄露的一個原因。

    原文鏈接: anturis 翻譯: ImportNew.com xiafei
    譯文鏈接: http://www.importnew.com/13556.html
    轉載請保留原文出處、譯者和譯文鏈接。]



    相關文章

    posted @ 2014-11-11 18:30 小馬歌 閱讀(160) | 評論 (0)編輯 收藏
     

    akullpp 在 Github 上發起維護的一個 Java 資源列表,內容包括:構建工具、數據庫、框架、模板、安全、代碼分析、日志、第三方庫、書籍、Twitter、Java站點等等。

    包括:

    Awesome XXX 系列:

    Github干貨系列:C++資源集合

    Github干貨系列:Go 語言資源集合

    Github干貨系列:PHP 資源集合

    Github干貨系列:Python 資源集合

    Github干貨系列:系統管理員免費資源集合

    Github干貨系列:Web性能優化

    Github干貨系列:React 資源集合

    閱讀原文 »

    › RSS訂閱Java話題,關注Java技術的最新動態和優秀文章!

    posted @ 2014-11-11 18:30 小馬歌 閱讀(734) | 評論 (0)編輯 收藏
     

    流程:把線程dump出來,然后分析

    1:Threaddump的方法:

    • kill -3 pid
    • jstack -l pid
    • jvisualvm中來thread dump

    2:找到導致cpu高的線程
    top -H -p pid
      PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND                                                             
     4691 root      19   0  448m 132m  13m S  0.0  7.5   0:00.01 java                                                                
     4692 root      19   0  448m 132m  13m S  0.0  7.5   0:00.39 java                                                                
     4698 root      15   0  448m 132m  13m S  0.0  7.5   0:14.14 java                                                                
     4699 root      15   0  448m 132m  13m S  0.0  7.5   0:00.43 java                                                                
     4700 root      15   0  448m 132m  13m S  0.0  7.5   0:00.63 java                                                                
     4701 root      18   0  448m 132m  13m S  0.0  7.5   0:00.00 java                                                               

     對應的線程id是十進制的,需要轉換為十六進制的在threaddump文件中才可以看到

    3:十進制轉十六進制
    -bash-3.2# python
    >>> print hex(4739)
    0×1283

    4:找到對應的線程
    vi threaddump.log
    查找:/0×1283
    找到對應的線程,把相關的方法找出來,可以精確到代碼的行號,自己修改相關源碼來fix bug。

    posted @ 2014-11-11 13:33 小馬歌 閱讀(204) | 評論 (0)編輯 收藏
     
         摘要: 假如我們對面向對象的思維已經C語言都很熟悉的話,對于我們學習Objective-C將會非常有用。假如我們對C語言還不熟悉的話,那我們需要學習一下C語言。AD:2014WOT全球軟件技術峰會北京站 課程視頻發布2010年11月編程語言排行榜和2月編程語言排行榜講的都是Objective-C。Objective-C是Mac軟件開發領域最主要的開發語言,假如我們對面向對象的思維已經C語言都很熟悉的話,對...  閱讀全文
    posted @ 2014-11-04 11:24 小馬歌 閱讀(281) | 評論 (0)編輯 收藏
     
    構建iOS持續集成平臺
     
    作者 劉先寧,火龍果軟件    發布于 2013-11-11
     

    (一)——自動化構建和依賴管理

    2000年Matin Fowler發表文章Continuous Integration【1】;2007年,Paul Duvall, Steve Matyas和 Andrew Glover合著的《Continuous Integration:Improving Software Quality and Reducing Risk》 【2】出版發行,該書獲得了2008年的圖靈大獎。持續集成理念經過10多年的發展,已經成為了業界的標準。在Java, Ruby的世界已經誕生了非常成熟的持續集成工具和實踐,而對于iOS領域來說,因為技術本身相對比較年輕和蘋果與生俱來的封閉思想,在持續集成方面的發展相對滯后一些,但是,隨著越來越多的iOS開發者的涌入,以及各個互聯網巨頭加大對iOS開發的投入,誕生了一大批非常好用的持續集成工具和服務,本文的目的就是介紹一下如何有效的利用這些類庫,服務快速構建一個iOS開發環境下的持續集成平臺。

    自動化構建

    在MartinFowler的文章[1]中關于自動化的構建定義如下:

    Anyone should be able to bring in a virgin machine, check the sources 
    out of the repository, issue a single command, and have a running
    system on their machine.

    因此,自動化構建的的首要前提是有一個支持自動化構建的命令行工具,可以讓開發人員可以通過一個簡單的命令運行當前項目。

    命令行工具

    自動化構建的命令行工具比持續集成的概念要誕生得早很多,幾十年前,Unix世界就已經有了Make,而Java世界有Ant,Maven,以及當前最流行的Gradle,.Net世界則有Nant和MSBuild。作為以GUI和命令行操作結合的完美性著稱的蘋果公司來說,當然也不會忘記為自己的封閉的iOS系統提供開發環境下命令行編譯工具:xcodebuild【3】

    xcodebuild

    在介紹xcodebuild之前,需要先弄清楚一些在XCode環境下的一些概念【4】:

    Workspace:簡單來說,Workspace就是一個容器,在該容器中可以存放多個你創建的Xcode Project, 以及其他的項目中需要使用到的文件。使用Workspace的好處有,1),擴展項目的可視域,即可以在多個項目之間跳轉,重構,一個項目可以使用另一個項目的輸出。Workspace會負責各個Project之間提供各種相互依賴的關系;2),多個項目之間共享Build目錄。

    Project:指一個項目,該項目會負責管理生成一個或者多個軟件產品的全部文件和配置,一個Project可以包含多個Target。

    Target:一個Target是指在一個Project中構建的一個產品,它包含了構建該產品的所有文件,以及如何構建該產品的配置。

    Scheme:一個定義好構建過程的Target成為一個Scheme。可在Scheme中定義的Target的構建過程有

    Build/Run/Test/Profile/Analyze/Archive

    BuildSetting:配置產品的Build設置,比方說,使用哪個Architectures?使用哪個版本的SDK?。在Xcode Project中,有Project級別的Build Setting,也有Target級別的Build Setting。Build一個產品時一定是針對某個Target的,因此,XCode中總是優先選擇Target的Build Setting,如果Target沒有配置,則會使用Project的Build Setting。

    弄清楚上面的這些概念之后,xcodebuild就很好理解了,官網上對其作用的描述如下:

    xcodebuild builds one or more targets contained in an Xcode 
    project, or builds a scheme contained in an Xcode workspace or
    Xcode project.

    xcodebuild就是用了構建產品的命令行工具,其用法可以歸結為3個部分:

    1.可構建的對象

    2.構建行為

    3.一些其他的輔助命令

    可以構建的對象有,默認情況下會運行project下的第一個target:

    1.workspace:必須和“-scheme”一起使用,構建該workspace下的一個scheme。

    2.project:當根目錄下有多個Project的時候,必須使用“-project”指定project,然后會運行

    3.target:構建某個Target

    4.scheme:和“-workspace”一起使用,指定構建的scheme。

    5.……

    構建行為包括:

    1.clean:清除build目錄下的

    2.build: 構建

    3.test: 測試某個scheme,必須和"-scheme"一起使用

    4.archive:打包,必須和“-scheme”一起使用

    5.……

    輔助命令包括:

    1.-sdk:指定構建使用的SDK

    2.-list:列出當前項目下所有的Target和scheme。

    3.-version:版本信息

    4.…...

    關于xcodebuild更多詳細的命令行請參見:https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man1/xcodebuild.1.html

    下圖是使用XcodeBuild運行一個scheme的build的結果:

    了解了xcodebuild的用法之后,接下來分析一下xcodebuild的主要缺陷:

    1.從上圖直接可以得到的感覺,其腳本輸出的可讀性極差,

    2.只能要么完整的運行一個target或者scheme,要么全部不運行。不能指定運行Target中特定的測試。

    3.最令人發指的是,XCode 4中的xcodebuild居然不支持iOSUnitTest的Target【5】,當我嘗試運行一個iOS App的測試target時,得到如下的錯誤:

    對于上面提到的缺陷,Facebook給出了他們的解決方案:xctool【6】

    xctool

    xctool在 其主頁直接表明了其目的:

    xctool is a replacement for Apple's xcodebuild that makes it easier  to build and
    test iOS and Mac products. It's especially helpful for continuous integration.

    其作用是替代xcodebuild,目的是讓構建和測試更加容易,更好的支持持續集成。從個人感受來看,它的確成功取代了xcodebuild。但是xctool說到底只是對xcodebuild的一個封裝,只是提供了更加豐富的build指令,因此,使用xctool的前提是xcodebuild已經存在,且能正常工作。

    安裝

    xctool的安裝非常簡單,只需要clone xctool的repository到項目根目錄就可以使用, 如果你的機器上安裝有Homebrew,可以通過“brew install xctool”命令直接安裝。(注意:使用xctool前一定要首先確認xcodebuild已安裝且能正確工作)。

    用法

    關于xctool的用法就更加人性化了,幾乎可以重用所有的xcodebuild的指令,配置。只需要注意一下幾點:

    1.xctool不支持target構建,只能使用scheme構建。

    2.支持“-only”指令運行指定的測試。

    3.支持多種格式的build報告。

    例子:

    path/to/xctool.sh 
    -workspaceYourWorkspace.xcworkspace
    -schemeYourScheme
    test -only SomeTestTarget:SomeTestClass/testSomeMethod

    下圖是我使用xctool運行test的效果:

    常見問題:

    No architectures to compile for (ONLY_ACTIVE_ARCH=YES, active arch=x86_64, VALID_ARCHS=armv7 armv7s).

    解決方法:到Project Setting中,把"Build Active Architecture Only"設置為NO

    Code Sign error: A valid provisioning profile matching the application's Identifier 'dk.muncken.MyApp' could not be found

    解決方法:通過“-sdkiphonesimulator”指定SDK,從而能夠使用符合iOS約定的application Identifier。

    依賴管理

    選定了命令行工具之后, 接下來可以考慮下依賴管理的問題了。我到現在還記得幾年前,剛從Ant轉到使用Maven的那種爽快的感覺。后來,進入Ruby的世界,其與生俱來的Gem管理系統,也讓其依賴管理變得極其簡單。 對于iOS平臺來說,在做項目時,經常需要使用到各種各樣的第三方Framework,這同樣需要一個爽快的依賴管理系統,不然的話,各位可以想象一下重復的下載Framework文件,拖入各個Target的Build Phase的Link Binary With Libraries中的場景。這種重復的勞動對于“懶惰”的程序員來說,是很難接受的,于是,活躍的社區開發者們提供了這樣的一個工具:Cocoapods【7】

    Cocoapods開始于2011年8月12日,經過2年多的發展,現在已經超過2500次提交,并且持續保持活躍更新,目前已成為iOS領域最流行的第三方依賴管理工具。從技術層面來說,其是一個Ruby Gem,從功能層面來說,其是一個iOS平臺下的依賴管理工具,為iOS項目開發提供了類似于在Ruby世界使用Gem的依賴管理體驗。

    安裝

    前面提到cocoapods本質上是一個Ruby Gem,因此,其使用前提首先是Ruby開發環境。慶幸的是,Mac下都自帶Ruby。這樣,只需要簡單的2條命令,就可以把cocoapods安裝好:

    $ [sudo] gem install cocoapods
    $ pod setup

    用法

    cocoapods的使用方式和使用Ruby Gem非常相似,首先需要在項目根目錄下創建文件Podfile,在Podfile中,開發人員只需要按照規則配置好如下內容就好:

    1.項目支持的平臺,版本(iOS/OSX)

    2.每個target的第三方依賴

    例子:

    platform :ios, '6.0'
    inhibit_all_warnings!
    xcodeproj `MyProject`
    pod 'ObjectiveSugar', '~> 0.5'
    target :test do
    pod 'OCMock', '~> 2.0.1'
    end
    post_install do |installer|
    installer.project.targets.each do |target|
    puts "#{target.name}"
    end
    end

    修改好配置文件之后,只需要簡單的使用“pod install”即可安裝好所有的依賴,執行該命令之后,在項目跟目錄下會出現“.xcworkspace”和“Pods”兩個目錄:

    接下來,開發者需要使用xcworkspace打開項目而不是使用xcodeproject,打開項目之后,在項目目錄下除了自己的project以外,還可以看到一個叫做Pods的項目,該項目會為每一個依賴創建一個target:

    在Podfile中,還可以指定依賴專屬于某個Target,

    target :CocoaPodsTest do
    pod 'OCMock', '~> 2.0.1'
    pod 'OCHamcrest'
    end

    如果你記不清楚某個依賴庫的名稱,可以使用“pod search <name>”模糊搜索依賴庫中的相似庫,另外,如果你想使用的庫在cocoapods的中央庫中找不到,那么,你可以考慮為開源社區做做貢獻,把你覺得好用的庫添加到中央庫中,Cocoapods的官網上有具體的步驟【8】

    原理

    CocoaPods的原理思想基本上來自于Jonah Williams的博客“Using Open Source Static Libraries in Xcode 4”【9】,當使用“pod install”安裝文件時,cocoapods做了如下這些事:

    1.創建或者更新當前的workspace

    2.創建一個新的項目來存放靜態庫

    3.把靜態庫會編譯生成的libpods.a文件配置到target的build phase的link with libraries中

    4.在依賴項目中創建*.xcconfig文件,指定在編譯時的一些參數和依賴

    5.添加一個新的名為“Copy Pods Resource”的Build Phase,該build phase會使用"${SRCROOT}/Pods/Pods-CocoaPodsTest-resources.sh"把Pods下的資源文件拷貝到app bundle下。

    注意事項

    當使用xctool作為命令行工具構建項目時,使用cocoapods管理依賴時,需要做一些額外的配置:

    1.編輯Scheme,把pods靜態庫項目作為顯式的依賴添加到項目的build中,

    2.把pods依賴項目拖動到本來的項目之上,表示先編譯pods靜態庫項目,再編譯自己的項目。

    (二)——測試框架

    測試框架

    有了自動化構建和依賴管理之后,開發者可以很輕松的在命令行構建整個項目,但是,作為持續集成平臺來說,最重要的還是測試,持續集成最大的好處在于能夠盡早發現問題,降低解決問題的成本。而發現問題的手段主要就是測試。在Martin Fowler的Test Pyramid【10】一文中論述了測試金子塔的概念,測試金字塔的概念來自Mike Cohn,在他的書Succeeding With Agile中有詳細描述:測試金字塔最底層是單元測試,然后是業務邏輯測試,如果更細化一點的話,可以分為把完整的測試策略分為如下的層級:

    作為持續集成平臺,能自動化的測試層級越多,平臺就能產生越大的價值。

    Unit Test

    目前,在iOS領域, 最流行的Unit測試框架有2個:OCUnit【11】和GHunit【12】,這兩個框架各有其優缺點:

     優點
    缺點
    OCUnit與Xcode無縫集成, 快捷鍵,Scheme配置都非常方便1. 只能一次運行整個測試,不能靈活的運行某個測試集; 2.測試結果輸出的可讀性不好,不容易找到失敗的測試
    GHUnit1.自帶GUI,測試結果清晰可見;2.可以靈活的運行指定的測試;3.開源項目1.需開發者安裝,配置略顯復雜;2. 對命令行運行測試的支持不是很好,
       

    OCUnit的運行結果會通過彈窗直接告訴開發者,運行的細節信息則會打印在Xcode的輸出窗口中:

    GHUnit的運行結果則全部顯示在自己的應用界面中,開發者可以在應用中查看所有的信息,以及做運行測試等各種各樣的操作。

    關于如何使用OCUnit和GHUnit, InfoQ上有高嘉峻的文章《iOS開發中的單元測試》(http://www.infoq.com/cn/articles/ios-unit-test-1)有詳細的介紹,我就不再這兒重復敘述了。

    如果單從單元測試框架來看,個人更喜歡GHUnit測試結果的可讀性和運行測試的靈活性,但是,隨著Facebook的xctool的發布,OCUnit華麗麗的逆襲了,因為xctool幫助OCUnit把運行測試的靈活性和測試結果的可讀性這兩塊短板給補齊了,再加上其和Xcode的集成優勢以及通過命令行運行的便捷性,讓其成為持續集成平臺的Unit測試框架的首選。

    在Java程序員的心中,Junit和Hamcrest永遠是一體的,Hamcrest為junit提供了非常豐富的斷言機制,極大的增強了測試的可讀性。越來越活躍的iOS開發社區,當然不會讓Object-C的世界缺失這樣一個優秀的框架,于是OCHamcrest【13】誕生了。

    在測試項目中使用OCHamcrest非常簡單,尤其是使用了cocoapods管理依賴的項目。只需要在Podfile文件中加上:

    target :<TestTargetName> do
    ...
    pod 'OCHamcrest'
    end

    然后,運行“pod install”命令安裝Hamcrest到測試Target,安裝好之后,為了在測試類中使用OCHamcrest的斷言。還需要在測試類的頭文件中加入如下代碼:

    #define HC_SHORTHAND
    #import<OCHamcrest/OCHamcrest.h>

    開發者可以把這段代碼加入<TestTargetName>-prefix.pch中,這樣所有的測試類就都可以使用OCHamcrest的斷言了。在前面提到的高嘉峻的文章中的第二部分更加詳細的講解了OCHamcrest的斷言,以及其和另一個斷言框架Expecta的對比,感興趣的同學可以跳過去看看。

    Component Test & Integration Test

    在開發手機應用時,總難免會和其他的系統集成,尤其當開發的應用是某個系統的手機客戶端時,這樣就涉及到很多第三方API的集成點需要測試,在成熟的Java世界中,誕生了EasyMock,Mockito,moco等針對這種集成點的測試工具。同樣的,活躍的社區力量正一步一步的在讓Object-C世界成熟,OCMock【14】誕生。

    OCMock

    有了cocoaPods,新加框架變得非常容易,基本上就是“哪里沒有加哪里”的節奏,添加OCMock框架,只需要在Podfile文件中加上:

    target :<TestTargetName> do
    ...
    pod 'OCMock', '~> 2.0.1'
    end

    然后,運行“pod install”命令安裝OCMock到測試Target,同樣的,需要把OCmock的頭文件添加<TestTargetName>-prefix.pch文件中

    #import<OCMock/OCMock.h>

    下面是一個簡單的使用OCMock的例子,更多的用法請參考OCMock的官網:http://ocmock.org/features/:

    - (void)testSimpeMockPass{
    idmockObject = [OCMockObjectmockForClass:NSString.class];
    [[[mockObject stub] andReturn:@"test"] lowercaseString];

    NSString * returnValue = [mockObjectlowercaseString];
    assertThat(returnValue, equalTo(@"test"));
    }

    moco

    moco【15】以其對系統集成點測試的貢獻榮獲了2013年的“Duke's Choice Award”獎,雖然其以Java寫成,主要的生態系統也是圍繞Java打造,但是,其Standalone模式可以非常方便的構造一個開發者期望的服務器,這對于Mobile領域的集成點測試來說,本就是一個非常好的Mock服務器的工具。Moco有如下的特點:

    易于配置,使用:一個Json配置文件,然后“java -jar moco-runner--standalone.jar -p 8080 ***.json”就可以啟動一個Mock服務器。該服務器的所有行為都在配置文件里。如果你想添加,修改服務器行為,只需要修改一下配置文件,然后重新啟動該服務器就行了。

    配置文件可讀性好,使用Json格式的配置文件,對絕大多數開發者來說都可以很容易理解。

    支持模擬客戶端需要的所有http操作,moco實現了針對請求Content、URI、Query Parameter、Http Method、Header、Xpath的模擬。對響應的格式支持有Content、Status Code、Header、URL、甚至支持Sequence請求,即根據對同一請求的調用次數返回不同的結果。

    完全開源,代碼不多也比較易懂,如果沒有覆蓋到我們的場景,完全可以在該項目基礎上實現一個自己的Mock服務器 。

    熊節在infoQ上發表的《企業系統集成點測試策略》【16】一文中,詳細的論述了在企業系統中,moco對測試系統集成點的 幫助。這些論點在Mobile開發領域同樣適用,因此合理的使用moco可以幫助iOS開發者更加容易的構建一個穩固的持續集成平臺。

    System Test

    對于iOS的系統(UI)測試來說,比較知名的工具有UIAutomation【17】和FonMonkey【18】。

    UIAutomation

    UIAutomation是隨著iOS SDK 4.0引入,幫助開發者在真實設備和模擬器上執行自動化的UI測試。其本質上是一個Javascript的類庫,通過 界面上的標簽和值的訪問性來獲得UI元素,完成相應的交互操作,從而達到測試的目的,類似于Web世界的Selenium。

    通過上面的描述,可以得知,使用UIAutomation做測試時,開發者必須掌握兩件事:

    1.如何找到界面上的一個UI元素

    2.如何指定針對一個UI元素的操作

    在UIAutomation中,界面就是由一堆UI元素構建的層級結構,所有UI元素都繼承對象UIAElement ,該對象提供了每個UI元素必須具備的一些屬性:

    1.name

    2.value

    3.elements

    4.parent

    5.…

    而整個界面的層級結構如下:

    Target(設備級別的UI,用于支持晃動,屏幕方向變動等操作)
    Application(設備上的應用,比方說Status Bar,keyboard等)
    Main window(應用的界面,比方說導航條)
    View(界面下的View,比方說UITableView)
    Element(View下的一個元素)
    Child element(元素下的一個子元素)

    下面是一個訪問到Child element的例子:

    UIATarget.localTarget().HamcrestDemo().tableViews()[0].cells()[0].elements()

    開發者還可以通過“UIATarget.localTarget().logElementTree()”在控制臺打印出該target下所有的的elements。

    找到UI元素之后,開發者可以基于該UI元素做期望的操作,UIAutomation作為原生的UI測試框架,基本上支持iOS上的所有UI元素和操作,比方說:

    1.點擊按鈕,例: ***.buttons[“add”].tap()

    2.輸入文本, 例:***.textfields[0].setValue(“new”)

    3.滾動屏幕,例:***.scrollToElementWithPredicate(“name begin with ’test’”)

    4.……

    關于使用UIAutomation做UI測試,推薦大家一定要看一下2010的WWDC的Session 306:Automating User Interface Testing with Instruments【19】。 另外,這兒還有一篇很好的博客,詳細的講解了如何使用UIAutomation做UI自動化測試:http://blog.manbolo.com/2012/04/08/ios-automated-tests-with-uiautomation

    Apple通過Instruments為UIAutomation測試用例的命令行運行提供了支持,這樣就為UIAutomation和CI服務器的集成提供了便利。開發者可以通過如下的步驟在命令行中運行UIAutomation測試腳本

    指定目標設備,構建被測應用,該應用會被安裝到指定的DSTROOT目錄下

    xcodebuild
    -project "/Users/twer/Documents/xcodeworkspace/AudioDemo/AudioDemo.xcodeproj"
    -schemeAudioDemo
    -sdk iphonesimulator6.1
    -configuration Release SYMROOT="/Users/twer/Documents/xcodeworkspace/
    AudioDemo/build" DSTROOT="/Users/twer/Documents/xcodeworkspace/AudioDemo/
    build" TARGETED_DEVICE_FAMILY="1"
    install

    啟動Instruments,基于第一步生成的應用運行UIAutomation測試

    instruments
    -t "/Applications/Xcode.app/Contents/Applications/Instruments.app/
    Contents/PlugIns/AutomationInstrument.bundle/Contents/Resources/
    Automation.tracetemplate" "/Users/twer/Documents/xcodeworkspace/AudioDemo
    /build/Applications/TestExample.app"
    -e UIASCRIPT <absolute_path_to_the_test_file>

    為了更好的展示測試效果以及與CI服務器集成,活躍的社區開發者們還嘗試把UIAutomation和Jasmine集成: https://github.com/shaune/jasmine-ios-acceptance-tests

    UIAutomation因其原生支持,并且通過和Instruments的絕佳配合,開發者可以非常方便的使用錄制操作自動生成測試腳本,贏得了很多開發者的支持,但是因蘋果公司的基因,其系統非常封閉,導致開發者難以擴展,于是活躍的社區開發者們開始制造自己的輪子,Fone Monkey就是其中的一個優秀成果。

    Fone Monkey

    Fone Monkey是由Gorilla Logic 公司創建并維護的一個iOS自動化測試工具,其功能和UIAutomation差不多,但是由于其開源特性,極大的解放了活躍開發者的生產力,開發者可以很容易的根據自身需要擴展其功能。

    Fone Monkey的安裝雖然簡單,但是比UIAutomation的原生支持來說,也算是一大劣勢了,具體的安裝過程可以參考:http://www.gorillalogic.com/fonemonkey-ios/fonemonkey-setup-guide/add-fonemonkey-your-xcode-project

    Fone Monkey的使用方式主要就是錄制/回放,也可以把錄制好的測試用例保存為腳本以其他方式運行。安裝好Fone Monkey啟動測試以后,應用界面會有點變化:

    開發者通過點擊Record按鈕錄制操作,點擊Play按鈕播放之前錄制的操作,點擊More按鈕可以添加一些針對元素的驗證, 這樣就形成了一個測試用例。

    在Fone Monkey中錄制的測試用例可以保存為3種格式,以支持多種運行方式:

    1.scriptName.fm:用于支持在Fone Monkey的窗口中運行測試

    2.scriptName.m:用于和Xcode的OCUnit test 集成,可以以OCUnit的測試用例的形式運行UI測試,這就讓UI具備了命令行運行和與CI集成的能力。

    3.scriptName.js:UIAutomation的格式,用于支持在Instruments中,以UIAutomation的形式運行測試。

    (三)——CI服務器與自動化部署

    CI服務器

    寫到這兒,對于iOS開發者來說,需要準備好:

    一個比較容易獲取的源代碼倉庫(包含源代碼)
    一套自動化構建腳本
    一系列圍繞構建的可執行測試
    接下來就需要一個CI服務器來根據源代碼的變更觸發構建,監控測試結果。目前,業界比較流行的,支持iOS構建的CI服務器有Travis CI和Jenkins

    Travis CI

    Travis CI【20】是一個免費的云服務平臺,主要功能就是為開源社區提供免費的CI服務,對于商業用戶可以使用Travis Pro版本,其基本上支持所有目前主流的語言,Object-C自然也在其中。但是,Travis CI只支持github極大的限制了其應用場景。但是也由于其只支持github,其把和github的集成做到了極致的平滑,易用,因此,對于本就把github作為代碼托管平臺的項目來說,Travis CI可以做為第一選擇。

    使用Travis CI只需要簡單的2步即可為你托管在github的項目增加一個CI服務器

    第一步:在項目的根目錄下創建travis CI配置文件“.travis.yml”,在配置文件指定語言,環境要求,構建腳本等

    language: objective-c
    before_install:
    - brew update
    - brew install xctool
    script: xctool -project LighterViewControllerDemo.xcodeproj -scheme
    LighterViewControllerDemo -sdkiphonesimulator test

    第二步:使用github賬號登陸Travis CI,在賬戶的repositories開啟該項目的自動構建功能,該設置會在github上該項目repository中開啟對Travis CI的Service Hook

    下圖就是我的一個iOS項目在Travis CI的構建記錄:

    除此之外,Travis CI還非常貼心的提供了一個指示燈,可以讓開發者在自己的repository展示構建狀態。使用指示燈的方法很簡單,只需要在repository的README.md中添加下面這行代碼就行了。

    [![Build Status](https://travis-ci.org/xianlinbox/iOSCIDemo.png)](https://travis-ci.
    org/xianlinbox/iOSCIDemo)

    效果如下:

    Jenkins

    Jenkins【21】經過多年的發展,其活躍的社區和豐富的插件讓其成為了業界最受歡迎的CI服務器。通過使用Xcode插件,可以非常方便在Jenkins中運行iOS項目的構建腳本。

    安裝

    Jenkins的安裝非常簡單,尤其是在Mac環境下使用Homebrew安裝,只需要簡單的使用“brew install jenkins”,即可成功安裝,這個安裝過程做的事情非常簡單,就是把對應版本的jenkins.war文件下載到對應的目錄“/usr/local/Cellar/jenkins/1.524/libexec/”。因此,如果沒有Homebrew,可以直接到官網下載安裝文件,自己安裝。

    配置安裝完之后,只需要使用“java -jar */jenkins.war”即可啟動Jenkins,開發者可以自己創建一個bash alias簡化輸入,在用戶目錄下的.bashrc文件中添加如下代碼

    aliasjenkins='java -jar /Applications/Jenkins/jenkins.war'

    啟動Jenkins之后,可以通過瀏覽器訪問http://localhost:8080查看Jenkins界面。

    然后,開發者可以到Manage Plugins界面,安裝需要的插件:Xcode Plugin,Git Plugin,Github Plugin(我使用git做源代碼管理),Cocoapods Plugin。安裝好插件之后,需要重啟Jenkins,一切就緒之后,開始配置自己的iOS構建過程。

    在Jenkins中配置一個iOS Job的步驟如下:

    1.新建Job,Job類型選擇“Build a free-style software project”。

    2.配置代碼倉庫,

    3.點擊“Add build step”添加構建步驟,如果已安裝Xcode插件,則可以在Step類型中看到Xcode選項:

    選擇Xcode,可以看到Xcode構建step的所有配置選項:

    4.點擊“Add build step”添加測試步驟,選擇“Execute shell”選項,然后,添加腳本,執行測試并生成期望的Report, 可以重復本步驟添加“Acceptaince Test”等構建步驟。

    path-to/xctool.sh 
    -workspaceAudioDemo.xcworkspace -scheme AudioDemo -sdkiphonesimulator
    -reporter junit:test-reports/junit-report.xml clean test

    5.點擊“Add post-build action”添加一個新的步驟,選擇“publish Junit test result report”,把測試報告展示在Jenkins中。

    配置好之后,可以點擊Build Now運行Job,下圖是在Jenkins中運行iOS構建 Job的結果圖:

    開發者可以點擊每次的構建,查看具體的構建信息及測試結果:

    常見問題

    啟動Jenkins提示運行“java”命令需要X11支持,

    解決方法:這是因為在OS X Mountain Lion系統中不再內置X11,當需要使用X11時,可通過安裝XQuartz project得到支持,具體信息:http://support.apple.com/kb/HT5293

    自動化部署

    這兒的想談的“部署”不是傳統意義上的直接部署到產品環境的部署,而是指如何把最新版本的應用快速的部署到測試用戶的機器上以收集反饋,或者做一些探索性的測試。

    在我寫第一個iOS應用的時候,我想把應用安裝到多個機器上測試的時候,需要非常繁瑣的步驟:

    1.需要申請到蘋果開發者賬號,獲得開發者證書。

    2.需要在蘋果的開發者網站上注冊我想使用的設備。

    3.使用開發者證書打包應用,使用Ad-HOC部署模式,生成ipa文件。

    4.通過ipa文件把應用安裝到iTunes上。

    5.通過iTunes把應用同步到多臺測試機器上。

    如果是測試機器在多個地理位置的時候,還需要把ipa文件發送到對應的地點,每個地點都需要重復的做第4,5步。 這樣一個繁瑣,且低效的過程讓開發者非常痛苦,直到TestFlight的出現。

    TestFlight

    TestFlight【22】就是一個專門解決上面提到的痛點的云服務方案,它可以幫助開發者:

    1.輕松采集測試用戶的UDID和iOS 版本、硬件版本,并發送給開發者。

    2.實時反饋應用是否成功安裝到測試機器

    3.輕松部署最新版本應用到測試用機上。

    4.開發者可以靈活選擇部署哪個版本到哪部分測試機器上。

    使用使用Test Flight服務非常簡單,只需要到Test Flight注冊一個賬號。然后把鏈接發送給測試設備,測試設備只要打開該鏈接,并授權給Test Flight,在Test Flight的設備中心就可以看到這些設備。

    而測試設備上,則會多一個Test Flight的應用。

    當應用有了新的測試包之后,只需要將IPA上傳到TestFlight網站,然后勾選合適的測試用戶或者合適的設備,點擊Update & Notify。

    TestFlight會向對應的測試設備發送更新通知,測試用戶只需在測試設備上打開TestFlight應用,點擊Install,TestFlight就會自動將新版本的IPA文件安裝到測試設備上。

    另外,TestFlight還提供了Upload API,這樣就等于提供了和CI服務器集成的能力。其Upload API非常簡單,就是一個簡單的,帶有指定參數的HTTP POST請求,具體細節可參考官網:https://www.testflightapp.com/api/doc/。

    在 CI服務器中,開發者可以在構建過程中,添加步驟通過upload API把通過測試的ipa文件自動上傳到TestFlight上,從而達到持續部署的目的。而像Jenkins這樣有豐富插件機制的CI服務器, 活躍的社區開發者們早為其開發了十分便于使用的TestFlight的插件。

    在Jenkins中使用TestFlight插件也非常簡單,安裝好插件,重啟Jenkins,然后在項目的構建過程配置頁面的Post-build Actions中,點擊add post-build action,可以看到Upload to Testflight選項:

    選擇之后,可以在頁面上看到TestFlight的配置項:

    為了增強安全性,該插件把Token的設置移到了Jenkins的Global Setting界面:

    配置好Token Pair之后,在在TestFlight的配置項 上選擇相應的pair即可,設置想要的參數,保存即可。

    你如果不喜歡使用插件或者說使用的其它CI服務器的話,可以通過添加一個Execute shell步驟,直接通過代碼上傳構建好的ipa文件:

    curl http://testflightapp.com/api/builds.json      
    -F file=@testflightapp.ipa
    -F dsym=@testflightapp.app.dSYM.zip
    -F api_token='your_api_token'
    -F team_token='your_team_token'
    -F notes='This build was uploaded via the upload API'
    -F notify=True
    -F distribution_lists='Internal, QA'

    結語

    《持續集成》一書中引用了Javaranch.com的創始人Kathy Sierra的一句話:

    There's a big difference between saying, "Eat an apple a day" and actually eating the apple

    正所謂知易行難,您幾乎很難聽到開發者說:“持續集成毫無價值”,但是,構建一個持續集成平臺并非易事,希望本文中介紹的iOS應用的構建過程,以及在構建過程的各個階段可以使用的一些優秀的類庫,服務,能夠讓iOS開發者們在想搭建一個持續集成平臺時有所參考,從而能夠更加堅定,且容易的為自己的項目搭建一個持續集成平臺。

    posted @ 2014-10-29 16:52 小馬歌 閱讀(364) | 評論 (0)編輯 收藏
     

    控制了一門語言的構建系統(build system),就控制了這門語言的命運,以及它的生態和社區。

    Objective-C 用很短的時間,取得了非常大的變化。在短短幾年間,這門語言從 NeXT 的“廢墟”中走出,成為頗具影響力的一門語言。開源社區對于 Objective-C 有著巨大的貢獻,其中一個很重要的方面是:開發工具。

    例如 CocoaPods,它充分證明了科技和社區結合的威力。兩年間,有超過 2700 個開源的庫或框架被添加進去,你只需要簡單的命令行 - pod install,就可以輕松管理第三方庫。

    開源社區對于 iOS 和 Mac OS X 開發的各個方面都有著巨大貢獻,第三方庫管理只是其中一個,其他方面還包括自動配置和分發、報告BUG文檔檢索等。

    但是本周,我們聚焦于這樣一個工具:它重新定義了構建過程,是新一代開發集成的基礎——xctool。

    xctool 是 Fred Potter 的開源項目,來自于他在 Facebook 工作中創建的自動構建系統。xctool 用于替換 Xcode.app 中的 xcodebuild。

    在 Xcode 中點擊“Build & Run”,所有的 project、build target 和 scheme settings 都被傳到 xcodebuild,xcodebuild 調用構建的命令行,然后執行 .ipa 文件運行在真機或模擬器上。

    這個過程我們只能祈禱它順利了,因為 Xcode 將自己的構建系統封閉起來,我們從外部很難訪問和控制。當我們試圖通過 Terminal.app 和 xcodebuild 交互的時候,會發現真的很難用。

    與其使用上個時代的工具,狂打斷點去遍歷所有錯誤,不如讓 xctool 來告訴你什么是現代的解決方案。

    美學和風格

    xctool 給人的第一印象是它那漂亮、彩色的輸出樣式。

    我們自己作為蘋果硬件和軟件的用戶,對設計絕對不會輕視。xctool 也是。 它把構建過程的每一步都組織的很整潔,通過 ANSI 標準色 和 Unicode 符號輸出易懂、易讀的報告。

    但是 xctool 的美麗不僅是外在,build 的過程中可以生成用其他工具可讀的報告:

      xctool -reporter plain:output.txt build

    報告類型:

    • pretty:(默認)輸出樣式使用 ANSI 標準色和 Unicode 符號
    • plain:類似 pretty,但沒有 ANSI 標準色和 Unicode 符號
    • phabricator:將構建/測試的結果輸出為 JSON 數組,可導入到 Phabricator 這個 code-review 工具
    • junit:生成兼容 JUnit/xUnit 的 XML 格式的測試結果
    • json-stream:輸出構建/測試的事件流 ( JSON 字典格式),一行一個(如圖)
    • json-compilation-database:輸出 JSON Compilation Database,可用于基于 Clang Tooling 的工具,如 OCLint

    集成構建系統

    相對于 xcodebuild,xctool 另一個重大改進是可以和 Xcode.app 一樣運行測試(xcodebuild 并不能分辨哪些 target 是 test target,從而單獨運行它們)。

    單單這個原因,對于 Objective-C 社區的持續集成測試這個領域,xctool 就有非常大的意義。

    Travis CI

    Travis CI 為開源項目提供免費的持續集成服務(商業項目收費),支持 Objective-C。它可以在你每次提交到 GitHub 時自動運行你的測試代碼,如果最新的提交導致構建失敗它會通知你。

    在你的 Objective-C 項目中添加 Travis CI,你需要創建賬號綁定 GitHub,然后在你的 repo 中添加 .travis.yml 文件:

    .travis.yml

    language: objective-c before_install:     - brew update     - brew install xctool script: xctool -workspace MyApp.xcworkspace -scheme MyApp test

    OCLint

    OCLint 是一個靜態代碼分析器,可以檢測 Objective-C 代碼(同時支持 C 和 C++),發現常見的問題:例如 if/else/try/catch/finally 聲明出錯、未被使用的本地實例和參數、過度復雜(有效代碼行數 和 循環復雜度太高)、冗余代碼、代碼異味、以及其他不好的代碼。

    還記得 xctool 的 json-compilation-database 格式吧,這種格式可以被 OCLint 直接讀取,進而進行神奇的靜態分析。

    在我寫這篇文章的時候,離構建系統集成被廣泛接受還有很長的路,但我的希望是,既然已經開始, 大家就應該齊心協力,讓這個有前途的工具變得更加的強大。

    這就像一座城市,隨著人口的增長,基礎設施就需要改變。通過各種各樣的方式,通過本地政府、新興組織,或者其他??傊?,環境需要改變,以適應人口的增長。

    Objective-C 已經并且還將隨著 iOS 設備的流行而快速進化。為更多新進開發者提供必要的基礎設施是社區的責任,當然這離不開與蘋果的協作(有時是反對或抗議)。我們在這方面做得如何,決定了我們是否真正理解并傳達了作為專業開發者應當扮演的角色,以及應當的承擔責任。

    我們是該成為平庸的業余者,還是該成為改善技術的關鍵角色?

    xctool,和社區的其他工具一樣,為這門語言的未來和生態,提供了希望和靈感。讓我們繼續創造這樣強大的工具,創造我們為之自豪的開發體驗。

    注:本文譯自 NSHipster

    posted @ 2014-10-29 16:38 小馬歌 閱讀(1660) | 評論 (0)編輯 收藏
    僅列出標題
    共95頁: First 上一頁 15 16 17 18 19 20 21 22 23 下一頁 Last 
     
    主站蜘蛛池模板: 国产美女a做受大片免费| a级毛片免费全部播放无码| 久久精品国产亚洲αv忘忧草| 亚洲黄色在线视频| 久久久久亚洲AV无码麻豆| 久久狠狠高潮亚洲精品| 亚洲精品高清国产麻豆专区| 亚洲影院在线观看| 亚洲大片免费观看| 亚洲不卡中文字幕| 亚洲国产精品自在自线观看| 亚洲成AV人影片在线观看| 色www免费视频| 精品无码一级毛片免费视频观看| 中文字幕乱码系列免费| 男人j进入女人j内部免费网站| 四虎影视在线影院在线观看免费视频| 十九岁在线观看免费完整版电影| 久久久高清日本道免费观看| 最近免费中文字幕大全免费版视频| 午夜福利不卡片在线播放免费| 精品国产麻豆免费网站| 亚洲不卡无码av中文字幕| 亚洲午夜国产精品无码老牛影视 | xxxxwww免费| 无码精品A∨在线观看免费| 女人被男人桶得好爽免费视频 | 中国人xxxxx69免费视频| 毛片a级毛片免费播放下载| 国产大片线上免费看| 国产AV无码专区亚洲AV手机麻豆| 亚洲AV无码久久精品色欲| 亚洲一区二区三区高清视频| 福利片免费一区二区三区| 日本三级在线观看免费| A在线观看免费网站大全| 亚洲VA综合VA国产产VA中| 久久亚洲精品成人av无码网站| 亚洲中文字幕精品久久| EEUSS影院WWW在线观看免费| 最近免费2019中文字幕大全|