mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Setup a Macrobenchmark for RNTester (#49486)
Summary: Benchmark to test changes from https://github.com/facebook/react-native/issues/49449 Might be nice to have some version of this in the repo. ## Changelog: [INTERNAL] [ADDED] - Setup a Macrobenchmark for RNTester Pull Request resolved: https://github.com/facebook/react-native/pull/49486 Test Plan: ### Methodology Picked various JS file from websites (facebook, instagram) to artificially grow RN tester bundle somewhat realistically. The files are required lazily from a button press callback to simulate the code being included, but not executed, as it would be in a large app that uses lazy requires for the different screens. I've also made the RN tester screens lazy so all their code is not loaded initially. This is more representative of real apps. Note this is implemented in a hacky way just for the purpose of this test. It would actually be nice to implement this properly. The tests were made using low end device Samsung Galaxy A03s. ### Compression ON with 10.5 mb bundle #### Peak allocated memory 60.9 mb #### ReactInstance.loadJSBundler 148.64 ms #### Benchmark timeToFullDisplayMs min 1,825.0, median 1,911.1, max 1,994.8 timeToInitialDisplayMs min 834.9, median 860.9, max 903.9 #### APK Size: 22.9 mb Download size: 14.5 mb ### Compression OFF with 10.5 mb bundle #### Peak allocated memory 51.5 mb #### ReactInstance.loadJSBundler 946 us #### Benchmark timeToFullDisplayMs min 1,752.8, median 1,827.2, max 1,977.5 timeToInitialDisplayMs min 837.7, median 881.3, max 937.2 #### APK Size: 28 mb Download size: 14.5 mb Reviewed By: rshest Differential Revision: D70002286 Pulled By: cortinico fbshipit-source-id: 436597f439ba244649373870c1facefdb12297d9
This commit is contained in:
committed by
Facebook GitHub Bot
parent
f94dbb30ee
commit
b614c966ab
@@ -12,6 +12,7 @@ plugins {
|
||||
alias(libs.plugins.download) apply false
|
||||
alias(libs.plugins.kotlin.android) apply false
|
||||
alias(libs.plugins.binary.compatibility.validator) apply true
|
||||
alias(libs.plugins.android.test) apply false
|
||||
}
|
||||
|
||||
val reactAndroidProperties = java.util.Properties()
|
||||
|
||||
@@ -10,12 +10,16 @@ agp = "8.8.2"
|
||||
androidx-annotation = "1.6.0"
|
||||
androidx-appcompat = "1.7.0"
|
||||
androidx-autofill = "1.1.0"
|
||||
androidx-benchmark-macro-junit4 = "1.3.3"
|
||||
androidx-profileinstaller = "1.4.1"
|
||||
androidx-swiperefreshlayout = "1.1.0"
|
||||
androidx-test = "1.5.0"
|
||||
androidx-test-junit = "1.2.1"
|
||||
androidx-tracing = "1.1.0"
|
||||
assertj = "3.21.0"
|
||||
binary-compatibility-validator = "0.13.2"
|
||||
download = "5.4.0"
|
||||
espresso-core = "3.6.1"
|
||||
fbjni = "0.7.0"
|
||||
fresco = "3.6.0"
|
||||
infer-annotation = "0.18.0"
|
||||
@@ -32,6 +36,7 @@ okhttp = "4.9.2"
|
||||
okio = "2.9.0"
|
||||
robolectric = "4.9.2"
|
||||
soloader = "0.12.1"
|
||||
uiautomator = "2.3.0"
|
||||
xstream = "1.4.20"
|
||||
yoga-proguard-annotations = "1.19.0"
|
||||
# Native Dependencies
|
||||
@@ -44,14 +49,19 @@ glog="0.3.5"
|
||||
gtest="1.12.1"
|
||||
|
||||
[libraries]
|
||||
androidx-annotation = { module = "androidx.annotation:annotation", version.ref = "androidx-annotation" }
|
||||
androidx-appcompat = { module = "androidx.appcompat:appcompat", version.ref = "androidx-appcompat" }
|
||||
androidx-appcompat-resources = { module = "androidx.appcompat:appcompat-resources", version.ref = "androidx-appcompat" }
|
||||
androidx-annotation = { module = "androidx.annotation:annotation", version.ref = "androidx-annotation" }
|
||||
androidx-autofill = { module = "androidx.autofill:autofill", version.ref = "androidx-autofill" }
|
||||
androidx-benchmark-macro-junit4 = { group = "androidx.benchmark", name = "benchmark-macro-junit4", version.ref = "androidx-benchmark-macro-junit4" }
|
||||
androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espresso-core" }
|
||||
androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "androidx-test-junit" }
|
||||
androidx-profileinstaller = { group = "androidx.profileinstaller", name = "profileinstaller", version.ref = "androidx-profileinstaller" }
|
||||
androidx-swiperefreshlayout = { module = "androidx.swiperefreshlayout:swiperefreshlayout", version.ref = "androidx-swiperefreshlayout" }
|
||||
androidx-tracing = { module = "androidx.tracing:tracing", version.ref = "androidx-tracing" }
|
||||
androidx-test-runner = { module = "androidx.test:runner", version.ref = "androidx-test" }
|
||||
androidx-test-rules = { module = "androidx.test:rules", version.ref = "androidx-test" }
|
||||
androidx-test-runner = { module = "androidx.test:runner", version.ref = "androidx-test" }
|
||||
androidx-tracing = { module = "androidx.tracing:tracing", version.ref = "androidx-tracing" }
|
||||
androidx-uiautomator = { group = "androidx.test.uiautomator", name = "uiautomator", version.ref = "uiautomator" }
|
||||
|
||||
fbjni = { module = "com.facebook.fbjni:fbjni", version.ref = "fbjni" }
|
||||
fresco = { module = "com.facebook.fresco:fresco", version.ref = "fresco" }
|
||||
@@ -84,3 +94,4 @@ download = { id = "de.undercouch.download", version.ref = "download" }
|
||||
nexus-publish = { id = "io.github.gradle-nexus.publish-plugin", version.ref = "nexus-publish" }
|
||||
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
|
||||
binary-compatibility-validator = { id = "org.jetbrains.kotlinx.binary-compatibility-validator", version.ref = "binary-compatibility-validator" }
|
||||
android-test = { id = "com.android.test", version.ref = "agp" }
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow strict-local
|
||||
* @format
|
||||
*/
|
||||
|
||||
import ReportFullyDrawnViewNativeComponent from './ReportFullyDrawnViewNativeComponent';
|
||||
|
||||
export default ReportFullyDrawnViewNativeComponent;
|
||||
@@ -0,0 +1,13 @@
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow strict-local
|
||||
* @format
|
||||
*/
|
||||
|
||||
import {View} from 'react-native';
|
||||
|
||||
export default View;
|
||||
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow strict-local
|
||||
* @format
|
||||
*/
|
||||
|
||||
import type {HostComponent} from 'react-native';
|
||||
import type {ViewProps} from 'react-native/Libraries/Components/View/ViewPropTypes';
|
||||
|
||||
import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent';
|
||||
|
||||
type NativeProps = $ReadOnly<{
|
||||
...ViewProps,
|
||||
}>;
|
||||
|
||||
export type ReportFullyDrawnViewType = HostComponent<ViewProps>;
|
||||
|
||||
export default (codegenNativeComponent<NativeProps>(
|
||||
'RNTReportFullyDrawnView',
|
||||
): ReportFullyDrawnViewType);
|
||||
@@ -0,0 +1 @@
|
||||
/build
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
plugins {
|
||||
alias(libs.plugins.android.test)
|
||||
alias(libs.plugins.kotlin.android)
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "com.example.benchmark"
|
||||
compileSdk = libs.versions.compileSdk.get().toInt()
|
||||
|
||||
defaultConfig {
|
||||
minSdk = libs.versions.minSdk.get().toInt()
|
||||
targetSdk = libs.versions.targetSdk.get().toInt()
|
||||
|
||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
// This benchmark buildType is used for benchmarking, and should function like your
|
||||
// release build (for example, with minification on). It"s signed with a debug key
|
||||
// for easy local/CI testing.
|
||||
create("benchmark") {
|
||||
isDebuggable = true
|
||||
signingConfig = getByName("debug").signingConfig
|
||||
matchingFallbacks += listOf("release")
|
||||
}
|
||||
}
|
||||
|
||||
flavorDimensions += listOf("vm")
|
||||
productFlavors {
|
||||
create("hermes") { dimension = "vm" }
|
||||
create("jsc") { dimension = "vm" }
|
||||
}
|
||||
|
||||
targetProjectPath = ":packages:rn-tester:android:app"
|
||||
experimentalProperties["android.experimental.self-instrumenting"] = true
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(libs.androidx.junit)
|
||||
implementation(libs.androidx.espresso.core)
|
||||
implementation(libs.androidx.uiautomator)
|
||||
implementation(libs.androidx.benchmark.macro.junit4)
|
||||
}
|
||||
|
||||
androidComponents { beforeVariants(selector().all()) { it.enable = it.buildType == "benchmark" } }
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
package com.facebook.react.uiapp.benchmark
|
||||
|
||||
import androidx.benchmark.macro.StartupMode
|
||||
import androidx.benchmark.macro.StartupTimingMetric
|
||||
import androidx.benchmark.macro.junit4.MacrobenchmarkRule
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.uiautomator.By
|
||||
import androidx.test.uiautomator.Until
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
/**
|
||||
* RNTester benchmarks.
|
||||
*
|
||||
* Run this benchmark from Android Studio to see startup measurements, and captured system traces
|
||||
* for investigating performance.
|
||||
*/
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class RNTesterStartupBenchmark {
|
||||
@get:Rule val benchmarkRule = MacrobenchmarkRule()
|
||||
|
||||
@Test
|
||||
fun startup() =
|
||||
benchmarkRule.measureRepeated(
|
||||
packageName = "com.facebook.react.uiapp",
|
||||
metrics = listOf(StartupTimingMetric()),
|
||||
iterations = 10,
|
||||
startupMode = StartupMode.COLD,
|
||||
setupBlock = { pressHome() }) {
|
||||
startActivityAndWait()
|
||||
|
||||
// Waits for an element that corresponds to fully drawn state
|
||||
device.wait(Until.hasObject(By.text("Components")), 10_000)
|
||||
device.waitForIdle()
|
||||
}
|
||||
}
|
||||
@@ -165,6 +165,7 @@ dependencies {
|
||||
"jscImplementation"(jscFlavor)
|
||||
|
||||
testImplementation(libs.junit)
|
||||
implementation(libs.androidx.profileinstaller)
|
||||
}
|
||||
|
||||
android {
|
||||
|
||||
@@ -1,88 +1,97 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<uses-feature
|
||||
android:name="android.software.leanback"
|
||||
android:required="false" />
|
||||
<uses-feature
|
||||
android:name="android.hardware.touchscreen"
|
||||
android:required="false" />
|
||||
<uses-feature
|
||||
android:name="android.hardware.location.gps"
|
||||
android:required="false" />
|
||||
<uses-feature
|
||||
android:name="android.hardware.camera"
|
||||
android:required="false" />
|
||||
<uses-feature
|
||||
android:name="android.software.leanback"
|
||||
android:required="false" />
|
||||
<uses-feature
|
||||
android:name="android.hardware.touchscreen"
|
||||
android:required="false" />
|
||||
<uses-feature
|
||||
android:name="android.hardware.location.gps"
|
||||
android:required="false" />
|
||||
<uses-feature
|
||||
android:name="android.hardware.camera"
|
||||
android:required="false" />
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
|
||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
|
||||
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
|
||||
<uses-permission android:name="android.permission.VIBRATE"/>
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
||||
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
|
||||
<uses-permission android:name="android.permission.VIBRATE" />
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <!-- Just to show permissions example -->
|
||||
<uses-permission android:name="android.permission.CAMERA" />
|
||||
<uses-permission android:name="android.permission.READ_CALENDAR" />
|
||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
||||
|
||||
<!--Just to show permissions example-->
|
||||
<uses-permission android:name="android.permission.CAMERA"/>
|
||||
<uses-permission android:name="android.permission.READ_CALENDAR"/>
|
||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
|
||||
<queries>
|
||||
<package android:name="com.facebook.katana" />
|
||||
<package android:name="com.facebook.lite" />
|
||||
<package android:name="com.facebook.android" />
|
||||
|
||||
<!--
|
||||
android:icon is used to display launcher icon on mobile devices.
|
||||
android:banner is used to display a rectangular banned launcher icon on Android TV devices.
|
||||
-->
|
||||
<application
|
||||
android:name=".RNTesterApplication"
|
||||
android:allowBackup="true"
|
||||
android:banner="@drawable/tv_banner"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/AppTheme"
|
||||
android:supportsRtl="true">
|
||||
<activity
|
||||
android:name=".RNTesterActivity"
|
||||
<intent>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
|
||||
<data android:scheme="https" />
|
||||
</intent>
|
||||
<intent>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
|
||||
<data android:scheme="geo" />
|
||||
</intent>
|
||||
<intent>
|
||||
<action android:name="android.intent.action.DIAL" />
|
||||
|
||||
<data android:scheme="tel" />
|
||||
</intent>
|
||||
</queries>
|
||||
|
||||
<application
|
||||
android:name=".RNTesterApplication"
|
||||
android:allowBackup="true"
|
||||
android:banner="@drawable/tv_banner"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:screenOrientation="fullSensor"
|
||||
android:launchMode="singleTask"
|
||||
android:configChanges="orientation|screenSize|uiMode"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
<!-- Needed to properly create a launch intent when running on Android TV -->
|
||||
<category android:name="android.intent.category.LEANBACK_LAUNCHER" />
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<!-- Accepts URIs that begin with "rntester://example” -->
|
||||
<data android:scheme="rntester" android:host="example" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<provider
|
||||
android:name="com.facebook.react.modules.blob.BlobProvider"
|
||||
android:authorities="@string/blob_provider_authority"
|
||||
android:exported="false"
|
||||
/>
|
||||
</application>
|
||||
<queries>
|
||||
<package android:name="com.facebook.katana" />
|
||||
<package android:name="com.facebook.lite" />
|
||||
<package android:name="com.facebook.android" />
|
||||
<intent>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<data android:scheme="https" />
|
||||
</intent>
|
||||
<intent>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<data android:scheme="geo" />
|
||||
</intent>
|
||||
<intent>
|
||||
<action android:name="android.intent.action.DIAL" />
|
||||
<data android:scheme="tel" />
|
||||
</intent>
|
||||
</queries>
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/AppTheme">
|
||||
<profileable
|
||||
android:shell="true"
|
||||
tools:targetApi="29" />
|
||||
|
||||
<activity
|
||||
android:name=".RNTesterActivity"
|
||||
android:configChanges="orientation|screenSize|uiMode"
|
||||
android:exported="true"
|
||||
android:label="@string/app_name"
|
||||
android:launchMode="singleTask"
|
||||
android:screenOrientation="fullSensor">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
<!-- Needed to properly create a launch intent when running on Android TV -->
|
||||
<category android:name="android.intent.category.LEANBACK_LAUNCHER" />
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<!-- Accepts URIs that begin with "rntester://example” -->
|
||||
<data
|
||||
android:host="example"
|
||||
android:scheme="rntester" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<provider
|
||||
android:name="com.facebook.react.modules.blob.BlobProvider"
|
||||
android:authorities="@string/blob_provider_authority"
|
||||
android:exported="false" />
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
|
||||
+3
@@ -45,6 +45,9 @@ internal class RNTesterActivity : ReactActivity() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
fullyDrawnReporter.addReporter()
|
||||
|
||||
// set background color so it will show below transparent system bars on forced edge-to-edge
|
||||
this.window?.setBackgroundDrawable(ColorDrawable(Color.BLACK))
|
||||
// register insets listener to update margins on the ReactRootView to avoid overlap w/ system
|
||||
|
||||
+7
-2
@@ -30,6 +30,7 @@ import com.facebook.react.shell.MainReactPackage
|
||||
import com.facebook.react.soloader.OpenSourceMergedSoMapping
|
||||
import com.facebook.react.uiapp.component.MyLegacyViewManager
|
||||
import com.facebook.react.uiapp.component.MyNativeViewManager
|
||||
import com.facebook.react.uiapp.component.ReportFullyDrawnViewManager
|
||||
import com.facebook.react.uimanager.ReactShadowNode
|
||||
import com.facebook.react.uimanager.ViewManager
|
||||
import com.facebook.soloader.SoLoader
|
||||
@@ -99,12 +100,15 @@ internal class RNTesterApplication : Application(), ReactApplication {
|
||||
): List<NativeModule> = emptyList()
|
||||
|
||||
override fun getViewManagerNames(reactContext: ReactApplicationContext) =
|
||||
listOf("RNTMyNativeView", "RNTMyLegacyNativeView")
|
||||
listOf("RNTMyNativeView", "RNTMyLegacyNativeView", "RNTReportFullyDrawnView")
|
||||
|
||||
override fun createViewManagers(
|
||||
reactContext: ReactApplicationContext
|
||||
): List<ViewManager<*, *>> =
|
||||
listOf(MyNativeViewManager(), MyLegacyViewManager(reactContext))
|
||||
listOf(
|
||||
MyNativeViewManager(),
|
||||
MyLegacyViewManager(reactContext),
|
||||
ReportFullyDrawnViewManager())
|
||||
|
||||
override fun createViewManager(
|
||||
reactContext: ReactApplicationContext,
|
||||
@@ -113,6 +117,7 @@ internal class RNTesterApplication : Application(), ReactApplication {
|
||||
when (viewManagerName) {
|
||||
"RNTMyNativeView" -> MyNativeViewManager()
|
||||
"RNTMyLegacyNativeView" -> MyLegacyViewManager(reactContext)
|
||||
"RNTReportFullyDrawnView" -> ReportFullyDrawnViewManager()
|
||||
else -> null
|
||||
}
|
||||
})
|
||||
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
package com.facebook.react.uiapp.component
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import com.facebook.react.uimanager.ThemedReactContext
|
||||
import com.facebook.react.views.view.ReactViewGroup
|
||||
|
||||
internal class ReportFullyDrawnView(context: ThemedReactContext) : ReactViewGroup(context) {
|
||||
private val reactApplicationContext = context.reactApplicationContext
|
||||
private var didReportFullyDrawn = false
|
||||
|
||||
override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
|
||||
super.onLayout(changed, left, top, right, bottom)
|
||||
|
||||
if (!didReportFullyDrawn) {
|
||||
didReportFullyDrawn = true
|
||||
|
||||
val activity = reactApplicationContext.currentActivity as? AppCompatActivity
|
||||
activity?.fullyDrawnReporter?.removeReporter()
|
||||
}
|
||||
}
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
package com.facebook.react.uiapp.component
|
||||
|
||||
import com.facebook.react.module.annotations.ReactModule
|
||||
import com.facebook.react.uimanager.ThemedReactContext
|
||||
import com.facebook.react.uimanager.ViewGroupManager
|
||||
import com.facebook.react.uimanager.ViewManagerDelegate
|
||||
import com.facebook.react.viewmanagers.RNTReportFullyDrawnViewManagerDelegate
|
||||
import com.facebook.react.viewmanagers.RNTReportFullyDrawnViewManagerInterface
|
||||
|
||||
/** View manager for ReportFullyDrawnView components. */
|
||||
@ReactModule(name = ReportFullyDrawnViewManager.REACT_CLASS)
|
||||
internal class ReportFullyDrawnViewManager :
|
||||
ViewGroupManager<ReportFullyDrawnView>(),
|
||||
RNTReportFullyDrawnViewManagerInterface<ReportFullyDrawnView> {
|
||||
|
||||
companion object {
|
||||
const val REACT_CLASS = "RNTReportFullyDrawnView"
|
||||
}
|
||||
|
||||
private val delegate: ViewManagerDelegate<ReportFullyDrawnView> =
|
||||
RNTReportFullyDrawnViewManagerDelegate(this)
|
||||
|
||||
override fun getDelegate(): ViewManagerDelegate<ReportFullyDrawnView> = delegate
|
||||
|
||||
override fun getName(): String = REACT_CLASS
|
||||
|
||||
override fun createViewInstance(reactContext: ThemedReactContext): ReportFullyDrawnView =
|
||||
ReportFullyDrawnView(reactContext)
|
||||
}
|
||||
@@ -26,6 +26,7 @@ import {
|
||||
getExamplesListWithRecentlyUsed,
|
||||
initialNavigationState,
|
||||
} from './utils/testerStateUtils';
|
||||
import ReportFullyDrawnView from '../ReportFullyDrawnView/ReportFullyDrawnView';
|
||||
import * as React from 'react';
|
||||
import {
|
||||
BackHandler,
|
||||
@@ -298,6 +299,7 @@ const RNTesterApp = ({
|
||||
handleNavBarPress={handleNavBarPress}
|
||||
/>
|
||||
</View>
|
||||
<ReportFullyDrawnView />
|
||||
</RNTesterThemeContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
+2
-1
@@ -18,7 +18,8 @@ include(
|
||||
":packages:react-native:ReactAndroid",
|
||||
":packages:react-native:ReactAndroid:hermes-engine",
|
||||
":packages:react-native:ReactAndroid:external-artifacts",
|
||||
":packages:rn-tester:android:app")
|
||||
":packages:rn-tester:android:app",
|
||||
":packages:rn-tester:android:app:benchmark")
|
||||
|
||||
includeBuild("packages/gradle-plugin/")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user