feat(suite-native): expo eas (#10898)

* feat(suite-native): build binaries for develop

* fix(suite-native): project ID map

* fix(suite-native): version
This commit is contained in:
Bohdan Juříček
2024-02-14 14:34:02 +00:00
committed by GitHub
parent 094b11f3fc
commit 02009f17cd
32 changed files with 388 additions and 1163 deletions

View File

@@ -14,137 +14,36 @@ concurrency:
cancel-in-progress: true
jobs:
android_develop:
build:
name: Install and build
runs-on: ubuntu-latest
environment: develop
timeout-minutes: 45
env:
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Setup node
uses: actions/setup-node@v3
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version-file: ".nvmrc"
- name: Setup react-native kernel and increase watchers
run: echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p
- name: Install dependecies
cache: yarn
- name: Setup EAS
uses: expo/expo-github-action@v8
with:
eas-version: latest
token: ${{ secrets.EXPO_TOKEN }}
- name: Install libs
run: yarn install
- name: Build JS libs
run: yarn build:libs
- name: Expo Prebuild
working-directory: suite-native/app/
env:
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
run: yarn expo prebuild --platform android
- name: Decode files
env:
ENCODED_STRING_KEYSTORE: ${{ secrets.DEVELOP_KEYSTORE_FILE }}
ENCODED_STRING_JSON_FILE: ${{secrets.GOOGLE_PLAY_JSON_KEY}}
run: |
echo $ENCODED_STRING_KEYSTORE | base64 -d > suite-native/app/android/app/release.keystore
echo $ENCODED_STRING_JSON_FILE > suite-native/app/android/firebase_key.json
- name: Ruby Setup for Fastlane
uses: ruby/setup-ruby@v1
with:
ruby-version: "3.2.1"
bundler-cache: true
- name: Install bundler
working-directory: suite-native/app/
run: gem install bundler
- name: Fastlane build and deploy
working-directory: suite-native/app/
env:
SIGNING_KEY_FILE: release.keystore
SIGNING_KEY_STORE_PASSWORD: ${{ secrets.SIGNING_KEY_STORE_PASSWORD }}
SIGNING_KEY_ALIAS: ${{ secrets.SIGNING_KEY_ALIAS }}
SIGNING_KEY_PASSWORD: ${{ secrets.SIGNING_KEY_PASSWORD }}
GOOGLE_PLAY_JSON_KEY_FILE: ./android/firebase_key.json
FIREBASE_APP_ID: ${{secrets.ANDROID_FIREBASE_APP_ID}}
# builds and publishes the app
run: |
bundle install
bundle exec fastlane android develop
- uses: actions/upload-artifact@v3
with:
name: app-apk
path: |
suite-native/app/android/**/*.apk
ios_develop:
runs-on: macos-12
environment: develop
timeout-minutes: 75
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Setup node
uses: actions/setup-node@v3
with:
node-version-file: ".nvmrc"
- name: Get yarn cache directory path
id: yarn-cache-dir-path
run: echo "::set-output name=dir::$(yarn config get cacheFolder)"
- name: Restore yarn cache
uses: actions/cache@v3
id: yarn-cache
with:
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
key: yarn-cache-folder-${{ hashFiles('**/yarn.lock', '.yarnrc.yml') }}
restore-keys: |
yarn-cache-folder-
- name: Decode files
env:
APPSTORE_CERTIFICATE_CONTENT: ${{ secrets.APPSTORE_CERTIFICATE_CONTENT }}
run: |
echo $APPSTORE_CERTIFICATE_CONTENT | base64 -d > suite-native/app/TrezorDistributionCertificate.p12
- name: Install missing Python deps (to build bcrypto lib in Node)
run: pip install setuptools
- name: Install dependecies
run: |
yarn install
yarn build:libs
- name: Expo Prebuild
working-directory: suite-native/app/
env:
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
run: yarn expo prebuild --platform ios
- name: Ruby Setup for Fastlane
uses: ruby/setup-ruby@v1
with:
ruby-version: "3.2.1"
bundler-cache: true
- name: Install bundler
working-directory: suite-native/app/
run: gem install bundler
- name: Fastlane build and deploy
working-directory: suite-native/app/
env:
APPSTORE_KEY_ID: ${{ secrets.APPSTORE_KEY_ID }}
APPSTORE_KEY_ISSUER_ID: ${{ secrets.APPSTORE_KEY_ISSUER_ID }}
APPSTORE_KEY_FILE_CONTENT: ${{ secrets.APPSTORE_KEY_FILE_CONTENT }}
APPSTORE_CERTIFICATE_PASSWORD: ${{ secrets.APPSTORE_CERTIFICATE_PASSWORD }}
TMP_KEYCHAIN_NAME: ${{ secrets.TMP_KEYCHAIN_NAME }}
TMP_KEYCHAIN_PASSWORD: ${{ secrets.TMP_KEYCHAIN_PASSWORD }}
# builds and publishes the app
run: |
bundle install
bundle exec fastlane ios develop
- name: Build on EAS Android
run: eas build
--platform android
--profile develop
--non-interactive
--no-wait
working-directory: suite-native/app
- name: Build on EAS iOS
run: eas build
--platform ios
--profile develop
--non-interactive
--auto-submit
--no-wait
working-directory: suite-native/app

View File

@@ -1,136 +1,23 @@
name: "[Release] suite-native production"
on:
workflow_dispatch:
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref }}
cancel-in-progress: true
jobs:
android_production:
runs-on: ubuntu-latest
environment: production
timeout-minutes: 45
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Setup node
uses: actions/setup-node@v3
with:
node-version-file: ".nvmrc"
- name: Setup react-native kernel and increase watchers
run: echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p
- name: Install dependecies
run: |
yarn install
yarn build:libs
- name: Expo Prebuild
working-directory: suite-native/app/
env:
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
run: yarn expo prebuild --platform android
- name: Decode files
env:
ENCODED_STRING_KEYSTORE: ${{ secrets.PRODUCTION_KEYSTORE_FILE }}
ENCODED_STRING_JSON_FILE: ${{secrets.PRODUCTION_GOOGLE_PLAY_JSON_KEY}}
run: |
echo $ENCODED_STRING_KEYSTORE | base64 -d > suite-native/app/android/app/prod-upload-key.keystore
echo $ENCODED_STRING_JSON_FILE > suite-native/app/android/google_play_key.json
- name: Ruby Setup for Fastlane
uses: ruby/setup-ruby@v1
with:
ruby-version: "3.2.1"
bundler-cache: true
- name: Install bundler
working-directory: suite-native/app/
run: gem install bundler
- name: Fastlane build and deploy
working-directory: suite-native/app/
env:
SIGNING_KEY_FILE: prod-upload-key.keystore
SIGNING_KEY_STORE_PASSWORD: ${{ secrets.SIGNING_KEY_STORE_PASSWORD_PROD }}
SIGNING_KEY_ALIAS: ${{ secrets.SIGNING_KEY_ALIAS_PROD }}
SIGNING_KEY_PASSWORD: ${{ secrets.SIGNING_KEY_PASSWORD_PROD }}
GOOGLE_PLAY_JSON_KEY_FILE: ./android/google_play_key.json
# builds and publishes the app
run: |
bundle install
bundle exec fastlane android production
ios_production:
runs-on: macos-12
environment: production
timeout-minutes: 75
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Setup node
uses: actions/setup-node@v3
with:
node-version-file: ".nvmrc"
- name: Get yarn cache directory path
id: yarn-cache-dir-path
run: echo "::set-output name=dir::$(yarn config get cacheFolder)"
- name: Restore yarn cache
uses: actions/cache@v3
id: yarn-cache
with:
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
key: yarn-cache-folder-${{ hashFiles('**/yarn.lock', '.yarnrc.yml') }}
restore-keys: |
yarn-cache-folder-
- name: Decode files
env:
APPSTORE_CERTIFICATE_CONTENT: ${{ secrets.APPSTORE_CERTIFICATE_CONTENT_PROD }}
run: |
echo $APPSTORE_CERTIFICATE_CONTENT | base64 -d > suite-native/app/TrezorDistributionCertificate.p12
- name: Install missing Python deps (to build bcrypto lib in Node)
run: pip install setuptools
- name: Install dependecies
run: |
yarn install
yarn build:libs
- name: Expo Prebuild
working-directory: suite-native/app/
env:
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
run: yarn expo prebuild --platform ios
- name: Ruby Setup for Fastlane
uses: ruby/setup-ruby@v1
with:
ruby-version: "3.2.1"
bundler-cache: true
- name: Install bundler
working-directory: suite-native/app/
run: gem install bundler
- name: Fastlane build and deploy
working-directory: suite-native/app/
env:
APPSTORE_KEY_ID: ${{ secrets.APPSTORE_KEY_ID_PROD }}
APPSTORE_KEY_ISSUER_ID: ${{ secrets.APPSTORE_KEY_ISSUER_ID_PROD }}
APPSTORE_KEY_FILE_CONTENT: ${{ secrets.APPSTORE_KEY_FILE_CONTENT_PROD }}
APPSTORE_CERTIFICATE_PASSWORD: ${{ secrets.APPSTORE_CERTIFICATE_PASSWORD_PROD }}
TMP_KEYCHAIN_NAME: ${{ secrets.APPSTORE_TMP_KEYCHAIN_NAME_PROD }}
TMP_KEYCHAIN_PASSWORD: ${{ secrets.APPSTORE_TMP_KEYCHAIN_PASSWORD_PROD }}
# builds and publishes the app
run: |
bundle install
bundle exec fastlane ios production
#name: "[Build] release"
#
#on: [pull_request]
#jobs:
# build:
# name: Install and build
# runs-on: ubuntu-latest
# steps:
# - uses: actions/checkout@v3
# - uses: actions/setup-node@v3
# with:
# node-version-file: ".nvmrc"
# cache: yarn
# - name: Setup EAS
# uses: expo/expo-github-action@v8
# with:
# eas-version: latest
# token: ${{ secrets.EXPO_TOKEN }}
# - name: Install libs
# run: yarn install
# - name: Build on EAS
# run: eas build --platform all --profile production --auto-submit --non-interactive
# working-directory: suite-native/app

View File

@@ -1,131 +0,0 @@
name: "[Release]: suite-native staging"
on:
workflow_dispatch:
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref }}
cancel-in-progress: true
jobs:
android_staging:
runs-on: ubuntu-latest
environment: staging
timeout-minutes: 45
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Setup node
uses: actions/setup-node@v3
with:
node-version-file: ".nvmrc"
- name: Setup react-native kernel and increase watchers
run: echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p
- name: Expo Prebuild
working-directory: suite-native/app/
env:
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
run: yarn expo prebuild --platform android
- name: Decode files
env:
ENCODED_STRING_KEYSTORE: ${{ secrets.STAGING_KEYSTORE_FILE }}
ENCODED_STRING_JSON_FILE: ${{secrets.GOOGLE_PLAY_JSON_KEY_STAGING}}
run: |
echo $ENCODED_STRING_KEYSTORE | base64 -d > suite-native/app/android/app/stag-upload-key.keystore
echo $ENCODED_STRING_JSON_FILE > suite-native/app/android/google_play_key.json
- name: Ruby Setup for Fastlane
uses: ruby/setup-ruby@v1
with:
ruby-version: "3.2.1"
bundler-cache: true
- name: Install bundler
working-directory: suite-native/app/
run: gem install bundler
- name: Fastlane build and deploy
working-directory: suite-native/app/
env:
SIGNING_KEY_FILE: stag-upload-key.keystore
SIGNING_KEY_STORE_PASSWORD: ${{ secrets.SIGNING_KEY_STORE_PASSWORD_STAGING }}
SIGNING_KEY_ALIAS: ${{ secrets.SIGNING_KEY_ALIAS_STAGING }}
SIGNING_KEY_PASSWORD: ${{ secrets.SIGNING_KEY_PASSWORD_STAGING }}
GOOGLE_PLAY_JSON_KEY_FILE: ./android/google_play_key.json
# builds and publishes the app
run: |
bundle install
bundle exec fastlane android staging
ios_staging:
runs-on: macos-12
environment: staging
timeout-minutes: 75
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Setup node
uses: actions/setup-node@v3
with:
node-version-file: ".nvmrc"
- name: Get yarn cache directory path
id: yarn-cache-dir-path
run: echo "::set-output name=dir::$(yarn config get cacheFolder)"
- name: Restore yarn cache
uses: actions/cache@v3
id: yarn-cache
with:
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
key: yarn-cache-folder-${{ hashFiles('**/yarn.lock', '.yarnrc.yml') }}
restore-keys: |
yarn-cache-folder-
- name: Decode files
env:
APPSTORE_CERTIFICATE_CONTENT: ${{ secrets.APPSTORE_CERTIFICATE_CONTENT_STAGING }}
run: |
echo $APPSTORE_CERTIFICATE_CONTENT | base64 -d > suite-native/app/TrezorDistributionCertificate.p12
- name: Install missing Python deps (to build bcrypto lib in Node)
run: pip install setuptools
- name: Install dependecies
run: |
yarn install
yarn build:libs
- name: Expo Prebuild
working-directory: suite-native/app/
env:
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
run: yarn expo prebuild --platform ios
- name: Ruby Setup for Fastlane
uses: ruby/setup-ruby@v1
with:
ruby-version: "3.2.1"
bundler-cache: true
- name: Install bundler
working-directory: suite-native/app/
run: gem install bundler
- name: Fastlane build and deploy
working-directory: suite-native/app/
env:
APPSTORE_KEY_ID: ${{ secrets.APPSTORE_KEY_ID_STAGING }}
APPSTORE_KEY_ISSUER_ID: ${{ secrets.APPSTORE_KEY_ISSUER_ID_STAGING }}
APPSTORE_KEY_FILE_CONTENT: ${{ secrets.APPSTORE_KEY_FILE_CONTENT_STAGING }}
APPSTORE_CERTIFICATE_PASSWORD: ${{ secrets.APPSTORE_CERTIFICATE_PASSWORD_STAGING }}
TMP_KEYCHAIN_NAME: ${{ secrets.APPSTORE_TMP_KEYCHAIN_NAME_STAGING }}
TMP_KEYCHAIN_PASSWORD: ${{ secrets.APPSTORE_TMP_KEYCHAIN_PASSWORD_STAGING }}
# builds and publishes the app
run: |
bundle install
bundle exec fastlane ios staging

View File

@@ -10,7 +10,10 @@ const MESSAGES_SRC = '../../packages/protobuf/messages.json';
const DIST = path.resolve(__dirname, '../build');
const commitHash = execSync('git rev-parse HEAD').toString().trim();
// Because of Expo EAS, we need to use the commit hash from expo to avoid failing git command inside EAS
// because we need to call `yarn build:libs during native build`
const commitHash =
process.env.EAS_BUILD_GIT_COMMIT_HASH || execSync('git rev-parse HEAD').toString().trim();
export const config: webpack.Configuration = {
target: 'web',

View File

@@ -25,6 +25,7 @@
"prepublish": "yarn g:tsx ../../scripts/prepublish.js"
},
"dependencies": {
"expo-constants": "15.4.5",
"ua-parser-js": "^1.0.37"
},
"peerDependencies": {

View File

@@ -1,6 +1,7 @@
import { Dimensions, Platform } from 'react-native';
import { getLocales } from 'expo-localization';
import Constants from 'expo-constants';
import { EnvUtils } from './types';
@@ -24,9 +25,9 @@ const getDeviceType = () => '';
const getOsVersion = () => `${Platform.Version}`;
const getSuiteVersion = () => process.env.EXPO_PUBLIC_VERSION || '';
const getSuiteVersion = () => Constants.expoConfig?.version || '';
const getCommitHash = () => process.env.EXPO_PUBLIC_COMMIT_HASH || '';
const getCommitHash = () => Constants.expoConfig?.extra?.commitHash;
const isFirefox = () => false;

View File

@@ -1,7 +1,3 @@
EXPO_PUBLIC_ENVIRONMENT=debug
EXPO_PUBLIC_COMMIT_HASH=
EXPO_PUBLIC_CHANGELOG=
EXPO_PUBLIC_VERSION=
EXPO_PUBLIC_BUILD_NUMBER=
EXPO_PUBLIC_CODESIGN_BUILD=false
EXPO_PUBLIC_JWS_PUBLIC_KEY='-----BEGIN PUBLIC KEY-----MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEbSUHJlr17+NywPS/w+xMkp3dSD8eWXSuAfFKwonZPe5fL63kISipJC+eJP7Mad0WxgyJoiMsZCV6BZPK2jIFdg==-----END PUBLIC KEY-----'

View File

@@ -1,7 +1,3 @@
EXPO_PUBLIC_ENVIRONMENT=develop
EXPO_PUBLIC_COMMIT_HASH=
EXPO_PUBLIC_CHANGELOG=
EXPO_PUBLIC_VERSION=
EXPO_PUBLIC_BUILD_NUMBER=
EXPO_PUBLIC_CODESIGN_BUILD=false
EXPO_PUBLIC_JWS_PUBLIC_KEY='-----BEGIN PUBLIC KEY-----MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEbSUHJlr17+NywPS/w+xMkp3dSD8eWXSuAfFKwonZPe5fL63kISipJC+eJP7Mad0WxgyJoiMsZCV6BZPK2jIFdg==-----END PUBLIC KEY-----'

View File

@@ -1,7 +1,3 @@
EXPO_PUBLIC_ENVIRONMENT=production
EXPO_PUBLIC_COMMIT_HASH=
EXPO_PUBLIC_CHANGELOG=
EXPO_PUBLIC_VERSION=
EXPO_PUBLIC_BUILD_NUMBER=
EXPO_PUBLIC_CODESIGN_BUILD=true
EXPO_PUBLIC_JWS_PUBLIC_KEY='-----BEGIN PUBLIC KEY-----MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAES7MbBzU/v5BsljkTM8Mz0Jsk+Nn5n2wH\no2/+MUI3TgCVdTbEHhn3HXaY7GJ6TLyWqxn+pIDY9wUUAyUqOStTUQ==-----END PUBLIC KEY-----'

View File

@@ -1,7 +0,0 @@
EXPO_PUBLIC_ENVIRONMENT=staging
EXPO_PUBLIC_COMMIT_HASH=
EXPO_PUBLIC_CHANGELOG=
EXPO_PUBLIC_VERSION=
EXPO_PUBLIC_BUILD_NUMBER=
EXPO_PUBLIC_CODESIGN_BUILD=false
EXPO_PUBLIC_JWS_PUBLIC_KEY='-----BEGIN PUBLIC KEY-----MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAES7MbBzU/v5BsljkTM8Mz0Jsk+Nn5n2wH\no2/+MUI3TgCVdTbEHhn3HXaY7GJ6TLyWqxn+pIDY9wUUAyUqOStTUQ==-----END PUBLIC KEY-----'

View File

@@ -36,14 +36,6 @@ Because of usage of new Fabric architecture, it is not possible to use Chrome de
Best way how to debug app is download [Flipper](https://fbflipper.com).
## Distribution
Fastlane is the easiest way to automate beta deployments and releases for iOS and Android apps.
More information about _fastlane_ can be found on [fastlane.tools](https://fastlane.tools).
The documentation of _fastlane_ can be found on [docs.fastlane.tools](https://docs.fastlane.tools).
### Installation
Make sure you have the latest version of the Xcode command line tools installed:
@@ -51,69 +43,3 @@ Make sure you have the latest version of the Xcode command line tools installed:
```sh
xcode-select --install
```
For _fastlane_ installation instructions, see [Installing _fastlane_](https://docs.fastlane.tools/#installing-fastlane)
### Available Actions
#### iOS
##### iOS develop
```sh
[bundle exec] fastlane ios develop
```
Push a new beta build to TestFlight for develop build schema.
---
##### iOS staging
```sh
[bundle exec] fastlane ios staging
```
Push a new beta build to TestFlight for staging build schema.
---
##### iOS production
```sh
[bundle exec] fastlane ios production
```
TODO
---
#### Android
##### android develop
```sh
[bundle exec] fastlane android develop
```
Build and upload the app (develop) to Firebase App Distribution for testing in a small group of testers.
---
##### android staging
```sh
[bundle exec] fastlane android staging
```
Build and upload the app (staging) to Google Play Store for internal testing.
---
##### android production
```sh
[bundle exec] fastlane android production
```
Build and upload the app (production) to Google Play Store for internal testing.

View File

@@ -4,31 +4,19 @@ import { ExpoConfig, ConfigContext } from 'expo/config';
import { suiteNativeVersion } from './package.json';
type BuildType = 'debug' | 'develop' | 'staging' | 'production';
const getBuildType = (): BuildType => {
if (process.env.ENVIRONMENT === 'production') return 'production';
if (process.env.ENVIRONMENT === 'staging') return 'staging';
if (process.env.ENVIRONMENT === 'develop') return 'develop';
return 'debug';
};
const buildType = getBuildType();
type BuildType = 'debug' | 'develop' | 'production';
const bundleIdentifiers = {
debug: 'io.trezor.suite.debug',
develop: 'io.trezor.suite.develop',
staging: 'io.trezor.suite.staging',
production: 'io.trezor.suite',
} as const satisfies Record<BuildType, string>;
const bundleIdentifier = bundleIdentifiers[buildType];
const appIconsIos = {
debug: './assets/debug/appIcon.png',
develop: './assets/develop/appIcon.png',
staging: './assets/staging/appIcon.png',
production: './assets/production/appIcon.png',
} as const satisfies Record<BuildType, string>;
const appIconIos = appIconsIos[buildType];
const appIconsAndroid = {
debug: {
@@ -37,95 +25,133 @@ const appIconsAndroid = {
develop: {
backgroundColor: '#900B0B',
},
staging: {
backgroundColor: '#E49C18',
},
production: {
backgroundColor: '#0F6148',
},
} as const;
const appIconAndroid = appIconsAndroid[buildType];
const appNames = {
debug: 'Trezor Suite Debug',
develop: 'Trezor Suite Develop',
staging: 'Trezor Suite Staging',
production: 'Trezor Suite',
} as const satisfies Record<BuildType, string>;
const appName = appNames[buildType];
const appSlug = appName.replace(/\s/g, '');
if (!process.env.SENTRY_AUTH_TOKEN && buildType !== 'debug') {
throw new Error('Missing SENTRY_AUTH_TOKEN env variable');
}
const projectIds = {
develop: '3e4ea82b-6c9f-4cd3-8975-54bddda3ec2d',
production: 'b9bbf16c-3d44-4d58-8f0c-ba9e6265276a',
debug: '',
} as const satisfies Record<BuildType, string>;
export default ({ config }: ConfigContext): ExpoConfig => ({
...config,
name: appName,
slug: appSlug,
version: suiteNativeVersion,
splash: {
image: './assets/splash_icon.png',
backgroundColor: '#25292E',
resizeMode: 'contain',
},
android: {
package: bundleIdentifier,
versionCode: 1,
adaptiveIcon: {
foregroundImage: './assets/appIcon_android.png',
monochromeImage: './assets/appIcon_android.png',
...appIconAndroid,
export default ({ config }: ConfigContext): ExpoConfig => {
const buildType = (process.env.ENVIRONMENT_EXPO as BuildType) ?? 'debug';
const name = appNames[buildType];
const slug = appNames[buildType].toLowerCase().split(' ').join('-');
const bundleIdentifier = bundleIdentifiers[buildType];
const projectId = projectIds[buildType];
const appIconIos = appIconsIos[buildType];
const appIconAndroid = appIconsAndroid[buildType];
if (!process.env.SENTRY_AUTH_TOKEN && buildType !== 'debug') {
throw new Error('Missing SENTRY_AUTH_TOKEN env variable');
}
return {
...config,
name,
slug,
version: suiteNativeVersion,
splash: {
image: './assets/splash_icon.png',
backgroundColor: '#25292E',
resizeMode: 'contain',
},
},
ios: {
bundleIdentifier,
icon: appIconIos,
},
plugins: [
[
'expo-font',
{
fonts: [
'../../packages/theme/fonts/TTSatoshi-Medium.otf',
'../../packages/theme/fonts/TTSatoshi-DemiBold.otf',
android: {
package: bundleIdentifier,
adaptiveIcon: {
foregroundImage: './assets/appIcon_android.png',
monochromeImage: './assets/appIcon_android.png',
...appIconAndroid,
},
},
ios: {
bundleIdentifier,
icon: appIconIos,
infoPlist: {
NSCameraUsageDescription:
'$(PRODUCT_NAME) needs access to your Camera to scan your XPUB.',
NSFaceIDUsageDescription:
'$(PRODUCT_NAME) needs Face ID and Touch ID to keep sensitive data about your portfolio private.',
NSMicrophoneUsageDescription: 'This app does not require access to the microphone.',
ITSAppUsesNonExemptEncryption: false,
UISupportedInterfaceOrientations: [
'UIInterfaceOrientationPortrait',
'UIInterfaceOrientationPortraitUpsideDown',
],
},
],
[
'@sentry/react-native/expo',
{
url: 'https://sentry.io/',
authToken: process.env.SENTRY_AUTH_TOKEN,
project: 'suite-native',
organization: 'satoshilabs',
},
],
[
'expo-barcode-scanner',
{
cameraPermission: 'Allow $(PRODUCT_NAME) to access camera for QR code scanning.',
},
],
[
'expo-build-properties',
{
android: {
minSdkVersion: 28,
},
ios: {
deploymentTarget: '14.0',
flipper: 'true',
NSAppTransportSecurity: {
NSAllowsArbitraryLoads: true,
NSExceptionDomains: {
localhost: {
NSExceptionAllowsInsecureHTTPLoads: true,
},
'data.trezor.io': {
NSExceptionAllowsInsecureHTTPLoads: true,
NSIncludesSubdomains: true,
},
},
},
},
},
plugins: [
[
'expo-font',
{
fonts: [
'../../packages/theme/fonts/TTSatoshi-Medium.otf',
'../../packages/theme/fonts/TTSatoshi-DemiBold.otf',
],
},
],
[
'@sentry/react-native/expo',
{
url: 'https://sentry.io/',
authToken: process.env.SENTRY_AUTH_TOKEN,
project: 'suite-native',
organization: 'satoshilabs',
},
],
[
'expo-barcode-scanner',
{
cameraPermission:
'Allow $(PRODUCT_NAME) to access camera for QR code scanning.',
},
],
[
'expo-build-properties',
{
android: {
minSdkVersion: 28,
},
ios: {
deploymentTarget: '14.0',
flipper: 'true',
},
},
],
'@trezor/react-native-usb/plugins/withUSBDevice.js',
// Define FLIPPER_VERSION
'./plugins/withGradleProperties.js',
// These should come last
'./plugins/withRemoveXcodeLocalEnv.js',
['./plugins/withEnvFile.js', { buildType }],
],
'@trezor/react-native-usb/plugins/withUSBDevice.js',
// Define FLIPPER_VERSION
'./plugins/withGradleProperties.js',
// These should come last
'./plugins/withRemoveXcodeLocalEnv.js',
['./plugins/withEnvFile.js', { buildType }],
// This plugin must be removed once we use EAS
'./plugins/withAndroidSigningConfig.js',
],
});
extra: {
commitHash: process.env.EAS_BUILD_GIT_COMMIT_HASH?.substring(-6) || '',
eas: {
projectId,
},
},
owner: 'trezorcompany',
};
};

57
suite-native/app/eas.json Normal file
View File

@@ -0,0 +1,57 @@
{
"cli": {
"version": ">= 7.1.1",
"promptToConfigurePushNotifications": false,
"appVersionSource": "remote"
},
"build": {
"develop": {
"env": {
"ENVIRONMENT_EXPO": "develop"
},
"autoIncrement": true,
"ios": {
"distribution": "store"
},
"android": {
"distribution": "internal"
}
},
"production": {
"env": {
"ENVIRONMENT_EXPO": "production"
},
"autoIncrement": true,
"android": {
"credentialsSource": "remote"
},
"ios": {
"credentialsSource": "remote"
}
}
},
"submit": {
"develop": {
"android": {
"track": "internal",
"changesNotSentForReview": true
},
"ios": {
"bundleIdentifier": "io.trezor.suite.develop",
"ascAppId": "1631884497",
"appleTeamId": "C3P22XVH2C"
}
},
"production": {
"android": {
"track": "internal",
"changesNotSentForReview": true
},
"ios": {
"bundleIdentifier": "io.trezor.suite",
"ascAppId": "1631884497",
"appleTeamId": "C3P22XVH2C"
}
}
}
}

View File

@@ -1,135 +0,0 @@
skip_docs
# Paths
APP_GRADLE_PATH = File.join(ANDROID_PATH, 'app/build.gradle').freeze
platform :android do
before_all do |lane|
if lane == :develop
fetch_and_bump_firebase_version
elsif lane == :staging
TRACK = "internal"
fetch_and_bump_play_version
elsif lane == :production
TRACK = "internal"
fetch_and_bump_play_version
end
ENV["ENVFILE"] = ".env"
replace_debug_info_environment_variables
end
desc "Android: Increments internal build number and version number"
private_lane :fetch_and_bump_play_version do
google_play_json_key_file = CredentialsManager::AppfileConfig.try_fetch_value(:json_key_file)
package_name = CredentialsManager::AppfileConfig.try_fetch_value(:package_name)
previous_build_number = google_play_track_version_codes(
package_name: package_name,
track: TRACK,
json_key: google_play_json_key_file,
)[0]
build_number_int = previous_build_number + 1
ENV["EXPO_PUBLIC_BUILD_NUMBER"] = "#{build_number_int}"
android_set_version_code(gradle_file: APP_GRADLE_PATH, version_code: build_number_int)
android_set_version_name(gradle_file: APP_GRADLE_PATH, version_name: ENV["EXPO_PUBLIC_VERSION"])
end
private_lane :fetch_and_bump_firebase_version do
google_play_json_key_file = CredentialsManager::AppfileConfig.try_fetch_value(:json_key_file)
latest_release = firebase_app_distribution_get_latest_release(
app: ANDROID_FIREBASE_APP_ID,
service_credentials_file: google_play_json_key_file,
)
build_number_int = latest_release[:buildVersion].to_i + 1
ENV["EXPO_PUBLIC_BUILD_NUMBER"] = "#{build_number_int}"
# when there are no Firebase releases yet
unless latest_release.nil?
android_set_version_code(gradle_file: APP_GRADLE_PATH, version_code: build_number_int)
end
android_set_version_name(gradle_file: APP_GRADLE_PATH, version_name: ENV["EXPO_PUBLIC_VERSION"])
end
desc "Build and upload the app to Google Play Store."
private_lane :deploy_android_play_store do |options|
productFlavor = options[:flavor]
gradle(task: 'clean', project_dir: ANDROID_PATH)
gradle(
task: 'bundle',
flavor: productFlavor,
print_command: true,
build_type: 'Release',
project_dir: ANDROID_PATH
)
# Upload Android App Bundle to PlayStore like Internal testing Release
upload_to_play_store(
track: TRACK,
# set as "draft" to complete the release at some other time in PlayStore
release_status: 'draft', # <http://docs.fastlane.tools/actions/upload_to_play_store/#parameters>
skip_upload_images: true,
skip_upload_screenshots: true,
skip_upload_apk: true
)
end
desc "Build Debug build."
lane :debugging do |options|
gradle(task: 'clean', project_dir: ANDROID_PATH)
gradle(
task: 'assemble',
flavor: 'Dev',
build_type: 'Debug',
project_dir: ANDROID_PATH
)
end
desc "Deploy staging build to Google Play Store."
lane :staging do |options|
deploy_android_play_store(flavor: "Stag")
end
desc "Deploy production build to Google Play Store."
lane :production do |options|
deploy_android_play_store(flavor: "Prod")
end
desc "Build and deploy the app to Firebase App Distribution for develop build."
lane :develop do |options|
google_play_json_key_file = CredentialsManager::AppfileConfig.try_fetch_value(:json_key_file)
gradle(task: 'clean', project_dir: ANDROID_PATH)
gradle(
task: 'assemble',
flavor: 'FirebaseDevelop',
build_type: 'Release',
project_dir: ANDROID_PATH
)
# find apk path
output_path = File.join(ANDROID_PATH, 'android/app/build/outputs/apk/').freeze
output_json_path = output_path + "output-metadata.json"
build_output = load_json(json_path: output_json_path)
elements = build_output["elements"][0]
apk_path = output_path + elements["outputFile"]
firebase_app_distribution(
app: ANDROID_FIREBASE_APP_ID,
apk_path: apk_path,
service_credentials_file: google_play_json_key_file,
release_notes: "#{ENV["EXPO_PUBLIC_COMMIT_HASH"]} - #{ENV["EXPO_PUBLIC_CHANGELOG"]}",
groups: "develop-testers",
debug: true
)
end
end

View File

@@ -1,36 +0,0 @@
# iOS
for_platform :ios do
itc_team_id("119058140") # App Store Connect Team ID
team_id("C3P22XVH2C") # Developer Portal Team ID
for_lane :debugging do
app_identifier 'io.trezor.suite.debug'
end
for_lane :develop do
app_identifier 'io.trezor.suite.develop'
end
for_lane :staging do
app_identifier 'io.trezor.suite.staging'
end
for_lane :production do
app_identifier 'io.trezor.suite'
end
end
# Android
for_platform :android do
json_key_file(ENV['GOOGLE_PLAY_JSON_KEY_FILE']) # Path to the json secret file - Follow https://docs.fastlane.tools/actions/supply/#setup to get one
for_lane :debugging do
package_name 'io.trezor.suite.debug'
end
for_lane :develop do
package_name 'io.trezor.suite.develop'
end
for_lane :staging do
package_name 'io.trezor.suite.staging'
end
for_lane :production do
package_name 'io.trezor.suite'
end
end

View File

@@ -1,63 +0,0 @@
# Common Functions and Requirements
# across Android/iOS Fastfiles
# necessary for sed when a branch name includes slash
def escape_slash(string)
string.gsub('/', '\/')
end
# Path Constants
SUITE_NATIVE_ROOT_PATH = File.expand_path('../', Dir.pwd).freeze
# Android project
ANDROID_PATH = File.join(SUITE_NATIVE_ROOT_PATH, 'android').freeze
ANDROID_FIREBASE_APP_ID = ENV['FIREBASE_APP_ID']
# iOS project
IOS_PATH = File.join(SUITE_NATIVE_ROOT_PATH, 'ios').freeze
# Retrieve version of Suite Native app in package.json
PACKAGE_JSON_PATH = File.join(SUITE_NATIVE_ROOT_PATH, 'package.json').freeze
commit = last_git_commit
commit_message = commit[:message]
commit_hash = commit[:abbreviated_commit_hash]
ENV["EXPO_PUBLIC_COMMIT_HASH"] = "#{commit_hash}"
ENV["EXPO_PUBLIC_CHANGELOG"] = escape_slash "[#{git_branch}] - #{commit_message}".strip
ENV["EXPO_PUBLIC_VERSION"] = load_json(json_path: "package.json")["suiteNativeVersion"]
private_lane :replace_debug_info_environment_variables do |options|
platform = lane_context[SharedValues::PLATFORM_NAME]
environment_file_name = ENV["ENVFILE"]
environment_file = File.join(SUITE_NATIVE_ROOT_PATH, environment_file_name)
commit_hash_substitute = "s/^(EXPO_PUBLIC_COMMIT_HASH)=(.*)$/\\1=#{ENV["EXPO_PUBLIC_COMMIT_HASH"]}/"
changelog_substitute = "s/^(EXPO_PUBLIC_CHANGELOG)=(.*)$/\\1=#{ENV["EXPO_PUBLIC_CHANGELOG"]}/"
version_substitute = "s/^(EXPO_PUBLIC_VERSION)=(.*)$/\\1=#{ENV["EXPO_PUBLIC_VERSION"]}/"
build_number_substitute = "s/^(EXPO_PUBLIC_BUILD_NUMBER)=(.*)$/\\1=#{ENV["EXPO_PUBLIC_BUILD_NUMBER"]}/"
if is_ci and platform == :ios
sh(
<<-SHELL
sed -r -i '' '#{commit_hash_substitute}' '#{environment_file}'
sed -r -i '' '#{changelog_substitute}' '#{environment_file}'
sed -r -i '' '#{version_substitute}' '#{environment_file}'
sed -r -i '' '#{build_number_substitute}' '#{environment_file}'
SHELL
)
elsif is_ci and platform == :android
sh(
<<-SHELL
sed -r -i '#{commit_hash_substitute}' '#{environment_file}'
sed -r -i '#{changelog_substitute}' '#{environment_file}'
sed -r -i '#{version_substitute}' '#{environment_file}'
sed -r -i '#{build_number_substitute}' '#{environment_file}'
SHELL
)
end
end
import "./IosFastfile"
import "./AndroidFastfile"

View File

@@ -1,249 +0,0 @@
skip_docs
# iOS Specific Constants
IOS_PROJECT = File.join(IOS_PATH, "TrezorSuite.xcodeproj").freeze
IOS_PROJECT_WORKSPACE = File.join(IOS_PATH, "TrezorSuite.xcworkspace").freeze
# temporary keychain database
def delete_temp_keychain(name)
delete_keychain(
name: name
) if File.exist? File.expand_path("~/Library/Keychains/#{name}-db")
end
def create_temp_keychain(name, password)
create_keychain(
name: name,
password: password,
unlock: true,
default_keychain: true,
add_to_search_list: true,
lock_when_sleeps: false,
timeout: 3600
)
end
def ensure_temp_keychain(name, password)
delete_temp_keychain(name)
create_temp_keychain(name, password)
end
platform :ios do
before_all do |lane|
xcversion(version: "14.1")
app_identifier = CredentialsManager::AppfileConfig.try_fetch_value(:app_identifier)
puts "Running lane #{lane} with App ID #{app_identifier}."
if lane != :debugging
PROVISIONING_NAME = "AppStore #{app_identifier}"
import_certificate_to_keychain
load_appstore_connect_api_key
fetch_and_bump_versions
else
PROVISIONING_NAME = "#{app_identifier} Development"
end
ENV["ENVFILE"] = ".env"
replace_debug_info_environment_variables
end
desc "Import certificate to keychain"
private_lane :import_certificate_to_keychain do
# creates temporary keychain
keychain_name = ENV['TMP_KEYCHAIN_NAME']
keychain_password = ENV['TMP_KEYCHAIN_PASSWORD']
ensure_temp_keychain(keychain_name, keychain_password)
# import certificate to temporary keychain
import_certificate(
keychain_name: ENV['TMP_KEYCHAIN_NAME'],
keychain_password: ENV['TMP_KEYCHAIN_PASSWORD'],
certificate_path: "TrezorDistributionCertificate.p12",
certificate_password: ENV["APPSTORE_CERTIFICATE_PASSWORD"] || "default"
)
end
desc "Load Appstore Connect API Key information to use in subsequent lanes"
private_lane :load_appstore_connect_api_key do
app_store_connect_api_key(
key_id: ENV['APPSTORE_KEY_ID'], # the Key ID used for Appstore Connect authentication
issuer_id: ENV['APPSTORE_KEY_ISSUER_ID'], # the issuer ID used for Appstore Connect authentication
key_content: ENV['APPSTORE_KEY_FILE_CONTENT'], # the base64-encoded private key (.p8) used for Appstore Connect authentication
is_key_content_base64: true,
duration: 1200,
in_house: false
)
end
desc "Check certs and profiles"
private_lane :prepare_distribution_signing do
app_identifier = CredentialsManager::AppfileConfig.try_fetch_value(:app_identifier)
api_key = lane_context[SharedValues::APP_STORE_CONNECT_API_KEY]
# it makes sure you have a valid certificate and its private key installed on the local machine
cert(
api_key: api_key,
keychain_path: "~/Library/Keychains/#{ENV['TMP_KEYCHAIN_NAME']}-db",
keychain_password: ENV["TMP_KEYCHAIN_PASSWORD"]
)
# it makes sure you have a valid provisioning profile installed locally, that matches the installed certificate
sigh(
api_key: api_key,
app_identifier: app_identifier,
provisioning_name: PROVISIONING_NAME,
force: true # always recreate this exact profile to ensure it's valid and not expired
)
end
desc "Increments internal build number and version number"
private_lane :fetch_and_bump_versions do
app_identifier = CredentialsManager::AppfileConfig.try_fetch_value(:app_identifier)
api_key = lane_context[SharedValues::APP_STORE_CONNECT_API_KEY]
previous_build_number = latest_testflight_build_number(
app_identifier: app_identifier,
api_key: api_key
)
build_number_int = previous_build_number + 1
ENV["EXPO_PUBLIC_BUILD_NUMBER"] = "#{build_number_int}"
increment_build_number(
xcodeproj: IOS_PROJECT,
build_number: build_number_int
)
increment_version_number(
xcodeproj: IOS_PROJECT,
version_number: ENV["EXPO_PUBLIC_VERSION"]
)
end
desc "Build the iOS app for testing"
private_lane :build_app_to_distribute do |options|
build_scheme = options[:scheme]
export_method = options[:export_method]
app_identifier = CredentialsManager::AppfileConfig.try_fetch_value(:app_identifier)
code_sign_identity = "iPhone Distribution" # sign an app before distributing it through the App Store
# update the code signing identities to match profile name and app bundle identifier
update_code_signing_settings(
use_automatic_signing: false, # turn off automatic signing during build so correct code signing identity is guaranteed to be used
targets: [build_scheme],
code_sign_identity: code_sign_identity,
bundle_identifier: app_identifier,
profile_name: PROVISIONING_NAME,
build_configurations: [build_scheme], # only toggle code signing settings for Release configurations
path: IOS_PROJECT
)
unlock_keychain(
path: "#{ENV['TMP_KEYCHAIN_NAME']}-db",
password: ENV["TMP_KEYCHAIN_PASSWORD"]
)
build_app(
scheme: build_scheme,
export_method: export_method,
output_name: "#{build_scheme}-TrezorSuite",
workspace: IOS_PROJECT_WORKSPACE,
configuration: build_scheme
)
end
desc "Sign, build and push a new build to TestFlight"
private_lane :build_to_testflight do |options|
api_key = lane_context[SharedValues::APP_STORE_CONNECT_API_KEY]
prepare_distribution_signing
build_app_to_distribute(scheme: options[:scheme], export_method: options[:export_method])
upload_to_testflight(
api_key: api_key,
skip_waiting_for_build_processing: true
)
end
desc "Sign, build and push a new build to App Store"
private_lane :build_to_app_store do |options|
api_key = lane_context[SharedValues::APP_STORE_CONNECT_API_KEY]
prepare_distribution_signing
build_app_to_distribute(scheme: options[:scheme], export_method: options[:export_method])
upload_to_app_store(
api_key: api_key,
run_precheck_before_submit: false,
force: true, # not to generate HTML report
reject_if_possible: true, # if the app is already waiting for the review and not reviewing yet, cancel it
skip_metadata: false,
skip_screenshots: true,
languages: ['en-US'],
release_notes: {
"default" => "TODO idea - this could be specified from Github action input?",
"en-US" => "TODO idea - this could be specified from Github action input?",
}
)
end
desc "Sign and build the app locally and get .ipa"
private_lane :build_local_ipa do |options|
build_scheme = options[:scheme]
export_method = options[:export_method]
app_identifier = CredentialsManager::AppfileConfig.try_fetch_value(:app_identifier)
# 0. get username (to get or generate provisioning profile with a certificate for requesting user)
# 1 provisioning profile has to be connected with 1 local certificate so every developer will have own provisioning profile
apple_username = prompt(text: "Please, write your Apple ID Username and confirm: ")
# 1. development signing
cert(
development: true,
username: apple_username
)
sigh(
development: true,
username: apple_username,
app_identifier: app_identifier,
provisioning_name: "#{PROVISIONING_NAME} - #{apple_username}",
force: true # always recreate this exact profile to ensure it's valid and not expired
)
# 2. development build
code_sign_identity = "Apple Development" # use app services during development and testing
# Configures Xcode's Codesigning options
update_code_signing_settings(
use_automatic_signing: true,
targets: [build_scheme],
code_sign_identity: code_sign_identity,
bundle_identifier: app_identifier,
build_configurations: [build_scheme], # only toggle code signing settings for Release configurations
path: IOS_PROJECT
)
build_app(
scheme: build_scheme,
export_method: export_method,
output_name: "#{build_scheme}-TrezorSuite",
workspace: IOS_PROJECT_WORKSPACE,
configuration: build_scheme
)
end
desc "Build debug version of the app"
lane :debugging do
build_local_ipa(scheme: "TrezorSuiteDebug", export_method: "development")
end
desc "Build develop version of the app"
lane :develop do
build_to_testflight(scheme: "TrezorSuiteDevelop", export_method: "app-store")
end
desc "Build staging version of the app and upload to App Store Connect"
lane :staging do
build_to_testflight(scheme: "TrezorSuiteStaging", export_method: "app-store")
end
desc "Build production version of the app and upload to App Store Connect"
lane :production do
build_to_app_store(scheme: "TrezorSuite", export_method: "app-store")
end
end

View File

@@ -1,9 +0,0 @@
# Autogenerated by fastlane
#
# Ensure this file is checked in to source control!
gem 'fastlane-plugin-load_json'
gem 'fastlane-plugin-versioning_android'
gem 'fastlane-plugin-update_android_strings'
gem 'fastlane-plugin-android_versioning'
gem 'fastlane-plugin-firebase_app_distribution'

View File

@@ -1,7 +1,7 @@
{
"name": "@suite-native/app",
"version": "1.0.0",
"suiteNativeVersion": "24.2.0",
"suiteNativeVersion": "24.3.1",
"main": "index.js",
"scripts": {
"android": "expo run:android",
@@ -12,6 +12,8 @@
"type-check": "yarn g:tsc -b",
"pods": "npx pod-install",
"prebuild": "expo prebuild",
"eas-build-post-install": "yarn build:libs",
"eas-build-on-success": "./upload-to-firebase.sh",
"prebuild:clean": "expo prebuild --clean"
},
"dependencies": {
@@ -70,6 +72,7 @@
"expo-barcode-scanner": "12.9.2",
"expo-build-properties": "^0.11.1",
"expo-clipboard": "5.0.1",
"expo-dev-client": "^3.3.7",
"expo-haptics": "12.8.1",
"expo-image": "1.10.6",
"expo-linear-gradient": "12.7.1",

View File

@@ -1,34 +0,0 @@
/* eslint-disable @typescript-eslint/no-shadow */
/*
* This plugin is only necessary for support of legacy fastlane setup. It must be removed once EAS is fully adopted.
*/
const { withAppBuildGradle } = require('expo/config-plugins');
const newDebugConfig = `
storeFile file(System.getenv("SIGNING_KEY_FILE"))
storePassword System.getenv("SIGNING_KEY_STORE_PASSWORD")
keyAlias System.getenv("SIGNING_KEY_ALIAS")
keyPassword System.getenv("SIGNING_KEY_PASSWORD")
`;
function updateAndroidGradleFile(contents) {
// Replacement string
const replacement = `signingConfigs {
debug {${newDebugConfig}
}`;
// Replace the content
const updatedGradleCode = contents.replace(
/signingConfigs\s*{\s*debug\s*{[^}]*}/,
replacement.trim(),
);
return updatedGradleCode;
}
module.exports = config =>
withAppBuildGradle(config, config => {
if (process.env.SIGNING_KEY_FILE) {
config.modResults.contents = updateAndroidGradleFile(config.modResults.contents);
}
return config;
});

View File

@@ -4,12 +4,9 @@ import { useSelector } from 'react-redux';
import * as Sentry from '@sentry/react-native';
import { selectIsAnalyticsEnabled } from '@suite-common/analytics';
import { getEnv, isDebugEnv, isDevelopEnv, isStagingEnv } from '@suite-native/config';
import { getEnv, isDebugEnv, isDevelopEnv } from '@suite-native/config';
import { selectIsOnboardingFinished } from '@suite-native/module-settings';
// Enforce sentry to be enabled in devs environments (dev,staging) because we want to catch all errors
const isAlwaysEnabled = isDevelopEnv() || isStagingEnv();
const initSentry = () => {
if (!isDebugEnv()) {
Sentry.init({
@@ -29,7 +26,8 @@ export const SentryProvider = ({ children }: { children: ReactNode }) => {
const isAnalyticsEnabled = useSelector(selectIsAnalyticsEnabled);
useEffect(() => {
if (!isAlwaysEnabled && isOnboardingFinished) {
// Enforce sentry to be enabled in dev environment because we want to catch all errors
if (!isDevelopEnv() && isOnboardingFinished) {
if (!isAnalyticsEnabled) {
Sentry.close();
} else {

View File

@@ -0,0 +1,17 @@
#!/bin/bash
if [[ "$EAS_BUILD_PLATFORM" == "android" ]]; then
curl -sL https://firebase.tools | bash
commit_hash=$(git log -1 --pretty=format:"%H")
release_notes="Bug fixes and improvements. Last commit hash: $commit_hash"
firebase appdistribution:distribute "$EAS_BUILD_WORKINGDIR"/suite-native/app/android/app/build/outputs/apk/release/app-release.apk \
--project pc-api-4710771878548015996-769 \
--app 1:191883890128:android:625bcdab76b3b3a644bdd5 \
--groups "develop-testers" \
--release-notes "$release_notes" \
--token "$FIREBASE_TOKEN"
elif [[ "$EAS_BUILD_PLATFORM" == "ios" ]]; then
exit 0
fi

View File

@@ -1,3 +0,0 @@
export const getBuildVersionNumber = () => process.env.EXPO_PUBLIC_BUILD_NUMBER || '';
export const getChangelog = () => process.env.EXPO_PUBLIC_CHANGELOG || '';

View File

@@ -1,6 +1,5 @@
export const isDebugEnv = () => process.env.EXPO_PUBLIC_ENVIRONMENT === 'debug';
export const isDevelopEnv = () => process.env.EXPO_PUBLIC_ENVIRONMENT === 'develop';
export const isStagingEnv = () => process.env.EXPO_PUBLIC_ENVIRONMENT === 'staging';
export const isProduction = () => process.env.EXPO_PUBLIC_ENVIRONMENT === 'production';
export const isDevelopOrDebugEnv = () => isDebugEnv() || isDevelopEnv();

View File

@@ -1,4 +1,3 @@
export * from './debugUtils';
export * from './environment';
export * from './supportedNetworks';
export * from './jws';

View File

@@ -1,13 +0,0 @@
import { getEnv, getChangelog, getBuildVersionNumber } from '@suite-native/config';
import { getSuiteVersion, getCommitHash } from '@trezor/env-utils';
import { ListItem, VStack } from '@suite-native/atoms';
export const BuildInfo = () => (
<VStack spacing="medium">
<ListItem
subtitle={`${getEnv()}-${getSuiteVersion()} (${getBuildVersionNumber()}), commit ${getCommitHash()}`}
title="Build version"
/>
<ListItem subtitle={getChangelog()} title="Changelog" />
</VStack>
);

View File

@@ -2,8 +2,8 @@ import { Alert } from 'react-native';
import * as Sentry from '@sentry/react-native';
import { isDebugEnv, isDevelopOrDebugEnv, isProduction } from '@suite-native/config';
import { Button, Card, VStack } from '@suite-native/atoms';
import { getEnv, isDebugEnv, isDevelopOrDebugEnv, isProduction } from '@suite-native/config';
import { Button, Card, ListItem, VStack } from '@suite-native/atoms';
import {
Screen,
StackProps,
@@ -12,8 +12,8 @@ import {
ScreenSubHeader,
} from '@suite-native/navigation';
import { clearStorage } from '@suite-native/storage';
import { getCommitHash, getSuiteVersion } from '@trezor/env-utils';
import { BuildInfo } from '../components/BuildInfo';
import { RenderingUtils } from '../components/RenderingUtils';
import { FeatureFlags } from '../components/FeatureFlags';
import { TestnetsToggle } from '../components/TestnetsToggle';
@@ -26,7 +26,12 @@ export const DevUtilsScreen = ({
<VStack>
<Card>
<VStack spacing="medium">
{!isDebugEnv() && <BuildInfo />}
{!isDebugEnv() && (
<ListItem
subtitle={`${getEnv()}-${getSuiteVersion()}, commit ${getCommitHash()}`}
title="Build version"
/>
)}
{isDebugEnv() && (
<Button onPress={() => navigation.navigate(DevUtilsStackRoutes.Demo)}>
See Component Demo

View File

@@ -31,6 +31,7 @@
"@suite-native/navigation": "workspace:*",
"@suite-native/storage": "workspace:*",
"@suite-native/theme": "workspace:*",
"@suite-native/toasts": "workspace:*",
"@trezor/connect": "workspace:*",
"@trezor/env-utils": "workspace:*",
"@trezor/styles": "workspace:*",

View File

@@ -1,32 +1,25 @@
import { S } from '@mobily/ts-belt';
import { Text, Box, HStack } from '@suite-native/atoms';
import { getBuildVersionNumber } from '@suite-native/config';
import { getSuiteVersion, getCommitHash } from '@trezor/env-utils';
import { ProductionDebug } from './ProductionDebug';
export const AppVersion = () => {
const hasVersionAndBuildInfo =
S.isNotEmpty(getSuiteVersion()) && S.isNotEmpty(getBuildVersionNumber());
const hasCommitHash = S.isNotEmpty(getCommitHash());
return (
<HStack marginHorizontal="medium" justifyContent="space-between">
<Box>
{hasVersionAndBuildInfo && (
<Text variant="hint" color="textDisabled">
Version: {`${getSuiteVersion()} (${getBuildVersionNumber()})`}
</Text>
)}
</Box>
<ProductionDebug>
{hasCommitHash && (
<Text variant="hint" color="textDisabled">
Last commit hash: {getCommitHash()}
</Text>
)}
</ProductionDebug>
</HStack>
);
};
export const AppVersion = () => (
<HStack marginHorizontal="medium" justifyContent="space-between">
<Box>
{S.isNotEmpty(getSuiteVersion()) && (
<Text variant="hint" color="textDisabled">
Version: {`${getSuiteVersion()}`}
</Text>
)}
</Box>
<ProductionDebug>
{S.isNotEmpty(getCommitHash()) && (
<Text variant="hint" color="textDisabled">
Last commit hash: {getCommitHash()}
</Text>
)}
</ProductionDebug>
</HStack>
);

View File

@@ -5,6 +5,7 @@ import { useSetAtom } from 'jotai';
import { isDevelopOrDebugEnv } from '@suite-native/config';
import { atomWithUnecryptedStorage } from '@suite-native/storage';
import { useToast } from '@suite-native/toasts';
type ProductionDebugProps = {
children: ReactNode;
@@ -18,6 +19,7 @@ export const isDevButtonVisibleAtom = atomWithUnecryptedStorage<boolean>(
export const ProductionDebug = ({ children }: ProductionDebugProps) => {
const setIsDevButtonVisible = useSetAtom(isDevButtonVisibleAtom);
const { showToast } = useToast();
const handleTapsCount = () => {
if (tapsCount < 7) {
@@ -25,6 +27,11 @@ export const ProductionDebug = ({ children }: ProductionDebugProps) => {
}
if (tapsCount === 7) {
setIsDevButtonVisible(true);
showToast({
variant: 'default',
message: 'Dev utils enabled.',
icon: 'check',
});
}
};

View File

@@ -23,6 +23,7 @@
{ "path": "../navigation" },
{ "path": "../storage" },
{ "path": "../theme" },
{ "path": "../toasts" },
{ "path": "../../packages/connect" },
{ "path": "../../packages/env-utils" },
{ "path": "../../packages/styles" },

102
yarn.lock
View File

@@ -7858,6 +7858,7 @@ __metadata:
expo-barcode-scanner: "npm:12.9.2"
expo-build-properties: "npm:^0.11.1"
expo-clipboard: "npm:5.0.1"
expo-dev-client: "npm:^3.3.7"
expo-haptics: "npm:12.8.1"
expo-image: "npm:1.10.6"
expo-linear-gradient: "npm:12.7.1"
@@ -8562,6 +8563,7 @@ __metadata:
"@suite-native/navigation": "workspace:*"
"@suite-native/storage": "workspace:*"
"@suite-native/theme": "workspace:*"
"@suite-native/toasts": "workspace:*"
"@trezor/connect": "workspace:*"
"@trezor/env-utils": "workspace:*"
"@trezor/styles": "workspace:*"
@@ -9565,6 +9567,7 @@ __metadata:
version: 0.0.0-use.local
resolution: "@trezor/env-utils@workspace:packages/env-utils"
dependencies:
expo-constants: "npm:15.4.5"
ua-parser-js: "npm:^1.0.37"
peerDependencies:
expo-localization: "*"
@@ -12341,6 +12344,18 @@ __metadata:
languageName: node
linkType: hard
"ajv@npm:8.11.0":
version: 8.11.0
resolution: "ajv@npm:8.11.0"
dependencies:
fast-deep-equal: "npm:^3.1.1"
json-schema-traverse: "npm:^1.0.0"
require-from-string: "npm:^2.0.2"
uri-js: "npm:^4.2.2"
checksum: aa0dfd6cebdedde8e77747e84e7b7c55921930974b8547f54b4156164ff70445819398face32dafda4bd4c61bbc7513d308d4c2bf769f8ea6cb9c8449f9faf54
languageName: node
linkType: hard
"ajv@npm:^6.10.0, ajv@npm:^6.12.0, ajv@npm:^6.12.4, ajv@npm:^6.12.5":
version: 6.12.6
resolution: "ajv@npm:6.12.6"
@@ -18382,14 +18397,65 @@ __metadata:
languageName: node
linkType: hard
"expo-constants@npm:~15.4.0":
version: 15.4.3
resolution: "expo-constants@npm:15.4.3"
"expo-constants@npm:15.4.5, expo-constants@npm:~15.4.0":
version: 15.4.5
resolution: "expo-constants@npm:15.4.5"
dependencies:
"@expo/config": "npm:~8.5.0"
peerDependencies:
expo: "*"
checksum: ece1bb5d83338874a7061a486ec9ba087f48a3caf12692fe492fa16df9b5b7160ae1b78590c1e98866e15be7d5c05d2fe9e4c597a0653d8c7b4189d0e544ff1e
checksum: 9eb256895aa24efd41ca8c48b7dd76c03ecad4662e86c32440ea7d4162397014c80775b73db499add5e9452721f236c6ba333af93d8a277ad964f1fd938305f1
languageName: node
linkType: hard
"expo-dev-client@npm:^3.3.7":
version: 3.3.8
resolution: "expo-dev-client@npm:3.3.8"
dependencies:
expo-dev-launcher: "npm:3.6.6"
expo-dev-menu: "npm:4.5.5"
expo-dev-menu-interface: "npm:1.7.2"
expo-manifests: "npm:~0.13.0"
expo-updates-interface: "npm:~0.15.1"
peerDependencies:
expo: "*"
checksum: 8f37117ceb767b51d442b6895f0ed8a76a719a5b4084e1f081d6711e2a02b0414405514e360ca4696e4916cc1fd9d019b7559200fc35a811a05526db356e60fb
languageName: node
linkType: hard
"expo-dev-launcher@npm:3.6.6":
version: 3.6.6
resolution: "expo-dev-launcher@npm:3.6.6"
dependencies:
ajv: "npm:8.11.0"
expo-dev-menu: "npm:4.5.5"
expo-manifests: "npm:~0.13.0"
resolve-from: "npm:^5.0.0"
semver: "npm:^7.5.3"
peerDependencies:
expo: "*"
checksum: 143cad2bda5d8f82f1f7388ac98f9123d3ad4aea6c0a76d2ca5bb2b5beb48c433b782c732eb695d465f43bb339c3c2c1c09f42cb2ce9d6f1f0110f8aadec6515
languageName: node
linkType: hard
"expo-dev-menu-interface@npm:1.7.2":
version: 1.7.2
resolution: "expo-dev-menu-interface@npm:1.7.2"
peerDependencies:
expo: "*"
checksum: 28df663590af53ec35014e934f61b61113f9acfdefa11dfded9be98a6f3875e32cd25750a6e1e1cccccef3ec6cc3faf08a2bf61ef02c6950e50327d1e01b84b3
languageName: node
linkType: hard
"expo-dev-menu@npm:4.5.5":
version: 4.5.5
resolution: "expo-dev-menu@npm:4.5.5"
dependencies:
expo-dev-menu-interface: "npm:1.7.2"
semver: "npm:^7.5.3"
peerDependencies:
expo: "*"
checksum: 7389c9a8d00edee6d2490ff4f72117a9dddd22dffa8bc10a2f532e6c0008f82d911d5a8bb0bff20531e0383795f601197233db31c1798e6e00524548af4899f0
languageName: node
linkType: hard
@@ -18453,6 +18519,13 @@ __metadata:
languageName: node
linkType: hard
"expo-json-utils@npm:~0.12.0":
version: 0.12.3
resolution: "expo-json-utils@npm:0.12.3"
checksum: aefaa9fa58514665d4dd761b0f2d09bf9e3b9a36f4dc7b943b1155b1e1f6a45985c9a5370f13ba01d2c38b0a4158e574c6cf7895b3b61e56a6d665696ae0d87b
languageName: node
linkType: hard
"expo-keep-awake@npm:~12.8.2":
version: 12.8.2
resolution: "expo-keep-awake@npm:12.8.2"
@@ -18493,6 +18566,18 @@ __metadata:
languageName: node
linkType: hard
"expo-manifests@npm:~0.13.0":
version: 0.13.2
resolution: "expo-manifests@npm:0.13.2"
dependencies:
"@expo/config": "npm:~8.5.0"
expo-json-utils: "npm:~0.12.0"
peerDependencies:
expo: "*"
checksum: 446712a856bf91c7034d08ad5dc98a8a0c139271baca1b5dfb8474108228cae79bb9f4d6a93b36dc51b2a03ce1ce6762516349251fdfbf348c30788b9baf1e58
languageName: node
linkType: hard
"expo-modules-autolinking@npm:1.10.3":
version: 1.10.3
resolution: "expo-modules-autolinking@npm:1.10.3"
@@ -18580,6 +18665,15 @@ __metadata:
languageName: node
linkType: hard
"expo-updates-interface@npm:~0.15.1":
version: 0.15.3
resolution: "expo-updates-interface@npm:0.15.3"
peerDependencies:
expo: "*"
checksum: 9c6caf30bbf6d0e850decdfde271c61fd2508bad7c6a9649f234c2f8ca949c67647c3d07734bacce6de377cdfa7662d442d2d2e57efa587a35f85a3480436992
languageName: node
linkType: hard
"expo@npm:50.0.6":
version: 50.0.6
resolution: "expo@npm:50.0.6"