diff --git a/android/app/build.gradle b/android/app/build.gradle
index fd124e105c38..bb9bb30a2c19 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -1,4 +1,5 @@
apply plugin: "com.android.application"
+apply plugin: "com.google.firebase.firebase-perf"
apply from: '../../node_modules/react-native-unimodules/gradle.groovy'
apply from: project(':react-native-config').projectDir.getPath() + "/dotenv.gradle"
@@ -233,6 +234,9 @@ dependencies {
implementation jscFlavor
}
+ implementation platform("com.google.firebase:firebase-bom:20.0.2")
+ implementation "com.google.firebase:firebase-perf"
+
// GIF support
implementation 'com.facebook.fresco:fresco:2.3.0'
implementation 'com.facebook.fresco:animated-gif:2.3.0'
diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml
index 6dc098f4797a..912a6f110cb4 100644
--- a/android/app/src/debug/AndroidManifest.xml
+++ b/android/app/src/debug/AndroidManifest.xml
@@ -4,5 +4,10 @@
-
+
+
+
diff --git a/android/app/src/main/java/com/expensify/chat/ExpensifyAppPackage.java b/android/app/src/main/java/com/expensify/chat/ExpensifyAppPackage.java
new file mode 100644
index 000000000000..63195d50b2cb
--- /dev/null
+++ b/android/app/src/main/java/com/expensify/chat/ExpensifyAppPackage.java
@@ -0,0 +1,29 @@
+package com.expensify.chat;
+
+import com.facebook.react.ReactPackage;
+import com.facebook.react.bridge.NativeModule;
+import com.facebook.react.bridge.ReactApplicationContext;
+import com.facebook.react.uimanager.ViewManager;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public class ExpensifyAppPackage implements ReactPackage {
+
+ @Override
+ public List createViewManagers(ReactApplicationContext reactContext) {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public List createNativeModules(
+ ReactApplicationContext reactContext) {
+ List modules = new ArrayList<>();
+
+ modules.add(new StartupTimer(reactContext));
+
+ return modules;
+ }
+
+}
diff --git a/android/app/src/main/java/com/expensify/chat/MainApplication.java b/android/app/src/main/java/com/expensify/chat/MainApplication.java
index 824148c2c1b6..0a01f65adc6c 100644
--- a/android/app/src/main/java/com/expensify/chat/MainApplication.java
+++ b/android/app/src/main/java/com/expensify/chat/MainApplication.java
@@ -42,6 +42,7 @@ protected List getPackages() {
// Packages that cannot be autolinked yet can be added manually here, for example:
// packages.add(new MyReactNativePackage());
packages.add(new PlaidPackage());
+ packages.add(new ExpensifyAppPackage());
// Add unimodules
List unimodules = Arrays.asList(
@@ -76,6 +77,11 @@ public void onCreate() {
FirebaseCrashlytics.getInstance().setCrashlyticsCollectionEnabled(false);
}
+ // Start the "js_load" custom performance tracing metric. This timer is stopped by a native
+ // module in the JS so we can measure total time starting in the native layer and ending in
+ // the JS layer.
+ StartupTimer.start();
+
// Increase SQLite DB write size
try {
Field field = CursorWindow.class.getDeclaredField("sCursorWindowSize");
diff --git a/android/app/src/main/java/com/expensify/chat/StartupTimer.java b/android/app/src/main/java/com/expensify/chat/StartupTimer.java
new file mode 100644
index 000000000000..de43519fcb15
--- /dev/null
+++ b/android/app/src/main/java/com/expensify/chat/StartupTimer.java
@@ -0,0 +1,39 @@
+package com.expensify.chat;
+import android.util.Log;
+
+import com.facebook.react.bridge.ReactApplicationContext;
+import com.facebook.react.bridge.ReactContextBaseJavaModule;
+import com.facebook.react.bridge.ReactMethod;
+import com.google.firebase.perf.FirebasePerformance;
+import com.google.firebase.perf.metrics.Trace;
+
+public class StartupTimer extends ReactContextBaseJavaModule {
+ StartupTimer(ReactApplicationContext context) {
+ super(context);
+ }
+
+ private static Trace trace = null;
+
+ @Override
+ public String getName() {
+ return "StartupTimer";
+ }
+
+ @ReactMethod
+ public void stop() {
+ if (trace == null) {
+ return;
+ }
+
+ trace.stop();
+ }
+
+ public static void start() {
+ if (BuildConfig.DEBUG) {
+ Log.d("StartupTimer", "Metric tracing disabled in DEBUG");
+ } else {
+ trace = FirebasePerformance.getInstance().newTrace("js_loaded");
+ trace.start();
+ }
+ }
+}
diff --git a/android/build.gradle b/android/build.gradle
index 25095cac7187..66a9c1a64a72 100644
--- a/android/build.gradle
+++ b/android/build.gradle
@@ -18,7 +18,8 @@ buildscript {
dependencies {
classpath("com.android.tools.build:gradle:4.1.0")
classpath("com.google.gms:google-services:4.3.4")
- classpath("com.google.firebase:firebase-crashlytics-gradle:2.3.0")
+ classpath("com.google.firebase:firebase-crashlytics-gradle:2.7.1")
+ classpath("com.google.firebase:perf-plugin:1.4.0")
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion"
diff --git a/ios/ExpensifyCash.xcodeproj/project.pbxproj b/ios/ExpensifyCash.xcodeproj/project.pbxproj
index 3f740ca957f2..eb03211ebd49 100644
--- a/ios/ExpensifyCash.xcodeproj/project.pbxproj
+++ b/ios/ExpensifyCash.xcodeproj/project.pbxproj
@@ -24,6 +24,8 @@
425866037F4C482AAB46CB8B /* GTAmericaExp-BdIt.otf in Resources */ = {isa = PBXBuildFile; fileRef = A8D6F2F722FD4E66A38EBBB6 /* GTAmericaExp-BdIt.otf */; };
52477A09739546F4814EA25F /* GTAmericaExpMono-Bd.otf in Resources */ = {isa = PBXBuildFile; fileRef = 0DE5D096095C41EE96746C9E /* GTAmericaExpMono-Bd.otf */; };
6856B78873B64C44A92E51DB /* GTAmericaExp-MdIt.otf in Resources */ = {isa = PBXBuildFile; fileRef = DB5A1365442D4419AF6F08E5 /* GTAmericaExp-MdIt.otf */; };
+ 7041848526A8E47D00E09F4D /* RCTStartupTimer.m in Sources */ = {isa = PBXBuildFile; fileRef = 7041848426A8E47D00E09F4D /* RCTStartupTimer.m */; };
+ 7041848626A8E47D00E09F4D /* RCTStartupTimer.m in Sources */ = {isa = PBXBuildFile; fileRef = 7041848426A8E47D00E09F4D /* RCTStartupTimer.m */; };
70CF6E82262E297300711ADC /* BootSplash.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 70CF6E81262E297300711ADC /* BootSplash.storyboard */; };
81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */; };
8821A238A081483FA947BC4E /* GTAmericaExp-RgIt.otf in Resources */ = {isa = PBXBuildFile; fileRef = 918D7FEFF96242E6B5F5E14D /* GTAmericaExp-RgIt.otf */; };
@@ -66,6 +68,8 @@
5150E5D0D7F74DBA8D7C1914 /* GTAmericaExpMono-RgIt.otf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = "GTAmericaExpMono-RgIt.otf"; path = "../assets/fonts/GTAmericaExpMono-RgIt.otf"; sourceTree = ""; };
5E0275D64694B453A3EE297D /* Pods-ExpensifyCash.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ExpensifyCash.release.xcconfig"; path = "Target Support Files/Pods-ExpensifyCash/Pods-ExpensifyCash.release.xcconfig"; sourceTree = ""; };
67D5C3A6A7FA417C8A853FC1 /* GTAmericaExp-Light.otf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = "GTAmericaExp-Light.otf"; path = "../assets/fonts/GTAmericaExp-Light.otf"; sourceTree = ""; };
+ 7041848326A8E40900E09F4D /* RCTStartupTimer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = RCTStartupTimer.h; path = ExpensifyCash/RCTStartupTimer.h; sourceTree = ""; };
+ 7041848426A8E47D00E09F4D /* RCTStartupTimer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = RCTStartupTimer.m; path = ExpensifyCash/RCTStartupTimer.m; sourceTree = ""; };
70CF6E81262E297300711ADC /* BootSplash.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = BootSplash.storyboard; path = ExpensifyCash/BootSplash.storyboard; sourceTree = ""; };
81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = LaunchScreen.storyboard; path = ExpensifyCash/LaunchScreen.storyboard; sourceTree = ""; };
8437A5A38F2047E0BCCD7C2F /* GTAmericaExpMono-Rg.otf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = "GTAmericaExpMono-Rg.otf"; path = "../assets/fonts/GTAmericaExpMono-Rg.otf"; sourceTree = ""; };
@@ -161,6 +165,8 @@
83CBB9F61A601CBA00E9B192 = {
isa = PBXGroup;
children = (
+ 7041848326A8E40900E09F4D /* RCTStartupTimer.h */,
+ 7041848426A8E47D00E09F4D /* RCTStartupTimer.m */,
18D050DF262400AF000D658B /* BridgingFile.swift */,
13B07FAE1A68108700A75B9A /* ExpensifyCash */,
832341AE1AAA6A7D00B99B32 /* Libraries */,
@@ -505,6 +511,10 @@
buildActionMask = 2147483647;
files = (
);
+ inputPaths = (
+ "${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}/Contents/Resources/DWARF/${TARGET_NAME}",
+ "$(SRCROOT)/$(BUILT_PRODUCTS_DIR)/$(INFOPLIST_PATH)",
+ );
name = "[CP-User] [RNFB] Crashlytics Configuration";
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
@@ -559,10 +569,13 @@
buildActionMask = 2147483647;
files = (
);
+ inputPaths = (
+ "$(SRCROOT)/$(BUILT_PRODUCTS_DIR)/$(INFOPLIST_PATH)",
+ );
name = "[CP-User] [RNFB] Core Configuration";
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "#!/usr/bin/env bash\n#\n# Copyright (c) 2016-present Invertase Limited & Contributors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this library except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\nset -e\n\n_MAX_LOOKUPS=2;\n_SEARCH_RESULT=''\n_RN_ROOT_EXISTS=''\n_CURRENT_LOOKUPS=1\n_JSON_ROOT=\"'react-native'\"\n_JSON_FILE_NAME='firebase.json'\n_JSON_OUTPUT_BASE64='e30=' # { }\n_CURRENT_SEARCH_DIR=${PROJECT_DIR}\n_PLIST_BUDDY=/usr/libexec/PlistBuddy\n_TARGET_PLIST=\"${BUILT_PRODUCTS_DIR}/${INFOPLIST_PATH}\"\n_DSYM_PLIST=\"${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}/Contents/Info.plist\"\n\n# plist arrays\n_PLIST_ENTRY_KEYS=()\n_PLIST_ENTRY_TYPES=()\n_PLIST_ENTRY_VALUES=()\n\nfunction setPlistValue {\n echo \"info: setting plist entry '$1' of type '$2' in file '$4'\"\n ${_PLIST_BUDDY} -c \"Add :$1 $2 '$3'\" $4 || echo \"info: '$1' already exists\"\n}\n\nfunction getFirebaseJsonKeyValue () {\n if [[ ${_RN_ROOT_EXISTS} ]]; then\n ruby -e \"require 'rubygems';require 'json'; output=JSON.parse('$1'); puts output[$_JSON_ROOT]['$2']\"\n else\n echo \"\"\n fi;\n}\n\nfunction jsonBoolToYesNo () {\n if [[ $1 == \"false\" ]]; then\n echo \"NO\"\n elif [[ $1 == \"true\" ]]; then\n echo \"YES\"\n else echo \"NO\"\n fi\n}\n\necho \"info: -> RNFB build script started\"\necho \"info: 1) Locating ${_JSON_FILE_NAME} file:\"\n\nif [[ -z ${_CURRENT_SEARCH_DIR} ]]; then\n _CURRENT_SEARCH_DIR=$(pwd)\nfi;\n\nwhile true; do\n _CURRENT_SEARCH_DIR=$(dirname \"$_CURRENT_SEARCH_DIR\")\n if [[ \"$_CURRENT_SEARCH_DIR\" == \"/\" ]] || [[ ${_CURRENT_LOOKUPS} -gt ${_MAX_LOOKUPS} ]]; then break; fi;\n echo \"info: ($_CURRENT_LOOKUPS of $_MAX_LOOKUPS) Searching in '$_CURRENT_SEARCH_DIR' for a ${_JSON_FILE_NAME} file.\"\n _SEARCH_RESULT=$(find \"$_CURRENT_SEARCH_DIR\" -maxdepth 2 -name ${_JSON_FILE_NAME} -print | head -n 1)\n if [[ ${_SEARCH_RESULT} ]]; then\n echo \"info: ${_JSON_FILE_NAME} found at $_SEARCH_RESULT\"\n break;\n fi;\n _CURRENT_LOOKUPS=$((_CURRENT_LOOKUPS+1))\ndone\n\nif [[ ${_SEARCH_RESULT} ]]; then\n _JSON_OUTPUT_RAW=$(cat \"${_SEARCH_RESULT}\")\n _RN_ROOT_EXISTS=$(ruby -e \"require 'rubygems';require 'json'; output=JSON.parse('$_JSON_OUTPUT_RAW'); puts output[$_JSON_ROOT]\" || echo '')\n\n if [[ ${_RN_ROOT_EXISTS} ]]; then\n _JSON_OUTPUT_BASE64=$(python -c 'import json,sys,base64;print(base64.b64encode(json.dumps(json.loads(open('\"'${_SEARCH_RESULT}'\"').read())['${_JSON_ROOT}'])))' || echo \"e30=\")\n fi\n\n _PLIST_ENTRY_KEYS+=(\"firebase_json_raw\")\n _PLIST_ENTRY_TYPES+=(\"string\")\n _PLIST_ENTRY_VALUES+=(\"$_JSON_OUTPUT_BASE64\")\n\n # config.messaging_auto_init_enabled\n _MESSAGING_AUTO_INIT=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"messaging_auto_init_enabled\")\n if [[ $_MESSAGING_AUTO_INIT ]]; then\n _PLIST_ENTRY_KEYS+=(\"FirebaseMessagingAutoInitEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_MESSAGING_AUTO_INIT\")\")\n fi\n\n # config.crashlytics_disable_auto_disabler - undocumented for now - mainly for debugging, document if becomes useful\n _CRASHLYTICS_AUTO_DISABLE_ENABLED=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"crashlytics_disable_auto_disabler\")\n if [[ $_CRASHLYTICS_AUTO_DISABLE_ENABLED == \"true\" ]]; then\n echo \"Disabled Crashlytics auto disabler.\" # do nothing\n else\n _PLIST_ENTRY_KEYS+=(\"FirebaseCrashlyticsCollectionEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"NO\")\n fi\n\n # config.admob_delay_app_measurement_init\n _ADMOB_DELAY_APP_MEASUREMENT=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"admob_delay_app_measurement_init\")\n if [[ $_ADMOB_DELAY_APP_MEASUREMENT == \"true\" ]]; then\n _PLIST_ENTRY_KEYS+=(\"GADDelayAppMeasurementInit\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"YES\")\n fi\n\n # config.admob_ios_app_id\n _ADMOB_IOS_APP_ID=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"admob_ios_app_id\")\n if [[ $_ADMOB_IOS_APP_ID ]]; then\n _PLIST_ENTRY_KEYS+=(\"GADApplicationIdentifier\")\n _PLIST_ENTRY_TYPES+=(\"string\")\n _PLIST_ENTRY_VALUES+=(\"$_ADMOB_IOS_APP_ID\")\n fi\nelse\n _PLIST_ENTRY_KEYS+=(\"firebase_json_raw\")\n _PLIST_ENTRY_TYPES+=(\"string\")\n _PLIST_ENTRY_VALUES+=(\"$_JSON_OUTPUT_BASE64\")\n echo \"warning: A firebase.json file was not found, whilst this file is optional it is recommended to include it to configure firebase services in React Native Firebase.\"\nfi;\n\necho \"info: 2) Injecting Info.plist entries: \"\n\n# Log out the keys we're adding\nfor i in \"${!_PLIST_ENTRY_KEYS[@]}\"; do\n echo \" -> $i) ${_PLIST_ENTRY_KEYS[$i]}\" \"${_PLIST_ENTRY_TYPES[$i]}\" \"${_PLIST_ENTRY_VALUES[$i]}\"\ndone\n\nfor plist in \"${_TARGET_PLIST}\" \"${_DSYM_PLIST}\" ; do\n if [[ -f \"${plist}\" ]]; then\n\n # paths with spaces break the call to setPlistValue. temporarily modify\n # the shell internal field separator variable (IFS), which normally\n # includes spaces, to consist only of line breaks\n oldifs=$IFS\n IFS=\"\n\"\n\n for i in \"${!_PLIST_ENTRY_KEYS[@]}\"; do\n setPlistValue \"${_PLIST_ENTRY_KEYS[$i]}\" \"${_PLIST_ENTRY_TYPES[$i]}\" \"${_PLIST_ENTRY_VALUES[$i]}\" \"${plist}\"\n done\n\n # restore the original internal field separator value\n IFS=$oldifs\n else\n echo \"warning: A Info.plist build output file was not found (${plist})\"\n fi\ndone\n\necho \"info: <- RNFB build script finished\"\n";
+ shellScript = "#!/usr/bin/env bash\n#\n# Copyright (c) 2016-present Invertase Limited & Contributors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this library except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\nset -e\n\n_MAX_LOOKUPS=2;\n_SEARCH_RESULT=''\n_RN_ROOT_EXISTS=''\n_CURRENT_LOOKUPS=1\n_JSON_ROOT=\"'react-native'\"\n_JSON_FILE_NAME='firebase.json'\n_JSON_OUTPUT_BASE64='e30=' # { }\n_CURRENT_SEARCH_DIR=${PROJECT_DIR}\n_PLIST_BUDDY=/usr/libexec/PlistBuddy\n_TARGET_PLIST=\"${BUILT_PRODUCTS_DIR}/${INFOPLIST_PATH}\"\n_DSYM_PLIST=\"${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}/Contents/Info.plist\"\n\n# plist arrays\n_PLIST_ENTRY_KEYS=()\n_PLIST_ENTRY_TYPES=()\n_PLIST_ENTRY_VALUES=()\n\nfunction setPlistValue {\n echo \"info: setting plist entry '$1' of type '$2' in file '$4'\"\n ${_PLIST_BUDDY} -c \"Add :$1 $2 '$3'\" $4 || echo \"info: '$1' already exists\"\n}\n\nfunction getFirebaseJsonKeyValue () {\n if [[ ${_RN_ROOT_EXISTS} ]]; then\n ruby -e \"require 'rubygems';require 'json'; output=JSON.parse('$1'); puts output[$_JSON_ROOT]['$2']\"\n else\n echo \"\"\n fi;\n}\n\nfunction jsonBoolToYesNo () {\n if [[ $1 == \"false\" ]]; then\n echo \"NO\"\n elif [[ $1 == \"true\" ]]; then\n echo \"YES\"\n else echo \"NO\"\n fi\n}\n\necho \"info: -> RNFB build script started\"\necho \"info: 1) Locating ${_JSON_FILE_NAME} file:\"\n\nif [[ -z ${_CURRENT_SEARCH_DIR} ]]; then\n _CURRENT_SEARCH_DIR=$(pwd)\nfi;\n\nwhile true; do\n _CURRENT_SEARCH_DIR=$(dirname \"$_CURRENT_SEARCH_DIR\")\n if [[ \"$_CURRENT_SEARCH_DIR\" == \"/\" ]] || [[ ${_CURRENT_LOOKUPS} -gt ${_MAX_LOOKUPS} ]]; then break; fi;\n echo \"info: ($_CURRENT_LOOKUPS of $_MAX_LOOKUPS) Searching in '$_CURRENT_SEARCH_DIR' for a ${_JSON_FILE_NAME} file.\"\n _SEARCH_RESULT=$(find \"$_CURRENT_SEARCH_DIR\" -maxdepth 2 -name ${_JSON_FILE_NAME} -print | head -n 1)\n if [[ ${_SEARCH_RESULT} ]]; then\n echo \"info: ${_JSON_FILE_NAME} found at $_SEARCH_RESULT\"\n break;\n fi;\n _CURRENT_LOOKUPS=$((_CURRENT_LOOKUPS+1))\ndone\n\nif [[ ${_SEARCH_RESULT} ]]; then\n _JSON_OUTPUT_RAW=$(cat \"${_SEARCH_RESULT}\")\n _RN_ROOT_EXISTS=$(ruby -e \"require 'rubygems';require 'json'; output=JSON.parse('$_JSON_OUTPUT_RAW'); puts output[$_JSON_ROOT]\" || echo '')\n\n if [[ ${_RN_ROOT_EXISTS} ]]; then\n _JSON_OUTPUT_BASE64=$(python -c 'import json,sys,base64;print(base64.b64encode(json.dumps(json.loads(open('\"'${_SEARCH_RESULT}'\"').read())['${_JSON_ROOT}'])))' || echo \"e30=\")\n fi\n\n _PLIST_ENTRY_KEYS+=(\"firebase_json_raw\")\n _PLIST_ENTRY_TYPES+=(\"string\")\n _PLIST_ENTRY_VALUES+=(\"$_JSON_OUTPUT_BASE64\")\n\n # config.analytics_auto_collection_enabled\n _ANALYTICS_AUTO_COLLECTION=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"analytics_auto_collection_enabled\")\n if [[ $_ANALYTICS_AUTO_COLLECTION ]]; then\n _PLIST_ENTRY_KEYS+=(\"FIREBASE_ANALYTICS_COLLECTION_ENABLED\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_AUTO_COLLECTION\")\")\n fi\n\n # config.perf_auto_collection_enabled\n _PERF_AUTO_COLLECTION=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"perf_auto_collection_enabled\")\n if [[ $_PERF_AUTO_COLLECTION ]]; then\n _PLIST_ENTRY_KEYS+=(\"firebase_performance_collection_enabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_PERF_AUTO_COLLECTION\")\")\n fi\n\n # config.messaging_auto_init_enabled\n _MESSAGING_AUTO_INIT=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"messaging_auto_init_enabled\")\n if [[ $_MESSAGING_AUTO_INIT ]]; then\n _PLIST_ENTRY_KEYS+=(\"FirebaseMessagingAutoInitEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_MESSAGING_AUTO_INIT\")\")\n fi\n\n # config.crashlytics_disable_auto_disabler - undocumented for now - mainly for debugging, document if becomes useful\n _CRASHLYTICS_AUTO_DISABLE_ENABLED=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"crashlytics_disable_auto_disabler\")\n if [[ $_CRASHLYTICS_AUTO_DISABLE_ENABLED == \"true\" ]]; then\n echo \"Disabled Crashlytics auto disabler.\" # do nothing\n else\n _PLIST_ENTRY_KEYS+=(\"FirebaseCrashlyticsCollectionEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"NO\")\n fi\nelse\n _PLIST_ENTRY_KEYS+=(\"firebase_json_raw\")\n _PLIST_ENTRY_TYPES+=(\"string\")\n _PLIST_ENTRY_VALUES+=(\"$_JSON_OUTPUT_BASE64\")\n echo \"warning: A firebase.json file was not found, whilst this file is optional it is recommended to include it to configure firebase services in React Native Firebase.\"\nfi;\n\necho \"info: 2) Injecting Info.plist entries: \"\n\n# Log out the keys we're adding\nfor i in \"${!_PLIST_ENTRY_KEYS[@]}\"; do\n echo \" -> $i) ${_PLIST_ENTRY_KEYS[$i]}\" \"${_PLIST_ENTRY_TYPES[$i]}\" \"${_PLIST_ENTRY_VALUES[$i]}\"\ndone\n\nfor plist in \"${_TARGET_PLIST}\" \"${_DSYM_PLIST}\" ; do\n if [[ -f \"${plist}\" ]]; then\n\n # paths with spaces break the call to setPlistValue. temporarily modify\n # the shell internal field separator variable (IFS), which normally\n # includes spaces, to consist only of line breaks\n oldifs=$IFS\n IFS=\"\n\"\n\n for i in \"${!_PLIST_ENTRY_KEYS[@]}\"; do\n setPlistValue \"${_PLIST_ENTRY_KEYS[$i]}\" \"${_PLIST_ENTRY_TYPES[$i]}\" \"${_PLIST_ENTRY_VALUES[$i]}\" \"${plist}\"\n done\n\n # restore the original internal field separator value\n IFS=$oldifs\n else\n echo \"warning: A Info.plist build output file was not found (${plist})\"\n fi\ndone\n\necho \"info: <- RNFB build script finished\"\n";
};
D91BC49ED9E5B6C37CAABCC6 /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
@@ -742,6 +755,7 @@
files = (
00E356F31AD99517003FC87E /* ExpensifyCashTests.m in Sources */,
0F5E5351263B73FD004CA14F /* EnvironmentChecker.m in Sources */,
+ 7041848626A8E47D00E09F4D /* RCTStartupTimer.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -752,6 +766,7 @@
13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */,
18D050E0262400AF000D658B /* BridgingFile.swift in Sources */,
0F5E5350263B73FD004CA14F /* EnvironmentChecker.m in Sources */,
+ 7041848526A8E47D00E09F4D /* RCTStartupTimer.m in Sources */,
13B07FC11A68108700A75B9A /* main.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
diff --git a/ios/ExpensifyCash/AppDelegate.m b/ios/ExpensifyCash/AppDelegate.m
index 5126598e3e3b..6bc463b79e9e 100644
--- a/ios/ExpensifyCash/AppDelegate.m
+++ b/ios/ExpensifyCash/AppDelegate.m
@@ -5,6 +5,7 @@
#import
#import
#import
+#import "RCTStartupTimer.h"
#import "RNBootSplash.h"
@@ -74,6 +75,10 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(
[RNBootSplash initWithStoryboard:@"BootSplash" rootView:rootView]; // <- initialization using the storyboard file name
+ // Start the "js_load" custom performance tracing metric. This timer is stopped by a native
+ // module in the JS so we can measure total time starting in the native layer and ending in
+ // the JS layer.
+ [RCTStartupTimer start];
return YES;
}
diff --git a/ios/ExpensifyCash/RCTStartupTimer.h b/ios/ExpensifyCash/RCTStartupTimer.h
new file mode 100644
index 000000000000..171aac44d4d6
--- /dev/null
+++ b/ios/ExpensifyCash/RCTStartupTimer.h
@@ -0,0 +1,19 @@
+//
+// RCTStartupTimer.h
+// ExpensifyCash
+//
+// Created by Marc Glasser on 7/21/21.
+//
+#import
+#import
+
+#ifndef RCTStartupTimer_h
+#define RCTStartupTimer_h
+
+
+#endif /* RCTStartupTimer_h */
+
+@interface RCTStartupTimer : NSObject
++ (void)start;
+
+@end
diff --git a/ios/ExpensifyCash/RCTStartupTimer.m b/ios/ExpensifyCash/RCTStartupTimer.m
new file mode 100644
index 000000000000..007e32571a49
--- /dev/null
+++ b/ios/ExpensifyCash/RCTStartupTimer.m
@@ -0,0 +1,33 @@
+//
+// RCTStartupTimer.m
+// ExpensifyCash
+//
+// Created by Marc Glasser on 7/21/21.
+//
+
+#import "RCTStartupTimer.h"
+
+@implementation RCTStartupTimer
+
+static FIRTrace *trace = nil;
+
++ (void)start {
+ #if DEBUG
+ // We don't want to record this on debug since it will skew the metrics we collect
+ NSLog(@"[StartupTimer] Metric tracing disabled in DEBUG");
+ #else
+ trace = [FIRPerformance startTraceWithName:@"js_loaded"];
+ #endif
+}
+
+RCT_EXPORT_METHOD(stop)
+{
+ if (trace) {
+ [trace stop];
+ }
+}
+
+// To export a module named StartupTimer
+RCT_EXPORT_MODULE(StartupTimer);
+
+@end
diff --git a/ios/Podfile.lock b/ios/Podfile.lock
index b0652b4a8517..3f4e4773ee98 100644
--- a/ios/Podfile.lock
+++ b/ios/Podfile.lock
@@ -24,45 +24,75 @@ PODS:
- React-Core (= 0.64.1)
- React-jsi (= 0.64.1)
- ReactCommon/turbomodule/core (= 0.64.1)
- - Firebase/Analytics (6.34.0):
+ - Firebase/Analytics (8.4.0):
- Firebase/Core
- - Firebase/Core (6.34.0):
+ - Firebase/Core (8.4.0):
- Firebase/CoreOnly
- - FirebaseAnalytics (= 6.9.0)
- - Firebase/CoreOnly (6.34.0):
- - FirebaseCore (= 6.10.4)
- - Firebase/Crashlytics (6.34.0):
+ - FirebaseAnalytics (~> 8.4.0)
+ - Firebase/CoreOnly (8.4.0):
+ - FirebaseCore (= 8.4.0)
+ - Firebase/Crashlytics (8.4.0):
- Firebase/CoreOnly
- - FirebaseCrashlytics (~> 4.6.2)
- - FirebaseAnalytics (6.9.0):
- - FirebaseCore (~> 6.10)
- - FirebaseInstallations (~> 1.7)
- - GoogleAppMeasurement (= 6.9.0)
- - GoogleUtilities/AppDelegateSwizzler (~> 6.7)
- - GoogleUtilities/MethodSwizzler (~> 6.7)
- - GoogleUtilities/Network (~> 6.7)
- - "GoogleUtilities/NSData+zlib (~> 6.7)"
- - nanopb (~> 1.30906.0)
- - FirebaseCore (6.10.4):
- - FirebaseCoreDiagnostics (~> 1.6)
- - GoogleUtilities/Environment (~> 6.7)
- - GoogleUtilities/Logger (~> 6.7)
- - FirebaseCoreDiagnostics (1.7.0):
- - GoogleDataTransport (~> 7.4)
- - GoogleUtilities/Environment (~> 6.7)
- - GoogleUtilities/Logger (~> 6.7)
- - nanopb (~> 1.30906.0)
- - FirebaseCrashlytics (4.6.2):
- - FirebaseCore (~> 6.10)
- - FirebaseInstallations (~> 1.6)
- - GoogleDataTransport (~> 7.2)
- - nanopb (~> 1.30906.0)
- - PromisesObjC (~> 1.2)
- - FirebaseInstallations (1.7.0):
- - FirebaseCore (~> 6.10)
- - GoogleUtilities/Environment (~> 6.7)
- - GoogleUtilities/UserDefaults (~> 6.7)
- - PromisesObjC (~> 1.2)
+ - FirebaseCrashlytics (~> 8.4.0)
+ - Firebase/Performance (8.4.0):
+ - Firebase/CoreOnly
+ - FirebasePerformance (~> 8.4.0)
+ - FirebaseABTesting (8.4.0):
+ - FirebaseCore (~> 8.0)
+ - FirebaseAnalytics (8.4.0):
+ - FirebaseAnalytics/AdIdSupport (= 8.4.0)
+ - FirebaseCore (~> 8.0)
+ - FirebaseInstallations (~> 8.0)
+ - GoogleUtilities/AppDelegateSwizzler (~> 7.4)
+ - GoogleUtilities/MethodSwizzler (~> 7.4)
+ - GoogleUtilities/Network (~> 7.4)
+ - "GoogleUtilities/NSData+zlib (~> 7.4)"
+ - nanopb (~> 2.30908.0)
+ - FirebaseAnalytics/AdIdSupport (8.4.0):
+ - FirebaseCore (~> 8.0)
+ - FirebaseInstallations (~> 8.0)
+ - GoogleAppMeasurement (= 8.4.0)
+ - GoogleUtilities/AppDelegateSwizzler (~> 7.4)
+ - GoogleUtilities/MethodSwizzler (~> 7.4)
+ - GoogleUtilities/Network (~> 7.4)
+ - "GoogleUtilities/NSData+zlib (~> 7.4)"
+ - nanopb (~> 2.30908.0)
+ - FirebaseCore (8.4.0):
+ - FirebaseCoreDiagnostics (~> 8.0)
+ - GoogleUtilities/Environment (~> 7.4)
+ - GoogleUtilities/Logger (~> 7.4)
+ - FirebaseCoreDiagnostics (8.4.0):
+ - GoogleDataTransport (~> 9.0)
+ - GoogleUtilities/Environment (~> 7.4)
+ - GoogleUtilities/Logger (~> 7.4)
+ - nanopb (~> 2.30908.0)
+ - FirebaseCrashlytics (8.4.0):
+ - FirebaseCore (~> 8.0)
+ - FirebaseInstallations (~> 8.0)
+ - GoogleDataTransport (~> 9.0)
+ - GoogleUtilities/Environment (~> 7.4)
+ - nanopb (~> 2.30908.0)
+ - PromisesObjC (< 3.0, >= 1.2)
+ - FirebaseInstallations (8.4.0):
+ - FirebaseCore (~> 8.0)
+ - GoogleUtilities/Environment (~> 7.4)
+ - GoogleUtilities/UserDefaults (~> 7.4)
+ - PromisesObjC (< 3.0, >= 1.2)
+ - FirebasePerformance (8.4.0):
+ - FirebaseCore (~> 8.0)
+ - FirebaseInstallations (~> 8.0)
+ - FirebaseRemoteConfig (~> 8.0)
+ - GoogleDataTransport (~> 9.0)
+ - GoogleUtilities/Environment (~> 7.4)
+ - GoogleUtilities/ISASwizzler (~> 7.4)
+ - GoogleUtilities/MethodSwizzler (~> 7.4)
+ - Protobuf (~> 3.15)
+ - FirebaseRemoteConfig (8.4.0):
+ - FirebaseABTesting (~> 8.0)
+ - FirebaseCore (~> 8.0)
+ - FirebaseInstallations (~> 8.0)
+ - GoogleUtilities/Environment (~> 7.4)
+ - "GoogleUtilities/NSData+zlib (~> 7.4)"
- Flipper (0.75.1):
- Flipper-Folly (~> 2.5)
- Flipper-RSocket (~> 1.3)
@@ -110,39 +140,49 @@ PODS:
- FlipperKit/Core
- FlipperKit/FlipperKitNetworkPlugin
- glog (0.3.5)
- - GoogleAppMeasurement (6.9.0):
- - GoogleUtilities/AppDelegateSwizzler (~> 6.7)
- - GoogleUtilities/MethodSwizzler (~> 6.7)
- - GoogleUtilities/Network (~> 6.7)
- - "GoogleUtilities/NSData+zlib (~> 6.7)"
- - nanopb (~> 1.30906.0)
- - GoogleDataTransport (7.5.1):
- - nanopb (~> 1.30906.0)
- - GoogleUtilities/AppDelegateSwizzler (6.7.2):
+ - GoogleAppMeasurement (8.4.0):
+ - GoogleAppMeasurement/AdIdSupport (= 8.4.0)
+ - GoogleUtilities/AppDelegateSwizzler (~> 7.4)
+ - GoogleUtilities/MethodSwizzler (~> 7.4)
+ - GoogleUtilities/Network (~> 7.4)
+ - "GoogleUtilities/NSData+zlib (~> 7.4)"
+ - nanopb (~> 2.30908.0)
+ - GoogleAppMeasurement/AdIdSupport (8.4.0):
+ - GoogleUtilities/AppDelegateSwizzler (~> 7.4)
+ - GoogleUtilities/MethodSwizzler (~> 7.4)
+ - GoogleUtilities/Network (~> 7.4)
+ - "GoogleUtilities/NSData+zlib (~> 7.4)"
+ - nanopb (~> 2.30908.0)
+ - GoogleDataTransport (9.1.0):
+ - GoogleUtilities/Environment (~> 7.2)
+ - nanopb (~> 2.30908.0)
+ - PromisesObjC (< 3.0, >= 1.2)
+ - GoogleUtilities/AppDelegateSwizzler (7.5.0):
- GoogleUtilities/Environment
- GoogleUtilities/Logger
- GoogleUtilities/Network
- - GoogleUtilities/Environment (6.7.2):
- - PromisesObjC (~> 1.2)
- - GoogleUtilities/Logger (6.7.2):
+ - GoogleUtilities/Environment (7.5.0):
+ - PromisesObjC (< 3.0, >= 1.2)
+ - GoogleUtilities/ISASwizzler (7.5.0)
+ - GoogleUtilities/Logger (7.5.0):
- GoogleUtilities/Environment
- - GoogleUtilities/MethodSwizzler (6.7.2):
+ - GoogleUtilities/MethodSwizzler (7.5.0):
- GoogleUtilities/Logger
- - GoogleUtilities/Network (6.7.2):
+ - GoogleUtilities/Network (7.5.0):
- GoogleUtilities/Logger
- "GoogleUtilities/NSData+zlib"
- GoogleUtilities/Reachability
- - "GoogleUtilities/NSData+zlib (6.7.2)"
- - GoogleUtilities/Reachability (6.7.2):
+ - "GoogleUtilities/NSData+zlib (7.5.0)"
+ - GoogleUtilities/Reachability (7.5.0):
- GoogleUtilities/Logger
- - GoogleUtilities/UserDefaults (6.7.2):
+ - GoogleUtilities/UserDefaults (7.5.0):
- GoogleUtilities/Logger
- libevent (2.1.12)
- - nanopb (1.30906.0):
- - nanopb/decode (= 1.30906.0)
- - nanopb/encode (= 1.30906.0)
- - nanopb/decode (1.30906.0)
- - nanopb/encode (1.30906.0)
+ - nanopb (2.30908.0):
+ - nanopb/decode (= 2.30908.0)
+ - nanopb/encode (= 2.30908.0)
+ - nanopb/decode (2.30908.0)
+ - nanopb/encode (2.30908.0)
- Onfido (20.1.0)
- onfido-react-native-sdk (1.3.3):
- Onfido (= 20.1.0)
@@ -155,7 +195,8 @@ PODS:
- Permission-LocationWhenInUse (3.0.1):
- RNPermissions
- Plaid (2.1.2)
- - PromisesObjC (1.2.12)
+ - PromisesObjC (2.0.0)
+ - Protobuf (3.17.0)
- RCT-Folly (2020.01.13.00):
- boost-for-react-native
- DoubleConversion
@@ -446,22 +487,26 @@ PODS:
- React-Core
- RNCPicker (1.9.11):
- React-Core
- - RNFBAnalytics (7.6.8):
- - Firebase/Analytics (~> 6.34.0)
+ - RNFBAnalytics (12.3.0):
+ - Firebase/Analytics (= 8.4.0)
- React-Core
- RNFBApp
- - RNFBApp (8.4.6):
- - Firebase/CoreOnly (~> 6.34.0)
+ - RNFBApp (12.3.0):
+ - Firebase/CoreOnly (= 8.4.0)
+ - React-Core
+ - RNFBCrashlytics (12.3.0):
+ - Firebase/Crashlytics (= 8.4.0)
- React-Core
- - RNFBCrashlytics (8.4.10):
- - Firebase/Crashlytics (~> 6.34.0)
+ - RNFBApp
+ - RNFBPerf (12.3.0):
+ - Firebase/Performance (= 8.4.0)
- React-Core
- RNFBApp
- RNGestureHandler (1.9.0):
- React-Core
- RNPermissions (3.0.1):
- React-Core
- - RNReanimated (2.1.0):
+ - RNReanimated (2.3.0-alpha.1):
- DoubleConversion
- FBLazyVector
- FBReactNativeSpec
@@ -596,6 +641,7 @@ DEPENDENCIES:
- "RNFBAnalytics (from `../node_modules/@react-native-firebase/analytics`)"
- "RNFBApp (from `../node_modules/@react-native-firebase/app`)"
- "RNFBCrashlytics (from `../node_modules/@react-native-firebase/crashlytics`)"
+ - "RNFBPerf (from `../node_modules/@react-native-firebase/perf`)"
- RNGestureHandler (from `../node_modules/react-native-gesture-handler`)
- RNPermissions (from `../node_modules/react-native-permissions`)
- RNReanimated (from `../node_modules/react-native-reanimated`)
@@ -623,11 +669,14 @@ SPEC REPOS:
- boost-for-react-native
- CocoaAsyncSocket
- Firebase
+ - FirebaseABTesting
- FirebaseAnalytics
- FirebaseCore
- FirebaseCoreDiagnostics
- FirebaseCrashlytics
- FirebaseInstallations
+ - FirebasePerformance
+ - FirebaseRemoteConfig
- Flipper
- Flipper-DoubleConversion
- Flipper-Folly
@@ -644,6 +693,7 @@ SPEC REPOS:
- OpenSSL-Universal
- Plaid
- PromisesObjC
+ - Protobuf
- YogaKit
EXTERNAL SOURCES:
@@ -747,6 +797,8 @@ EXTERNAL SOURCES:
:path: "../node_modules/@react-native-firebase/app"
RNFBCrashlytics:
:path: "../node_modules/@react-native-firebase/crashlytics"
+ RNFBPerf:
+ :path: "../node_modules/@react-native-firebase/perf"
RNGestureHandler:
:path: "../node_modules/react-native-gesture-handler"
RNPermissions:
@@ -795,13 +847,16 @@ SPEC CHECKSUMS:
DoubleConversion: cf9b38bf0b2d048436d9a82ad2abe1404f11e7de
EXHaptics: 337c160c148baa6f0e7166249f368965906e346b
FBLazyVector: 7b423f9e248eae65987838148c36eec1dbfe0b53
- FBReactNativeSpec: d65967936e86fe0fe6cca5c0125c237636868d4a
- Firebase: c23a36d9e4cdf7877dfcba8dd0c58add66358999
- FirebaseAnalytics: 3bb096873ee0d7fa4b6c70f5e9166b6da413cc7f
- FirebaseCore: d3a978a3cfa3240bf7e4ba7d137fdf5b22b628ec
- FirebaseCoreDiagnostics: 770ac5958e1372ce67959ae4b4f31d8e127c3ac1
- FirebaseCrashlytics: 1a747c9cc084a24dc6d9511c991db1cd078154eb
- FirebaseInstallations: 466c7b4d1f58fe16707693091da253726a731ed2
+ FBReactNativeSpec: 884d4cc2b011759361797a4035c47e10099393b5
+ Firebase: 54cdc8bc9c9b3de54f43dab86e62f5a76b47034f
+ FirebaseABTesting: 4cb61aeeb50f60680af1c01fff781dfaf9293916
+ FirebaseAnalytics: 4751d6a49598a2b58da678cc07df696bcd809ab9
+ FirebaseCore: 31f389c37ac1ea52454a53d3081f2d7019485a4a
+ FirebaseCoreDiagnostics: cad03be1904b975f845e632f2720c3337da27faf
+ FirebaseCrashlytics: c9eb562b2f6bd5ee5e880144fd5ef1bfe46c5dc5
+ FirebaseInstallations: 1585729afc787877763208c2088ed84221161f77
+ FirebasePerformance: b6a1fd3ca81f5d54c4216e43562aa9dcd4f54b19
+ FirebaseRemoteConfig: 0b813f093033c56fe74a91996044a239ab5acb02
Flipper: d3da1aa199aad94455ae725e9f3aa43f3ec17021
Flipper-DoubleConversion: 38631e41ef4f9b12861c67d17cb5518d06badc41
Flipper-Folly: 755929a4f851b2fb2c347d533a23f191b008554c
@@ -810,11 +865,11 @@ SPEC CHECKSUMS:
Flipper-RSocket: 127954abe8b162fcaf68d2134d34dc2bd7076154
FlipperKit: 8a20b5c5fcf9436cac58551dc049867247f64b00
glog: 73c2498ac6884b13ede40eda8228cb1eee9d9d62
- GoogleAppMeasurement: a6a3a066369828db64eda428cb2856dc1cdc7c4e
- GoogleDataTransport: f56af7caa4ed338dc8e138a5d7c5973e66440833
- GoogleUtilities: 7f2f5a07f888cdb145101d6042bc4422f57e70b3
+ GoogleAppMeasurement: 6b6a08fd9c71f4dbc89e0e812acca81d797aa342
+ GoogleDataTransport: 85fd18ff3019bb85d3f2c551d04c481dedf71fc9
+ GoogleUtilities: eea970f4a389963963bffe8d8fabe43540678b9c
libevent: 4049cae6c81cdb3654a443be001fb9bdceff7913
- nanopb: 59317e09cf1f1a0af72f12af412d54edf52603fc
+ nanopb: a0ba3315591a9ae0a16a309ee504766e90db0c96
Onfido: 116a268e4cb8b767c15285e8071c2e8304673cdf
onfido-react-native-sdk: b8f1b7cbe1adab6479d735275772390161630dcd
OpenSSL-Universal: 1aa4f6a6ee7256b83db99ec1ccdaa80d10f9af9b
@@ -822,7 +877,8 @@ SPEC CHECKSUMS:
Permission-LocationAlways: 7f7f373d086af7a81b2f4f20d65d29266ca2043b
Permission-LocationWhenInUse: 3ae82a9feb5da4e94e386dba17c7dd3531af9feb
Plaid: c02276ccc630a726a9ed790bf923d29839ff4017
- PromisesObjC: 3113f7f76903778cf4a0586bd1ab89329a0b7b97
+ PromisesObjC: 68159ce6952d93e17b2dfe273b8c40907db5ba58
+ Protobuf: 7327d4444215b5f18e560a97f879ff5503c4581c
RCT-Folly: ec7a233ccc97cc556cf7237f0db1ff65b986f27c
RCTRequired: ec2ebc96b7bfba3ca5c32740f5a0c6a014a274d2
RCTTypeSafety: 22567f31e67c3e088c7ac23ea46ab6d4779c0ea5
@@ -861,12 +917,13 @@ SPEC CHECKSUMS:
RNCClipboard: 5e299c6df8e0c98f3d7416b86ae563d3a9f768a3
RNCMaskedView: 138134c4d8a9421b4f2bf39055a79aa05c2d47b1
RNCPicker: 6780c753e9e674065db90d9c965920516402579d
- RNFBAnalytics: 2dc4dd9e2445faffca041b10447a23a71dcdabf8
- RNFBApp: 7eacc7da7ab19f96c05e434017d44a9f09410da8
- RNFBCrashlytics: 4870c14cf8833053b6b5648911abefe1923854d2
+ RNFBAnalytics: 8ba84c2d31c64374d054c8621b998f25145ffddc
+ RNFBApp: 64c90ab78b6010ed5c3ade026dfe5ff6442c21fd
+ RNFBCrashlytics: 1de18b8cc36d9bcf86407c4a354399228cc84a61
+ RNFBPerf: e3a7269f573a4787810a32de51647cdcbe08dfb4
RNGestureHandler: 9b7e605a741412e20e13c512738a31bd1611759b
RNPermissions: eb94f9fdc0a8ecd02fcce0676d56ffb1395d41e1
- RNReanimated: b8c8004b43446e3c2709fe64b2b41072f87428ad
+ RNReanimated: 833ebd229b31e18a8933ebd0cd744a0f47d88c42
RNScreens: e8e8dd0588b5da0ab57dcca76ab9b2d8987757e0
RNSVG: ce9d996113475209013317e48b05c21ee988d42e
UMAppLoader: aae896b81e3fcaa6528992e2e19ec8db38c2cedd
diff --git a/package-lock.json b/package-lock.json
index e0c96fb08c44..5436ff2b5e89 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -7856,27 +7856,32 @@
"integrity": "sha512-CW7eOhxduIxA723aZlKMOnBEz1o5Cjo5ibMNsf81TcjNqtsamRHm8jFS98za7t5P7XdhM0MhzkbaS90cwOlN+Q=="
},
"@react-native-firebase/analytics": {
- "version": "7.6.8",
- "resolved": "https://registry.npmjs.org/@react-native-firebase/analytics/-/analytics-7.6.8.tgz",
- "integrity": "sha512-gm4xoJva6lfPCQVprbymm6TY6FwdRsLUwVZt9GM0XY+KrvJV3yk6vhlCafvpRZCEhvVQmW8QDCf0p9VaIygv9g=="
+ "version": "12.3.0",
+ "resolved": "https://registry.npmjs.org/@react-native-firebase/analytics/-/analytics-12.3.0.tgz",
+ "integrity": "sha512-0+ea3ebMLwxk/qnp41mo7SQ3NbPAbQnytmqXhh0XmZW9uXCsfmYdGiUKpdswWe0jq7hCKIQtKvxbClA+Bfhcmg=="
},
"@react-native-firebase/app": {
- "version": "8.4.6",
- "resolved": "https://registry.npmjs.org/@react-native-firebase/app/-/app-8.4.6.tgz",
- "integrity": "sha512-4eZR133QuScvGs4IQQd6qMvQ5E1mtydVTy3DtuBCeiIqtvN8ZxBYoSMgcUmYGS4VafbS2nPh85g4e3BlaIJ2XA==",
+ "version": "12.3.0",
+ "resolved": "https://registry.npmjs.org/@react-native-firebase/app/-/app-12.3.0.tgz",
+ "integrity": "sha512-8jF7PXtvAA59YN9Hqf7mqMV4kvmEXO1XrGc8fRuOQ08g6OKEYZPDBvDsiLVy3oLw911Vznu2dllwQVm+K7Wcgw==",
"requires": {
"opencollective-postinstall": "^2.0.1",
"superstruct": "^0.6.2"
}
},
"@react-native-firebase/crashlytics": {
- "version": "8.4.10",
- "resolved": "https://registry.npmjs.org/@react-native-firebase/crashlytics/-/crashlytics-8.4.10.tgz",
- "integrity": "sha512-nrRHkMvaz/sgQL56hZLMoIY15L6HAjJmnCe134Vw3IPn95OKHTuF4iSa17uV/ezvOIJNSngHHZHFnySBRsu+Jg==",
+ "version": "12.3.0",
+ "resolved": "https://registry.npmjs.org/@react-native-firebase/crashlytics/-/crashlytics-12.3.0.tgz",
+ "integrity": "sha512-XECsCS01PST+UuDoS5bJrh7oUSfHCbb09YCGOeHt7tvd2hZ0Go/UenUZlvf1Uxeu1rVj7oL6lpiLHG2J9+dmiw==",
"requires": {
"stacktrace-js": "^2.0.0"
}
},
+ "@react-native-firebase/perf": {
+ "version": "12.3.0",
+ "resolved": "https://registry.npmjs.org/@react-native-firebase/perf/-/perf-12.3.0.tgz",
+ "integrity": "sha512-9AA2xrx+6122IuahhA2P3CRddr0ObuTkWnLxKhWg1DXq9cHG/DOA3kB/j7HqPnOQgBoR+zYeLrJUf3+vceK9sQ=="
+ },
"@react-native-masked-view/masked-view": {
"version": "0.2.4",
"resolved": "https://registry.npmjs.org/@react-native-masked-view/masked-view/-/masked-view-0.2.4.tgz",
diff --git a/package.json b/package.json
index d2e5b39b5f76..ec2d90e8238b 100644
--- a/package.json
+++ b/package.json
@@ -44,9 +44,10 @@
"@react-native-community/netinfo": "^5.9.10",
"@react-native-community/progress-bar-android": "^1.0.4",
"@react-native-community/progress-view": "^1.2.3",
- "@react-native-firebase/analytics": "^7.6.7",
- "@react-native-firebase/app": "^8.4.5",
- "@react-native-firebase/crashlytics": "^8.4.9",
+ "@react-native-firebase/analytics": "^12.3.0",
+ "@react-native-firebase/app": "^12.3.0",
+ "@react-native-firebase/crashlytics": "^12.3.0",
+ "@react-native-firebase/perf": "^12.3.0",
"@react-native-masked-view/masked-view": "^0.2.4",
"@react-native-picker/picker": "^1.9.11",
"@react-navigation/compat": "^5.3.15",
diff --git a/src/Expensify.js b/src/Expensify.js
index 421658fb55ee..750efc617062 100644
--- a/src/Expensify.js
+++ b/src/Expensify.js
@@ -20,6 +20,7 @@ import GrowlNotification from './components/GrowlNotification';
import {growlRef} from './libs/Growl';
import Navigation from './libs/Navigation/Navigation';
import ROUTES from './ROUTES';
+import StartupTimer from './libs/StartupTimer';
// Initialize the store when the app loads for the first time
Onyx.init({
@@ -94,6 +95,10 @@ class Expensify extends PureComponent {
}
componentDidMount() {
+ // This timer is set in the native layer when launching the app and we stop it here so we can measure how long
+ // it took for the main app itself to load.
+ StartupTimer.stop();
+
// Run any Onyx schema migrations and then continue loading the main app
migrateOnyx()
.then(() => {
diff --git a/src/libs/StartupTimer/index.js b/src/libs/StartupTimer/index.js
new file mode 100644
index 000000000000..7b53266e50d9
--- /dev/null
+++ b/src/libs/StartupTimer/index.js
@@ -0,0 +1,7 @@
+/**
+ * Web noop as there is no "startup" to time from the native layer.
+ */
+
+export default {
+ stop() {},
+};
diff --git a/src/libs/StartupTimer/index.native.js b/src/libs/StartupTimer/index.native.js
new file mode 100644
index 000000000000..29bbef8cfe3d
--- /dev/null
+++ b/src/libs/StartupTimer/index.native.js
@@ -0,0 +1,12 @@
+import {NativeModules} from 'react-native';
+
+/**
+ * Stop the startup trace for the app.
+ */
+function stop() {
+ NativeModules.StartupTimer.stop();
+}
+
+export default {
+ stop,
+};