Applying DevOps in Flutter Mobile Development 

CI / CD

Why Should we start doing this?

 

1- Improve speed to market and our internal testers

2-  Ensure quality

3- Deploying is seamless

4- improves disaster recovery 

5- improve business agility

What is difficult of CI in Mobile development

 

1- Android Emulator required for instrumentation tests

2- iOS simulator required for iOS UI tests

3- iOS apps cannot be build on linux / windows

Tools?

 

Travis CI

Circle CI

Jenkins

Github Actions 

GitLab CI

Code Magic 

Never Code

Fastlane

  1. Capture screenshots automatically
  2. Distribute beta builds
  3. publish your app with the push of a button
  4. automate code signing for iOS
  5. Handle your build by code (code as infrastructure)  
  6. Open source / Written in Ruby / Gem

Commandline

platform :android do

# your lanes for Android here 

end


platform :ios do

# your lanes for iOS here 

end
platform :android do

  desc "Build and release to beta"
  lane :beta_internal_release do
    prepare(release: false)
    setup_new_changelog
    release_to_store(track: 'internal')
  end
  
end
platform :ios do

  desc "Push a new release to TestFlight"
  lane :build_and_deploy_testflight do |options|
    setup_travis
    prepare(release: false)
    setup_new_changelog
    upload_to_testflight(
        skip_waiting_for_build_processing: true,
        ipa: "Runner.ipa",
        username: username,
        changelog: changelog,
    )
    slack(
        message: "#{version_number}+#{build_number}: 
        iOS beta released to TestFlight \n 
        Changelog: \n #{emojified_changelog}",
        slack_url: slack_url,
    )
    # git_actions(release: false)
  end

end
platform :ios do

  desc "Prepare and archive app"
  lane :prepare do |options|
    puts "Building and deploying version #{version_number}, current build #{latest_testflight_build_number}"
    handle_versioning
    flutter_build_no_sign
    generate_icons
    beta_badge(hide: options[:release])
    code_signing
    build_ios_app(
        workspace: workspace_path,
        configuration: "Release",
        scheme: "Runner",
        silent: true,
        clean: true,
        export_team_id: export_team_id,
        export_method: "app-store",
        # Verify that the right signing identity is used for publishing.
        codesigning_identity: codesigning_identity,
        xcargs: "DEVELOPMENT_TEAM='#{export_team_id}'"
    )
  end
end

Share one code signing identity across your development team to simplify your codesigning setup and prevent code signing issues.

 

codesigning.guide

 

match

🔄 Automatically sync your iOS keys and profiles across all your team members using git
📦 Handle all the heavy lifting of creating and storing your certificates and profiles
💻 Setup codesigning on a new machine in under a minute
🎯 Designed to work with apps with multiple targets and bundle identifiers
🔒 You have full control over your files and Git repo, no third party service involved
Provisioning profile will always match the correct certificate
💥 Easily reset your existing profiles and certificates if your current account has expired or invalid profiles
♻️ Automatically renew your provisioning profiles to include all your devices using the --force option
👥 Support for multiple Apple accounts and multiple teams
Tightly integrated with fastlane to work seamlessly with gym and other build tools
#Matchfile

git_url("git@github.com:YOURACCOUNT/YOUR_CERT_REPO.git")
storage_mode("git")
type("appstore") # The default type, can be: appstore, adhoc, enterprise or development
app_identifier(["no.futurehome.futurehomeApp"])
username("majid@futurehome.no") # Your Apple Developer Portal username

Google Cloud Storage

Github

platform :ios do
  desc "Sing code using Match and fastlane"
  lane :code_signing do
    # Stop fastlane from echoing back ENV var.
    # Doesn't matter too much since Travis doesn't echo back encrypted variables
    # anyway :D
    suppress_output {
      # Retrieves all the necessary certs and provisioning profiles.
      # match   # alias for "sync_code_signing"
      sync_code_signing(readonly: true)
    }
    puts 'Certificates and profiles installed'
    # Modify the Xcode project to use the new team and profile.
    # It will put the git state to dirty but Travis will be wiped after
    # then run session.
    disable_automatic_code_signing
    update_project_provisioning(
        build_configuration: 'Release',
        profile: ENV["sigh_#{app_identifier}_appstore_profile-path"]
    )
  end
end
platform :ios do
  desc "Handle version and build number"
  lane :handle_versioning do
    build_number = latest_testflight_build_number + 1
    puts "new build number now is #{build_number} and build version is #{version_number}"
  end
end




platform :android do
  desc "Handle version and build number"
  lane :handle_versioning do
    build_number = current_build + 1
    puts "new build number now is #{build_number} and build version is #{raw_version}"
  end
end

Build Version

platform :ios do
  desc "Build app with no signing for ios and increase build number or version number"
  lane :flutter_build_no_sign do
    Dir.chdir "../#{project_ios_path}" do
      sh("flutter", "doctor")
      sh("flutter", "packages", "get")
      sh("flutter", "clean")
      sh("flutter", "build", "ios", "--build-number=#{build_number}", "--build-name=#{version_number} ", "--release", "--no-codesign")
    end
  end
end

Run Test / other commands

platform :android do
  desc "Create change log and make it ready for both slack and google play"
  lane :setup_new_changelog do
    changelog = read_changelog(
        changelog_path: "../CHANGELOG.md",
        section_identifier: "[Build: #{version_number}]", # Specify what section to read
        excluded_markdown_elements: ['-', '###'] # Specify which markdown elements should be excluded
    )
    emojified_changelog = emojify_changelog

    # write for Google store at the moment we have only no-NO
    path = "./metadata/android/no-NO/changelogs"
    dir = File.dirname(path)
    unless File.directory?(dir)
      FileUtils.mkdir_p(dir)
    end
    path << "/#{build_number}.txt"
    File.new(path, 'w')
    File.write(path, changelog)

    puts "Changelog for version #{version_number}+#{build_number}: #{changelog}"
  end
end

Change Log / Metadata

platform :android do
  
  desc "update git"
  lane :git_actions do
    # Ensure that your git status is not dirty
    ensure_git_status_clean
    #add git tag
    add_git_tag(build_number: version_number)
    # Commit the version bump
    commit_version_bump
    # Push the new commit and tag back to your git remote
    push_to_git_remote
  end
  
  # and many more 
  # capture screenshots for android
  # upload to Google Play
  # Run tests
  # generate icons
  # add beta badge 
  # lots of other plugins 
end

more Lanes

Summary

Thanks

Applying DevOps in Flutter Mobile Development

By Majid Hajian

Applying DevOps in Flutter Mobile Development

  • 35
Loading comments...

More from Majid Hajian