feat: Implement Android keystore setup for secure signing in release builds and update documentation for local and CI/CD environments
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -119,7 +119,6 @@ vite.config.ts.timestamp-*
|
|||||||
# Android
|
# Android
|
||||||
.gradle/
|
.gradle/
|
||||||
**/android/app/libs/
|
**/android/app/libs/
|
||||||
**/android/key.properties
|
|
||||||
**/android/local.properties
|
**/android/local.properties
|
||||||
|
|
||||||
# Build outputs
|
# Build outputs
|
||||||
@@ -193,3 +192,4 @@ AGENTS.md
|
|||||||
CLAUDE.md
|
CLAUDE.md
|
||||||
GEMINI.md
|
GEMINI.md
|
||||||
TASKS.md
|
TASKS.md
|
||||||
|
\n# Android Signing (Secure)\n**.jks\n**key.properties
|
||||||
|
|||||||
@@ -26,7 +26,60 @@ The project is organized into modular packages to ensure separation of concerns
|
|||||||
### 1. Prerequisites
|
### 1. Prerequisites
|
||||||
Ensure you have the Flutter SDK installed and configured.
|
Ensure you have the Flutter SDK installed and configured.
|
||||||
|
|
||||||
### 2. Initial Setup
|
### 2. Android Keystore Setup (Required for Release Builds)
|
||||||
|
|
||||||
|
To build release APKs/AABs for Android, you need the signing keystores. The keystore configuration (`key.properties`) is committed to the repository, but the actual keystore files are **not** for security reasons.
|
||||||
|
|
||||||
|
#### For Local Development (First-time Setup)
|
||||||
|
|
||||||
|
Contact your team lead to obtain the keystore files:
|
||||||
|
- `krow_with_us_client_dev.jks` - Client app signing keystore
|
||||||
|
- `krow_with_us_staff_dev.jks` - Staff app signing keystore
|
||||||
|
|
||||||
|
Once you have the keystores, copy them to the respective app directories:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Copy keystores to their locations
|
||||||
|
cp krow_with_us_client_dev.jks apps/mobile/apps/client/android/app/
|
||||||
|
cp krow_with_us_staff_dev.jks apps/mobile/apps/staff/android/app/
|
||||||
|
```
|
||||||
|
|
||||||
|
The `key.properties` configuration files are already in the repository:
|
||||||
|
- `apps/mobile/apps/client/android/key.properties`
|
||||||
|
- `apps/mobile/apps/staff/android/key.properties`
|
||||||
|
|
||||||
|
No manual property file creation is needed — just place the `.jks` files in the correct locations.
|
||||||
|
|
||||||
|
#### For CI/CD (CodeMagic)
|
||||||
|
|
||||||
|
CodeMagic uses a native keystore management system. Follow these steps:
|
||||||
|
|
||||||
|
**Step 1: Upload Keystores to CodeMagic**
|
||||||
|
1. Go to **CodeMagic Team Settings** → **Code signing identities** → **Android keystores**
|
||||||
|
2. Upload the keystore files with these **Reference names** (important!):
|
||||||
|
- `krow_client_dev` (for dev builds)
|
||||||
|
- `krow_client_staging` (for staging builds)
|
||||||
|
- `krow_client_prod` (for production builds)
|
||||||
|
- `krow_staff_dev` (for dev builds)
|
||||||
|
- `krow_staff_staging` (for staging builds)
|
||||||
|
- `krow_staff_prod` (for production builds)
|
||||||
|
3. When uploading, enter the keystore password, key alias, and key password for each keystore
|
||||||
|
|
||||||
|
**Step 2: Automatic Environment Variables**
|
||||||
|
CodeMagic automatically injects the following environment variables based on the keystore reference:
|
||||||
|
- `CM_KEYSTORE_PATH_CLIENT` / `CM_KEYSTORE_PATH_STAFF` - Path to the keystore file
|
||||||
|
- `CM_KEYSTORE_PASSWORD_CLIENT` / `CM_KEYSTORE_PASSWORD_STAFF` - Keystore password
|
||||||
|
- `CM_KEY_ALIAS_CLIENT` / `CM_KEY_ALIAS_STAFF` - Key alias
|
||||||
|
- `CM_KEY_PASSWORD_CLIENT` / `CM_KEY_PASSWORD_STAFF` - Key password
|
||||||
|
|
||||||
|
**Step 3: Build Configuration**
|
||||||
|
The `build.gradle.kts` files are already configured to:
|
||||||
|
- Use CodeMagic environment variables when running in CI (`CI=true`)
|
||||||
|
- Fall back to `key.properties` for local development
|
||||||
|
|
||||||
|
Reference: [CodeMagic Android Signing Documentation](https://docs.codemagic.io/yaml-code-signing/signing-android/)
|
||||||
|
|
||||||
|
### 3. Initial Setup
|
||||||
Run the following command from the **project root** to install Melos, bootstrap all packages, generate localization files, and generate the Firebase Data Connect SDK:
|
Run the following command from the **project root** to install Melos, bootstrap all packages, generate localization files, and generate the Firebase Data Connect SDK:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
@@ -42,7 +95,7 @@ This command will:
|
|||||||
|
|
||||||
**Note:** The Firebase Data Connect SDK files (`dataconnect_generated/`) are auto-generated and not committed to the repository. They will be regenerated automatically when you run `make mobile-install` or any mobile development commands.
|
**Note:** The Firebase Data Connect SDK files (`dataconnect_generated/`) are auto-generated and not committed to the repository. They will be regenerated automatically when you run `make mobile-install` or any mobile development commands.
|
||||||
|
|
||||||
### 3. Running the Apps
|
### 4. Running the Apps
|
||||||
You can run the applications using Melos scripts or through the `Makefile`:
|
You can run the applications using Melos scripts or through the `Makefile`:
|
||||||
|
|
||||||
First, find your device ID:
|
First, find your device ID:
|
||||||
|
|||||||
3
apps/mobile/apps/client/android/.gitignore
vendored
3
apps/mobile/apps/client/android/.gitignore
vendored
@@ -7,8 +7,7 @@ gradle-wrapper.jar
|
|||||||
GeneratedPluginRegistrant.java
|
GeneratedPluginRegistrant.java
|
||||||
.cxx/
|
.cxx/
|
||||||
|
|
||||||
# Remember to never publicly share your keystore.
|
# Remember to never publicly share your keystore files.
|
||||||
# See https://flutter.dev/to/reference-keystore
|
# See https://flutter.dev/to/reference-keystore
|
||||||
key.properties
|
|
||||||
**/*.keystore
|
**/*.keystore
|
||||||
**/*.jks
|
**/*.jks
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import java.util.Base64
|
import java.util.Base64
|
||||||
|
import java.util.Properties
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id("com.android.application")
|
id("com.android.application")
|
||||||
@@ -20,6 +21,13 @@ dartDefinesString.split(",").forEach {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val keystoreProperties = Properties().apply {
|
||||||
|
val propertiesFile = rootProject.file("key.properties")
|
||||||
|
if (propertiesFile.exists()) {
|
||||||
|
load(propertiesFile.inputStream())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
namespace = "com.krowwithus.client"
|
namespace = "com.krowwithus.client"
|
||||||
compileSdk = flutter.compileSdkVersion
|
compileSdk = flutter.compileSdkVersion
|
||||||
@@ -44,14 +52,32 @@ android {
|
|||||||
versionCode = flutter.versionCode
|
versionCode = flutter.versionCode
|
||||||
versionName = flutter.versionName
|
versionName = flutter.versionName
|
||||||
|
|
||||||
manifestPlaceholders["GOOGLE_MAPS_API_KEY"] = dartEnvironmentVariables["GOOGLE_MAPS_API_KEY"] ?: ""
|
manifestPlaceholders["GOOGLE_MAPS_API_KEY"] = dartEnvironmentVariables["GOOGLE_MAPS_API_KEY"] ?: ""
|
||||||
|
}
|
||||||
|
|
||||||
|
signingConfigs {
|
||||||
|
create("release") {
|
||||||
|
if (System.getenv()["CI"] == "true") {
|
||||||
|
// CodeMagic CI environment
|
||||||
|
storeFile = file(System.getenv()["CM_KEYSTORE_PATH_CLIENT"] ?: "")
|
||||||
|
storePassword = System.getenv()["CM_KEYSTORE_PASSWORD_CLIENT"]
|
||||||
|
keyAlias = System.getenv()["CM_KEY_ALIAS_CLIENT"]
|
||||||
|
keyPassword = System.getenv()["CM_KEY_PASSWORD_CLIENT"]
|
||||||
|
} else {
|
||||||
|
// Local development environment
|
||||||
|
keyAlias = keystoreProperties["keyAlias"] as String?
|
||||||
|
keyPassword = keystoreProperties["keyPassword"] as String?
|
||||||
|
storeFile = keystoreProperties["storeFile"]?.let { file(it) }
|
||||||
|
storePassword = keystoreProperties["storePassword"] as String?
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
buildTypes {
|
buildTypes {
|
||||||
release {
|
release {
|
||||||
// TODO: Add your own signing config for the release build.
|
// TODO: Add your own signing config for the release build.
|
||||||
// Signing with the debug keys for now, so `flutter run --release` works.
|
// Signing with the debug keys for now, so `flutter run --release` works.
|
||||||
signingConfig = signingConfigs.getByName("debug")
|
signingConfig = signingConfigs.getByName("release")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -86,11 +86,11 @@
|
|||||||
},
|
},
|
||||||
"oauth_client": [
|
"oauth_client": [
|
||||||
{
|
{
|
||||||
"client_id": "933560802882-fbqg2icq24bmci3f84evjrbth5huh87f.apps.googleusercontent.com",
|
"client_id": "933560802882-qbl6keingmd14fepn6qp76agdmbr84fg.apps.googleusercontent.com",
|
||||||
"client_type": 1,
|
"client_type": 1,
|
||||||
"android_info": {
|
"android_info": {
|
||||||
"package_name": "com.krowwithus.client",
|
"package_name": "com.krowwithus.client",
|
||||||
"certificate_hash": "c3efbe1642239c599c16ad04c7fac340902fe280"
|
"certificate_hash": "f5491c60ec20eb27bb3ec581352ba653053f3740"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -130,11 +130,11 @@
|
|||||||
},
|
},
|
||||||
"oauth_client": [
|
"oauth_client": [
|
||||||
{
|
{
|
||||||
"client_id": "933560802882-ikdfv3o5f47g36qqgvfq55o4m19n7gk4.apps.googleusercontent.com",
|
"client_id": "933560802882-nh589kkndmur9hgibkgg5g8lhmo7mg3v.apps.googleusercontent.com",
|
||||||
"client_type": 1,
|
"client_type": 1,
|
||||||
"android_info": {
|
"android_info": {
|
||||||
"package_name": "com.krowwithus.staff",
|
"package_name": "com.krowwithus.staff",
|
||||||
"certificate_hash": "ac917ae8470ab29f1107c773c6017ff5ea5d102d"
|
"certificate_hash": "a6ef7fe8ade313e69377b178544192d835b29153"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
9
apps/mobile/apps/client/android/key.properties
Normal file
9
apps/mobile/apps/client/android/key.properties
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
storePassword=krowwithus
|
||||||
|
keyPassword=krowwithus
|
||||||
|
keyAlias=krow_client_dev
|
||||||
|
storeFile=app/krow_with_us_client_dev.jks
|
||||||
|
|
||||||
|
###
|
||||||
|
### Client
|
||||||
|
### SHA1: F5:49:1C:60:EC:20:EB:27:BB:3E:C5:81:35:2B:A6:53:05:3F:37:40
|
||||||
|
### SHA256: 27:88:E4:EB:6C:BF:8E:25:66:37:76:B3:5D:DA:92:8A:CB:1A:6F:24:F3:38:9B:EA:DE:F0:25:62:FD:7A:7E:77
|
||||||
3
apps/mobile/apps/staff/android/.gitignore
vendored
3
apps/mobile/apps/staff/android/.gitignore
vendored
@@ -7,8 +7,7 @@ gradle-wrapper.jar
|
|||||||
GeneratedPluginRegistrant.java
|
GeneratedPluginRegistrant.java
|
||||||
.cxx/
|
.cxx/
|
||||||
|
|
||||||
# Remember to never publicly share your keystore.
|
# Remember to never publicly share your keystore files.
|
||||||
# See https://flutter.dev/to/reference-keystore
|
# See https://flutter.dev/to/reference-keystore
|
||||||
key.properties
|
|
||||||
**/*.keystore
|
**/*.keystore
|
||||||
**/*.jks
|
**/*.jks
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import java.util.Base64
|
import java.util.Base64
|
||||||
|
import java.util.Properties
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id("com.android.application")
|
id("com.android.application")
|
||||||
@@ -20,6 +21,13 @@ dartDefinesString.split(",").forEach {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val keystoreProperties = Properties().apply {
|
||||||
|
val propertiesFile = rootProject.file("key.properties")
|
||||||
|
if (propertiesFile.exists()) {
|
||||||
|
load(propertiesFile.inputStream())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
namespace = "com.krowwithus.staff"
|
namespace = "com.krowwithus.staff"
|
||||||
compileSdk = flutter.compileSdkVersion
|
compileSdk = flutter.compileSdkVersion
|
||||||
@@ -44,14 +52,32 @@ android {
|
|||||||
versionCode = flutter.versionCode
|
versionCode = flutter.versionCode
|
||||||
versionName = flutter.versionName
|
versionName = flutter.versionName
|
||||||
|
|
||||||
manifestPlaceholders["GOOGLE_MAPS_API_KEY"] = dartEnvironmentVariables["GOOGLE_MAPS_API_KEY"] ?: ""
|
manifestPlaceholders["GOOGLE_MAPS_API_KEY"] = dartEnvironmentVariables["GOOGLE_MAPS_API_KEY"] ?: ""
|
||||||
|
}
|
||||||
|
|
||||||
|
signingConfigs {
|
||||||
|
create("release") {
|
||||||
|
if (System.getenv()["CI"] == "true") {
|
||||||
|
// CodeMagic CI environment
|
||||||
|
storeFile = file(System.getenv()["CM_KEYSTORE_PATH_STAFF"] ?: "")
|
||||||
|
storePassword = System.getenv()["CM_KEYSTORE_PASSWORD_STAFF"]
|
||||||
|
keyAlias = System.getenv()["CM_KEY_ALIAS_STAFF"]
|
||||||
|
keyPassword = System.getenv()["CM_KEY_PASSWORD_STAFF"]
|
||||||
|
} else {
|
||||||
|
// Local development environment
|
||||||
|
keyAlias = keystoreProperties["keyAlias"] as String?
|
||||||
|
keyPassword = keystoreProperties["keyPassword"] as String?
|
||||||
|
storeFile = keystoreProperties["storeFile"]?.let { file(it) }
|
||||||
|
storePassword = keystoreProperties["storePassword"] as String?
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
buildTypes {
|
buildTypes {
|
||||||
release {
|
release {
|
||||||
// TODO: Add your own signing config for the release build.
|
// TODO: Add your own signing config for the release build.
|
||||||
// Signing with the debug keys for now, so `flutter run --release` works.
|
// Signing with the debug keys for now, so `flutter run --release` works.
|
||||||
signingConfig = signingConfigs.getByName("debug")
|
signingConfig = signingConfigs.getByName("release")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -86,11 +86,11 @@
|
|||||||
},
|
},
|
||||||
"oauth_client": [
|
"oauth_client": [
|
||||||
{
|
{
|
||||||
"client_id": "933560802882-fbqg2icq24bmci3f84evjrbth5huh87f.apps.googleusercontent.com",
|
"client_id": "933560802882-qbl6keingmd14fepn6qp76agdmbr84fg.apps.googleusercontent.com",
|
||||||
"client_type": 1,
|
"client_type": 1,
|
||||||
"android_info": {
|
"android_info": {
|
||||||
"package_name": "com.krowwithus.client",
|
"package_name": "com.krowwithus.client",
|
||||||
"certificate_hash": "c3efbe1642239c599c16ad04c7fac340902fe280"
|
"certificate_hash": "f5491c60ec20eb27bb3ec581352ba653053f3740"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -130,11 +130,11 @@
|
|||||||
},
|
},
|
||||||
"oauth_client": [
|
"oauth_client": [
|
||||||
{
|
{
|
||||||
"client_id": "933560802882-ikdfv3o5f47g36qqgvfq55o4m19n7gk4.apps.googleusercontent.com",
|
"client_id": "933560802882-nh589kkndmur9hgibkgg5g8lhmo7mg3v.apps.googleusercontent.com",
|
||||||
"client_type": 1,
|
"client_type": 1,
|
||||||
"android_info": {
|
"android_info": {
|
||||||
"package_name": "com.krowwithus.staff",
|
"package_name": "com.krowwithus.staff",
|
||||||
"certificate_hash": "ac917ae8470ab29f1107c773c6017ff5ea5d102d"
|
"certificate_hash": "a6ef7fe8ade313e69377b178544192d835b29153"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -167,4 +167,4 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"configuration_version": "1"
|
"configuration_version": "1"
|
||||||
}
|
}
|
||||||
|
|||||||
9
apps/mobile/apps/staff/android/key.properties
Normal file
9
apps/mobile/apps/staff/android/key.properties
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
storePassword=krowwithus
|
||||||
|
keyPassword=krowwithus
|
||||||
|
keyAlias=krow_staff_dev
|
||||||
|
storeFile=app/krow_with_us_staff_dev.jks
|
||||||
|
|
||||||
|
###
|
||||||
|
### Staff
|
||||||
|
### SHA1: A6:EF:7F:E8:AD:E3:13:E6:93:77:B1:78:54:41:92:D8:35:B2:91:53
|
||||||
|
### SHA256: 26:B5:BD:1A:DE:18:92:1F:A3:7B:59:99:5E:4E:D0:BB:DF:93:D6:F6:01:16:04:55:0F:AA:57:55:C1:6B:7D:95
|
||||||
@@ -339,7 +339,6 @@ class AuthRepositoryImpl implements AuthRepositoryInterface {
|
|||||||
Future<void> signOut() async {
|
Future<void> signOut() async {
|
||||||
try {
|
try {
|
||||||
await _service.auth.signOut();
|
await _service.auth.signOut();
|
||||||
dc.ClientSessionStore.instance.clear();
|
|
||||||
_service.clearCache();
|
_service.clearCache();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw Exception('Error signing out: ${e.toString()}');
|
throw Exception('Error signing out: ${e.toString()}');
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ import 'package:design_system/design_system.dart';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:flutter_modular/flutter_modular.dart';
|
import 'package:flutter_modular/flutter_modular.dart';
|
||||||
import 'package:krow_core/core.dart';
|
|
||||||
import 'package:krow_domain/krow_domain.dart';
|
import 'package:krow_domain/krow_domain.dart';
|
||||||
|
|
||||||
import '../blocs/tax_forms/tax_forms_cubit.dart';
|
import '../blocs/tax_forms/tax_forms_cubit.dart';
|
||||||
import '../blocs/tax_forms/tax_forms_state.dart';
|
import '../blocs/tax_forms/tax_forms_state.dart';
|
||||||
|
|
||||||
@@ -14,39 +14,10 @@ class TaxFormsPage extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: const UiAppBar(
|
||||||
backgroundColor: UiColors.primary,
|
title: 'Tax Documents',
|
||||||
elevation: 0,
|
subtitle: 'Complete required forms to start working',
|
||||||
leading: IconButton(
|
showBackButton: true,
|
||||||
icon: const Icon(UiIcons.arrowLeft, color: UiColors.bgPopup),
|
|
||||||
onPressed: () => Modular.to.popSafe(),
|
|
||||||
),
|
|
||||||
title: Text(
|
|
||||||
'Tax Documents',
|
|
||||||
style: UiTypography.headline3m.textSecondary,
|
|
||||||
),
|
|
||||||
bottom: PreferredSize(
|
|
||||||
preferredSize: const Size.fromHeight(24),
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.only(
|
|
||||||
left: UiConstants.space5,
|
|
||||||
right: UiConstants.space5,
|
|
||||||
bottom: UiConstants.space5,
|
|
||||||
),
|
|
||||||
child: Row(
|
|
||||||
children: <Widget>[
|
|
||||||
Expanded(
|
|
||||||
child: Text(
|
|
||||||
'Complete required forms to start working',
|
|
||||||
style: UiTypography.body3r.copyWith(
|
|
||||||
color: UiColors.primaryForeground.withValues(alpha: 0.8),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
body: BlocProvider<TaxFormsCubit>(
|
body: BlocProvider<TaxFormsCubit>(
|
||||||
create: (BuildContext context) {
|
create: (BuildContext context) {
|
||||||
@@ -84,7 +55,7 @@ class TaxFormsPage extends StatelessWidget {
|
|||||||
vertical: UiConstants.space6,
|
vertical: UiConstants.space6,
|
||||||
),
|
),
|
||||||
child: Column(
|
child: Column(
|
||||||
spacing: UiConstants.space6,
|
spacing: UiConstants.space4,
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
_buildProgressOverview(state.forms),
|
_buildProgressOverview(state.forms),
|
||||||
...state.forms.map(
|
...state.forms.map(
|
||||||
|
|||||||
@@ -351,14 +351,13 @@ class _FileTypesBanner extends StatelessWidget {
|
|||||||
vertical: UiConstants.space3,
|
vertical: UiConstants.space3,
|
||||||
),
|
),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: UiColors.tagActive,
|
color: UiColors.primary.withAlpha(20),
|
||||||
borderRadius: BorderRadius.circular(UiConstants.radiusBase),
|
borderRadius: BorderRadius.circular(UiConstants.radiusBase),
|
||||||
border: Border.all(color: UiColors.primary.withValues(alpha: 0.3)),
|
|
||||||
),
|
),
|
||||||
child: Row(
|
child: Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Icon(UiIcons.info, size: 20, color: UiColors.primary),
|
const Icon(UiIcons.info, size: 20, color: UiColors.primary),
|
||||||
const SizedBox(width: UiConstants.space3),
|
const SizedBox(width: UiConstants.space3),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Text(message, style: UiTypography.body2r.textSecondary),
|
child: Text(message, style: UiTypography.body2r.textSecondary),
|
||||||
|
|||||||
@@ -1,3 +1,7 @@
|
|||||||
|
# Note: key.properties files are now committed to the repository
|
||||||
|
# CodeMagic keystores are uploaded via Team Settings > Code signing identities > Android keystores
|
||||||
|
# The keystores are referenced in each workflow's environment section with custom variable names
|
||||||
|
|
||||||
# Reusable script for building the Flutter app
|
# Reusable script for building the Flutter app
|
||||||
client-app-android-apk-build-script: &client-app-android-apk-build-script
|
client-app-android-apk-build-script: &client-app-android-apk-build-script
|
||||||
name: 👷🤖 Build Client App APK (Android)
|
name: 👷🤖 Build Client App APK (Android)
|
||||||
@@ -170,6 +174,12 @@ workflows:
|
|||||||
cocoapods: default
|
cocoapods: default
|
||||||
groups:
|
groups:
|
||||||
- client_app_dev_credentials
|
- client_app_dev_credentials
|
||||||
|
android_signing:
|
||||||
|
- keystore: krow_client_dev
|
||||||
|
keystore_environment_variable: CM_KEYSTORE_PATH_CLIENT
|
||||||
|
keystore_password_environment_variable: CM_KEYSTORE_PASSWORD_CLIENT
|
||||||
|
key_alias_environment_variable: CM_KEY_ALIAS_CLIENT
|
||||||
|
key_password_environment_variable: CM_KEY_PASSWORD_CLIENT
|
||||||
vars:
|
vars:
|
||||||
ENV: dev
|
ENV: dev
|
||||||
scripts:
|
scripts:
|
||||||
@@ -185,6 +195,12 @@ workflows:
|
|||||||
cocoapods: default
|
cocoapods: default
|
||||||
groups:
|
groups:
|
||||||
- client_app_staging_credentials
|
- client_app_staging_credentials
|
||||||
|
android_signing:
|
||||||
|
- keystore: krow_client_staging
|
||||||
|
keystore_environment_variable: CM_KEYSTORE_PATH_CLIENT
|
||||||
|
keystore_password_environment_variable: CM_KEYSTORE_PASSWORD_CLIENT
|
||||||
|
key_alias_environment_variable: CM_KEY_ALIAS_CLIENT
|
||||||
|
key_password_environment_variable: CM_KEY_PASSWORD_CLIENT
|
||||||
vars:
|
vars:
|
||||||
ENV: staging
|
ENV: staging
|
||||||
scripts:
|
scripts:
|
||||||
@@ -197,6 +213,12 @@ workflows:
|
|||||||
environment:
|
environment:
|
||||||
groups:
|
groups:
|
||||||
- client_app_prod_credentials
|
- client_app_prod_credentials
|
||||||
|
android_signing:
|
||||||
|
- keystore: krow_client_prod
|
||||||
|
keystore_environment_variable: CM_KEYSTORE_PATH_CLIENT
|
||||||
|
keystore_password_environment_variable: CM_KEYSTORE_PASSWORD_CLIENT
|
||||||
|
key_alias_environment_variable: CM_KEY_ALIAS_CLIENT
|
||||||
|
key_password_environment_variable: CM_KEY_PASSWORD_CLIENT
|
||||||
vars:
|
vars:
|
||||||
ENV: prod
|
ENV: prod
|
||||||
scripts:
|
scripts:
|
||||||
@@ -254,6 +276,12 @@ workflows:
|
|||||||
cocoapods: default
|
cocoapods: default
|
||||||
groups:
|
groups:
|
||||||
- staff_app_dev_credentials
|
- staff_app_dev_credentials
|
||||||
|
android_signing:
|
||||||
|
- keystore: krow_staff_dev
|
||||||
|
keystore_environment_variable: CM_KEYSTORE_PATH_STAFF
|
||||||
|
keystore_password_environment_variable: CM_KEYSTORE_PASSWORD_STAFF
|
||||||
|
key_alias_environment_variable: CM_KEY_ALIAS_STAFF
|
||||||
|
key_password_environment_variable: CM_KEY_PASSWORD_STAFF
|
||||||
vars:
|
vars:
|
||||||
ENV: dev
|
ENV: dev
|
||||||
scripts:
|
scripts:
|
||||||
@@ -269,6 +297,12 @@ workflows:
|
|||||||
cocoapods: default
|
cocoapods: default
|
||||||
groups:
|
groups:
|
||||||
- staff_app_staging_credentials
|
- staff_app_staging_credentials
|
||||||
|
android_signing:
|
||||||
|
- keystore: krow_staff_staging
|
||||||
|
keystore_environment_variable: CM_KEYSTORE_PATH_STAFF
|
||||||
|
keystore_password_environment_variable: CM_KEYSTORE_PASSWORD_STAFF
|
||||||
|
key_alias_environment_variable: CM_KEY_ALIAS_STAFF
|
||||||
|
key_password_environment_variable: CM_KEY_PASSWORD_STAFF
|
||||||
vars:
|
vars:
|
||||||
ENV: staging
|
ENV: staging
|
||||||
scripts:
|
scripts:
|
||||||
@@ -284,6 +318,12 @@ workflows:
|
|||||||
cocoapods: default
|
cocoapods: default
|
||||||
groups:
|
groups:
|
||||||
- staff_app_prod_credentials
|
- staff_app_prod_credentials
|
||||||
|
android_signing:
|
||||||
|
- keystore: krow_staff_prod
|
||||||
|
keystore_environment_variable: CM_KEYSTORE_PATH_STAFF
|
||||||
|
keystore_password_environment_variable: CM_KEYSTORE_PASSWORD_STAFF
|
||||||
|
key_alias_environment_variable: CM_KEY_ALIAS_STAFF
|
||||||
|
key_password_environment_variable: CM_KEY_PASSWORD_STAFF
|
||||||
vars:
|
vars:
|
||||||
ENV: prod
|
ENV: prod
|
||||||
scripts:
|
scripts:
|
||||||
|
|||||||
Reference in New Issue
Block a user