diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 1c3cdc1441..2cba775fa5 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -140,7 +140,7 @@ jobs: MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }} MATCH_USERNAME: ${{ secrets.MATCH_USERNAME }} - name: Collect apps metrics - uses: getsentry/action-app-sdk-overhead-metrics@v1 + uses: antonis/action-app-sdk-overhead-metrics@67d7579b9398ac756bcf2cd5693782ca4b02a92f with: name: ${{ matrix.name }} (${{ matrix.rn-architecture }}) config: ./performance-tests/metrics-${{ matrix.platform }}.yml diff --git a/performance-tests/TestAppPlain/App.js b/performance-tests/TestAppPlain/App.js index f85f38d87a..7fbde7f5be 100644 --- a/performance-tests/TestAppPlain/App.js +++ b/performance-tests/TestAppPlain/App.js @@ -6,7 +6,8 @@ * @flow strict-local */ -import React from 'react'; +import React, { useEffect } from 'react'; +import { NativeModules } from 'react-native'; import type {Node} from 'react'; import { SafeAreaView, @@ -52,7 +53,15 @@ const Section = ({children, title}): Node => { ); }; +const { ActivityStarter } = NativeModules; + const App: () => Node = () => { + useEffect(() => { + if (Platform.OS === 'android') { + ActivityStarter.startAppReadyActivity(); + } + }, []); + const isDarkMode = useColorScheme() === 'dark'; const backgroundStyle = { diff --git a/performance-tests/TestAppPlain/android/app/src/main/AndroidManifest.xml b/performance-tests/TestAppPlain/android/app/src/main/AndroidManifest.xml index e9f850a4f2..1634c6c5f6 100644 --- a/performance-tests/TestAppPlain/android/app/src/main/AndroidManifest.xml +++ b/performance-tests/TestAppPlain/android/app/src/main/AndroidManifest.xml @@ -22,5 +22,6 @@ + diff --git a/performance-tests/TestAppPlain/android/app/src/main/java/com/testappplain/AppReadyActivity.java b/performance-tests/TestAppPlain/android/app/src/main/java/com/testappplain/AppReadyActivity.java new file mode 100644 index 0000000000..005ed5226a --- /dev/null +++ b/performance-tests/TestAppPlain/android/app/src/main/java/com/testappplain/AppReadyActivity.java @@ -0,0 +1,26 @@ +package com.testappplain; + +import android.os.Bundle; +import android.view.Gravity; +import android.view.ViewGroup.LayoutParams; +import android.widget.LinearLayout; +import android.widget.TextView; +import androidx.appcompat.app.AppCompatActivity; + +public class AppReadyActivity extends AppCompatActivity { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + // Add a simple text saying that the app is fully loaded + LinearLayout layout = new LinearLayout(this); + layout.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); + layout.setGravity(Gravity.CENTER); + TextView textView = new TextView(this); + textView.setText("The App is fully loaded!\nTap/swipe back to close this view."); + textView.setTextSize(24); + textView.setGravity(Gravity.CENTER); + layout.addView(textView); + setContentView(layout); + } +} diff --git a/performance-tests/TestAppPlain/android/app/src/main/java/com/testappplain/AppReadyModule.java b/performance-tests/TestAppPlain/android/app/src/main/java/com/testappplain/AppReadyModule.java new file mode 100644 index 0000000000..1b3bdab939 --- /dev/null +++ b/performance-tests/TestAppPlain/android/app/src/main/java/com/testappplain/AppReadyModule.java @@ -0,0 +1,28 @@ +package com.testappplain; + +import android.content.Intent; +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.bridge.ReactContextBaseJavaModule; +import com.facebook.react.bridge.ReactMethod; + +public class AppReadyModule extends ReactContextBaseJavaModule { + + private final ReactApplicationContext reactContext; + + public AppReadyModule(ReactApplicationContext reactContext) { + super(reactContext); + this.reactContext = reactContext; + } + + @Override + public String getName() { + return "ActivityStarter"; + } + + @ReactMethod + public void startAppReadyActivity() { + Intent intent = new Intent(reactContext, AppReadyActivity.class); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + reactContext.startActivity(intent); + } +} diff --git a/performance-tests/TestAppPlain/android/app/src/main/java/com/testappplain/MainActivity.java b/performance-tests/TestAppPlain/android/app/src/main/java/com/testappplain/MainActivity.java index 3e1bac8e05..4d6468c286 100644 --- a/performance-tests/TestAppPlain/android/app/src/main/java/com/testappplain/MainActivity.java +++ b/performance-tests/TestAppPlain/android/app/src/main/java/com/testappplain/MainActivity.java @@ -15,6 +15,14 @@ protected String getMainComponentName() { return "TestAppPlain"; } + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + Intent intent = new Intent(this, AppReadyActivity.class); + startActivity(intent); + } + /** * Returns the instance of the {@link ReactActivityDelegate}. There the RootView is created and * you can specify the renderer you wish to use - the new renderer (Fabric) or the old renderer diff --git a/performance-tests/TestAppPlain/android/app/src/main/java/com/testappplain/MainApplication.java b/performance-tests/TestAppPlain/android/app/src/main/java/com/testappplain/MainApplication.java index 3417a18c82..8ef513bac5 100644 --- a/performance-tests/TestAppPlain/android/app/src/main/java/com/testappplain/MainApplication.java +++ b/performance-tests/TestAppPlain/android/app/src/main/java/com/testappplain/MainApplication.java @@ -7,10 +7,15 @@ import com.facebook.react.ReactInstanceManager; import com.facebook.react.ReactNativeHost; import com.facebook.react.ReactPackage; +import com.facebook.react.bridge.NativeModule; +import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.config.ReactFeatureFlags; +import com.facebook.react.uimanager.ViewManager; import com.facebook.soloader.SoLoader; import com.testappplain.newarchitecture.MainApplicationReactNativeHost; import java.lang.reflect.InvocationTargetException; +import java.util.Arrays; +import java.util.Collections; import java.util.List; public class MainApplication extends Application implements ReactApplication { @@ -22,12 +27,24 @@ public boolean getUseDeveloperSupport() { return BuildConfig.DEBUG; } + ReactPackage appReadyPackage = + new ReactPackage() { + @Override + public List createNativeModules(ReactApplicationContext reactContext) { + return Arrays.asList(new AppReadyModule(reactContext)); + } + + @Override + public List createViewManagers(ReactApplicationContext reactContext) { + return Collections.emptyList(); + } + }; + @Override protected List getPackages() { @SuppressWarnings("UnnecessaryLocalVariable") List packages = new PackageList(this).getPackages(); - // Packages that cannot be autolinked yet can be added manually here, for example: - // packages.add(new MyReactNativePackage()); + packages.add(appReadyPackage); return packages; } diff --git a/performance-tests/TestAppSentry/App.js b/performance-tests/TestAppSentry/App.js index 0133c64368..55baf96c53 100644 --- a/performance-tests/TestAppSentry/App.js +++ b/performance-tests/TestAppSentry/App.js @@ -6,7 +6,8 @@ * @flow strict-local */ -import React from 'react'; +import React, { useEffect } from 'react'; +import { NativeModules } from 'react-native'; import type {Node} from 'react'; import { SafeAreaView, @@ -58,7 +59,15 @@ const Section = ({children, title}): Node => { ); }; +const { ActivityStarter } = NativeModules; + const App: () => Node = () => { + useEffect(() => { + if (Platform.OS === 'android') { + ActivityStarter.startAppReadyActivity(); + } + }, []); + const isDarkMode = useColorScheme() === 'dark'; const backgroundStyle = { diff --git a/performance-tests/TestAppSentry/android/app/src/main/AndroidManifest.xml b/performance-tests/TestAppSentry/android/app/src/main/AndroidManifest.xml index cd2501980d..ec30f9d6d9 100644 --- a/performance-tests/TestAppSentry/android/app/src/main/AndroidManifest.xml +++ b/performance-tests/TestAppSentry/android/app/src/main/AndroidManifest.xml @@ -22,5 +22,6 @@ + diff --git a/performance-tests/TestAppSentry/android/app/src/main/java/com/testappsentry/AppReadyActivity.java b/performance-tests/TestAppSentry/android/app/src/main/java/com/testappsentry/AppReadyActivity.java new file mode 100644 index 0000000000..05c7ffda19 --- /dev/null +++ b/performance-tests/TestAppSentry/android/app/src/main/java/com/testappsentry/AppReadyActivity.java @@ -0,0 +1,26 @@ +package com.testappsentry; + +import android.os.Bundle; +import android.view.Gravity; +import android.view.ViewGroup.LayoutParams; +import android.widget.LinearLayout; +import android.widget.TextView; +import androidx.appcompat.app.AppCompatActivity; + +public class AppReadyActivity extends AppCompatActivity { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + // Add a simple text saying that the app is fully loaded + LinearLayout layout = new LinearLayout(this); + layout.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); + layout.setGravity(Gravity.CENTER); + TextView textView = new TextView(this); + textView.setText("The App is fully loaded!\nTap/swipe back to close this view."); + textView.setTextSize(24); + textView.setGravity(Gravity.CENTER); + layout.addView(textView); + setContentView(layout); + } +} diff --git a/performance-tests/TestAppSentry/android/app/src/main/java/com/testappsentry/AppReadyModule.java b/performance-tests/TestAppSentry/android/app/src/main/java/com/testappsentry/AppReadyModule.java new file mode 100644 index 0000000000..5f3873b9af --- /dev/null +++ b/performance-tests/TestAppSentry/android/app/src/main/java/com/testappsentry/AppReadyModule.java @@ -0,0 +1,28 @@ +package com.testappsentry; + +import android.content.Intent; +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.bridge.ReactContextBaseJavaModule; +import com.facebook.react.bridge.ReactMethod; + +public class AppReadyModule extends ReactContextBaseJavaModule { + + private final ReactApplicationContext reactContext; + + public AppReadyModule(ReactApplicationContext reactContext) { + super(reactContext); + this.reactContext = reactContext; + } + + @Override + public String getName() { + return "ActivityStarter"; + } + + @ReactMethod + public void startAppReadyActivity() { + Intent intent = new Intent(reactContext, AppReadyActivity.class); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + reactContext.startActivity(intent); + } +} diff --git a/performance-tests/TestAppSentry/android/app/src/main/java/com/testappsentry/MainApplication.java b/performance-tests/TestAppSentry/android/app/src/main/java/com/testappsentry/MainApplication.java index de25c69494..68c2d32288 100644 --- a/performance-tests/TestAppSentry/android/app/src/main/java/com/testappsentry/MainApplication.java +++ b/performance-tests/TestAppSentry/android/app/src/main/java/com/testappsentry/MainApplication.java @@ -7,10 +7,15 @@ import com.facebook.react.ReactInstanceManager; import com.facebook.react.ReactNativeHost; import com.facebook.react.ReactPackage; +import com.facebook.react.bridge.NativeModule; +import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.config.ReactFeatureFlags; +import com.facebook.react.uimanager.ViewManager; import com.facebook.soloader.SoLoader; import com.testappsentry.newarchitecture.MainApplicationReactNativeHost; import java.lang.reflect.InvocationTargetException; +import java.util.Arrays; +import java.util.Collections; import java.util.List; public class MainApplication extends Application implements ReactApplication { @@ -22,12 +27,24 @@ public boolean getUseDeveloperSupport() { return BuildConfig.DEBUG; } + ReactPackage appReadyPackage = + new ReactPackage() { + @Override + public List createNativeModules(ReactApplicationContext reactContext) { + return Arrays.asList(new AppReadyModule(reactContext)); + } + + @Override + public List createViewManagers(ReactApplicationContext reactContext) { + return Collections.emptyList(); + } + }; + @Override protected List getPackages() { @SuppressWarnings("UnnecessaryLocalVariable") List packages = new PackageList(this).getPackages(); - // Packages that cannot be autolinked yet can be added manually here, for example: - // packages.add(new MyReactNativePackage()); + packages.add(appReadyPackage); return packages; } diff --git a/performance-tests/metrics-android.yml b/performance-tests/metrics-android.yml index 04d4333eae..70e70f6c1d 100644 --- a/performance-tests/metrics-android.yml +++ b/performance-tests/metrics-android.yml @@ -1,14 +1,16 @@ apps: - name: com.testappplain activity: MainActivity + measureActivity: AppReadyActivity path: TestAppPlain/android/app/build/outputs/apk/release/app-release.apk - name: com.testappsentry activity: MainActivity + measureActivity: AppReadyActivity path: TestAppSentry/android/app/build/outputs/apk/release/app-release.apk startupTimeTest: runs: 50 - diffMin: -20 + diffMin: 0 diffMax: 150 binarySizeTest: