feat: Add Podfile and PrivacyInfo.xcprivacy; update Info.plist for im… #678
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Flutter CI | |
| permissions: | |
| contents: write | |
| on: | |
| push: | |
| branches: [master] | |
| paths: | |
| - 'client/**' | |
| - '.github/workflows/flutter-ci.yml' | |
| pull_request: | |
| branches: [master] | |
| paths: | |
| - 'client/**' | |
| - '.github/workflows/flutter-ci.yml' | |
| workflow_dispatch: | |
| env: | |
| FLUTTER_WORKING_DIR: client | |
| jobs: | |
| test: | |
| runs-on: ubuntu-latest | |
| container: 'ghcr.io/cirruslabs/flutter:3.38.8' | |
| defaults: | |
| run: | |
| working-directory: ${{ env.FLUTTER_WORKING_DIR }} | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Cache pub dependencies | |
| uses: actions/cache@v4 | |
| with: | |
| path: ~/.pub-cache | |
| key: ${{ runner.os }}-pub-cache-${{ hashFiles('client/pubspec.yaml', 'client/pubspec.lock', 'client/packages/*/pubspec.yaml') }} | |
| restore-keys: ${{ runner.os }}-pub-cache- | |
| - name: Add pub cache to PATH | |
| run: echo "$HOME/.pub-cache/bin" >> $GITHUB_PATH | |
| - name: Activate melos and bootstrap | |
| run: | | |
| dart pub global activate melos | |
| melos bootstrap | |
| - name: Run Melos format check | |
| run: melos format --set-exit-if-changed . | |
| - name: Run analyze | |
| run: melos run analyze | |
| - name: Run tests | |
| run: | | |
| flutter test | |
| melos run test:dart --no-select | |
| build-apk: | |
| needs: test | |
| runs-on: ubuntu-latest | |
| container: 'ghcr.io/cirruslabs/flutter:3.38.8' | |
| defaults: | |
| run: | |
| working-directory: ${{ env.FLUTTER_WORKING_DIR }} | |
| outputs: | |
| version: ${{ steps.get_version.outputs.version }} | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Decode keystore from base64 | |
| shell: bash | |
| run: | | |
| printf "%s" "$KEYSTORE_BASE64" | base64 -d > android/app/keystore.jks | |
| env: | |
| KEYSTORE_BASE64: ${{ secrets.KEYSTORE_BASE64 }} | |
| - name: Set up signing properties | |
| run: | | |
| cat > android/app/key.properties << EOF | |
| storeFile=keystore.jks | |
| keyAlias=${{ secrets.KEYSTORE_KEY_ALIAS }} | |
| storePassword=${{ secrets.KEYSTORE_PASSWORD }} | |
| keyPassword=${{ secrets.KEYSTORE_PASSWORD }} | |
| EOF | |
| - name: Validate Android keystore | |
| shell: bash | |
| run: | | |
| keytool -list -keystore android/app/keystore.jks -storepass "$KEYSTORE_PASSWORD" -alias "$KEYSTORE_KEY_ALIAS" | |
| env: | |
| KEYSTORE_PASSWORD: ${{ secrets.KEYSTORE_PASSWORD }} | |
| KEYSTORE_KEY_ALIAS: ${{ secrets.KEYSTORE_KEY_ALIAS }} | |
| - name: Cache pub dependencies | |
| uses: actions/cache@v4 | |
| with: | |
| path: ~/.pub-cache | |
| key: ${{ runner.os }}-pub-cache-${{ hashFiles('client/pubspec.yaml', 'client/pubspec.lock', 'client/packages/*/pubspec.yaml') }} | |
| restore-keys: ${{ runner.os }}-pub-cache- | |
| - name: Cache Gradle dependencies | |
| uses: actions/cache@v4 | |
| with: | |
| path: | | |
| ~/.gradle/caches | |
| ~/.gradle/wrapper | |
| key: ${{ runner.os }}-gradle-${{ hashFiles('client/**/*.gradle*', 'client/**/gradle-wrapper.properties') }} | |
| restore-keys: ${{ runner.os }}-gradle- | |
| - name: Add pub cache to PATH | |
| run: echo "$HOME/.pub-cache/bin" >> $GITHUB_PATH | |
| - name: Activate melos and bootstrap | |
| run: | | |
| dart pub global activate melos | |
| melos bootstrap | |
| - name: Get Flutter dependencies | |
| run: flutter pub get | |
| - name: Get version from pubspec.yaml | |
| id: get_version | |
| run: | | |
| VERSION=$(grep '^version:' pubspec.yaml | head -n1 | awk '{print $2}' | cut -d'+' -f1) | |
| echo "version=$VERSION" >> $GITHUB_OUTPUT | |
| - name: Build APK | |
| run: flutter build apk --release --target-platform android-arm64 --build-number ${{ github.run_number }} | |
| - name: Rename APK with version | |
| run: | | |
| mv build/app/outputs/flutter-apk/app-release.apk \ | |
| build/app/outputs/flutter-apk/borneo-app-ce-${{ steps.get_version.outputs.version }}.apk | |
| - name: Upload APK artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: borneo-app-ce-${{ steps.get_version.outputs.version }} | |
| path: ${{ github.workspace }}/${{ env.FLUTTER_WORKING_DIR }}/build/app/outputs/flutter-apk/borneo-app-ce-${{ steps.get_version.outputs.version }}.apk | |
| build-windows: | |
| needs: test | |
| runs-on: windows-latest | |
| defaults: | |
| run: | |
| working-directory: ${{ env.FLUTTER_WORKING_DIR }} | |
| outputs: | |
| version: ${{ steps.get_version.outputs.version }} | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup Flutter | |
| uses: subosito/flutter-action@v2 | |
| with: | |
| channel: stable | |
| flutter-version-file: client/pubspec.yaml | |
| cache: true | |
| - name: Cache pub dependencies | |
| uses: actions/cache@v4 | |
| with: | |
| path: ~/.pub-cache | |
| key: ${{ runner.os }}-pub-cache-${{ hashFiles('client/pubspec.yaml', 'client/pubspec.lock', 'client/packages/*/pubspec.yaml') }} | |
| restore-keys: ${{ runner.os }}-pub-cache- | |
| # Cache NuGet packages to speed MSBuild / CMake native deps | |
| - name: Cache NuGet packages | |
| uses: actions/cache@v4 | |
| with: | |
| path: ~/.nuget/packages | |
| key: ${{ runner.os }}-nuget-${{ hashFiles('client/windows/**') }} | |
| restore-keys: ${{ runner.os }}-nuget- | |
| - name: Cache MSBuild | |
| uses: actions/cache@v4 | |
| with: | |
| path: ~/AppData/Local/Microsoft/VisualStudio | |
| key: ${{ runner.os }}-msbuild-${{ hashFiles('client/windows/**') }} | |
| restore-keys: ${{ runner.os }}-msbuild- | |
| # Pre-download Flutter engine/artifacts for Windows (avoid on-the-fly downloads) | |
| - name: Flutter precache (windows) | |
| run: flutter precache --windows | |
| - name: Activate melos and bootstrap | |
| run: | | |
| dart pub global activate melos | |
| melos bootstrap | |
| - name: Get Flutter dependencies | |
| run: flutter pub get | |
| - name: Get version from pubspec.yaml | |
| id: get_version | |
| run: | | |
| $version = (Select-String -Path pubspec.yaml -Pattern '^version:' | Select-Object -First 1).Line.Split(':')[1].Trim().Split('+')[0] | |
| echo "version=$version" | Out-File -FilePath $env:GITHUB_OUTPUT -Append | |
| - name: Build Windows executable | |
| run: flutter build windows --release --build-number ${{ github.run_number }} | |
| - name: Create and zip Windows release | |
| run: | | |
| pwsh ./scripts/windows-dist-pack.ps1 ce-${{ steps.get_version.outputs.version }} | |
| - name: Upload Windows zip artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: borneo-app-ce-${{ steps.get_version.outputs.version }}-windows-x64 | |
| path: client/build/windows/dist/borneo-app-ce-${{ steps.get_version.outputs.version }}-windows-x64.zip | |
| build-ios: | |
| needs: test | |
| runs-on: macos-14 | |
| defaults: | |
| run: | |
| working-directory: ${{ env.FLUTTER_WORKING_DIR }} | |
| outputs: | |
| version: ${{ steps.get_version.outputs.version }} | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup Flutter | |
| uses: subosito/flutter-action@v2 | |
| with: | |
| channel: stable | |
| flutter-version-file: client/pubspec.yaml | |
| cache: true | |
| - name: Cache pub dependencies | |
| uses: actions/cache@v4 | |
| with: | |
| path: ~/.pub-cache | |
| key: ${{ runner.os }}-pub-cache-${{ hashFiles('client/pubspec.yaml', 'client/pubspec.lock', 'client/packages/*/pubspec.yaml') }} | |
| restore-keys: ${{ runner.os }}-pub-cache- | |
| - name: Cache CocoaPods | |
| uses: actions/cache@v4 | |
| with: | |
| path: | | |
| ~/.cocoapods | |
| ~/Library/Caches/CocoaPods | |
| ${{ github.workspace }}/client/ios/Pods | |
| key: ${{ runner.os }}-pods-${{ hashFiles('client/ios/Podfile.lock') }} | |
| restore-keys: ${{ runner.os }}-pods- | |
| - name: Flutter precache (iOS) | |
| run: flutter precache --ios | |
| - name: Activate melos and bootstrap | |
| run: | | |
| dart pub global activate melos | |
| melos bootstrap | |
| - name: Get Flutter dependencies | |
| run: flutter pub get | |
| - name: Get version from pubspec.yaml | |
| id: get_version | |
| run: | | |
| VERSION=$(grep '^version:' pubspec.yaml | head -n1 | awk '{print $2}' | cut -d'+' -f1) | |
| echo "version=$VERSION" >> $GITHUB_OUTPUT | |
| - name: Build iOS app (no codesign) | |
| run: flutter build ios --release --no-codesign --build-number ${{ github.run_number }} | |
| release: | |
| needs: [build-apk, build-windows, build-ios] | |
| runs-on: ubuntu-latest | |
| if: github.ref == 'refs/heads/master' | |
| steps: | |
| - name: Download artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| path: ./release-artifacts | |
| merge-multiple: true | |
| - name: Set prerelease flag | |
| id: set_prerelease | |
| run: | | |
| if [[ "${{ needs.build-apk.outputs.version }}" == *beta* || "${{ needs.build-apk.outputs.version }}" == *alpha* ]]; then | |
| echo "prerelease=true" >> $GITHUB_OUTPUT | |
| else | |
| echo "prerelease=false" >> $GITHUB_OUTPUT | |
| fi | |
| - name: Create Versionized GitHub Release | |
| uses: softprops/action-gh-release@v2 | |
| with: | |
| tag_name: app-ce-v${{ needs.build-apk.outputs.version }} | |
| name: Borneo-IoT App Release app-ce-v${{ needs.build-apk.outputs.version }} | |
| draft: false | |
| overwrite_files: true | |
| prerelease: ${{ steps.set_prerelease.outputs.prerelease }} | |
| files: | | |
| release-artifacts/borneo-app-ce-${{ needs.build-apk.outputs.version }}.apk | |
| release-artifacts/borneo-app-ce-${{ needs.build-windows.outputs.version }}-windows-x64.zip | |
| - name: Manage latest tag via API | |
| uses: actions/github-script@v8 | |
| with: | |
| github-token: ${{ secrets.GITHUB_TOKEN }} | |
| script: | | |
| const tag = 'release-app-latest'; | |
| const refName = `tags/${tag}`; | |
| const fullRef = `refs/tags/${tag}`; | |
| try { | |
| await github.rest.git.deleteRef({ owner: context.repo.owner, repo: context.repo.repo, ref: refName }); | |
| console.log(`Deleted existing tag ${tag}`); | |
| } catch (err) { | |
| if (err.status !== 404) throw err; | |
| console.log(`Tag ${tag} did not exist, proceeding to create`); | |
| } | |
| await github.rest.git.createRef({ owner: context.repo.owner, repo: context.repo.repo, ref: fullRef, sha: context.sha }); | |
| console.log(`Created tag ${tag} pointing to ${context.sha}`); | |
| - name: Remove previous release assets | |
| uses: actions/github-script@v8 | |
| with: | |
| github-token: ${{ secrets.GITHUB_TOKEN }} | |
| script: | | |
| const tag = 'release-app-latest'; | |
| try { | |
| const rel = await github.rest.repos.getReleaseByTag({ owner: context.repo.owner, repo: context.repo.repo, tag }); | |
| const release_id = rel.data.id; | |
| const assets = await github.paginate(github.rest.repos.listReleaseAssets, { owner: context.repo.owner, repo: context.repo.repo, release_id }); | |
| for (const a of assets) { | |
| console.log(`Deleting asset ${a.name} (${a.id})`); | |
| await github.rest.repos.deleteReleaseAsset({ owner: context.repo.owner, repo: context.repo.repo, asset_id: a.id }); | |
| } | |
| console.log('Previous release assets removed.'); | |
| } catch (err) { | |
| if (err.status === 404) { | |
| console.log('Release not found, nothing to delete.'); | |
| } else { | |
| throw err; | |
| } | |
| } | |
| - name: Create GitHub Latest App Release | |
| uses: softprops/action-gh-release@v2 | |
| with: | |
| tag_name: release-app-latest | |
| name: Latest App Release | |
| draft: false | |
| overwrite_files: true | |
| files: release-artifacts/* |