完整解析使用 Github Action 構(gòu)建和發(fā)布 Flutter 應(yīng)用

Github Actions 是 Github 提供的免費(fèi)自動化構(gòu)建實現(xiàn),特別適用于持續(xù)集成和持續(xù)交付的場景,它具備自動化完成許多不同任務(wù)的能力左腔,例如構(gòu)建诈泼、測試和部署等等懂拾。

一、簡單介紹

用戶只需要在自己 Github 的開源項目下創(chuàng)建 .github/workflows 腳本就可以完成接入铐达,另外針對 Github Actions 官方還提供了 marketplace 用于開發(fā)者提交或者引用別人寫好的 aciton 岖赋,所以很多時候開發(fā)者在使用 Github Actions 時,其實會變成了在 marketplace 里挑選和組合 action 的場景瓮孙。當(dāng)然唐断,這樣各有利弊,后面我們會講到 杭抠。

image.png

要在 Github 存儲庫中使用 Github Actions脸甘,首先需要創(chuàng)建目錄.github/workflows/,然后在 workflows 文件夾里創(chuàng)建不同的 .yml 文件用于響應(yīng)或者執(zhí)行不同的事件祈争,比如 git push 斤程、pull request 等,例如:

name: GitHub Actions Demo
on: [push]
jobs:
  Explore-GitHub-Actions:
    runs-on: ubuntu-latest
    steps:
      - run: echo "?? The job was automatically triggered by a ${{ github.event_name }} event."
      - run: echo "?? This job is now running on a ${{ runner.os }} server hosted by GitHub!"
      - run: echo "?? The name of your branch is ${{ github.ref }} and your repository is ${{ github.repository }}."
      - name: Check out repository code
        uses: actions/checkout@v2
      - run: echo "?? The ${{ github.repository }} repository has been cloned to the runner."
      - run: echo "??? The workflow is now ready to test your code on the runner."
      - name: List files in the repository
        run: |
          ls ${{ github.workspace }}
      - run: echo "?? This job's status is ${{ job.status }}."

上面是 Github doc 里關(guān)于 Action 的一個基本的工作流 yml 文件,具體參數(shù)含義 :

  • name:這表示該工作流文件的名稱忿墅,將在 Github 的 actions 選項卡作為名稱顯示 扁藕;
  • on:這將觸發(fā)該工作流的事件名稱,它可以包含事件列表疚脐,例如這里監(jiān)聽的事 push亿柑;
  • jobs:每個工作流會包含一個或多個 jobs ,在這里只有一個棍弄,主要是用于表示不同工作任務(wù)望薄;
  • Explore-GitHub-Actions :這是工作 ID,你也可以根據(jù)自己的需要命名呼畸,會在 action 的執(zhí)行過程中顯示痕支;
  • runs-on:jobs 需要運(yùn)行在虛擬機(jī)上,在這里中使用了 ubuntu-latest蛮原,當(dāng)然你也可以使用windows-latest 或者 macos-latest卧须;
  • steps:每個 jobs 可以將需要執(zhí)行的內(nèi)容劃分為不同步驟;
  • run:用于提供執(zhí)行命令儒陨,例如這里使用了echo 打印日志花嘶;
  • name: steps 里的 name 是可選項,主要是在日志中用來做標(biāo)記的蹦漠;
  • uses :使用一些官方或者第三方的 actions 來執(zhí)行椭员,例如這里使用官方的 actions/checkout@v2,它會check-out 我們的 repo 笛园,之后工作流可以直接訪問 repo 里的文件隘击;

在 GitHub 倉庫添加完對應(yīng)的 .github/workflows/ci.yml 文件之后,以后每次 push 都可以觸發(fā) action 的自動執(zhí)行喘沿,以此來完成可持續(xù)的自動集成和構(gòu)建能力闸度。

二、構(gòu)建 Flutter 和發(fā)布到 Github Release

簡單介紹完 Github Action 蚜印,接著我們介紹如何利用 Github Action 構(gòu)建 Flutter 和發(fā)布 apk 到 Github Release,如下代碼所示是 gsy_github_app_flutter 項目里使用到的 github action 腳本:

name: CI

on:
  push:
    branches:
      - master
    tags:
      - '*'
  pull_request:
    paths-ignore:
      - '**/*.md'
      - '**/*.txt'
      - '**/*.png'
      - '**/*.jpg'

jobs:
  build:
    name: Build
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - uses: actions/setup-java@v2
        with:
          distribution: 'zulu'
          java-version: 11
      - uses: subosito/flutter-action@v1
        with:
          flutter-version: '2.8.1'
      - uses: finnp/create-file-action@master
        env:
          FILE_NAME: lib/common/config/ignoreConfig.dart
          FILE_DATA: class NetConfig { static const CLIENT_ID = "${{ secrets.CLIENT_ID }}"; static const CLIENT_SECRET = "${{ secrets.CLIENT_SECRET }}";}
      - run: flutter pub get
      - run: flutter build apk --release --target-platform=android-arm64 --no-shrink

  apk:
    name: Generate APK
    if: startsWith(github.ref, 'refs/tags/')
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v2
      - name: Setup JDK
        uses: actions/setup-java@v2
        with:
          distribution: 'zulu'
          java-version: 8
      - uses: subosito/flutter-action@v1
        with:
          flutter-version: '2.5.3'
      - uses: finnp/create-file-action@master
        env:
          FILE_NAME: lib/common/config/ignoreConfig.dart
          FILE_DATA: class NetConfig { static const CLIENT_ID = "${{ secrets.CLIENT_ID }}"; static const CLIENT_SECRET = "${{ secrets.CLIENT_SECRET }}";}
      - run: flutter pub get
      - run: flutter build apk --release --target-platform=android-arm64 --no-shrink
      - name: Upload APK
        uses: actions/upload-artifact@v2
        with:
          name: apk
          path: build/app/outputs/apk/release/app-release.apk
  release:
    name: Release APK
    needs: apk
    if: startsWith(github.ref, 'refs/tags/')
    runs-on: ubuntu-latest
    steps:
      - name: Download APK from build
        uses: actions/download-artifact@v2
        with:
          name: apk
      - name: Display structure of downloaded files
        run: ls -R

      - name: Create Release
        id: create_release
        uses: actions/create-release@v1.1.4
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        with:
          tag_name: ${{ github.ref }}
          release_name: ${{ github.ref }}
      - name: Upload Release APK
        id: upload_release_asset
        uses: actions/upload-release-asset@v1.0.1
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        with:
          upload_url: ${{ steps.create_release.outputs.upload_url }}
          asset_path: ./app-release.apk
          asset_name: app-release.apk
          asset_content_type: application/zip

根據(jù)上述腳本留量,首先可以看到:

  • push 事件里我們指定了只監(jiān)聽 master 分支和 tags 相關(guān)的提交窄赋;

  • 然后在 pull_request 事件里忽略了關(guān)于 .md、 .text 和圖片相關(guān)的內(nèi)容楼熄,也就是這部分內(nèi)容提交不觸發(fā) action 忆绰,具體可以看你自己的需求;

  • 接著進(jìn)入到 jobs 里可岂,首先不管是 push 還是 pull_request 都會執(zhí)行到 Build 事件错敢,運(yùn)行在 ubuntu-latest 虛擬機(jī)上,之后利用 actions/checkout@v2 checkout 代碼;

  • 接著使用 actions/setup-java@v2 配置 java 環(huán)境稚茅,這里使用的是 Zulu OpenJDK 版本 11 纸淮,下面表格是 setup-java 支持的可選 java 類型;

    Keyword Distribution Official site License
    temurin Eclipse Temurin Link Link
    zulu Zulu OpenJDK Link Link
    adopt or adopt-hotspot Adopt OpenJDK Hotspot Link Link
    adopt-openj9 Adopt OpenJDK OpenJ9 Link Link
    liberica Liberica JDK Link Link
    microsoft Microsoft Build of OpenJDK Link Link
  • 接著就是使用第三方的 subosito/flutter-action@v1 配置 flutter 環(huán)境亚享,直接通過 flutter-version: '2.8.1' 指定了 Flutter 版本咽块;

  • 接著是使用第三方的 finnp/create-file-action@master 創(chuàng)建文件,因為 gsy_github_app_flutter 項目有一個配置文件是需要用戶根據(jù)自己的 ID 和 SECRET 手動創(chuàng)建欺税,所以這里通過 create-file-action 創(chuàng)建文件并輸入內(nèi)容侈沪;

  • 在上述輸入內(nèi)容部分,有一個 secrets.xxx 的參數(shù)晚凿,因為構(gòu)建時需要將自己的一些密鑰信息配置到 action 里亭罪,所以如下圖所示,可以在 SettingsSecrets 里添加對應(yīng)的內(nèi)容歼秽,就可以在 action 里通過 secrets.xxx 讀扔σ邸;

  • 接著配置好環(huán)境之后哲银,就可以執(zhí)行 flutter pub getflutter build apk 執(zhí)行構(gòu)建扛吞;

完成 Build 任務(wù)的邏輯介紹之后,可以看到在 Build 任務(wù)下面還有一個 apk 任務(wù)荆责,該任務(wù)基本和 Build 任務(wù)一直滥比,不同之處在于:

  • 多了一個 if: startsWith(github.ref, 'refs/tags/') ,也就是存在 tag 的時候才會觸發(fā)該任務(wù)執(zhí)行做院;
  • 多了一個 actions/upload-artifact@v2 用于將構(gòu)建出來的 build/app/outputs/apk/release/app-release.apk上傳盲泛,并等到 release 任務(wù)內(nèi)使用;

完成 apk 任務(wù)之后键耕,會進(jìn)入到 release 任務(wù)寺滚,該任務(wù)同樣通過 if 指定了只在 tag 提交時運(yùn)行:

  • 任務(wù)首先會通過 actions/download-artifact@v2 下載剛剛上傳的 apk;
  • 然后就通過 actions/create-release@v1.1.4 創(chuàng)建一個 release 版本屈雄,這里使用的 secrets.GITHUB_TOKEN 是官方內(nèi)置的 secrets 村视,我們直接使用就可以了;
  • 最后通過 actions/upload-release-asset@v1.0.1 將 apk 上傳到剛剛創(chuàng)建的 release 版本里酒奶,自此就完成了 action 的發(fā)布流程蚁孔;

可以看到整個過程其實都是在組合不同的 action ,可以很靈活方便地配置構(gòu)建邏輯惋嚎,例如如果你的項目是單純的 android sdk 項目杠氢,那同樣可以通過如下腳本進(jìn)行發(fā)布管理:

name: CI

on:
  push:
    branches:
      - master
    paths-ignore:
      - '.idea/**'
      - '.gitattributes'
      - '.github/**.json'
      - '.gitignore'
      - '.gitmodules'
      - '**.md'
      - '**/*.txt'
      - '**/*.png'
      - '**/*.jpg'
      - 'LICENSE'
      - 'NOTICE'
  pull_request:
    paths-ignore:
      - '.idea/**'
      - '.gitattributes'
      - '.github/**.json'
      - '.gitignore'
      - '.gitmodules'
      - '**.md'
      - '**/*.txt'
      - '**/*.png'
      - '**/*.jpg'
      - 'LICENSE'
      - 'NOTICE'

jobs:
  publish:
    name: Publish to MavenLocal
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-java@v3
        with:
          distribution: 'zulu'
          java-version: 17
      - uses: gradle/gradle-build-action@v2
        with:
          arguments: publishToMavenLocal

  build:
    name: Build
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-java@v3
        with:
          distribution: 'zulu'
          java-version: 17
      - uses: gradle/gradle-build-action@v2
        with:
          arguments: app:assembleDebug

當(dāng)然,如果你需要打包的是 iOS 另伍,那么你就需要使用 macos-latest 的環(huán)境鼻百,另外還需要配置相關(guān)的開發(fā)者證書,這個過程可能會比較難受,相關(guān)可以參考 《Flutter 搭建 iOS 命令行服務(wù)打包發(fā)布全保姆式流程》 温艇。

三因悲、隱私安全問題

最后,關(guān)于 Github Actions 之前存在過出現(xiàn)泄露敏感數(shù)據(jù)的問題中贝,比如 Github 的 Token 等 囤捻,舉個例子,如上面的腳本邻寿,它在執(zhí)行任務(wù)時都會需要秘鑰 蝎土,如果你使用的第三方 action 在執(zhí)行過程中獲取了你的密鑰并干了一些“非法” 的事情,就可能出現(xiàn)異常泄漏問題绣否。

所以一般情況下建議大家都要去看下非官方的腳本實現(xiàn)里是否安全誊涯,但是由于 tag 和 branch 是可以修改,所以建議不要@分支或tag蒜撮,而是應(yīng)該 checkout 對應(yīng)的提交哈希暴构,這樣有利于你審查使用時的腳本是否安全。

另外段磨,例如還有人提到可以通過 pull_request 來惡意攻擊獲取對應(yīng)隱私:

  • 1取逾、fork 一個正在使用 GitHub Actions 的公開代碼庫;

  • 2苹支、創(chuàng)建一個基于該項目的 pull 請求砾隅;

  • 3、使用 pull_request_target 事件創(chuàng)建一個惡意 Actions 工作流债蜜,然后單獨向該 fork 庫 commit晴埂;

  • 4、將第二步基分支的 pull 請求更新為第三步的 commit 哈希寻定;

之后惡意 Actions 工作流就會運(yùn)行儒洛,并從目標(biāo) repos 里獲取到執(zhí)行過程的敏感數(shù)據(jù),此時攻擊者將擁有對目標(biāo)存儲庫的寫訪問權(quán)限狼速,除此之外他們還可以通過 GitHub 訪問與倉庫之成的任何服務(wù)琅锻。

所以雖然 GitHub Action 很便捷,但是如果出于商業(yè)考慮的話向胡,還需要謹(jǐn)慎抉擇安全問題浅浮。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市捷枯,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌专执,老刑警劉巖淮捆,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡攀痊,警方通過查閱死者的電腦和手機(jī)桐腌,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來苟径,“玉大人案站,你說我怎么就攤上這事〖郑” “怎么了蟆盐?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長遭殉。 經(jīng)常有香客問我石挂,道長,這世上最難降的妖魔是什么险污? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任痹愚,我火速辦了婚禮,結(jié)果婚禮上蛔糯,老公的妹妹穿的比我還像新娘拯腮。我一直安慰自己,他們只是感情好蚁飒,可當(dāng)我...
    茶點故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布动壤。 她就那樣靜靜地躺著,像睡著了一般飒箭。 火紅的嫁衣襯著肌膚如雪狼电。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天弦蹂,我揣著相機(jī)與錄音肩碟,去河邊找鬼。 笑死凸椿,一個胖子當(dāng)著我的面吹牛削祈,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播脑漫,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼髓抑,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了优幸?” 一聲冷哼從身側(cè)響起吨拍,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎网杆,沒想到半個月后羹饰,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體伊滋,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年队秩,在試婚紗的時候發(fā)現(xiàn)自己被綠了笑旺。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡馍资,死狀恐怖筒主,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情鸟蟹,我是刑警寧澤乌妙,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站戏锹,受9級特大地震影響冠胯,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜锦针,卻給世界環(huán)境...
    茶點故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一荠察、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧奈搜,春花似錦悉盆、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至宏粤,卻和暖如春脚翘,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背绍哎。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工来农, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人崇堰。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓沃于,卻偏偏與公主長得像,于是被迫代替她去往敵國和親海诲。 傳聞我的和親對象是個殘疾皇子繁莹,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,577評論 2 353

推薦閱讀更多精彩內(nèi)容