1. 程式人生 > >iOS持續整合jenkins+xcode+svn+七牛

iOS持續整合jenkins+xcode+svn+七牛

吐個槽:隨著程式碼的不斷累積每次iOS打包都要焦急等待小十分鐘,Xcode卡爆了有沒有,Archives有時證書都無法驗證,上傳20M的.ipa檔案一定要看網路給不給力。

jenkins實現目標:

  • 生成ipa檔案
  • 生成plist檔案
  • ipa、plist七牛自動上傳
  • 郵件反饋,生成下載連結、連結二維碼等

思路:將生成的.ipa檔案放在${WORKSPACE}/build/${BUILD_NUMBER}/下,通過Execute shell生成.plist檔案(讓plist與ipa檔名稱保持一致),Inject environment variables將ipa檔名稱定義全域性變數,構建成功後通過

qiniu-plugin將plist、ipa檔案上傳到七牛,然後郵件將構建資訊、線上plist連結告知。

一、jenkins安裝以及系統配置

  1. jenkins安裝配置

    • brew install jenkins(安裝)
    • jenkins (啟動)
    • /Users/apple(電腦使用者名稱)/.jenkins(brew安裝jenkins位置,${WORKSPACE} 值為 /Users/apple(電腦使用者名稱)/.jenkins/jobs/qiniuTest(job名稱)/workspace/)
  2. 管理外掛(系統管理–管理外掛)

    • Subversion Plug-in(svn)
    • Xcode integration(Xcode)
    • Environment Injector Plugin(自定義全域性變數)
    • Email Extension Plugin(郵件)
  3. 系統設定(系統管理–系統設定)

    1. Xcode Builder(鑰匙串設定)

      Xcode Builder

      需填寫的內容:

      • Keychain Name:iPhone Distribution: *(dis證書常用名)
      • Keychain path:${HOME}/Library/Keychains/login.keychain(dis證書路徑)
      • Keychain password:*
      • Add to keychain search path after build:Yes
      • Default keychain:iPhone Distribution: *
    2. Extended E-mail Notification(郵件配置)

      郵件配置

      • 點選“高階”
        郵件配置高階

      需填寫的內容:

      • SMTP server:smtp.exmail.qq.com(我用的是QQ郵箱)
      • Default Subject:構建通知:${PROJECT_NAME}${SVN_REVISION}${BUILD_NUMBER}持續整合${BUILD_STATUS}
      • Default Content: 後文有寫到
    3. 七牛設定項(七牛Accesskey/Secretkey配置)

      七牛設定項

      Accesskey/Secretkey 值可在七牛中檢視

      七牛

二、job構建

  1. jenkins–新建

    新建job

    “新建”–“構建一個自由風格的軟體專案”–“OK”

    • Item名稱(job名稱)
  2. 原始碼管理(svn配置)

    svn配置

    選擇的Subversion,倉庫路徑:svn打包的程式碼路徑(一般是trunk上吧)

  3. xcode配置

    新增構建步驟:
    新增構建步驟

    General build settings:
    General build settings

    Advanced Xcode build options:
    Advanced Xcode build options

    需填寫的內容:

    • General build settings:
      Target:為整合的Target名稱 targetName
      勾選“Clean before build?”
      Configution:Release(Debug/Release按需求可選)

    • 勾選“Pack application and build ipa?”
      ipa filename pattern:targetName_${SHORT_VERSION}(target名稱_version版本)
      Output directory:${WORKSPACE}/build/${BUILD_NUMBER}/

    • Code signing & OS X keychain options:
      在系統Xcode Builder(鑰匙串設定)已配置

    • Advanced Xcode build options:
      勾選“Clean test reports?”
      Build output directory:${WORKSPACE}/build/${BUILD_NUMBER}/

  4. Execute shell

    Execute shell

    需填寫的內容:(獲取生成的ipa檔名稱,寫入全域性變數,生成plist檔案)
    Command:

    "${WORKSPACE}/build/${BUILD_NUMBER}"
    
    for file in "*.ipa"
    do
        PLIST_NAME=`echo $file`
    done
    
    PLIST_NAME=${PLIST_NAME%.*}
    
    cd "${WORKSPACE}/build"
    echo "PLIST_NAME=$PLIST_NAME" > jenkinsUserGlobal.properties
    
    cat << EOF > ${WORKSPACE}/build/${BUILD_NUMBER}/$PLIST_NAME.plist
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
    <plist version="1.0">
    <dict>
            <key>items</key>
            <array>
                    <dict>
                            <key>assets</key>
                            <array>
                                    <dict>
                                            <key>kind</key>
                                            <string>software-package</string>
                                            <key>url</key>
                                            <string>https://******/$PLIST_NAME.ipa</string>
                                    </dict>
                            </array>
                            <key>metadata</key>
                            <dict>
                                    <key>bundle-identifier</key>
                                    <string>***.***.***</string>
                                    <key>bundle-version</key>
                                    <string>1</string>
                                    <key>kind</key>
                                    <string>software</string>
                                    <key>title</key>
                                    <string>***</string>
                            </dict>
                    </dict>
            </array>
    </dict>
    </plist>
    EOF
  5. Inject environment variables

    全域性變數檔案地址

    需填寫的內容:(將在Execute shell中生成的全域性變數檔案地址放入 Properties File Path中)
    Properties File Path:${WORKSPACE}/build/jenkinsUserGlobal.properties

  6. Editable Email Notification(郵件配置)

    1. 郵件配置

      郵件基本配置:
      郵件基本配置

      觸發器:構建成功、失敗觸發(擴充套件一下:失敗點“高階”設定只發送給自己)
      觸發器

      需填寫的內容:

      • Project Recipient List: 郵件接收人(多個時用”,“分割)

      • Project Reply-To List:$DEFAULT_REPLYTO

      • Content Type:選擇”HTML(text/html)“

      • Default Subject:${PROJECT_NAME}構建通知:第${BUILD_NUMBER}次持續整合${PLIST_NAME}構建${BUILD_STATUS}

      • Default Content:(將ipa全域性變數傳遞到郵件生成下載連結和連結二維碼)
      <!DOCTYPE html>
      <html>
      <head>
      <meta charset="UTF-8">
      <title>${ENV, var="JOB_NAME"}-第${BUILD_NUMBER}次構建日誌</title>
      </head>
      
      <body leftmargin="8" marginwidth="0" topmargin="8" marginheight="4"
          ffset="0">
          <table width="95%" cellpadding="0" cellspacing="0"
              style="font-size: 11pt; font-family: Tahoma, Arial, Helvetica, sans-serif">
              <tr>
                  <td><h2>
                          <font color="#0000FF">構建結果 - ${BUILD_STATUS}</font>
                      </h2></td>
              </tr>
              <tr>
                      <td><h2>
                          <font color="#FF0000">App下載連結:<a href="itms-services://?action=download-manifest&url=https://******/${PLIST_NAME}.plist">itms-services://?action=download-manifest&url=https://******/${PLIST_NAME}.plist</a></font>
                      </h2></td>
              </tr>
              <tr>
                     <td><h2>
                            <font color="#FF0000">二維碼圖片:</font>
                     </h2></td>
              </tr>
              <tr>
                      <td>
                          <img src="http://qr.liantu.com/api.php?text=itms-services://?action=download-manifest%26url=https://******/${PLIST_NAME}.plist" height="300" width="300">
                      </td>
              </tr>
              <tr>
                  <td><br />
                  <b><font color="#0B610B">構建資訊</font></b>
                  <hr size="2" width="100%" align="center" /></td>
              </tr>
              <tr>
                  <td>
                      <ul>
                          <li>專案名稱&nbsp;:&nbsp;${PROJECT_NAME}</li>
                          <li>構建編號&nbsp;:&nbsp;第${BUILD_NUMBER}次構建</li>
                          <li>SVN&nbsp;版本:&nbsp;${SVN_REVISION}</li>
                          <li>觸發原因:&nbsp;${CAUSE}</li>
                          <li>構建日誌:&nbsp;<a href="${BUILD_URL}console">${BUILD_URL}console</a></li>
                          <li>構建&nbsp;&nbsp;Url&nbsp;:&nbsp;<a href="${BUILD_URL}">${BUILD_URL}</a></li>
                          <li>工作目錄&nbsp;:&nbsp;<a href="${PROJECT_URL}ws">${PROJECT_URL}ws</a></li>
                          <li>專案&nbsp;&nbsp;Url&nbsp;:&nbsp;<a href="${PROJECT_URL}">${PROJECT_URL}</a></li>
                      </ul>
                  </td>
              </tr>
              <tr>
                  <td><b><font color="#0B610B">Changes Since Last
                              Successful Build:</font></b>
                  <hr size="2" width="100%" align="center" /></td>
              </tr>
              <tr>
                  <td>
                      <ul>
                          <li>歷史變更記錄 : <a href="${PROJECT_URL}changes">${PROJECT_URL}changes</a></li>
                      </ul> ${CHANGES_SINCE_LAST_SUCCESS,reverse=true, format="Changes for Build #%n:<br />%c<br />",showPaths=true,changesFormat="<pre>[%a]<br />%m</pre>",pathFormat="&nbsp;&nbsp;&nbsp;&nbsp;%p"}
                  </td>
              </tr>
              <tr>
                  <td><b>Failed Test Results</b>
                  <hr size="2" width="100%" align="center" /></td>
              </tr>
              <tr>
                  <td><pre
                          style="font-size: 11pt; font-family: Tahoma, Arial, Helvetica, sans-serif">$FAILED_TESTS</pre>
                      <br /></td>
              </tr>
              <tr>
                  <td><b><font color="#0B610B">構建日誌 (最後 100行):</font></b>
                  <hr size="2" width="100%" align="center" /></td>
              </tr>
              <tr>
                  <td><textarea cols="80" rows="30" readonly="readonly"
                          style="font-family: Courier New">${BUILD_LOG, maxLines=100}</textarea>
                  </td>
              </tr>
          </table>
      </body>
      </html>
    2. 郵件截圖

      截圖1:
      郵件截圖1

      截圖2:
      郵件截圖2

  7. 上傳到七牛

    1. 上傳到七牛配置

      這裡寫圖片描述

      需填寫的內容:

      • 七牛配置項:系統設定-七牛-設定項名稱
      • 檔案路徑:**/build/${BUILD_NUMBER}/*.ipa,**/build/${BUILD_NUMBER}/*.plist
      • 要上傳到的 bucke:上傳到七牛的 空間 名稱
      • 勾選“構建失敗則不上傳”
    2. 1、編譯過程中發現在我的mac上會報錯,檢視原始碼發現System.console().printf(profile.getName() + "\n");是這個引起的(System.console returns the unique Console object associated with the current Java virtual machine, if any.可能電腦上麼有java虛擬機器吧,so就遮蔽這行程式碼吧或者使用前進行判斷一下Console c = System.console();
      if (c == null) {
      System.out.println("No console available");
      } else {
      // Use the returned Console.
      }
      (這個還未驗證))

      構建日誌:
      Failed控制檯輸出
      
      Started by user admin
      Building in workspace /Users/apple/.jenkins/jobs/qiniuTest/workspace
      開始上傳到七牛...
      ERROR: Build step failed with exception
      java.lang.NullPointerException
          at net.zouxin.lab.qiniuplugin.QiniuPublisher$DescriptorImpl.getProfileByName(QiniuPublisher.java:183)
          at net.zouxin.lab.qiniuplugin.QiniuPublisher.perform(QiniuPublisher.java:89)
          at hudson.tasks.BuildStepMonitor$2.perform(BuildStepMonitor.java:32)
          at hudson.model.AbstractBuild$AbstractBuildExecution.perform(AbstractBuild.java:782)
          at hudson.model.AbstractBuild$AbstractBuildExecution.performAllBuildSteps(AbstractBuild.java:723)
          at hudson.model.Build$BuildExecution.post2(Build.java:185)
          at hudson.model.AbstractBuild$AbstractBuildExecution.post(AbstractBuild.java:668)
          at hudson.model.Run.execute(Run.java:1763)
          at hudson.model.FreeStyleBuild.run(FreeStyleBuild.java:43)
          at hudson.model.ResourceController.execute(ResourceController.java:98)
          at hudson.model.Executor.run(Executor.java:410)
      Build step '上傳到七牛' marked build as failure
      Finished: FAILURE

      2、上傳到七牛的bucket中的檔案路徑對我來說可能有點多餘,作者傳遞的"key":"build/${BUILD_NUMBER}/*.plist"這樣的,生成的路徑會成https://***/build/${BUILD_NUMBER}/*.plist,在原始碼107行進行替換,這樣生成的連結就會變成https://***/*.plist

      //String keyPath = path.getRemote().replace(wsPath, "");
      //String key = keyPath.replace(File.separator, "/");
      String fileName = path.getName();

      jenkins外掛是.hpi檔案(可以在下載我已編譯好的hpi檔案),編譯需要安裝maven,然後package,具體流程如下:

      1、首先在網上下載qiniu-plugin,我就放在Downloads下。按需修改QiniuPublisher.java檔案
      2、brew install maven
      3、雙擊執行qiniu-plugin-master下Debug檔案
      (export MAVEN_OPTS="-Xdebug -Xrunjdwp:transport=dt_socket,server=y,address=8000,suspend=n"
      mvn hpi:run
      )
      4、cd /Users/apple/Downloads/qiniu-plugin-master
      5、man clean//刪除target,第一次無需執行這個
      6、man package//打包生成Tagret,新生成的.hpi檔案就在target下

    3. 安裝jenkins外掛

      系統管理–管理外掛–高階–上傳外掛

三、多Target擴充套件

對多Target的工程我們可在”開始構建“前手工選擇Target,然後將這target名稱在xcode編譯時傳遞過去。

  1. 配置引數化構建過程:

    配置target

    需填寫的內容:(擴充套件一下:還可以自定義郵件標題,郵件正文新增一段ipa升級資訊等)

    • 新增引數–選擇”Choicce“
    • Name為引數名,會在下面xcode配置時用到
    • Choices為Target名稱,將工程的Targets名稱全放進去
    • Description為描述:請選擇一個Target。
  2. Xcode配置:

    xcode呼叫target

    xcode使用target:

    • Target:${targetName} (xcode打包對應得target名稱)
    • .ipa filename pattern:${targetName}_${SHORT_VERSION}(ipa生成的包名)
  3. 配置引數化構建效果圖:

    構建效果