injectCI function
Implementation
Future<void> injectCI(String projectName) async {
final ciDir =
Directory(p.join(projectName, '.github', 'workflows'));
ciDir.createSync(recursive: true);
File(p.join(ciDir.path, 'flutter_ci.yml')).writeAsStringSync('''
name: Flutter CI
on:
push:
branches: [ main ]
pull_request:
concurrency:
group: flutter-ci-\${{ github.ref }}
cancel-in-progress: true
jobs:
android:
runs-on: ubuntu-latest
env:
ANDROID_KEYSTORE_PASSWORD: \${{ secrets.ANDROID_KEYSTORE_PASSWORD }}
ANDROID_KEY_ALIAS: \${{ secrets.ANDROID_KEY_ALIAS }}
ANDROID_KEY_PASSWORD: \${{ secrets.ANDROID_KEY_PASSWORD }}
ANDROID_KEYSTORE_BASE64: \${{ secrets.ANDROID_KEYSTORE_BASE64 }}
steps:
- uses: actions/checkout@v4
- name: Set up Java
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: '17'
- name: Setup Flutter
uses: subosito/flutter-action@v2
with:
channel: stable
- name: Cache Pub
uses: actions/cache@v4
with:
path: ~/.pub-cache
key: pub-\${{ runner.os }}-\${{ hashFiles('**/pubspec.lock') }}
- name: Cache Gradle
uses: actions/cache@v4
with:
path: ~/.gradle
key: gradle-\${{ runner.os }}-\${{ hashFiles('**/*.gradle*') }}
- run: flutter pub get
- run: flutter analyze
# Optional Android Signing
- name: Decode Keystore
if: \${{ env.ANDROID_KEYSTORE_BASE64 != '' }}
run: |
echo "\$ANDROID_KEYSTORE_BASE64" | base64 -d > android/app/release.keystore
- name: Build Dev APK
run: flutter build apk --flavor dev -t lib/main_dev.dart --release
- name: Upload Dev APK
uses: actions/upload-artifact@v4
with:
name: android-dev-apk
path: build/app/outputs/flutter-apk/*.apk
- name: Build Prod AAB
run: flutter build appbundle --flavor prod -t lib/main_prod.dart --release
- name: Upload Prod AAB
uses: actions/upload-artifact@v4
with:
name: android-prod-aab
path: build/app/outputs/bundle/**/*.aab
ios:
runs-on: macos-latest
env:
APPLE_CERTIFICATE_BASE64: \${{ secrets.APPLE_CERTIFICATE_BASE64 }}
APPLE_CERTIFICATE_PASSWORD: \${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
APPLE_PROVISION_PROFILE_BASE64: \${{ secrets.APPLE_PROVISION_PROFILE_BASE64 }}
steps:
- uses: actions/checkout@v4
- name: Setup Flutter
uses: subosito/flutter-action@v2
with:
channel: stable
- run: flutter pub get
# Optional iOS Signing
- name: Install Certificate
if: \${{ env.APPLE_CERTIFICATE_BASE64 != '' }}
run: |
echo "\$APPLE_CERTIFICATE_BASE64" | base64 -d > certificate.p12
security create-keychain -p "" build.keychain
security import certificate.p12 -k build.keychain -P "\$APPLE_CERTIFICATE_PASSWORD" -T /usr/bin/codesign
security list-keychains -d user -s build.keychain
security default-keychain -s build.keychain
security unlock-keychain -p "" build.keychain
security set-key-partition-list -S apple-tool:,apple: -s -k "" build.keychain
- name: Install Provisioning Profile
if: \${{ env.APPLE_PROVISION_PROFILE_BASE64 != '' }}
run: |
mkdir -p ~/Library/MobileDevice/Provisioning\\ Profiles
echo "\$APPLE_PROVISION_PROFILE_BASE64" | base64 -d > ~/Library/MobileDevice/Provisioning\\ Profiles/profile.mobileprovision
- name: Build Dev IPA
run: |
if [ -z "\$APPLE_CERTIFICATE_BASE64" ]; then
flutter build ipa -t lib/main_dev.dart --release --no-codesign
else
flutter build ipa -t lib/main_dev.dart --release
fi
- name: Upload Dev IPA
uses: actions/upload-artifact@v4
with:
name: ios-dev-ipa
path: build/ios/ipa/*.ipa
- name: Build Prod IPA
run: |
if [ -z "\$APPLE_CERTIFICATE_BASE64" ]; then
flutter build ipa -t lib/main_prod.dart --release --no-codesign
else
flutter build ipa -t lib/main_prod.dart --release
fi
- name: Upload Prod IPA
uses: actions/upload-artifact@v4
with:
name: ios-prod-ipa
path: build/ios/ipa/*.ipa
''');
print('✅ Enterprise GitHub CI injected successfully.');
}