Flutter Integration
CI/CD Integration
Automate your Flutter package publishing and dependency management with CI/CD pipelines.
Prerequisites
Before setting up CI/CD:
- Create API Key with publishing permissions
- Add key as secret in your CI/CD platform
- Configure pub-tokens.json in pipeline
GitHub Actions
Basic Publishing Workflow
Create .github/workflows/publish.yml:
name: Publish Package
on:
push:
tags:
- 'v*' # Trigger on version tags
jobs:
publish:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Flutter
uses: subosito/flutter-action@v2
with:
flutter-version: '3.16.0'
channel: 'stable'
- name: Install dependencies
run: flutter pub get
- name: Run tests
run: flutter test
- name: Analyze code
run: flutter analyze
- name: Setup credentials
env:
GF_PUB_TOKEN: ${{ secrets.GAME_FRAMEWORK_TOKEN }}
run: |
mkdir -p ~/.pub-cache
cat > ~/.pub-cache/pub-tokens.json << EOF
{
"version": 1,
"hosted": [
{
"url": "https://registry.yourcompany.com",
"token": "\${GF_PUB_TOKEN}",
"env": "GF_PUB_TOKEN"
}
]
}
EOF
- name: Publish to Game Framework
env:
GF_PUB_TOKEN: ${{ secrets.GAME_FRAMEWORK_TOKEN }}
run: |
flutter pub publish --force --server=https://registry.yourcompany.comAdvanced Workflow with Matrix
Test on multiple Flutter versions:
name: Test and Publish
on:
pull_request:
push:
branches: [main]
tags: ['v*']
jobs:
test:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
flutter-version: ['3.13.0', '3.16.0']
steps:
- uses: actions/checkout@v4
- uses: subosito/flutter-action@v2
with:
flutter-version: ${{ matrix.flutter-version }}
- run: flutter pub get
- run: flutter test
- run: flutter analyze
publish:
needs: test
if: startsWith(github.ref, 'refs/tags/v')
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: subosito/flutter-action@v2
with:
flutter-version: '3.16.0'
- name: Publish
env:
GF_PUB_TOKEN: ${{ secrets.GAME_FRAMEWORK_TOKEN }}
run: |
mkdir -p ~/.pub-cache
echo '{"version":1,"hosted":[{"url":"https://registry.yourcompany.com","token":"${GF_PUB_TOKEN}","env":"GF_PUB_TOKEN"}]}' > ~/.pub-cache/pub-tokens.json
flutter pub get
flutter pub publish --force --server=https://registry.yourcompany.comMonorepo Publishing
Publish multiple packages:
name: Publish Packages
on:
push:
tags: ['v*']
jobs:
publish:
runs-on: ubuntu-latest
strategy:
matrix:
package: [auth, ui, utils, core]
steps:
- uses: actions/checkout@v4
- uses: subosito/flutter-action@v2
with:
flutter-version: '3.16.0'
- name: Publish ${{ matrix.package }}
env:
GF_PUB_TOKEN: ${{ secrets.GAME_FRAMEWORK_TOKEN }}
working-directory: packages/${{ matrix.package }}
run: |
mkdir -p ~/.pub-cache
echo '{"version":1,"hosted":[{"url":"https://registry.yourcompany.com","token":"${GF_PUB_TOKEN}","env":"GF_PUB_TOKEN"}]}' > ~/.pub-cache/pub-tokens.json
flutter pub get
flutter pub publish --force --server=https://registry.yourcompany.comGitLab CI
Basic Configuration
Create .gitlab-ci.yml:
stages:
- test
- publish
variables:
FLUTTER_VERSION: "3.16.0"
before_script:
- apt-get update -qq && apt-get install -y -qq git curl unzip
- git clone https://github.com/flutter/flutter.git -b stable --depth 1
- export PATH="$PATH:`pwd`/flutter/bin"
- flutter --version
test:
stage: test
image: cirrusci/flutter:stable
script:
- flutter pub get
- flutter test
- flutter analyze
only:
- branches
- tags
publish:
stage: publish
image: cirrusci/flutter:stable
script:
- export GF_PUB_TOKEN=$GAME_FRAMEWORK_TOKEN
- mkdir -p ~/.pub-cache
- echo '{"version":1,"hosted":[{"url":"https://registry.yourcompany.com","token":"${GF_PUB_TOKEN}","env":"GF_PUB_TOKEN"}]}' > ~/.pub-cache/pub-tokens.json
- flutter pub get
- flutter pub publish --force --server=https://registry.yourcompany.com
only:
- tags
environment:
name: productionWith Docker
publish:
stage: publish
image: google/dart:latest
services:
- docker:dind
before_script:
- git clone https://github.com/flutter/flutter.git -b stable
- export PATH="$PATH:$PWD/flutter/bin"
script:
- flutter pub get
- flutter test
- |
mkdir -p ~/.pub-cache
cat > ~/.pub-cache/pub-tokens.json << EOF
{
"version": 1,
"hosted": [
{
"url": "https://registry.yourcompany.com",
"token": "\${GF_PUB_TOKEN}",
"env": "GF_PUB_TOKEN"
}
]
}
EOF
- flutter pub publish --force --server=https://registry.yourcompany.com
only:
- tagsJenkins
Jenkinsfile
pipeline {
agent any
environment {
GF_PUB_TOKEN = credentials('game-framework-token')
FLUTTER_HOME = '/opt/flutter'
PATH = "${FLUTTER_HOME}/bin:${env.PATH}"
}
stages {
stage('Setup') {
steps {
sh '''
flutter --version
flutter pub get
'''
}
}
stage('Test') {
steps {
sh '''
flutter test
flutter analyze
'''
}
}
stage('Publish') {
when {
tag "v*"
}
steps {
sh '''
mkdir -p ~/.pub-cache
cat > ~/.pub-cache/pub-tokens.json << EOF
{
"version": 1,
"hosted": [
{
"url": "https://registry.yourcompany.com",
"token": "${GF_PUB_TOKEN}",
"env": "GF_PUB_TOKEN"
}
]
}
EOF
flutter pub publish --force --server=https://registry.yourcompany.com
'''
}
}
}
post {
always {
cleanWs()
}
}
}CircleCI
.circleci/config.yml
version: 2.1
orbs:
flutter: circleci/flutter@2.0.0
jobs:
test:
executor:
name: flutter/default
flutter-version: "3.16.0"
steps:
- checkout
- flutter/install_sdk_and_pub
- run: flutter test
- run: flutter analyze
publish:
executor:
name: flutter/default
flutter-version: "3.16.0"
steps:
- checkout
- flutter/install_sdk_and_pub
- run:
name: Setup credentials
command: |
mkdir -p ~/.pub-cache
echo '{"version":1,"hosted":[{"url":"https://registry.yourcompany.com","token":"${GF_PUB_TOKEN}","env":"GF_PUB_TOKEN"}]}' > ~/.pub-cache/pub-tokens.json
- run:
name: Publish package
command: flutter pub publish --force --server=https://registry.yourcompany.com
workflows:
test-and-publish:
jobs:
- test
- publish:
requires:
- test
filters:
tags:
only: /^v.*/
branches:
ignore: /.*/Azure DevOps
azure-pipelines.yml
trigger:
tags:
include:
- v*
pool:
vmImage: 'ubuntu-latest'
variables:
FLUTTER_VERSION: '3.16.0'
steps:
- task: FlutterInstall@0
inputs:
channel: 'stable'
version: $(FLUTTER_VERSION)
- script: flutter pub get
displayName: 'Install dependencies'
- script: flutter test
displayName: 'Run tests'
- script: flutter analyze
displayName: 'Analyze code'
- script: |
mkdir -p ~/.pub-cache
cat > ~/.pub-cache/pub-tokens.json << EOF
{
"version": 1,
"hosted": [
{
"url": "https://registry.yourcompany.com",
"token": "\$(GF_PUB_TOKEN)",
"env": "GF_PUB_TOKEN"
}
]
}
EOF
flutter pub publish --force --server=https://registry.yourcompany.com
env:
GF_PUB_TOKEN: $(GAME_FRAMEWORK_TOKEN)
displayName: 'Publish package'Bitbucket Pipelines
bitbucket-pipelines.yml
image: cirrusci/flutter:stable
pipelines:
tags:
v*:
- step:
name: Test and Publish
caches:
- flutter
script:
- flutter --version
- flutter pub get
- flutter test
- flutter analyze
- mkdir -p ~/.pub-cache
- echo '{"version":1,"hosted":[{"url":"https://registry.yourcompany.com","token":"${GF_PUB_TOKEN}","env":"GF_PUB_TOKEN"}]}' > ~/.pub-cache/pub-tokens.json
- flutter pub publish --force --server=https://registry.yourcompany.com
definitions:
caches:
flutter: ~/.pub-cacheDocker-based CI
Dockerfile for CI
FROM cirrusci/flutter:stable
# Set environment
ENV PUB_HOSTED_URL=https://registry.yourcompany.com
ENV GF_PUB_TOKEN=${GF_PUB_TOKEN}
# Setup credentials
RUN mkdir -p /root/.pub-cache && \
echo '{"version":1,"hosted":[{"url":"https://registry.yourcompany.com","token":"${GF_PUB_TOKEN}","env":"GF_PUB_TOKEN"}]}' \
> /root/.pub-cache/pub-tokens.json
WORKDIR /workspace
# Copy package files
COPY pubspec.* ./
RUN flutter pub get
# Copy source
COPY . .
# Run tests
RUN flutter test && flutter analyze
# Publish
CMD ["flutter", "pub", "publish", "--force", "--server=https://registry.yourcompany.com"]Best Practices
1. Version Tagging
Always trigger on version tags:
# Create and push tag
git tag -a v1.2.3 -m "Release 1.2.3"
git push origin v1.2.32. Dry Run First
Add a dry-run step before publishing:
- name: Dry run
run: flutter pub publish --dry-run --server=https://registry.yourcompany.com
- name: Publish
if: startsWith(github.ref, 'refs/tags/v')
run: flutter pub publish --force --server=https://registry.yourcompany.com3. Cache Dependencies
Speed up builds with caching:
# GitHub Actions
- name: Cache pub dependencies
uses: actions/cache@v3
with:
path: ~/.pub-cache
key: ${{ runner.os }}-pub-${{ hashFiles('**/pubspec.lock') }}
restore-keys: |
${{ runner.os}}-pub-4. Secrets Management
Never hardcode tokens:
# ✗ Bad
env:
TOKEN: "gf_live_abc123..."
# ✓ Good
env:
GF_PUB_TOKEN: ${{ secrets.GAME_FRAMEWORK_TOKEN }}5. Notifications
Add notifications for failures:
- name: Notify on failure
if: failure()
uses: 8398a7/action-slack@v3
with:
status: ${{ job.status }}
text: 'Package publish failed!'
webhook_url: ${{ secrets.SLACK_WEBHOOK }}Troubleshooting
"Unauthorized" in CI
Check:
- Secret is set correctly in CI/CD platform
- Secret name matches environment variable
- Token has necessary permissions
"pub-tokens.json not found"
Ensure you're creating the file:
mkdir -p ~/.pub-cache
echo '...' > ~/.pub-cache/pub-tokens.jsonVersion Already Published
Add version check:
# Check if version exists before publishing
VERSION=$(grep '^version:' pubspec.yaml | sed 's/version: //')
if curl -f https://registry.yourcompany.com/v1/packages/my_package/versions/$VERSION; then
echo "Version $VERSION already published"
exit 0
fiNext Steps
- Authentication - Token management
- Webhooks - Set up publish notifications
- Best Practices - Team workflows
Examples Repository: Check out our CI/CD examples repository for more templates.