From 0b0b421530a8ff50e5119c7e6d73068a4b7f99fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lui=CC=81s=20Arteiro?= Date: Tue, 17 Oct 2023 13:35:06 +0100 Subject: [PATCH 01/38] fix: Upgrading the `flutter-quill` dependencies and adding multidex support. --- android/app/build.gradle | 3 +-- .../app/FlutterMultiDexApplication.java | 25 +++++++++++++++++++ macos/Flutter/GeneratedPluginRegistrant.swift | 2 ++ .../flutter/generated_plugin_registrant.cc | 3 +++ windows/flutter/generated_plugins.cmake | 1 + 5 files changed, 32 insertions(+), 2 deletions(-) create mode 100644 android/app/src/main/java/io/flutter/app/FlutterMultiDexApplication.java diff --git a/android/app/build.gradle b/android/app/build.gradle index 6cd87e7c..8fb8fe4c 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -48,8 +48,7 @@ android { // You can update the following values to match your application needs. // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration. - // Changed because of `gallery_saver` of `flutter_quill`. Though, it will be switched with `gal` in a different PR. Change this back once that occurs - minSdkVersion 21 + minSdkVersion flutter.minSdkVersion targetSdkVersion flutter.targetSdkVersion versionCode flutterVersionCode.toInteger() versionName flutterVersionName diff --git a/android/app/src/main/java/io/flutter/app/FlutterMultiDexApplication.java b/android/app/src/main/java/io/flutter/app/FlutterMultiDexApplication.java new file mode 100644 index 00000000..752fc185 --- /dev/null +++ b/android/app/src/main/java/io/flutter/app/FlutterMultiDexApplication.java @@ -0,0 +1,25 @@ +// Generated file. +// +// If you wish to remove Flutter's multidex support, delete this entire file. +// +// Modifications to this file should be done in a copy under a different name +// as this file may be regenerated. + +package io.flutter.app; + +import android.app.Application; +import android.content.Context; +import androidx.annotation.CallSuper; +import androidx.multidex.MultiDex; + +/** + * Extension of {@link android.app.Application}, adding multidex support. + */ +public class FlutterMultiDexApplication extends Application { + @Override + @CallSuper + protected void attachBaseContext(Context base) { + super.attachBaseContext(base); + MultiDex.install(this); + } +} diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index 27b7c556..2045890f 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -8,6 +8,7 @@ import Foundation import device_info_plus import emoji_picker_flutter import file_selector_macos +import gal import pasteboard import path_provider_foundation import shared_preferences_foundation @@ -17,6 +18,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin")) EmojiPickerFlutterPlugin.register(with: registry.registrar(forPlugin: "EmojiPickerFlutterPlugin")) FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin")) + GalPlugin.register(with: registry.registrar(forPlugin: "GalPlugin")) PasteboardPlugin.register(with: registry.registrar(forPlugin: "PasteboardPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc index e94be21a..40808cbb 100644 --- a/windows/flutter/generated_plugin_registrant.cc +++ b/windows/flutter/generated_plugin_registrant.cc @@ -8,6 +8,7 @@ #include #include +#include #include #include @@ -16,6 +17,8 @@ void RegisterPlugins(flutter::PluginRegistry* registry) { registry->GetRegistrarForPlugin("EmojiPickerFlutterPluginCApi")); FileSelectorWindowsRegisterWithRegistrar( registry->GetRegistrarForPlugin("FileSelectorWindows")); + GalPluginCApiRegisterWithRegistrar( + registry->GetRegistrarForPlugin("GalPluginCApi")); PasteboardPluginRegisterWithRegistrar( registry->GetRegistrarForPlugin("PasteboardPlugin")); UrlLauncherWindowsRegisterWithRegistrar( diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index 0231913d..d4ab75b5 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -5,6 +5,7 @@ list(APPEND FLUTTER_PLUGIN_LIST emoji_picker_flutter file_selector_windows + gal pasteboard url_launcher_windows ) From e1178fca2aafcd53a742d1c90e34d5b7b48a513c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lui=CC=81s=20Arteiro?= Date: Tue, 17 Oct 2023 13:35:15 +0100 Subject: [PATCH 02/38] chore: Upgrading deps. --- pubspec.lock | 71 +++++++++------------------------------------------- pubspec.yaml | 8 +++--- 2 files changed, 15 insertions(+), 64 deletions(-) diff --git a/pubspec.lock b/pubspec.lock index 5b7b2741..f7228c93 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -374,11 +374,6 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.3" - flutter_driver: - dependency: transitive - description: flutter - source: sdk - version: "0.0.0" flutter_inappwebview: dependency: transitive description: @@ -468,18 +463,18 @@ packages: dependency: "direct main" description: name: flutter_quill - sha256: "6350f7b93bd5dc30d12f8235c32f66727c4844f328a0e91869e36ecda4fdb2fa" + sha256: "7e3459678362a2e2cc3645df065a357ed60ff5e7863127046f5a2ca548cbf6f5" url: "https://pub.dev" source: hosted - version: "7.4.7" + version: "7.4.11" flutter_quill_extensions: dependency: "direct main" description: name: flutter_quill_extensions - sha256: "2881381283c2f31697ba0a5ce4f1b4eb1639d33b10c4252c0de601e4ae640347" + sha256: "8ad561415a00db5555e1b4dd353abdc8a815f945a0a61faac3c187138b616343" url: "https://pub.dev" source: hosted - version: "0.4.1" + version: "0.5.0" flutter_svg: dependency: transitive description: @@ -506,19 +501,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.2.0" - fuchsia_remote_debug_protocol: - dependency: transitive - description: flutter - source: sdk - version: "0.0.0" - gallery_saver: + gal: dependency: transitive description: - name: gallery_saver - sha256: df8b7e207ca12d64c71e0710a7ee3bc48aa7206d51cc720716fedb1543a66712 + name: gal + sha256: ebc581bea458be47e8e80761c4449ad3a0f045db206f6f4648885ac474444246 url: "https://pub.dev" source: hosted - version: "2.3.2" + version: "2.1.2" glob: dependency: transitive description: @@ -555,10 +545,10 @@ packages: dependency: "direct main" description: name: http - sha256: "5895291c13fa8a3bd82e76d5627f69e0d85ca6a30dcac95c4ea19a5d555879c2" + sha256: "759d1a329847dd0f39226c688d3e06a6b8679668e350e2891a6474f8b4bb8525" url: "https://pub.dev" source: hosted - version: "0.13.6" + version: "1.1.0" http_multi_server: dependency: transitive description: @@ -647,11 +637,6 @@ packages: url: "https://pub.dev" source: hosted version: "0.2.1+1" - integration_test: - dependency: "direct dev" - description: flutter - source: sdk - version: "0.0.0" intl: dependency: transitive description: @@ -896,10 +881,10 @@ packages: dependency: transitive description: name: platform - sha256: "4a451831508d7d6ca779f7ac6e212b4023dd5a7d08a27a63da33756410e32b76" + sha256: "0a279f0707af40c890e80b1e9df8bb761694c074ba7e1d4ab1bc4b728e200b59" url: "https://pub.dev" source: hosted - version: "3.1.0" + version: "3.1.3" plugin_platform_interface: dependency: transitive description: @@ -916,14 +901,6 @@ packages: url: "https://pub.dev" source: hosted version: "1.5.1" - process: - dependency: transitive - description: - name: process - sha256: "53fd8db9cec1d37b0574e12f07520d582019cb6c44abf5479a01505099a34a09" - url: "https://pub.dev" - source: hosted - version: "4.2.4" provider: dependency: transitive description: @@ -1129,22 +1106,6 @@ packages: url: "https://pub.dev" source: hosted version: "1.2.0" - string_validator: - dependency: transitive - description: - name: string_validator - sha256: b419cf5d21d608522e6e7cafed4deb34b6f268c43df866e63c320bab98a08cf6 - url: "https://pub.dev" - source: hosted - version: "1.0.0" - sync_http: - dependency: transitive - description: - name: sync_http - sha256: "7f0cd72eca000d2e026bcd6f990b81d0ca06022ef4e32fb257b30d3d1014a961" - url: "https://pub.dev" - source: hosted - version: "0.3.1" term_glyph: dependency: transitive description: @@ -1393,14 +1354,6 @@ packages: url: "https://pub.dev" source: hosted version: "2.4.0" - webdriver: - dependency: transitive - description: - name: webdriver - sha256: "3c923e918918feeb90c4c9fdf1fe39220fa4c0e8e2c0fffaded174498ef86c49" - url: "https://pub.dev" - source: hosted - version: "3.0.2" webkit_inspection_protocol: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index cca6e51d..e6c73449 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -19,14 +19,14 @@ dependencies: equatable: ^2.0.5 # Flutter Quill - flutter_quill: ^7.4.7 - flutter_quill_extensions: ^0.4.1 + flutter_quill: ^7.4.11 + flutter_quill_extensions: ^0.5.0 file_picker: ^5.3.3 universal_io: ^2.2.2 universal_html: ^2.2.3 path: ^1.8.3 path_provider: ^2.1.0 - http: ^0.13.6 + http: ^1.1.0 mime: ^1.0.4 http_parser: ^4.0.2 @@ -40,8 +40,6 @@ dependencies: dartz: ^0.10.1 dev_dependencies: - integration_test: - sdk: flutter flutter_test: sdk: flutter flutter_lints: ^2.0.2 From 757455b635c011c02ca75ae917828e154449453a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lui=CC=81s=20Arteiro?= Date: Tue, 17 Oct 2023 13:47:34 +0100 Subject: [PATCH 03/38] chore: Add pre-requisites in deployment documentation. #342 --- deployment.md | 142 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 142 insertions(+) create mode 100644 deployment.md diff --git a/deployment.md b/deployment.md new file mode 100644 index 00000000..630a228c --- /dev/null +++ b/deployment.md @@ -0,0 +1,142 @@ +# Deployment Guide 📩 + +This guide will help you through deploying a `Flutter` application +into the two main app stores in the mobile ecosystem: +`iOS AppStore` and `Android PlayStore`. + +Because we are using `Flutter`, +the way one builds, packages and ships an application +will differ from the native way. + +So, let's start! + +- [Deployment Guide 📩](#deployment-guide-) + - [🤖 Google `PlayStore`](#-google-playstore) + - [0. Pre-requisites](#0-pre-requisites) + - [Creating a `Google Play` account](#creating-a-google-play-account) + - [Review your app files](#review-your-app-files) + - [Setting up a splash screen](#setting-up-a-splash-screen) + - [Adding a launcher icon](#adding-a-launcher-icon) + - [Reviewing the `AndroidManifest` file](#reviewing-the-androidmanifest-file) + - [Reviewing the `Gradle` build configuration](#reviewing-the-gradle-build-configuration) + + +## 🤖 Google `PlayStore` + +Let's start with Google's `PlayStore`! + + +### 0. Pre-requisites + +Before we start our guide, +we are going to make sure everything is correctly setup +so **every time we need to deploy, we can go back here and follow the checklist properly**. + + +#### Creating a `Google Play` account + +We first need to create a `Google Play` account, +so we can distribute our applications. +Head over to https://developer.android.com/distribute +and click on `Sign In` on the top right corner. +You may use your personal or company's Google account to do this. + +

+ +

+ +After signing in, click on the `Sign in to Play Console`. +This will redirect you to a sign-up page, +where you will need to choose between using a **personal developer account** +or **as part of an organization**. + +If you choose the latter, +you will have to provide additional information. +If you're not using an e-mail with your company's domain, +Google will suggest you to use the "personal account" route. + +In this guide's case, +we'll choose the `Yourself` option, +as it's easier to setup. +What matters here is that we have an account that we can use to publish apps. + +

+ +

+ + +// TODO FINISH + + +#### Review your app files + +Now that we have created an account, +before publishing an app, +we ought to review some files. +It's not necessary to do this *every time* we update the app, +since these changes can be made in one go and be persisted across the development cycle. + +*However*, we'll list them here as a preliminary check-up +before rolling out the first version of the app. + + +##### Setting up a splash screen + +Splash screens (also known as launch screens) +provide a simple initial experience while the Android app loads. +They set the stage for your application, +while allowing time for the app engine to load and your app to initialize. + +We recommend checking the official guide over at +https://docs.flutter.dev/platform-integration/android/splash-screen +to set up a simple splash screen. +It's a simple couple of changes that ultimately make a heap of difference! + + +##### Adding a launcher icon + +When a new Flutter app is created, it has a default launcher icon. +To customize this icon, +the most practical way is using +[`flutter_launcher_icons`](https://pub.dev/packages/flutter_launcher_icons). +By using this package, it will automatically generate icons on all platforms +with the appropriate dimensions, covering all edge cases. + + +##### Reviewing the `AndroidManifest` file + +Reviewing the default [App Manifest](https://developer.android.com/guide/topics/manifest/manifest-intro) +found in `AndroidManifest.xml`, +located in `android/app/src/main` +is important, as it holds relevant information regarding the application +that will be shown on the store. +It also defines permissions needed when using the application. +Two important changes include: + +- `application`: editing the `android:label` in the +[application](https://developer.android.com/guide/topics/manifest/application-element) tag will ultimately be the final name of the application. +- `uses-permission`: adding `android.permission.INTERNET` +[permission](https://developer.android.com/guide/topics/manifest/uses-permission-element) +will be needed if the app needs internet access. + + +##### Reviewing the `Gradle` build configuration + +Next up, checking if the [`Gradle build file`](https://developer.android.com/studio/build/#module-level) +located in `android/app` is important for the building phase of the application. +The most important fields to check are: + +- `applicationId`, which specifies the [application ID](https://developer.android.com/build/configure-app-module#set-application-id). +- `minSdkVersion`, specifying the [minimum API level](https://developer.android.com/studio/publish/versioning#minsdk) needed to run the app. +With Flutter, it defaults to `flutter.minSdkVersion`, +though you may have to change this specifically sometimes +if some library requires it. +- `targetSdkVersion`, the target API level the app was designed to run. +Defaults to `flutter.targetSdkVersion`. +- `versionCode`, integer number used as an [internal version number](https://developer.android.com/studio/publish/versioning). +It is used to determine whether one version of the app +is more recent than another. +**It is not shown to users**. +- `versionName`, version number of the app shown to users. +- `compileSdkVersion`, specifying the API level `Gradle` should use to compile the app. +Defaults to `flutter.compileSdkVersion`. From d779502363d7401c3c7366e47938cf64db32c62f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lui=CC=81s=20Arteiro?= Date: Tue, 17 Oct 2023 15:31:42 +0100 Subject: [PATCH 04/38] chore: Add google play instructions. --- deployment.md | 77 +++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 75 insertions(+), 2 deletions(-) diff --git a/deployment.md b/deployment.md index 630a228c..938daf2f 100644 --- a/deployment.md +++ b/deployment.md @@ -61,11 +61,84 @@ as it's easier to setup. What matters here is that we have an account that we can use to publish apps.

- +

+Choose the option. +In our case, +we'll have these requirements. +You'll have to pay a `25 USD` fee in either one. + +

+ +

+ +After clicking on `Continue`, you'll have to create a payment profile +for verification purposes. +This payment profile will also be used to pay the registration fee. + +Click on `Create or select payments profile` +and go through the steps of adding your debit/credit card. +Once that is finished, +you may press `Next`. + +After clicking `Next`, +you will be prompted to fill in your **Public Developer Profile**. + +

+ +

+ +Just fill the requested fields with your e-mail address, +acknowledging sending the information to Google. + +Click `Next`. + +

+ +

+ +Fill out the requested information. +Google will ask you for information regarding prior experience +you may have had developing applications in the Play Store. +It will also ask if you've used other Google Accounts +in the `Google Play` ecosystem (this is just to speed up verification). + +Fill the requested parameters and click `Next`. + +

+ +

+ +In this `Apps` section, +just truthfully answer your app development plans. + +Click `Next`. + +

+ + +

+ +Agree to all the terms, +pay the registration fee and, +upon success, +you will have your very own developer account! 🎉 + +After this, you can access your newly created developer account +in the `Play Console` by clicking the `Go to Play Console` button. + +

+ +

+ +You may be asked to finish setting up your account. +You will need to complete the verification +by sending your legal documents so Google knows it's really you +who's creating the account. + +**You will need to complete this verification to publish apps on `Google Play`**. -// TODO FINISH #### Review your app files From fd3dcd709003cb25e137a7ccac9edd496f9aaa5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lui=CC=81s=20Arteiro?= Date: Tue, 17 Oct 2023 17:27:49 +0100 Subject: [PATCH 05/38] chore: Adding app signings. --- android/app/build.gradle | 21 ++++- deployment.md | 169 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 187 insertions(+), 3 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index 8fb8fe4c..e89e19f1 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -25,6 +25,15 @@ apply plugin: 'com.android.application' apply plugin: 'kotlin-android' apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +// Referencing the keystore. +def keystoreProperties = new Properties() +def keystorePropertiesFile = rootProject.file('key.properties') +if (keystorePropertiesFile.exists()) { + keystoreProperties.load(new FileInputStream(keystorePropertiesFile)) +} + + android { compileSdkVersion flutter.compileSdkVersion ndkVersion flutter.ndkVersion @@ -54,11 +63,17 @@ android { versionName flutterVersionName } + signingConfigs { + release { + keyAlias keystoreProperties['keyAlias'] + keyPassword keystoreProperties['keyPassword'] + storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null + storePassword keystoreProperties['storePassword'] + } + } buildTypes { release { - // TODO: Add your own signing config for the release build. - // Signing with the debug keys for now, so `flutter run --release` works. - signingConfig signingConfigs.debug + signingConfig signingConfigs.release } } } diff --git a/deployment.md b/deployment.md index 938daf2f..e7552201 100644 --- a/deployment.md +++ b/deployment.md @@ -19,8 +19,17 @@ So, let's start! - [Adding a launcher icon](#adding-a-launcher-icon) - [Reviewing the `AndroidManifest` file](#reviewing-the-androidmanifest-file) - [Reviewing the `Gradle` build configuration](#reviewing-the-gradle-build-configuration) + - [1. Signing the application](#1-signing-the-application) + - [Creating an upload keystore](#creating-an-upload-keystore) + - [Reference the keystore from the app](#reference-the-keystore-from-the-app) +> [!WARNING] +> +> This guide assumes you have `Flutter` installed. +> If you don't, please check https://github.com/dwyl/learn-flutter +> for more information. + ## 🤖 Google `PlayStore` Let's start with Google's `PlayStore`! @@ -213,3 +222,163 @@ is more recent than another. - `versionName`, version number of the app shown to users. - `compileSdkVersion`, specifying the API level `Gradle` should use to compile the app. Defaults to `flutter.compileSdkVersion`. + + + +### 1. Signing the application + +To publish on the `Play Store`, +you need to give the app a digital signature. + + +#### Creating an upload keystore + +On `Android`, there are two different signing keys: +- **deployment key** - end-users that download the [`.apk` file](https://en.wikipedia.org/wiki/Apk_(file_format)) +will have this key embedded. +- **upload key** - is used to authenticate the uploaded `.apk` by developers +onto the `Play Store` +and is *re-signed with the deployment key* once in the `Play Store`. + +So let's create our **upload keystore**! +If you have one, skip this step. +If you *don't*, you have two ways of doing this: + +- following the [Android Studio key generation steps](https://developer.android.com/studio/publish/app-signing#sign-apk). +- or running the following commands. + +```shell +keytool -genkey -v -keystore ~/upload-keystore.jks -keyalg RSA \ + -keysize 2048 -validity 10000 -alias upload + +``` + +> [!NOTE] +> +> If you're on Windows, run this in `Powershell`. +> +> ```shell +> keytool -genkey -v -keystore %userprofile%\upload-keystore.jks ^ +> -storetype JKS -keyalg RSA -keysize 2048 -validity 10000 ^ +> -alias upload +> ``` + +You may run into this error when running the command. + +``` +The operation couldn’t be completed. Unable to locate a Java Runtime. +Please visit http://www.java.com for information on installing Java. +``` + +This means that the `Java` binary needed to run the command +is not in your path. +To fix this, run `flutter doctor -v` and locate the path that is printed +after `"Java binary at:"`. +After this, **use this path** and replace `java` with `keytool`. + +```shell +/Applications/Android\ Studio.app/Contents/jre/Contents/Home/bin/keytool +``` + +> [!WARNING] +> +> If your path includes space-separated names, +> such as `Program Files`, use platform-appropriate notation for the names. +> For example, on Mac/Linux use `Program\ Files`, and on Windows use `"Program Files"`. + +Instead of `keytool`, use the path above to run the command. +You will be prompted to create a password (make sure to remember it!) +and will ask you for some information about yourself. + +After this, the keystore should be created +and now it should work 😊. + +Running this command will store the `upload-keystore.jks` file in your home directory. +**Do not check this file into public source control**. +It is meant to be private. + + +#### Reference the keystore from the app + +With the keystore created, +we need to reference it from the app. +Create a file in `android` called `key.properties` +with the following information. + +Fill in the placeholder properties with your own. + +```properties +storePassword= +keyPassword= +keyAlias=upload +storeFile= +``` + +The keystore file location, +as it was previously mentioned, +is by default in your homepage. +Check `/Users//upload-keystore.jks` for it. + +**Do not check this file into source control**. +Add it to your `.ignorefile` if it's not already. + + +Now that we've created our `key.properties` files +with references to our upload keystore, +we need to *use it in our app*. +To do so, +head over to `android/app/build.gradle` and: + +- Add the keystore information from the `key.properties` file +**before the `android` block**. + +```gradle + def keystoreProperties = new Properties() + def keystorePropertiesFile = rootProject.file('key.properties') + if (keystorePropertiesFile.exists()) { + keystoreProperties.load(new FileInputStream(keystorePropertiesFile)) + } + + android { + ... + } +``` + +- Find the `buildTypes` block. + +```gradle + buildTypes { + release { + // TODO: Add your own signing config for the release build. + // Signing with the debug keys for now, + // so `flutter run --release` works. + signingConfig signingConfigs.debug + } + } +``` + +And replace it with the following. + +```gradle + signingConfigs { + release { + keyAlias keystoreProperties['keyAlias'] + keyPassword keystoreProperties['keyPassword'] + storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null + storePassword keystoreProperties['storePassword'] + } + } + buildTypes { + release { + signingConfig signingConfigs.release + } + } +``` + +Congratulations! +Release builds of your app will now be signed automatically! 🥳 + +For good measure, +run `flutter clean` after making these changes. +Some cached builds might linger from before these changes, +so we want to clear that possibility straight away. \ No newline at end of file From 66a1e1de631f664242be56da1d0102612117da0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lui=CC=81s=20Arteiro?= Date: Tue, 17 Oct 2023 21:18:46 +0100 Subject: [PATCH 06/38] chore: Add new rest of sections in Google. --- deployment.md | 157 +++++++++++++++++++++++++++++++++++++++++++++++--- pubspec.yaml | 2 +- 2 files changed, 151 insertions(+), 8 deletions(-) diff --git a/deployment.md b/deployment.md index e7552201..9f2d903f 100644 --- a/deployment.md +++ b/deployment.md @@ -2,7 +2,7 @@ This guide will help you through deploying a `Flutter` application into the two main app stores in the mobile ecosystem: -`iOS AppStore` and `Android PlayStore`. +`iOS AppStore` and `Google Play Store`. Because we are using `Flutter`, the way one builds, packages and ships an application @@ -11,7 +11,7 @@ will differ from the native way. So, let's start! - [Deployment Guide 📩](#deployment-guide-) - - [🤖 Google `PlayStore`](#-google-playstore) + - [🤖 Google `Play Store`](#-google-play-store) - [0. Pre-requisites](#0-pre-requisites) - [Creating a `Google Play` account](#creating-a-google-play-account) - [Review your app files](#review-your-app-files) @@ -22,6 +22,10 @@ So, let's start! - [1. Signing the application](#1-signing-the-application) - [Creating an upload keystore](#creating-an-upload-keystore) - [Reference the keystore from the app](#reference-the-keystore-from-the-app) + - [2. Building app for release](#2-building-app-for-release) + - [Build an `app bundle`](#build-an-app-bundle) + - [Build an `APK`](#build-an-apk) + - [3. Publishing to `Play Store`](#3-publishing-to-play-store) > [!WARNING] @@ -30,9 +34,9 @@ So, let's start! > If you don't, please check https://github.com/dwyl/learn-flutter > for more information. -## 🤖 Google `PlayStore` +## 🤖 Google `Play Store` -Let's start with Google's `PlayStore`! +Let's start with Google's `Play Store`! ### 0. Pre-requisites @@ -201,7 +205,6 @@ Two important changes include: [permission](https://developer.android.com/guide/topics/manifest/uses-permission-element) will be needed if the app needs internet access. - ##### Reviewing the `Gradle` build configuration Next up, checking if the [`Gradle build file`](https://developer.android.com/studio/build/#module-level) @@ -223,7 +226,11 @@ is more recent than another. - `compileSdkVersion`, specifying the API level `Gradle` should use to compile the app. Defaults to `flutter.compileSdkVersion`. - +> [!NOTE] +> +> In `Flutter`, most of these are using default settings from the `Flutter` version. +> In the case of the version names and integers, +> they are fetched from the `pubspec.yaml` file. ### 1. Signing the application @@ -381,4 +388,140 @@ Release builds of your app will now be signed automatically! 🥳 For good measure, run `flutter clean` after making these changes. Some cached builds might linger from before these changes, -so we want to clear that possibility straight away. \ No newline at end of file +so we want to clear that possibility straight away. + + +### 2. Building app for release + +With our signing keystore ready to go, +we can now create **release bundles**. + +At this stage, before creating a release bundle, +you may want to consider [obfuscating your Dart source code](https://docs.flutter.dev/deployment/obfuscate) +to make it difficult to reverse engineer. + +This can bring security benefits, +prevent competitors, hackers or malicious actors from reverse-engineering your app +and safeguard proprietary algorithms or paid features from being copied or used. +It can additionally reduce the size of the Flutter app, +which is always a plus ➕. + +To do this, we only just need to add a couple of flags +to the build command, +and maintain additional files to de-obfuscate stack traces +in case the app crashes. + +> [!NOTE] +> +> For more information on how to de-obfuscate a stack trace, +> check https://docs.flutter.dev/deployment/obfuscate#read-an-obfuscated-stack-trace. +> It will explain the `flutter symbolize` command that is used for this effect. + + +Now can release our app in two formats to later be published to the `Play Store`: + +- **`app bundle`** (recommended). +- **`APK`**. + + +Let's go over each one. + +> [!NOTE] +> +> Before making the bundle release, +> you need to increase the `version` of the app +> in the `pubspec.yaml` file. + + +#### Build an `app bundle` + +If you are keen in knowing *why* releasing `app bundles` is better, +follow https://developer.android.com/guide/app-bundle. +Making long story short, you're deferring APK generation +and signing to Google Play. +They will optimize your app for you for each device, +making this much easier on our side. + +In fact, from August 2021, `Google Play` **requires** apps +to be published in this format. + +Let's create our `app bundle`! + +Go to your project folder, and simply run: + +```shell +flutter build appbundle +``` + +> [!NOTE] +> +> If you want to obfuscate your code, run: +> ```shell +> flutter build appbundle --obfuscate --split-debug-info=// +> ``` + +This will show the output of the `aab` file, +the app bundle. + +Now, if we want to test this bundle tool, +we can do so in two ways: + +- **offline**, by using the [`bundletool`](https://github.com/google/bundletool) command. +After installing this, you will **generate `apk` files which you can run** +to test the application. +For this, simply run `bundletool build-apks --bundle= output=`. +For example, + +```shell +bundletool build-apks --bundle build/app/outputs/bundle/release/app-release.aab --output build_aab_apks/app-release.apks +``` + +This will create a folder `build_aab_apks` with the `.apk` file that you can run on a device to test it. +Now, you can plug in your device to the computer +and run `bundletool install-apks --apks=build_aab_apks/app-release.apks` +(change the location of the `.apks` you've created accordingly). + +- **using `Google Play`**, by uploading the bundle to `Google Play` +to test it. You should use the internal test track, or alpha/beta channels +to test the bundle before production. +For this, simply follow the instructions in https://developer.android.com/studio/publish/upload-bundle. + + +#### Build an `APK` + +Although `app bundles` are required to publish to the `Play Store`, +you may want to publish your app in other stores, +which may not yet support `app bundles`. +For this, just release the `APK` for each [target ABI](https://en.wikipedia.org/wiki/Application_binary_interface). + +Go to your project folder, and simply run: + +```shell +flutter build apk --split-per-abi +``` + +> [!NOTE] +> +> If you want to obfuscate your code, run: +> ```shell +> flutter build apk --split-per-abi --obfuscate --split-debug-info=// +> ``` + +This command will create **three `APK` files** +in `/build/app/outputs/apk/release/`. + +To test this `APK`, it's quite easy. +Similarly to before, +connect your Android device to your computer, +go to your project folder +and run `flutter install`. + + +### 3. Publishing to `Play Store` + +Now that we have our `app bundle` ready, +we ought to deploy it to `Play Store`. +For a more in-depth tutorial, please check https://developer.android.com/distribute. + + +//TODO add steps after getting verified diff --git a/pubspec.yaml b/pubspec.yaml index e6c73449..1a4aa42b 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: dwyl_app description: Clear your mind. Organise your life. Ignore distractions. Focus on what matters. publish_to: 'none' -version: 0.1.0 +version: 0.0.1 homepage: https://github.com/dwyl/app repository: https://github.com/dwyl/app issue_tracker: https://github.com/dwyl/app/issues From 19bce03bc6ec63bd55bec3c220fdfc58394fddd9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lui=CC=81s=20Arteiro?= Date: Wed, 18 Oct 2023 10:17:23 +0100 Subject: [PATCH 07/38] chore: Beginning Apple section. --- deployment.md | 118 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 116 insertions(+), 2 deletions(-) diff --git a/deployment.md b/deployment.md index 9f2d903f..9a82040c 100644 --- a/deployment.md +++ b/deployment.md @@ -12,7 +12,7 @@ So, let's start! - [Deployment Guide 📩](#deployment-guide-) - [🤖 Google `Play Store`](#-google-play-store) - - [0. Pre-requisites](#0-pre-requisites) + - [0. Prerequisites](#0-prerequisites) - [Creating a `Google Play` account](#creating-a-google-play-account) - [Review your app files](#review-your-app-files) - [Setting up a splash screen](#setting-up-a-splash-screen) @@ -26,6 +26,12 @@ So, let's start! - [Build an `app bundle`](#build-an-app-bundle) - [Build an `APK`](#build-an-apk) - [3. Publishing to `Play Store`](#3-publishing-to-play-store) + - [4. *(Optional)* ⛓️ Automating deployment with Github Actions](#4-optional-️-automating-deployment-with-github-actions) + - [🍏 Apple `App Store`](#-apple-app-store) + - [0. Prerequisites](#0-prerequisites-1) + - [Install X-Code](#install-x-code) + - [Ensure app adheres to the guidelines](#ensure-app-adheres-to-the-guidelines) + - [Make sure you're enrolled in the `Apple Developer Program`](#make-sure-youre-enrolled-in-the-apple-developer-program) > [!WARNING] @@ -39,7 +45,7 @@ So, let's start! Let's start with Google's `Play Store`! -### 0. Pre-requisites +### 0. Prerequisites Before we start our guide, we are going to make sure everything is correctly setup @@ -525,3 +531,111 @@ For a more in-depth tutorial, please check https://developer.android.com/distrib //TODO add steps after getting verified + + +### 4. *(Optional)* ⛓️ Automating deployment with Github Actions + +Now that we know how to build, +bundle and release our app to the public, +it's time to learn how to automate this process! + +// TODO add section to create Github Actions to deploy to `Play Store` + + +## 🍏 Apple `App Store` + +Now that we know how to release our app in Google's `Play Store`, +it's time to go to the other side +and get our app available to iPhone users! + + +### 0. Prerequisites + +Similarly to before, +we need to make sure some prerequisites are fulfilled +in order to publish our app. + +#### Install X-Code + +If you don't already have `XCode` installed, +open your `AppStore`, search for "XCode" and press `Install`. +It's that easy. + +

+ +

+ + +#### Ensure app adheres to the guidelines + +You need to make sure the app follow's `App Store`'s guidelines. +If not, it *won't get published*. + +You can check the guidelines in https://developer.apple.com/app-store/review/guidelines/. + + +#### Make sure you're enrolled in the `Apple Developer Program` + +So you can publish apps, your Apple account +needs to be part of the `Apple Developer Program`. + +Chances are you're already enrolled. +However, if you're not, +please visit https://developer.apple.com/programs/enroll/. + +

+ +

+ +Click on `Start Enrollment` and fill in your `Apple ID` account information. + +

+ +

+ +After logging in with your account, +you will be prompted with the Apple Developer Agreement. + +

+ +

+ +After agreeing, +you will be logged in into your Apple Developer account. + +

+ +

+ +Now click on `Enroll Now`. +You will be shown the option +to adhere to the Apple Developer Program +through their app or through the web. +In our case, let's choose the latter. + +

+ +

+ +You'll have to go through filling your information, +selecting the entity type (whether you're an individual or an organization) +and agree to the legal terms. + +

+ + + +

+ +After doing those, you'll need to pay a fee, +which you can renew annually or not. + +

+ +

+ +After completing this purchase, +you'll be ready to start publishing your own applications +in the Apple ecosystem! + +Great job! 👏 \ No newline at end of file From 90a08035b891c52d13fec1f070bc69571fcdd71c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lui=CC=81s=20Arteiro?= Date: Wed, 18 Oct 2023 12:24:43 +0100 Subject: [PATCH 08/38] fix: Fixing service_worker.js patch file. --- build_tools/web/flutter_service_worker.js.patch | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/build_tools/web/flutter_service_worker.js.patch b/build_tools/web/flutter_service_worker.js.patch index 3f37e8d8..d4d82579 100644 --- a/build_tools/web/flutter_service_worker.js.patch +++ b/build_tools/web/flutter_service_worker.js.patch @@ -1,17 +1,17 @@ Patched flutter_service_worker.js splits up the loading of files so they are parallel. see: https://github.com/dwyl/app/issues/326#issuecomment-1478314967 ---- flutter_service_worker.js 2023-03-24 19:00:29 -+++ flutter_service_worker2.js 2023-03-24 19:04:42 -@@ -28,22 +28,11 @@ - +--- flutter_service_worker.js 2023-10-18 11:49:35 ++++ flutter_service_worker_new.js 2023-10-18 11:56:09 +@@ -55,21 +55,9 @@ + "canvaskit/skwasm.worker.js": "51253d3321b11ddb8d73fa8aa87d3b15"}; // The application shell files that are downloaded before a service worker can // start. --const CORE = [ -- "main.dart.js", +-const CORE = ["main.dart.js", -"index.html", -"assets/AssetManifest.json", -"assets/FontManifest.json"]; + -// During install, the TEMP cache is populated with the application shell files. -self.addEventListener("install", (event) => { - self.skipWaiting(); From a1ea765a1d5a70c45cd8b0f4a3d0f6e78e760038 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lui=CC=81s=20Arteiro?= Date: Wed, 18 Oct 2023 12:33:32 +0100 Subject: [PATCH 09/38] chore: Temporarily checking if deploy works. --- .github/workflows/deploy.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 49b31a3d..1f10bf5d 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -2,6 +2,8 @@ name: Deploy to Github Pages on: push: branches: [ main ] + pull_request: + branches: [ "main" ] permissions: contents: write From cf9e1f975970e4efab0fbcf9d5a6e2d1b23870ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lui=CC=81s=20Arteiro?= Date: Wed, 18 Oct 2023 13:02:47 +0100 Subject: [PATCH 10/38] chore: Reverting last commit. --- .github/workflows/deploy.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 1f10bf5d..49b31a3d 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -2,8 +2,6 @@ name: Deploy to Github Pages on: push: branches: [ main ] - pull_request: - branches: [ "main" ] permissions: contents: write From 81e57d55c67c4c2f30c60cc74b19f3d3f1e69364 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lui=CC=81s=20Arteiro?= Date: Wed, 18 Oct 2023 13:05:10 +0100 Subject: [PATCH 11/38] chore: Refactoring workflows. #344 --- .github/workflows/build.yml | 79 +++++++++++++++++++ .github/workflows/ci.yml | 79 ------------------- .../workflows/{deploy.yml => deploy_web.yml} | 2 +- 3 files changed, 80 insertions(+), 80 deletions(-) create mode 100644 .github/workflows/build.yml delete mode 100644 .github/workflows/ci.yml rename .github/workflows/{deploy.yml => deploy_web.yml} (96%) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 00000000..59d17182 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,79 @@ +name: Build & Test + +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + +jobs: + build: + runs-on: macos-latest + + steps: + - uses: actions/checkout@v3 + + # Installing Flutter because it's easier to generate .lcov files for test coverage + - name: Install Flutter + uses: subosito/flutter-action@v2 + with: + channel: 'stable' + + - name: Install dependencies + run: flutter pub get + + - name: Flutter analyze + run: flutter analyze + + # Your project will need to have tests in test/ and a dependency on + # package:test for this step to succeed. Note that Flutter projects will + # want to change this to 'flutter test'. + - name: Run tests + run: flutter test --coverage + + - uses: codecov/codecov-action@v3 + with: + files: coverage/lcov.info + verbose: true # optional (default = false) + + + # Continuous Deployment to Fly.io + # https://fly.io/docs/app-guides/continuous-deployment-with-github-actions/ + # flutter_deploy: + # name: Deploy Flutter app + # runs-on: ubuntu-latest +# + # needs: [build] + # # https://stackoverflow.com/questions/58139406/only-run-job-on-specific-branch-with-github-actions + # if: github.ref == 'refs/heads/main' + # env: + # FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }} + # steps: + # - uses: actions/checkout@v3 +# + # - name: Install Flutter + # uses: subosito/flutter-action@v2 + # with: + # channel: 'stable' +# + # # Your project will need to have tests in test/ and a dependency on + # # package:test for this step to succeed. Note that Flutter projects will + # # want to change this to 'flutter test'. + # - name: Check build + # run: flutter analyze +# + # - name: Create release build + # # github.com/dwyl/app/issues/315#issuecomment-1443747737 + # run: flutter build web --release --web-renderer html + # +# + # # See https://github.com/dwyl/app/issues/326. + # # This will fetch files concurrently needed for the app and not wait for `flutter.js` to load + # - name: Run post-build script to download files concurrently + # run: | + # chmod +x ./build_tools/patch_web.sh + # sh ./build_tools/patch_web.sh --ignore-whitespace +# + # - uses: superfly/flyctl-actions@1.1 + # with: + # args: "deploy" \ No newline at end of file diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml deleted file mode 100644 index ed8021b2..00000000 --- a/.github/workflows/ci.yml +++ /dev/null @@ -1,79 +0,0 @@ -name: build - -on: - push: - branches: [ "main" ] - pull_request: - branches: [ "main" ] - -jobs: - build: - runs-on: macos-latest - - steps: - - uses: actions/checkout@v3 - - # Installing Flutter because it's easier to generate .lcov files for test coverage - - name: Install Flutter - uses: subosito/flutter-action@v2 - with: - channel: 'stable' - - - name: Install dependencies - run: flutter pub get - - - name: Flutter analyze - run: flutter analyze - - # Your project will need to have tests in test/ and a dependency on - # package:test for this step to succeed. Note that Flutter projects will - # want to change this to 'flutter test'. - - name: Run tests - run: flutter test --coverage - - - uses: codecov/codecov-action@v3 - with: - files: coverage/lcov.info - verbose: true # optional (default = false) - - - # Continuous Deployment to Fly.io - # https://fly.io/docs/app-guides/continuous-deployment-with-github-actions/ - flutter_deploy: - name: Deploy Flutter app - runs-on: ubuntu-latest - - needs: [build] - # https://stackoverflow.com/questions/58139406/only-run-job-on-specific-branch-with-github-actions - if: github.ref == 'refs/heads/main' - env: - FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }} - steps: - - uses: actions/checkout@v3 - - - name: Install Flutter - uses: subosito/flutter-action@v2 - with: - channel: 'stable' - - # Your project will need to have tests in test/ and a dependency on - # package:test for this step to succeed. Note that Flutter projects will - # want to change this to 'flutter test'. - - name: Check build - run: flutter analyze - - - name: Create release build - # github.com/dwyl/app/issues/315#issuecomment-1443747737 - run: flutter build web --release --web-renderer html - - - # See https://github.com/dwyl/app/issues/326. - # This will fetch files concurrently needed for the app and not wait for `flutter.js` to load - - name: Run post-build script to download files concurrently - run: | - chmod +x ./build_tools/patch_web.sh - sh ./build_tools/patch_web.sh --ignore-whitespace - - - uses: superfly/flyctl-actions@1.1 - with: - args: "deploy" \ No newline at end of file diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy_web.yml similarity index 96% rename from .github/workflows/deploy.yml rename to .github/workflows/deploy_web.yml index 49b31a3d..d7d774f9 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy_web.yml @@ -1,4 +1,4 @@ -name: Deploy to Github Pages +name: Deploy Web (GitHub Pages) on: push: branches: [ main ] From 73ff7848e8d196e872c3f712464c3bdecfdf51e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lui=CC=81s=20Arteiro?= Date: Wed, 18 Oct 2023 14:04:18 +0100 Subject: [PATCH 12/38] chore: Only running `deploy_web` after build succeeds. --- .github/workflows/build.yml | 5 ++--- .github/workflows/deploy_web.yml | 16 ++++++++++++---- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 59d17182..0bf839d1 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -26,15 +26,14 @@ jobs: run: flutter analyze # Your project will need to have tests in test/ and a dependency on - # package:test for this step to succeed. Note that Flutter projects will - # want to change this to 'flutter test'. + # package:test for this step to succeed. - name: Run tests run: flutter test --coverage - uses: codecov/codecov-action@v3 with: files: coverage/lcov.info - verbose: true # optional (default = false) + verbose: true # Continuous Deployment to Fly.io diff --git a/.github/workflows/deploy_web.yml b/.github/workflows/deploy_web.yml index d7d774f9..af7db60a 100644 --- a/.github/workflows/deploy_web.yml +++ b/.github/workflows/deploy_web.yml @@ -1,10 +1,18 @@ name: Deploy Web (GitHub Pages) on: + # Only trigger, when the "build" workflow succeeded + workflow_run: + workflows: ["CI build"] + types: + - completed + + # Only trigger, when pushing into the `main` branch push: - branches: [ main ] + branches: [main] permissions: contents: write + jobs: build-and-deploy: runs-on: ubuntu-latest @@ -12,17 +20,17 @@ jobs: steps: - name: Checkout code uses: actions/checkout@v3 - + - name: Install Flutter uses: subosito/flutter-action@v2 with: - channel: 'stable' + channel: "stable" - name: Install dependencies run: flutter pub get # See stackoverflow.com/questions/74164386/flutter-web-shows-blank-page-on-github-deployment - - name: Install and Build + - name: Install and Build run: flutter build web --release --web-renderer html - name: Deploy to Github Pages From cb079e6fea6e4e455a3b1d40533eff49b114a5c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lui=CC=81s=20Arteiro?= Date: Wed, 18 Oct 2023 15:48:52 +0100 Subject: [PATCH 13/38] chore: Starting out Android deploy. --- .github/workflows/build.yml | 4 +-- .github/workflows/deploy_android.yml | 41 ++++++++++++++++++++++++++++ .github/workflows/deploy_web.yml | 7 +++-- 3 files changed, 47 insertions(+), 5 deletions(-) create mode 100644 .github/workflows/deploy_android.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 0bf839d1..fb993699 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -13,11 +13,11 @@ jobs: steps: - uses: actions/checkout@v3 - # Installing Flutter because it's easier to generate .lcov files for test coverage - name: Install Flutter uses: subosito/flutter-action@v2 with: - channel: 'stable' + flutter-version: "3.13.5" + channel: "stable" - name: Install dependencies run: flutter pub get diff --git a/.github/workflows/deploy_android.yml b/.github/workflows/deploy_android.yml new file mode 100644 index 00000000..6abb11f6 --- /dev/null +++ b/.github/workflows/deploy_android.yml @@ -0,0 +1,41 @@ +name: Deploy Android (Google Play Store) +on: + # Only trigger, when the "build" workflow succeeded (only works in the Master Branch) + workflow_run: + workflows: ["Build & Test"] + types: + - completed + + # Only trigger, when pushing into the `main` branch + push: + branches: [main] + +permissions: + contents: write + +jobs: + build-and-deploy_android: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + # Needed to base64 decode the upload keystore + - name: ⚙️ Setup Java + uses: actions/setup-java@v3 + with: + distribution: 'zulu' + java-version: "12.x" + cache: 'gradle' + id: java + + # Needed to run Flutter-based commands + - name: Install Flutter + uses: subosito/flutter-action@v2 + with: + flutter-version: "3.13.5" + channel: "stable" + + - name: Install dependencies + run: flutter pub get diff --git a/.github/workflows/deploy_web.yml b/.github/workflows/deploy_web.yml index af7db60a..116ebac0 100644 --- a/.github/workflows/deploy_web.yml +++ b/.github/workflows/deploy_web.yml @@ -1,8 +1,8 @@ name: Deploy Web (GitHub Pages) on: - # Only trigger, when the "build" workflow succeeded + # Only trigger, when the "build" workflow succeeded (only works in the Master Branch) workflow_run: - workflows: ["CI build"] + workflows: ["Build & Test"] types: - completed @@ -14,7 +14,7 @@ permissions: contents: write jobs: - build-and-deploy: + build-and-deploy_web: runs-on: ubuntu-latest steps: @@ -24,6 +24,7 @@ jobs: - name: Install Flutter uses: subosito/flutter-action@v2 with: + flutter-version: "3.13.5" channel: "stable" - name: Install dependencies From a0200e4a9b560dd616acee9e176a6fbf6fc054ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lui=CC=81s=20Arteiro?= Date: Wed, 18 Oct 2023 17:32:03 +0100 Subject: [PATCH 14/38] chore: Creating bundle. #342 --- .github/workflows/deploy_android.yml | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/.github/workflows/deploy_android.yml b/.github/workflows/deploy_android.yml index 6abb11f6..d1b1bd62 100644 --- a/.github/workflows/deploy_android.yml +++ b/.github/workflows/deploy_android.yml @@ -18,7 +18,7 @@ jobs: runs-on: ubuntu-latest steps: - - name: Checkout code + - name: ⬇️ Checkout code uses: actions/checkout@v3 # Needed to base64 decode the upload keystore @@ -31,11 +31,30 @@ jobs: id: java # Needed to run Flutter-based commands - - name: Install Flutter + - name: 🐦 Install Flutter uses: subosito/flutter-action@v2 with: flutter-version: "3.13.5" channel: "stable" - - name: Install dependencies + - name: 📚 Install dependencies run: flutter pub get + + - name: 🔒 Retrieve base64 keystore and decode it to a file + env: + KEYSTORE_BASE64: ${{ secrets.KEYSTORE_FILE_BASE64 }} + run: echo $KEYSTORE_BASE64 | base64 --decode > "${{ github.workspace }}/decoded_android-keystore.jks" + + - name: 📝🔐 Create keystore.properties file + env: + KEYSTORE_PROPERTIES_PATH: ${{ github.workspace }}/app/android/keystore.properties + run: | + echo 'StoreFile=${{ github.workspace }}/decoded_android-keystore.jks' > $KEYSTORE_PROPERTIES_PATH + echo 'KeyAlias=${{ secrets.KEYSTORE_KEY_ALIAS }}' >> $KEYSTORE_PROPERTIES_PATH + echo 'StorePassword=${{ secrets.KEYSTORE_PASSWORD }}' >> $KEYSTORE_PROPERTIES_PATH + echo 'KeyPassword=${{ secrets.KEYSTORE_KEY_PASSWORD }}' >> $KEYSTORE_PROPERTIES_PATH + + - name: 🤖📦 Create Android appbundle release + run: | + flutter build appbundle \ + --obfuscate From df19266acc0efee762abce8b46666a9c62374821 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lui=CC=81s=20Arteiro?= Date: Wed, 18 Oct 2023 17:32:41 +0100 Subject: [PATCH 15/38] chore: Temporarily checking if android works. #342 --- .github/workflows/deploy_android.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/deploy_android.yml b/.github/workflows/deploy_android.yml index d1b1bd62..86097ed8 100644 --- a/.github/workflows/deploy_android.yml +++ b/.github/workflows/deploy_android.yml @@ -9,6 +9,8 @@ on: # Only trigger, when pushing into the `main` branch push: branches: [main] + pull_request: + branches: [ "main" ] permissions: contents: write From ad96f9e829ecf17e57d382ff73ef62082a9ec9bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lui=CC=81s=20Arteiro?= Date: Wed, 18 Oct 2023 17:57:42 +0100 Subject: [PATCH 16/38] chore: Trying to fix creating keystore file. #342 --- .github/workflows/deploy_android.yml | 7 +++++-- android/app/build.gradle | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/.github/workflows/deploy_android.yml b/.github/workflows/deploy_android.yml index 86097ed8..2df54c47 100644 --- a/.github/workflows/deploy_android.yml +++ b/.github/workflows/deploy_android.yml @@ -47,10 +47,13 @@ jobs: KEYSTORE_BASE64: ${{ secrets.KEYSTORE_FILE_BASE64 }} run: echo $KEYSTORE_BASE64 | base64 --decode > "${{ github.workspace }}/decoded_android-keystore.jks" - - name: 📝🔐 Create keystore.properties file + # Creates keystore file. + # Needs to be the same as the one defined in `android/app/build.gradle` + - name: 📝🔐 Create key.properties file env: - KEYSTORE_PROPERTIES_PATH: ${{ github.workspace }}/app/android/keystore.properties + KEYSTORE_PROPERTIES_PATH: ${{ github.workspace }}/app/android/key.properties run: | + touch $KEYSTORE_PROPERTIES_PATH echo 'StoreFile=${{ github.workspace }}/decoded_android-keystore.jks' > $KEYSTORE_PROPERTIES_PATH echo 'KeyAlias=${{ secrets.KEYSTORE_KEY_ALIAS }}' >> $KEYSTORE_PROPERTIES_PATH echo 'StorePassword=${{ secrets.KEYSTORE_PASSWORD }}' >> $KEYSTORE_PROPERTIES_PATH diff --git a/android/app/build.gradle b/android/app/build.gradle index e89e19f1..4dfee349 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -26,7 +26,7 @@ apply plugin: 'kotlin-android' apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" -// Referencing the keystore. +// Referencing the keystore def keystoreProperties = new Properties() def keystorePropertiesFile = rootProject.file('key.properties') if (keystorePropertiesFile.exists()) { From 02ed0eb32024ef8f529acdea796a79e15002f7dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lui=CC=81s=20Arteiro?= Date: Wed, 18 Oct 2023 18:00:31 +0100 Subject: [PATCH 17/38] chore: Trying to fix. --- .github/workflows/deploy_android.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/deploy_android.yml b/.github/workflows/deploy_android.yml index 2df54c47..2b3215cb 100644 --- a/.github/workflows/deploy_android.yml +++ b/.github/workflows/deploy_android.yml @@ -51,7 +51,7 @@ jobs: # Needs to be the same as the one defined in `android/app/build.gradle` - name: 📝🔐 Create key.properties file env: - KEYSTORE_PROPERTIES_PATH: ${{ github.workspace }}/app/android/key.properties + KEYSTORE_PROPERTIES_PATH: ${{ github.workspace }}/android/key.properties run: | touch $KEYSTORE_PROPERTIES_PATH echo 'StoreFile=${{ github.workspace }}/decoded_android-keystore.jks' > $KEYSTORE_PROPERTIES_PATH From 85f041c1c982959ed4bbd2baa92a202482cdc5a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lui=CC=81s=20Arteiro?= Date: Wed, 18 Oct 2023 18:12:16 +0100 Subject: [PATCH 18/38] chore: Debugging info folder. #342 --- .github/workflows/deploy_android.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/deploy_android.yml b/.github/workflows/deploy_android.yml index 2b3215cb..a2dc6dd4 100644 --- a/.github/workflows/deploy_android.yml +++ b/.github/workflows/deploy_android.yml @@ -62,4 +62,5 @@ jobs: - name: 🤖📦 Create Android appbundle release run: | flutter build appbundle \ - --obfuscate + --obfuscate \ + --split-debug-info=${{ github.workspace }}/debug_info From 2baae5dbda3f699cb83eba1065d13e091e373cd2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lui=CC=81s=20Arteiro?= Date: Wed, 18 Oct 2023 18:59:54 +0100 Subject: [PATCH 19/38] chore: Check key properties keystore file. #342 --- .github/workflows/deploy_android.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/workflows/deploy_android.yml b/.github/workflows/deploy_android.yml index a2dc6dd4..6b1f1ba2 100644 --- a/.github/workflows/deploy_android.yml +++ b/.github/workflows/deploy_android.yml @@ -9,6 +9,8 @@ on: # Only trigger, when pushing into the `main` branch push: branches: [main] + + # DELETE THIS pull_request: branches: [ "main" ] @@ -59,6 +61,12 @@ jobs: echo 'StorePassword=${{ secrets.KEYSTORE_PASSWORD }}' >> $KEYSTORE_PROPERTIES_PATH echo 'KeyPassword=${{ secrets.KEYSTORE_KEY_PASSWORD }}' >> $KEYSTORE_PROPERTIES_PATH + # DELETE THIS + - name: Cat + env: + KEYSTORE_PROPERTIES_PATH: ${{ github.workspace }}/android/key.properties + run: cat $KEYSTORE_PROPERTIES_PATH + - name: 🤖📦 Create Android appbundle release run: | flutter build appbundle \ From 6d73625afd9dc7fdba24435255d95a109eca2ff3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lui=CC=81s=20Arteiro?= Date: Wed, 18 Oct 2023 19:10:44 +0100 Subject: [PATCH 20/38] chore: Checking the location of key.properties. --- .github/workflows/deploy_android.yml | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/.github/workflows/deploy_android.yml b/.github/workflows/deploy_android.yml index 6b1f1ba2..6faeab96 100644 --- a/.github/workflows/deploy_android.yml +++ b/.github/workflows/deploy_android.yml @@ -60,13 +60,11 @@ jobs: echo 'KeyAlias=${{ secrets.KEYSTORE_KEY_ALIAS }}' >> $KEYSTORE_PROPERTIES_PATH echo 'StorePassword=${{ secrets.KEYSTORE_PASSWORD }}' >> $KEYSTORE_PROPERTIES_PATH echo 'KeyPassword=${{ secrets.KEYSTORE_KEY_PASSWORD }}' >> $KEYSTORE_PROPERTIES_PATH - - # DELETE THIS - - name: Cat - env: - KEYSTORE_PROPERTIES_PATH: ${{ github.workspace }}/android/key.properties - run: cat $KEYSTORE_PROPERTIES_PATH + # DELETE THIS + - name: ls + run: ls ${{ github.workspace }}/android + - name: 🤖📦 Create Android appbundle release run: | flutter build appbundle \ From 3694416e3cde3cdde7731012306ad1304ec9af5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lui=CC=81s=20Arteiro?= Date: Wed, 18 Oct 2023 19:18:06 +0100 Subject: [PATCH 21/38] chore: Checking decoded android keystore location --- .github/workflows/deploy_android.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/deploy_android.yml b/.github/workflows/deploy_android.yml index 6faeab96..d277a771 100644 --- a/.github/workflows/deploy_android.yml +++ b/.github/workflows/deploy_android.yml @@ -63,7 +63,7 @@ jobs: # DELETE THIS - name: ls - run: ls ${{ github.workspace }}/android + run: ls ${{ github.workspace }}/ - name: 🤖📦 Create Android appbundle release run: | From cd4169377624ef73dbd2d6737c98e9ae8ce208a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lui=CC=81s=20Arteiro?= Date: Wed, 18 Oct 2023 19:32:53 +0100 Subject: [PATCH 22/38] fix: Hopefully fixing the signing error. #342 --- .github/workflows/deploy_android.yml | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/.github/workflows/deploy_android.yml b/.github/workflows/deploy_android.yml index d277a771..2501f74b 100644 --- a/.github/workflows/deploy_android.yml +++ b/.github/workflows/deploy_android.yml @@ -56,17 +56,14 @@ jobs: KEYSTORE_PROPERTIES_PATH: ${{ github.workspace }}/android/key.properties run: | touch $KEYSTORE_PROPERTIES_PATH - echo 'StoreFile=${{ github.workspace }}/decoded_android-keystore.jks' > $KEYSTORE_PROPERTIES_PATH - echo 'KeyAlias=${{ secrets.KEYSTORE_KEY_ALIAS }}' >> $KEYSTORE_PROPERTIES_PATH - echo 'StorePassword=${{ secrets.KEYSTORE_PASSWORD }}' >> $KEYSTORE_PROPERTIES_PATH - echo 'KeyPassword=${{ secrets.KEYSTORE_KEY_PASSWORD }}' >> $KEYSTORE_PROPERTIES_PATH + echo 'storeFile=${{ github.workspace }}/decoded_android-keystore.jks' > $KEYSTORE_PROPERTIES_PATH + echo 'keyAlias=${{ secrets.KEYSTORE_KEY_ALIAS }}' >> $KEYSTORE_PROPERTIES_PATH + echo 'storePassword=${{ secrets.KEYSTORE_PASSWORD }}' >> $KEYSTORE_PROPERTIES_PATH + echo 'keyPassword=${{ secrets.KEYSTORE_KEY_PASSWORD }}' >> $KEYSTORE_PROPERTIES_PATH - # DELETE THIS - - name: ls - run: ls ${{ github.workspace }}/ - name: 🤖📦 Create Android appbundle release run: | flutter build appbundle \ --obfuscate \ - --split-debug-info=${{ github.workspace }}/debug_info + --split-debug-info=${{ github.workspace }}/debug_info \ No newline at end of file From dc8d75a07dfeb1ee9dad101a1338577c59f077b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lui=CC=81s=20Arteiro?= Date: Mon, 23 Oct 2023 17:08:14 +0100 Subject: [PATCH 23/38] chore: Testing if deploying works on Android. #342 --- .github/workflows/deploy_android.yml | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/.github/workflows/deploy_android.yml b/.github/workflows/deploy_android.yml index 2501f74b..573063c5 100644 --- a/.github/workflows/deploy_android.yml +++ b/.github/workflows/deploy_android.yml @@ -62,8 +62,20 @@ jobs: echo 'keyPassword=${{ secrets.KEYSTORE_KEY_PASSWORD }}' >> $KEYSTORE_PROPERTIES_PATH - - name: 🤖📦 Create Android appbundle release + - name: 📦 Create Android appbundle release run: | flutter build appbundle \ --obfuscate \ - --split-debug-info=${{ github.workspace }}/debug_info \ No newline at end of file + --split-debug-info=${{ github.workspace }}/debug_info + + - name: 🚀 Upload Android Release to Play Store + uses: r0adkll/upload-google-play@v1.1.2 + with: + # MUST match the package name defined in `android/app/build.gradle` + packageName: "com.dwyl.app" + + # Can be 'alpha'/'beta'/'internal'/'production' + track: production + + releaseFiles: ${{ github.workspace }}/build/app/outputs/bundle/release/app-release.aab + serviceAccountJsonPlainText: "${{ secrets.GOOGLE_PLAY_SERVICE_ACCOUNT_KEY_JSON }}" \ No newline at end of file From ea4c71077fde4aed025c1c0a0813e4feb23e9a77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lui=CC=81s=20Arteiro?= Date: Mon, 23 Oct 2023 19:35:55 +0100 Subject: [PATCH 24/38] fix: Making worflow only work on `main`. --- .github/workflows/deploy_android.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/deploy_android.yml b/.github/workflows/deploy_android.yml index 573063c5..90360e40 100644 --- a/.github/workflows/deploy_android.yml +++ b/.github/workflows/deploy_android.yml @@ -11,8 +11,8 @@ on: branches: [main] # DELETE THIS - pull_request: - branches: [ "main" ] + #pull_request: + # branches: [ "main" ] permissions: contents: write @@ -72,10 +72,10 @@ jobs: uses: r0adkll/upload-google-play@v1.1.2 with: # MUST match the package name defined in `android/app/build.gradle` - packageName: "com.dwyl.app" + packageName: com.dwyl.app # Can be 'alpha'/'beta'/'internal'/'production' track: production - + releaseFiles: ${{ github.workspace }}/build/app/outputs/bundle/release/app-release.aab serviceAccountJsonPlainText: "${{ secrets.GOOGLE_PLAY_SERVICE_ACCOUNT_KEY_JSON }}" \ No newline at end of file From d6e6a16bea27e94244198be2c8c8bf61f95bd690 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lui=CC=81s=20Arteiro?= Date: Mon, 23 Oct 2023 20:44:32 +0100 Subject: [PATCH 25/38] chore: Add section on pre-requisites for Android release roll out. #342 --- deployment.md | 365 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 364 insertions(+), 1 deletion(-) diff --git a/deployment.md b/deployment.md index 9a82040c..59922840 100644 --- a/deployment.md +++ b/deployment.md @@ -27,6 +27,14 @@ So, let's start! - [Build an `APK`](#build-an-apk) - [3. Publishing to `Play Store`](#3-publishing-to-play-store) - [4. *(Optional)* ⛓️ Automating deployment with Github Actions](#4-optional-️-automating-deployment-with-github-actions) + - [Pre-requisites](#pre-requisites) + - [Create app inside Google Play and set it up](#create-app-inside-google-play-and-set-it-up) + - [Create a service account and connect it to our app](#create-a-service-account-and-connect-it-to-our-app) + - [First manual release of app](#first-manual-release-of-app) + - [Keystore file](#keystore-file) + - [Gradle file](#gradle-file) + - [`Github` secrets check-up](#github-secrets-check-up) + - [Implementing our workflow file](#implementing-our-workflow-file) - [🍏 Apple `App Store`](#-apple-app-store) - [0. Prerequisites](#0-prerequisites-1) - [Install X-Code](#install-x-code) @@ -539,7 +547,362 @@ Now that we know how to build, bundle and release our app to the public, it's time to learn how to automate this process! -// TODO add section to create Github Actions to deploy to `Play Store` +Ideally, you will want *at least* two separate environments +when deploying your application. +Many teams work with three different branches/environments +during the development cycle of any application: + +- `production`: the production version of the app. +It's the stable version of the application that is shown to the end-client. +- [`UAT`](https://uit.stanford.edu/pmo/UAT): also known as "staging". +Can be thought out as a "pre-production" environment that is meant +to test the application with a small group of people +before being shipped into the `production` branch/env. +- `dev`: branch for the development. +Only accessible for developers and will not affect any real data +from real clients. + + +Therefore, you **should employ different workflows and builds for each env**. +You should have a `prod`, `UAT` and `dev` version of your application. + +However, for sake of brevity and simplicity, +we'll show you a way of automating the workflow +**only for one branch** +(in this case, we'll consider it to be the `prod`/`main` branch). + + +#### Pre-requisites + +Before proceeding with creating our own Github Actions workflow file, +we need to sort some pre-requisites +that are **mandatory** in order for everything to work. + +Let's go through them right now. + + +##### Create app inside Google Play and set it up + +Firstly, you need to create an app project in your +`Google Play Console` account. + +

+ +

+ +Go to https://console.cloud.google.com/home/dashboard, +head to `All Apps` section to the left +and click on the **`Create app`** button. + +

+ +

+ +Follow through the instructions in the page and click on +`Create app` once you're finished. +You will create a new **app project**, +with its own dashboard and settings. + +You will be redirected to the `Dashboard` page +of your newly created app, like shown in the picture below. + +

+ +

+ +You will see that, in order to be able to access some features +shown in the page, +you will have to first **set the app**. +This means giving information about the application, +what it does, who it is meant for, and a myriad of other information. + +You will need to go through **each required option** +and fill the information. + +Like in the picture above, +you'll want to have all the steps completed in order to continue. +For each one, you'll have a button redirecting you +to a specific page where you'll fill out the requested information. + +After completing all of these steps, +you will be cleared to continue! 🥳 + + +##### Create a service account and connect it to our app + +Now that we've set everything up in our app, +we will need to create a [**service account**](https://cloud.google.com/iam/docs/service-account-overview). +A service account will be the agent that will use the `Google Play API` +to upload new releases of our app. + +Let's create this account and add it to our account. + +First, we are going to head over to **`Google Cloud Console`** +and create a new project. +Head over to https://console.cloud.google.com/projectcreate +and create your own project. + +

+ +

+ +After that, we need to **enable the API** +in our `Google Cloud` project we've just created. +For this, go to https://console.developers.google.com/apis/api/androidpublisher.googleapis.com/, +choose the project and enable `Google Play Developer API`. + +

+ +

+ + +Awesome! 👏 + +Now we are ready to *create a service account*. +For this, head over to +https://console.cloud.google.com/iam-admin/serviceaccounts, +and select your project. +You are now in the `Service Accounts` tab. + +Click on `Create service account` and follow the steps. + +

+ + +

+ +After these, you will have created a service account. + +

+ +

+ + +Next, go to the `Users & Permissions` page +and click on `Invite new users`. + +

+ +

+ +Put an e-mail address for your service account in the `email address` field, +and grant the necessary rights to perform actions. + +

+ +

+ +Grant the following permissions: + +- View financial data, orders, and cancellation survey responses +- Manage orders and subscriptions + +

+ +

+ +After setting the permissions, just click `Invite user`! + +

+ +

+ +After clicking it, you will see that you've just created +your very own service account! + +

+ +

+ + +Now that we have our service account, +**all that's left is retrieving the `json` file that holds its keys**, +so that we can use it in our workflow! + +Head over to https://console.cloud.google.com/iam-admin/serviceaccounts/details/, +which will lead you to `IAM & Admin` and to `Service Accounts` +inside `Google Cloud Console`. + +In here, choose the service account you've just created, +click on the `Actions` icon +and click on `Manage keys`. + +

+ +

+ +Then, click on `Add key` and `Create new key`. + +

+ +

+ +Now, click on the `JSON` option. + +

+ +

+ +Once you do this, +a `json` file will automatically download. +**Do not share this `json` file with anyone**. +It contains *private keys*. + +And that's it! +Great job so far! 🎉 + + +##### First manual release of app + +In order to automate our app release, +we first need to do it manually (only for the first time). +This is because the app does not yet exist +and we haven’t uploaded the first artifact +to our `Google Play` application manually. + +With this in mind, +let's create our first release! + +Head over to `Google Play Console` +at https://play.google.com/console +and select the app you've created prior. +Then, head over to `Production` +on the left tab, +and create `New release`. + +

+ +

+ +You will be prompted a page +in which you you will add details to the release. + +You will first need to choose +how your apps will be signed. +Choose the first option, +in which Google itself will sign the apps for you. + +Then, you will need to upload the app bundle. +If you've executed the commands properly, +the default path in which this bundle lives +should be +`build/app/outputs/bundle/release/app-release.aab`. + +Finally, add a release name. + +

+ + + +

+ +After this, +proceed with the instructions. +You will be shown a preview page, like so: + +

+ +

+ + +> [!WARNING] +> +> If you are shown errors, like in the picture below, +> you'll need to sort those out in order to continue. +> +>

+> +>

+> +> This means the app wasn't initially set up all the way through. +> Click on each error and fix it, following instructions. + + +After this, +click on `Create release` +and that's it! +You've just created the first release of your application! + +Remember, this was needed in order to automate +the release process in the future. + + +##### Keystore file + +Even before publishing your app, +you would have needed an **upload keystore**. + +If you haven't created one, +please go to [Creating an upload keystore](#creating-an-upload-keystore) +and follow the instructions. + + +##### Gradle file + +You need to make some adjustments to the `android/app/build.gradle` file. +Head over to [Reference the keystore from the app](#reference-the-keystore-from-the-app) +to make the needed modifications. + + + +#### `Github` secrets check-up + +Now that all the pre-requisites are fulfilled, +before proceeding with implementing +our Github Action workflow file, +we need to +**define a set of repository secrets** +that will later be used in it. + +Here are the secrets that you will need to have implemented +in your repository. + +- `KEYSTORE_FILE_BASE64`, +this is the uploaded file encoded +as a *base64 string*. +**You should have one keystore per environment**. +In our case, we'll just have one, +for production release. + +To encode the upload keystore file +into a [base64](https://en.wikipedia.org/wiki/Base64) string, +you can run the following command (on `MacOS` and `Linux`). + +```sh +base64 -i company_prod_keystore.jks -o company_prod_keystore.jks.base64 +``` + +You can then copy the `company_prod_keystore.jks.base64` contents +into the secret. + +- `KEYSTORE_PASSWORD`: the keystore password that is present +in the upload keystore file. +It is the password that will be used by the Android build command +to decode the keystore itself. + +- `KEYSTORE_KEY_ALIAS`: a simple key, you can choose pretty much anything. +For example, use `my_company` as an alias for prod +and `my_company_uat` for UAT. +Can be the same as the one found in the upload keystore file. + +- `KEYSTORE_KEY_PASSWORD`: the keystore key password that is present +in the upload keystore file. +It is a password that will be used by the Android build command +to decode the key inside the keystore. +It is identical to `KEYSTORE_PASSWORD`. + +- `GOOGLE_PLAY_SERVICE_ACCOUNT_KEY_JSON`: the contents +of the service account `json` file +that we downloaded earlier. + +After you've set all of these secrets, +we are now ready to roll! 🛼 + + +#### Implementing our workflow file + +// TODO add workflow file here. + ## 🍏 Apple `App Store` From 68468227cbf2264ed2cafec729b85d59606a5db0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lui=CC=81s=20Arteiro?= Date: Mon, 23 Oct 2023 20:46:50 +0100 Subject: [PATCH 26/38] chore: Testing if release actually works when bumping version and not errors out. --- .github/workflows/deploy_android.yml | 4 ++-- pubspec.yaml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/deploy_android.yml b/.github/workflows/deploy_android.yml index 90360e40..2125acb7 100644 --- a/.github/workflows/deploy_android.yml +++ b/.github/workflows/deploy_android.yml @@ -11,8 +11,8 @@ on: branches: [main] # DELETE THIS - #pull_request: - # branches: [ "main" ] + pull_request: + branches: [ "main" ] permissions: contents: write diff --git a/pubspec.yaml b/pubspec.yaml index 1a4aa42b..ce034096 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: dwyl_app description: Clear your mind. Organise your life. Ignore distractions. Focus on what matters. publish_to: 'none' -version: 0.0.1 +version: 0.0.3 homepage: https://github.com/dwyl/app repository: https://github.com/dwyl/app issue_tracker: https://github.com/dwyl/app/issues From 4d56c828a86972092cf43940a282cb258ef42dc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lui=CC=81s=20Arteiro?= Date: Mon, 23 Oct 2023 21:01:52 +0100 Subject: [PATCH 27/38] chore: Change pubspec see if it works now. --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index ce034096..fc4d138e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: dwyl_app description: Clear your mind. Organise your life. Ignore distractions. Focus on what matters. publish_to: 'none' -version: 0.0.3 +version: 0.0.2+2 homepage: https://github.com/dwyl/app repository: https://github.com/dwyl/app issue_tracker: https://github.com/dwyl/app/issues From 3a26a0931936b1aad2d5211a5fd0026bd17e4e4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lui=CC=81s=20Arteiro?= Date: Mon, 23 Oct 2023 21:20:20 +0100 Subject: [PATCH 28/38] Revert "chore: Testing if release actually works when bumping version and not errors out." This reverts commit 68468227cbf2264ed2cafec729b85d59606a5db0. # Conflicts: # pubspec.yaml --- .github/workflows/deploy_android.yml | 4 ++-- pubspec.yaml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/deploy_android.yml b/.github/workflows/deploy_android.yml index 2125acb7..90360e40 100644 --- a/.github/workflows/deploy_android.yml +++ b/.github/workflows/deploy_android.yml @@ -11,8 +11,8 @@ on: branches: [main] # DELETE THIS - pull_request: - branches: [ "main" ] + #pull_request: + # branches: [ "main" ] permissions: contents: write diff --git a/pubspec.yaml b/pubspec.yaml index fc4d138e..1a4aa42b 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: dwyl_app description: Clear your mind. Organise your life. Ignore distractions. Focus on what matters. publish_to: 'none' -version: 0.0.2+2 +version: 0.0.1 homepage: https://github.com/dwyl/app repository: https://github.com/dwyl/app issue_tracker: https://github.com/dwyl/app/issues From a9533cdf5d9ea29d5741532dfef10e9583449aab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lui=CC=81s=20Arteiro?= Date: Mon, 23 Oct 2023 21:25:54 +0100 Subject: [PATCH 29/38] chore: Add disclaimer about version code increasing. --- deployment.md | 45 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 42 insertions(+), 3 deletions(-) diff --git a/deployment.md b/deployment.md index 59922840..561368fb 100644 --- a/deployment.md +++ b/deployment.md @@ -34,6 +34,7 @@ So, let's start! - [Keystore file](#keystore-file) - [Gradle file](#gradle-file) - [`Github` secrets check-up](#github-secrets-check-up) + - [A note before releasing a new version](#a-note-before-releasing-a-new-version) - [Implementing our workflow file](#implementing-our-workflow-file) - [🍏 Apple `App Store`](#-apple-app-store) - [0. Prerequisites](#0-prerequisites-1) @@ -694,8 +695,13 @@ and grant the necessary rights to perform actions. Grant the following permissions: -- View financial data, orders, and cancellation survey responses -- Manage orders and subscriptions +- Admin (all permissions) + +> [!NOTE] +> +> You can definitely narrow the permissions down. +> We're giving all the permissions to make this as simple as possible +> for you 😀.

@@ -719,7 +725,7 @@ Now that we have our service account, **all that's left is retrieving the `json` file that holds its keys**, so that we can use it in our workflow! -Head over to https://console.cloud.google.com/iam-admin/serviceaccounts/details/, +Head over to https://console.cloud.google.com/iam-admin/serviceaccounts/, which will lead you to `IAM & Admin` and to `Service Accounts` inside `Google Cloud Console`. @@ -899,6 +905,39 @@ After you've set all of these secrets, we are now ready to roll! 🛼 +#### A note before releasing a new version + +When you merge a new feature to the `main`/`prod` branch +or want to release a new version of your app, +don't forget to upgrade the version +in your `pubspec.yaml` file. + +We recommend you upgrade the version +with the following format. + +`A.B.C+X` + +`A.B.C` represents the `versionName` such as 1.0.0. + +`X` (the number after the +) represents the `versionCode` such as 1, 2, 3, etc. + +You can check [Android's reference link](http://developer.android.com/guide/topics/manifest/manifest-element.html) +to understand the difference between `versionName` and `versionCode`. +But, to put it simply, +the `versionCode` is **an internal version number** that is used +to determine whether one version is more recent than another. +`versionName` is the version name shown to the end-user. + +Therefore, for each release, you are **obliged to increase the `versionCode` +for the new release and workflow to work. +You can maintain the version that is *shown to the user* +by silently maintaining the `versionName` and increasing the `versionCode`. + +For more information, +please check +https://stackoverflow.com/questions/53570575/flutter-upgrade-the-version-code-for-play-store. + + #### Implementing our workflow file // TODO add workflow file here. From b98ffa5bf8736e6c2dbad87429d6263f5a82befa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lui=CC=81s=20Arteiro?= Date: Tue, 24 Oct 2023 12:01:53 +0100 Subject: [PATCH 30/38] chore: Adding disclaimers and comments. #342 --- .github/workflows/deploy_android.yml | 6 +++++- deployment.md | 32 ++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/.github/workflows/deploy_android.yml b/.github/workflows/deploy_android.yml index 90360e40..fc512bbd 100644 --- a/.github/workflows/deploy_android.yml +++ b/.github/workflows/deploy_android.yml @@ -38,6 +38,7 @@ jobs: - name: 🐦 Install Flutter uses: subosito/flutter-action@v2 with: + # If the flutter version that is used in development increases, it's recommended this one increases as well flutter-version: "3.13.5" channel: "stable" @@ -74,7 +75,10 @@ jobs: # MUST match the package name defined in `android/app/build.gradle` packageName: com.dwyl.app - # Can be 'alpha'/'beta'/'internal'/'production' + # Can be 'alpha'/'beta'/'internal'/'production'. + # 'production' is relevant to the final stable version released to ALL clients + # 'internal' can be used for development versions and testing + # 'alpha' and 'beta' can be used for pre-release/staging purposes, with a smaller userbase track: production releaseFiles: ${{ github.workspace }}/build/app/outputs/bundle/release/app-release.aab diff --git a/deployment.md b/deployment.md index 561368fb..ec374bdf 100644 --- a/deployment.md +++ b/deployment.md @@ -584,6 +584,15 @@ Let's go through them right now. ##### Create app inside Google Play and set it up +> [!WARNING] +> +> When you create an app, it is permanent. +> Although you can [ask Google to delete it](https://stackoverflow.com/questions/14850708/delete-an-unpublished-app-from-google-play), +> it will only work if it doesn't have any installs. +> +> You can *unpublish* an application, but the package name is tied to it *forever*. +> Check https://stackoverflow.com/questions/34846872/how-to-unpublish-an-app-in-google-play-developer-console. + Firstly, you need to create an app project in your `Google Play Console` account. @@ -940,6 +949,29 @@ https://stackoverflow.com/questions/53570575/flutter-upgrade-the-version-code-fo #### Implementing our workflow file +Now that everything is correctly set up, +we can start going over a simple workflow Github Action +that is suitable for the `main` (or `prod`) branch. + +In this workflow, we will want to +**mainly create the app bundle and ship it to our published app** +on `Google Play Console`. + +We'll create a new workflow +inside `.github/workflows` +and name it `deploy_android.yml`. + +Because we're only interested in +deploying features merged into the `main` branch, +this workflow will solely be dedicated to it. + +However, +as we've stated before, +you may + + + + // TODO add workflow file here. From 11f4552f1ea0dd2516b150fa0752e33fb5fff978 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lui=CC=81s=20Arteiro?= Date: Tue, 24 Oct 2023 14:02:01 +0100 Subject: [PATCH 31/38] feat: Finishing Android section and changing app name to unused "org.dwyl.app". #342 --- .github/workflows/deploy_android.yml | 4 +- android/app/build.gradle | 2 +- android/app/src/debug/AndroidManifest.xml | 2 +- android/app/src/main/AndroidManifest.xml | 2 +- .../kotlin/com/example/todo/MainActivity.kt | 2 +- android/app/src/profile/AndroidManifest.xml | 2 +- deployment.md | 223 +++++++++++++++++- ios/Runner.xcodeproj/project.pbxproj | 6 +- linux/CMakeLists.txt | 2 +- macos/Runner/Configs/AppInfo.xcconfig | 2 +- 10 files changed, 228 insertions(+), 19 deletions(-) diff --git a/.github/workflows/deploy_android.yml b/.github/workflows/deploy_android.yml index fc512bbd..5af2daf2 100644 --- a/.github/workflows/deploy_android.yml +++ b/.github/workflows/deploy_android.yml @@ -67,13 +67,13 @@ jobs: run: | flutter build appbundle \ --obfuscate \ - --split-debug-info=${{ github.workspace }}/debug_info + --split-debug-info=${{ github.workspace }}/build/app/outputs/symbols - name: 🚀 Upload Android Release to Play Store uses: r0adkll/upload-google-play@v1.1.2 with: # MUST match the package name defined in `android/app/build.gradle` - packageName: com.dwyl.app + packageName: org.dwyl.app # Can be 'alpha'/'beta'/'internal'/'production'. # 'production' is relevant to the final stable version released to ALL clients diff --git a/android/app/build.gradle b/android/app/build.gradle index 4dfee349..1562754d 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -53,7 +53,7 @@ android { defaultConfig { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). - applicationId "com.dwyl.app" + applicationId "org.dwyl.app" // You can update the following values to match your application needs. // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration. diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml index 47897f0c..37753418 100644 --- a/android/app/src/debug/AndroidManifest.xml +++ b/android/app/src/debug/AndroidManifest.xml @@ -1,5 +1,5 @@ + package="org.dwyl.app">