Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Discipline your Android builds to be delivered ...

Discipline your Android builds to be delivered at any time.

Strategies and tools used to distribute an android app in beta and prod environments at any time.

Erik Jhordan Rey

August 26, 2020
Tweet

More Decks by Erik Jhordan Rey

Other Decks in Programming

Transcript

  1. Practice where members of a team integrate their work frequently,

    usually each person integrates at least daily Continuous Integration
  2. Discipline where you build software in such a way that

    the software can be released to production at any time Continuous Delivery
  3. Means that every change goes through the pipeline and automatically

    gets put into production Continuous Development
  4. Distribution Challenges • The team lead generate the build manually

    on their machine • One member of the team has the keys to signing the app • Attend issues and make Hotfixes easier • APK is shared on slack, drive, dropbox, email or another. • Connect a QA's device to your personal computer to someone can test a version (apk or bundle) • The wrong signed app builds (third-party libs keys) • Nobody knows the features included in the release • Impossible to show premature versions • Google Play Internal test can not be used instantaneously • Firebase Distribution does not support app bundles
  5. Why automate the app release matters? • Satisfy the customer

    through early and continuous delivery of valuable software. • Visibility to all team about the development • Fix broken builds Immediately • Make it easy for anyone to get the latest version • Deliver working software frequently • A standardized way to make releases
  6. “This is a guide on which tools and strategies, I

    have implemented in real-world projects. Not rules or silver bullet tools!”
  7. Proprietary + Confidential Android Delivery Guide Workflow Reduced Risk Source:

    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem Distribution
  8. “A great development workflow will make your good developers great,

    and your great developers exceptional. A bad workflow will take your best engineers' productivity down to level and make wish he worked elsewhere.”
  9. Contributor Guide Tools to d Define a contributor guide of

    integration code, where developers can read, guidelines, styles, tools, and resources to start to collaborate with the project. Branches • Our main branch is master • We work on feature branches and do PRs to merge them to master. • We used a release branch to prepare the Release Candidates, HotFix and finally do the Release.
  10. Define Build Types Tools to d Design strategies to build

    different versions of the app to test different environments Builds Debug: Build Feature Integration with development rules, logging tools, and available test in a staging environment used by the development team. Preview: Build Candidate with production rules without logs tools, but available test in production environment used by the Internal team (All Team) Production: Build Production to be uploaded to Google Play Note: If you're using flavors, consider the different combinations
  11. Preview Validate Build Deploy Workflow Prod Debug Pull Requests CI

    Job merge to master release branch Tag Release Google Play Firebase App Distribution
  12. CI setup Tools to d Each integration is verified by

    an automated build to detect integration errors as quickly as possible • Specify branches a. master b. "release-0.1.0" - /^release-\d+\.\d+\.\d+$/ c. "0.1.0" - /^\d+\.\d+\.\d+$/ • Keep the build fast • Try different configurations until finding the most performed to your project
  13. Assemble Builds Tools to d A key part of doing

    a continuous build is that if the mainline build fails, it needs to be fixed right away. • Prevent merge broken PR's • Easier back to previous code versions • You're always developing on a known stable code base
  14. APK Assemble main outputs for all the variants ./gradlew assemble

    ./gradlew assembleDebug ./gradlew assemblePreview ./gradlew assembleProd ----------------------------- Dynamic Features - BundleToStandaloneApkTask ./gradlew packageDebugUniversalApk
  15. Code Analysis Tools Tools to d Analyze your source code

    to find potential vulnerabilities such as bugs and ensure conformance to coding guidelines. Keep your code healthy and maintain code quality. • Android Lint: Inspect & Validate Java, Kotlin & XML • detekt: Highly configurable analysis tool for your Kotlin projects (code smells & complexity) • ktlint: Kotlin linter based on kotlinlang.org rules and code formatter • PMD: Multi analyzer code for Java, Xml & more • FindBugs: Detects possible bugs in Java • checkstyle: Check for naming conventions, structural issues, class design for Java code
  16. Testing Pipeline Tools to d Make your build self testing

    catch bugs more quickly and efficiently is to include automated tests in the build process. • Testing the business logic • Testing the integration with a server API’s • Testing User Interface • Testing Persistence Integration
  17. Run Tests ./gradlew test ./gradlew connectedAndroidTest The Gradle check task

    depends on the test task which means test is executed before check is run. ./gradlew check
  18. App Signing automatically Create a file inside the project to

    store the signing keys debug.properties APP_DEBUG_STORE_PASSWORD=YourStorePassword APP_DEBUG_KEY_ALIAS=YourAlias APP_DEBUG_KEY_PASSWORD=YourkeyPassword
  19. signing.gradle ext { signingDebug = { def propertiesFile = loadPropertiesFile("debug")

    android.signingConfigs.debug { storeFile loadFileFromGoogleDir("debug.keystore") if (propertiesFile.exists()) { def properties = loadProperties(propertiesFile) storePassword properties.APP_DEBUG_STORE_PASSWORD keyAlias properties.APP_DEBUG_KEY_ALIAS keyPassword properties.APP_DEBUG_KEY_PASSWORD } else { storePassword System.getenv("APP_DEBUG_STORE_PASSWORD") keyAlias System.getenv("APP_DEBUG_KEY_ALIAS") keyPassword System.getenv("APP_DEBUG_KEY_PASSWORD") } } } https://erikjhordan-rey.github.io/blog/2020/03/15/ANDROID-launch-android-apps.html
  20. Version Properties Increase the version on master ( increasing the

    MAJOR, MINOR or PATCH, ie. move to 1.5.0 version.properties MAJOR=1 MINOR=5 PATCH=0
  21. Version Code & Name Generate automatically the version code and

    name app-distribution.gradle ext { versionMajor = getVersionMajor() versionMinor = getVersionMinor() versionPatch = getVersionPatch() version_name = "${versionMajor}.${versionMinor}.${versionPatch}" version_code = versionMajor * 10000 + versionMinor * 100 + versionPatch version_date = generateBuildTime() }
  22. version.properties private def getVersionMajor() { Properties properties = getVersionProperties() return

    properties['MAJOR'].toInteger() } private def getVersionMinor() { Properties properties = getVersionProperties() return properties['MINOR'].toInteger() } private def getVersionPatch() { Properties properties = getVersionProperties() return properties['PATCH'].toInteger() } private def getVersionProperties() { def content = rootProject.file("gradle-scripts/distribution/version.properties") Properties properties = new Properties() InputStream is = new ByteArrayInputStream(content.getBytes()) properties.load(is) return properties }
  23. android.gradle defaultConfig { ... versionCode version_code versionName version_name } Android

    Module Config - com.android.library apply from: rootProject.file("gradle-scripts/shared-config/android.gradle") Dynamic Feature Config - com.android.dynamic-feature apply from: rootProject.file("gradle-scripts/shared-config/dynamic-feature.gradle") Shared Configuration Module A Module B Module C
  24. Internal Distribution Write Code Push Code Run Tests & Checks

    on CI Distribution QA Team Debug Preview
  25. Firebase App Distribution apply plugin: 'com.android.application' // ... apply plugin:

    'com.google.firebase.appdistribution' firebaseAppDistribution { releaseNotesFile = "path/release-notes.txt" groups = "internal-testers" serviceCredentialsFile = rootProject.file("gradle-scripts/distribution/service-account.json") }
  26. Firebase App Distribution + Debug Build Type debug { def

    type = "debug" applicationIdSuffix ".${type}" versionNameSuffix "-${type}" .... signingConfig signingConfigs.debug firebaseAppDistribution { releaseNotesFile = "./release-notes.txt" groups = "internal-testers" serviceCredentialsFile = rootProject.file("gradle-scripts/distribution/service-account.json") } }
  27. Firebase App Distribution + Preview Build Type preview { def

    type = "preview" applicationIdSuffix ".${type}" versionNameSuffix "-${type}" .... ... firebaseAppDistribution { releaseNotesFile = "gradle-scripts/distribution/release_notes.txt" groups = "internal-testers" serviceCredentialsFile = rootProject.file("gradle-scripts/distribution/service-account.json") } }
  28. Debug + Publishing Universal APK ./gradlew appDistributionUploadDebug Travis CI -

    master deploy: - provider: script script: ./gradlew appDistributionUploadDebug on: branch: master
  29. Preview + Publishing Universal APK ./gradlew appDistributionUploadPreview Travis CI -

    Release Branch - release-1.5.0 deploy: - provider: script script: ./gradlew appDistributionUploadPreview on: all_branches: true condition: $TRAVIS_BRANCH =~ ^release-.*$
  30. Communication Plan Tools to d Each new release impacts the

    whole team and company, not just the mobile developers, we need to communicate the most relevant changes included in the app. • Debug: Auto Generate release notes with last commit message • Preview: Add release notes with the most relevant changes • Production: Every ticket in JIRA linked to a merged PR should set the field “Fix Version/s:” to the next Release. This will help to generate automatically the changelog at the end of each release
  31. Generate Release Notes Automatically task generateReleaseNotes { doLast({ def releaseNotes

    = new File('release-notes.txt') releaseNotes.delete() releaseNotes << "Release Notes - Version $name_version (${date_version})\n\n" releaseNotes << "Change Log \n\n" def lastCommitCommand = "git log --format=%s --no-merges -n 1" def commitMessageLines = lastCommitCommand.execute() commitMessageLines.in.eachLine { line -> releaseNotes << "* " + line + "\n\n\n" } releaseNotes << "This file was automatically generated." }) } ./gradlew generateReleaseNotes
  32. Firebase App Distribution Release Notes When a PR is merged

    to master release notes is generated automatically with the latest commit
  33. QA Team Tools to d Things always go wrong in

    production, but this does not have to be a bad thing. It’s an opportunity to learn about your system and the real world with which it interacts. Product: Ensure a product team test the requirements business logic QA: Help you gain a richer understanding of the real issues your system faces (Test automation means that you are more empowered in your role than ever.)
  34. Dynamic URL Environment Tools to d Implement a hidden feature

    (Dynamic URL) to your team can test an app pointing to different URL Environments without a new release. App Builds Debug: Set a specific URL environment with a development build Preview: Set a specific URL environment with a pre-production build
  35. Gradle Play Publisher classpath "com.github.triplet.gradle:play-publisher:2.7.2" ... apply plugin: "com.github.triplet.play" ...

    play { serviceAccountCredentials = rootProject.file("gradle-scripts/distribution/service-account.json") track = "internal" userFraction = 0.5 releaseStatus = "inProgress" }
  36. Publishing APKs ./gradlew publishApk Publishing Bundles ./gradlew publishReleaseBundle Travis CI

    - Tag - 1.5.0 deploy: - provider: script script: ./gradlew publishReleaseBundle on: tags: true
  37. Staged Rollout Tools to d With a staged rollout, your

    update reaches only a percentage of your users, which you can increase over time. • New and existing users are eligible to receive updates from staged rollouts and are chosen at random for each new release rollout. • During a staged rollout, it's a good idea to closely monitor crash reports and user feedback. • Increase your staged rollout percentage according to the number of user installs
  38. Monitoring Your App Tools to d Gathering operational data about

    a system is common practice, particularly metrics that indicate app behavior as performance, memory usage, crash-free user, daily active users, analytics data, etc • Use Firebase Crashlytics is a lightweight, realtime crash reporter that helps you track, prioritize, and fix stability issues that erode your app quality. • Integrate used services to be notified as soon as possible ej. (Slack + Firebase Crashlytics ) • Verify performance and analytics data
  39. Feature Toggles Tools to d Is a set of patterns

    which can help us to deliver new functionality to users rapidly but safely without a new release • Use Firebase Remote Config is a cloud service that lets you change the behavior and appearance of your app without requiring users to download an app update • Create your own platform or system to turn on/off features
  40. 11 Weeks of Android: App distribution and monetization on Google

    Play Tools to d https://android-developers.googleblog.com/2020/08/11-weeks-of-android-app-distribution.html https://developer.android.com/distribute/play-policies
  41. Recommendations • Not needed to have a complex workflow to

    implement CI/CD, start with minimum checks and validations • Try different setups in order to find the correct or fits your needs • Considerate company's resources and the size team at the moment choose a CI tool • Use kotlin DSL if you feel more comfortable to avoid Gradle files. • Keep the builds fast • Satisfy the customer through early and continuous delivery of valuable software. ¡Automate all the things!
  42. Further Reading • https://ronjeffries.com/xprog/what-is-extreme-programming/#whole • https://martinfowler.com/articles/continuousIntegration.html • https://martinfowler.com/bliki/ContinuousDelivery.html • https://martinfowler.com/articles/qa-in-production.html

    • https://firebase.google.com/docs/app-distribution • https://github.com/Triple-T/gradle-play-publisher • https://android-developers.googleblog.com/2020/08/11-weeks-of-android-app-distribu tion.html • https://speakerdeck.com/erikjhordan_rey/pragmatic-mobile-testing-strategies • https://erikjhordan-rey.github.io/blog/2020/03/15/ANDROID-launch-android-apps.html • https://anchor.fm/erik-jhordan-rey