mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Compare commits
16
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0ec20e0c90 | ||
|
|
dab8a45623 | ||
|
|
40c60adacf | ||
|
|
a7cd3cc08f | ||
|
|
87f8e85b7f | ||
|
|
f6f5ea0b2e | ||
|
|
6c49572ee4 | ||
|
|
529f55c8c9 | ||
|
|
481fb612a2 | ||
|
|
3ce6a05aac | ||
|
|
813b9441ca | ||
|
|
cf5040b4f8 | ||
|
|
019a553ea4 | ||
|
|
2ae5a74f06 | ||
|
|
3d4a4caac8 | ||
|
|
cdc4a8ead4 |
@@ -19,6 +19,7 @@ on:
|
||||
|
||||
jobs:
|
||||
create_release:
|
||||
if: github.repository == 'facebook/react-native'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
|
||||
@@ -23,6 +23,7 @@ jobs:
|
||||
|
||||
prepare_hermes_workspace:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository == 'facebook/react-native'
|
||||
env:
|
||||
HERMES_WS_DIR: /tmp/hermes
|
||||
HERMES_VERSION_FILE: packages/react-native/sdks/.hermesversion
|
||||
@@ -50,8 +51,8 @@ jobs:
|
||||
- name: Build HermesC Apple
|
||||
uses: ./.github/actions/build-hermesc-apple
|
||||
with:
|
||||
hermes-version: ${{ needs.prepare_hermes_workspace.output.hermes-version }}
|
||||
react-native-version: ${{ needs.prepare_hermes_workspace.output.react-native-version }}
|
||||
hermes-version: ${{ needs.prepare_hermes_workspace.outputs.hermes-version }}
|
||||
react-native-version: ${{ needs.prepare_hermes_workspace.outputs.react-native-version }}
|
||||
|
||||
build_apple_slices_hermes:
|
||||
runs-on: macos-14
|
||||
@@ -75,7 +76,7 @@ jobs:
|
||||
uses: ./.github/actions/build-apple-slices-hermes
|
||||
with:
|
||||
flavor: ${{ matrix.flavor }}
|
||||
slice: ${{ matrix.slice}}
|
||||
slice: ${{ matrix.slice }}
|
||||
hermes-version: ${{ needs.prepare_hermes_workspace.outputs.hermes-version }}
|
||||
react-native-version: ${{ needs.prepare_hermes_workspace.outputs.react-native-version }}
|
||||
|
||||
@@ -101,6 +102,7 @@ jobs:
|
||||
flavor: ${{ matrix.flavor }}
|
||||
|
||||
prebuild_apple_dependencies:
|
||||
if: github.repository == 'facebook/react-native'
|
||||
uses: ./.github/workflows/prebuild-ios-dependencies.yml
|
||||
secrets: inherit
|
||||
|
||||
@@ -145,6 +147,7 @@ jobs:
|
||||
|
||||
build_android:
|
||||
runs-on: 8-core-ubuntu
|
||||
if: github.repository == 'facebook/react-native'
|
||||
needs: [set_release_type]
|
||||
container:
|
||||
image: reactnativecommunity/react-native-android:latest
|
||||
|
||||
@@ -9,6 +9,7 @@ on:
|
||||
jobs:
|
||||
publish_bumped_packages:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository == 'facebook/react-native'
|
||||
env:
|
||||
GHA_NPM_TOKEN: ${{ secrets.GHA_NPM_TOKEN }}
|
||||
steps:
|
||||
|
||||
@@ -21,6 +21,7 @@ jobs:
|
||||
|
||||
prepare_hermes_workspace:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository == 'facebook/react-native'
|
||||
env:
|
||||
HERMES_WS_DIR: /tmp/hermes
|
||||
HERMES_VERSION_FILE: packages/react-native/sdks/.hermesversion
|
||||
@@ -98,6 +99,7 @@ jobs:
|
||||
flavor: ${{ matrix.flavor }}
|
||||
|
||||
prebuild_apple_dependencies:
|
||||
if: github.repository == 'facebook/react-native'
|
||||
uses: ./.github/workflows/prebuild-ios-dependencies.yml
|
||||
secrets: inherit
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ on:
|
||||
jobs:
|
||||
rerun:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository == 'facebook/react-native'
|
||||
steps:
|
||||
- name: rerun ${{ inputs.run_id }}
|
||||
env:
|
||||
|
||||
@@ -11,6 +11,7 @@ on:
|
||||
jobs:
|
||||
set_release_type:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository == 'facebook/react-native'
|
||||
outputs:
|
||||
RELEASE_TYPE: ${{ steps.set_release_type.outputs.RELEASE_TYPE }}
|
||||
env:
|
||||
@@ -34,6 +35,7 @@ jobs:
|
||||
|
||||
prepare_hermes_workspace:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository == 'facebook/react-native'
|
||||
env:
|
||||
HERMES_WS_DIR: /tmp/hermes
|
||||
HERMES_VERSION_FILE: packages/react-native/sdks/.hermesversion
|
||||
@@ -112,6 +114,7 @@ jobs:
|
||||
flavor: ${{ matrix.flavor }}
|
||||
|
||||
prebuild_apple_dependencies:
|
||||
if: github.repository == 'facebook/react-native'
|
||||
uses: ./.github/workflows/prebuild-ios-dependencies.yml
|
||||
secrets: inherit
|
||||
|
||||
@@ -594,6 +597,7 @@ jobs:
|
||||
|
||||
test_js:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository == 'facebook/react-native'
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
@@ -608,6 +612,7 @@ jobs:
|
||||
|
||||
lint:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository == 'facebook/react-native'
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
steps:
|
||||
|
||||
@@ -27,6 +27,7 @@ on:
|
||||
jobs:
|
||||
validate-dotslash-artifacts:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository == 'facebook/react-native'
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
+6
-1
@@ -23,6 +23,7 @@ import com.facebook.react.utils.PropertyUtils.SCOPED_USE_THIRD_PARTY_JSC
|
||||
import com.facebook.react.utils.PropertyUtils.USE_THIRD_PARTY_JSC
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.file.DirectoryProperty
|
||||
import org.jetbrains.kotlin.gradle.plugin.extraProperties
|
||||
|
||||
internal object ProjectUtils {
|
||||
|
||||
@@ -75,7 +76,11 @@ internal object ProjectUtils {
|
||||
(project.hasProperty(HERMES_V1_ENABLED) &&
|
||||
project.property(HERMES_V1_ENABLED).toString().toBoolean()) ||
|
||||
(project.hasProperty(SCOPED_HERMES_V1_ENABLED) &&
|
||||
project.property(SCOPED_HERMES_V1_ENABLED).toString().toBoolean())
|
||||
project.property(SCOPED_HERMES_V1_ENABLED).toString().toBoolean()) ||
|
||||
(project.extraProperties.has(HERMES_V1_ENABLED) &&
|
||||
project.extraProperties.get(HERMES_V1_ENABLED).toString().toBoolean()) ||
|
||||
(project.extraProperties.has(SCOPED_HERMES_V1_ENABLED) &&
|
||||
project.extraProperties.get(SCOPED_HERMES_V1_ENABLED).toString().toBoolean())
|
||||
|
||||
internal fun Project.needsCodegenFromPackageJson(rootProperty: DirectoryProperty): Boolean {
|
||||
val parsedPackageJson = readPackageJsonFile(this, rootProperty)
|
||||
|
||||
+3
-3
@@ -33,9 +33,9 @@ class GeneratePackageListTaskTest {
|
||||
val inputFile = tempFolder.newFile("config.json")
|
||||
|
||||
val task =
|
||||
createTestTask<GeneratePackageListTask> {
|
||||
it.generatedOutputDirectory.set(outputFolder)
|
||||
it.autolinkInputFile.set(inputFile)
|
||||
createTestTask<GeneratePackageListTask> { testTask ->
|
||||
testTask.generatedOutputDirectory.set(outputFolder)
|
||||
testTask.autolinkInputFile.set(inputFile)
|
||||
}
|
||||
|
||||
assertThat(task.inputs.files.singleFile).isEqualTo(inputFile)
|
||||
|
||||
+5
-5
@@ -37,11 +37,11 @@ class PrepareBoostTaskTest {
|
||||
val project = createProject()
|
||||
val boostThirdPartyJniPath = File(project.projectDir, "src/main/jni/third-party/boost/")
|
||||
val task =
|
||||
createTestTask<PrepareBoostTask>(project = project) {
|
||||
it.boostPath.setFrom(boostpath)
|
||||
it.boostThirdPartyJniPath.set(boostThirdPartyJniPath)
|
||||
it.boostVersion.set("1.0.0")
|
||||
it.outputDir.set(output)
|
||||
createTestTask<PrepareBoostTask>(project = project) { task ->
|
||||
task.boostPath.setFrom(boostpath)
|
||||
task.boostThirdPartyJniPath.set(boostThirdPartyJniPath)
|
||||
task.boostVersion.set("1.0.0")
|
||||
task.outputDir.set(output)
|
||||
}
|
||||
File(boostThirdPartyJniPath, "CMakeLists.txt").apply {
|
||||
parentFile.mkdirs()
|
||||
|
||||
+5
-5
@@ -82,11 +82,11 @@ class PrepareGflagsTaskTest {
|
||||
val gflagsThirdPartyPath = tempFolder.newFolder("gflagspath/jni")
|
||||
val output = tempFolder.newFolder("output")
|
||||
val task =
|
||||
createTestTask<PrepareGflagsTask> {
|
||||
it.gflagsPath.setFrom(gflagspath)
|
||||
it.gflagsThirdPartyPath.set(gflagsThirdPartyPath)
|
||||
it.gflagsVersion.set("1.0.0")
|
||||
it.outputDir.set(output)
|
||||
createTestTask<PrepareGflagsTask> { taskConfig ->
|
||||
taskConfig.gflagsPath.setFrom(gflagspath)
|
||||
taskConfig.gflagsThirdPartyPath.set(gflagsThirdPartyPath)
|
||||
taskConfig.gflagsVersion.set("1.0.0")
|
||||
taskConfig.outputDir.set(output)
|
||||
}
|
||||
File(gflagspath, "gflags-1.0.0/src/gflags_declare.h.in").apply {
|
||||
parentFile.mkdirs()
|
||||
|
||||
@@ -50,6 +50,7 @@ Pod::Spec.new do |s|
|
||||
add_dependency(s, "React-jsinspectorcdp", :framework_name => 'jsinspector_moderncdp')
|
||||
add_dependency(s, "React-jsinspectornetwork", :framework_name => 'jsinspector_modernnetwork')
|
||||
add_dependency(s, "React-NativeModulesApple", :additional_framework_paths => ["build/generated/ios"])
|
||||
add_dependency(s, "React-networking", :framework_name => 'React_networking')
|
||||
|
||||
add_rn_third_party_dependencies(s)
|
||||
add_rncore_dependency(s)
|
||||
|
||||
@@ -67,7 +67,7 @@ template <typename T>
|
||||
facebook::react::LazyVector<T> RCTBridgingToVec(id value, T (^ctor)(id element))
|
||||
{
|
||||
NSArray *array = RCTBridgingToArray(value);
|
||||
typedef typename facebook::react::LazyVector<T>::size_type _size_t;
|
||||
using _size_t = typename facebook::react::LazyVector<T>::size_type;
|
||||
_size_t size = static_cast<_size_t>(array.count);
|
||||
return facebook::react::LazyVector<T>::fromUnsafeRawValue(array, size, ctor);
|
||||
}
|
||||
|
||||
@@ -721,13 +721,13 @@ NSData *__nullable RCTGzipData(NSData *__nullable input, float level)
|
||||
|
||||
void *libz = dlopen("/usr/lib/libz.dylib", RTLD_LAZY);
|
||||
|
||||
typedef int (*DeflateInit2_)(z_streamp, int, int, int, int, int, const char *, int);
|
||||
using DeflateInit2_ = int (*)(z_streamp, int, int, int, int, int, const char *, int);
|
||||
DeflateInit2_ deflateInit2_ = (DeflateInit2_)dlsym(libz, "deflateInit2_");
|
||||
|
||||
typedef int (*Deflate)(z_streamp, int);
|
||||
using Deflate = int (*)(z_streamp, int);
|
||||
Deflate deflate = (Deflate)dlsym(libz, "deflate");
|
||||
|
||||
typedef int (*DeflateEnd)(z_streamp);
|
||||
using DeflateEnd = int (*)(z_streamp);
|
||||
DeflateEnd deflateEnd = (DeflateEnd)dlsym(libz, "deflateEnd");
|
||||
|
||||
z_stream stream;
|
||||
|
||||
+1
-1
@@ -96,7 +96,7 @@ public class CatalystInstanceImpl implements CatalystInstance {
|
||||
private final TraceListener mTraceListener;
|
||||
private final JavaScriptModuleRegistry mJSModuleRegistry;
|
||||
private final JSBundleLoader mJSBundleLoader;
|
||||
private final ArrayList<PendingJSCall> mJSCallsPendingInit = new ArrayList<PendingJSCall>();
|
||||
private final ArrayList<PendingJSCall> mJSCallsPendingInit = new ArrayList<>();
|
||||
private final Object mJSCallsPendingInitLock = new Object();
|
||||
|
||||
private final NativeModuleRegistry mNativeModuleRegistry;
|
||||
|
||||
+1
-1
@@ -83,6 +83,6 @@ internal class BridgelessDevSupportManager(
|
||||
}
|
||||
|
||||
fun tracingState(): TracingState {
|
||||
return TracingState.DISABLED
|
||||
return TracingState.ENABLEDINCDPMODE
|
||||
}
|
||||
}
|
||||
|
||||
+12
-8
@@ -68,6 +68,7 @@ import com.facebook.react.devsupport.interfaces.StackFrame
|
||||
import com.facebook.react.devsupport.interfaces.TracingState
|
||||
import com.facebook.react.devsupport.interfaces.TracingStateProvider
|
||||
import com.facebook.react.devsupport.perfmonitor.PerfMonitorDevHelper
|
||||
import com.facebook.react.devsupport.perfmonitor.PerfMonitorOverlayManager
|
||||
import com.facebook.react.internal.featureflags.ReactNativeFeatureFlags
|
||||
import com.facebook.react.internal.featureflags.ReactNativeNewArchitectureFeatureFlags
|
||||
import com.facebook.react.modules.core.RCTNativeAppEventEmitter
|
||||
@@ -77,6 +78,7 @@ import java.io.File
|
||||
import java.net.MalformedURLException
|
||||
import java.net.URL
|
||||
import java.util.Locale
|
||||
import javax.inject.Provider
|
||||
|
||||
public abstract class DevSupportManagerBase(
|
||||
protected val applicationContext: Context,
|
||||
@@ -182,7 +184,7 @@ public abstract class DevSupportManagerBase(
|
||||
null
|
||||
}
|
||||
|
||||
private var perfMonitorOverlayManager: PerfMonitorOverlayViewManager? = null
|
||||
private var perfMonitorOverlayManager: PerfMonitorOverlayManager? = null
|
||||
private var tracingStateProvider: TracingStateProvider? = null
|
||||
|
||||
init {
|
||||
@@ -215,19 +217,19 @@ public abstract class DevSupportManagerBase(
|
||||
if (
|
||||
ReactNativeNewArchitectureFeatureFlags.enableBridgelessArchitecture() &&
|
||||
ReactNativeFeatureFlags.perfMonitorV2Enabled() &&
|
||||
reactInstanceDevHelper is PerfMonitorDevHelper &&
|
||||
perfMonitorOverlayManager == null
|
||||
reactInstanceDevHelper is PerfMonitorDevHelper
|
||||
) {
|
||||
perfMonitorOverlayManager =
|
||||
PerfMonitorOverlayViewManager(
|
||||
Supplier {
|
||||
PerfMonitorOverlayManager(
|
||||
reactInstanceDevHelper,
|
||||
Provider {
|
||||
val context = reactInstanceDevHelper.currentActivity
|
||||
if (context == null || context.isFinishing) {
|
||||
return@Supplier null
|
||||
return@Provider null
|
||||
}
|
||||
context
|
||||
},
|
||||
reactInstanceDevHelper.inspectorTarget,
|
||||
{ openDebugger(DebuggerFrontendPanelName.PERFORMANCE.toString()) },
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -548,10 +550,11 @@ public abstract class DevSupportManagerBase(
|
||||
override fun onNewReactContextCreated(reactContext: ReactContext) {
|
||||
resetCurrentContext(reactContext)
|
||||
|
||||
if (perfMonitorOverlayManager != null && reactInstanceDevHelper is PerfMonitorDevHelper) {
|
||||
if (reactInstanceDevHelper is PerfMonitorDevHelper) {
|
||||
perfMonitorOverlayManager?.let { manager ->
|
||||
reactInstanceDevHelper.inspectorTarget?.addPerfMonitorListener(manager)
|
||||
}
|
||||
perfMonitorOverlayManager?.enable()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -882,6 +885,7 @@ public abstract class DevSupportManagerBase(
|
||||
|
||||
override fun onPackagerDisconnected() {
|
||||
isPackagerConnected = false
|
||||
perfMonitorOverlayManager?.disable()
|
||||
}
|
||||
|
||||
override fun onPackagerReloadCommand() {
|
||||
|
||||
-20
@@ -1,20 +0,0 @@
|
||||
/*
|
||||
* 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.devsupport.interfaces
|
||||
|
||||
/** [Experimental] Interface to manage the V2 Perf Monitor overlay. */
|
||||
internal interface PerfMonitorOverlayManager {
|
||||
/** Enable the Perf Monitor overlay. Will be shown when updates are received. */
|
||||
public fun enable()
|
||||
|
||||
/** Disable the Perf Monitor overlay. Will remain hidden when updates are received. */
|
||||
public fun disable()
|
||||
|
||||
/** Reset the Perf Monitor overlay, e.g. after a reload. */
|
||||
public fun reset()
|
||||
}
|
||||
+5
@@ -7,11 +7,16 @@
|
||||
|
||||
package com.facebook.react.devsupport.perfmonitor
|
||||
|
||||
import com.facebook.react.devsupport.interfaces.TracingState
|
||||
|
||||
/**
|
||||
* [Experimental] Interface implemented by [com.facebook.react.runtime.ReactHostInspectorTarget]
|
||||
* exposing actions for the V2 Perf Monitor.
|
||||
*/
|
||||
internal interface PerfMonitorInspectorTargetBinding {
|
||||
/** Get the current CDP or background performance tracing state. */
|
||||
public fun getTracingState(): TracingState
|
||||
|
||||
/** Attempt to pause the current background performance trace, and open in DevTools. */
|
||||
public fun pauseAndAnalyzeBackgroundTrace()
|
||||
|
||||
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* 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.devsupport.perfmonitor
|
||||
|
||||
import android.content.Context
|
||||
import com.facebook.react.bridge.UiThreadUtil
|
||||
import com.facebook.react.devsupport.interfaces.TracingState
|
||||
import javax.inject.Provider
|
||||
|
||||
internal class PerfMonitorOverlayManager(
|
||||
private val devHelper: PerfMonitorDevHelper,
|
||||
private val contextProvider: Provider<Context?>,
|
||||
private val onRequestOpenDevTools: () -> Unit,
|
||||
) : PerfMonitorUpdateListener {
|
||||
private var enabled: Boolean = false
|
||||
private var initialized: Boolean = false
|
||||
private var view: PerfMonitorOverlayView? = null
|
||||
private var tracingState: TracingState = TracingState.ENABLEDINCDPMODE
|
||||
|
||||
private fun init() {
|
||||
if (initialized || !enabled) {
|
||||
return
|
||||
}
|
||||
|
||||
UiThreadUtil.runOnUiThread {
|
||||
val context = contextProvider.get() ?: return@runOnUiThread
|
||||
view = PerfMonitorOverlayView(context, ::handleRecordingButtonPress)
|
||||
|
||||
// Start background tracing
|
||||
devHelper.inspectorTarget?.resumeBackgroundTrace()
|
||||
|
||||
view?.show()
|
||||
initialized = true
|
||||
}
|
||||
}
|
||||
|
||||
/** Enable the Perf Monitor overlay. Will be shown when updates are received. */
|
||||
fun enable() {
|
||||
enabled = true
|
||||
init()
|
||||
UiThreadUtil.runOnUiThread { view?.show() }
|
||||
}
|
||||
|
||||
/** Disable the Perf Monitor overlay. Will remain hidden when updates are received. */
|
||||
fun disable() {
|
||||
UiThreadUtil.runOnUiThread { view?.hide() }
|
||||
enabled = false
|
||||
}
|
||||
|
||||
/** Reset the Perf Monitor overlay, e.g. after a reload. */
|
||||
fun reset() {
|
||||
UiThreadUtil.runOnUiThread { view?.resetState() }
|
||||
|
||||
// Update with current recording state
|
||||
onRecordingStateChanged(
|
||||
devHelper.inspectorTarget?.getTracingState() ?: TracingState.ENABLEDINCDPMODE
|
||||
)
|
||||
}
|
||||
|
||||
override fun onNewFocusedEvent(data: PerfMonitorUpdateListener.LongTaskEventData) {
|
||||
view?.updateFocusedEvent(data)
|
||||
}
|
||||
|
||||
override fun onRecordingStateChanged(state: TracingState) {
|
||||
tracingState = state
|
||||
view?.updateRecordingState(state)
|
||||
}
|
||||
|
||||
private fun handleRecordingButtonPress() {
|
||||
when (tracingState) {
|
||||
TracingState.ENABLEDINBACKGROUNDMODE -> {
|
||||
devHelper.inspectorTarget?.pauseAndAnalyzeBackgroundTrace()
|
||||
onRequestOpenDevTools()
|
||||
}
|
||||
TracingState.DISABLED -> {
|
||||
devHelper.inspectorTarget?.resumeBackgroundTrace()
|
||||
}
|
||||
TracingState.ENABLEDINCDPMODE -> Unit
|
||||
}
|
||||
}
|
||||
}
|
||||
+142
-108
@@ -5,7 +5,7 @@
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
package com.facebook.react.devsupport
|
||||
package com.facebook.react.devsupport.perfmonitor
|
||||
|
||||
import android.app.Dialog
|
||||
import android.content.Context
|
||||
@@ -20,107 +20,110 @@ import android.view.Window
|
||||
import android.view.WindowManager
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.TextView
|
||||
import androidx.core.util.Supplier
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
import com.facebook.react.R
|
||||
import com.facebook.react.bridge.UiThreadUtil
|
||||
import com.facebook.react.devsupport.interfaces.PerfMonitorOverlayManager
|
||||
import com.facebook.react.devsupport.interfaces.TracingState
|
||||
import com.facebook.react.devsupport.perfmonitor.PerfMonitorInspectorTargetBinding
|
||||
import com.facebook.react.devsupport.perfmonitor.PerfMonitorUpdateListener
|
||||
import com.facebook.react.uimanager.DisplayMetricsHolder
|
||||
import com.facebook.react.uimanager.PixelUtil
|
||||
import java.util.Locale
|
||||
|
||||
internal class PerfMonitorOverlayViewManager(
|
||||
private val contextSupplier: Supplier<Context?>,
|
||||
private val inspectorTarget: PerfMonitorInspectorTargetBinding?,
|
||||
) : PerfMonitorOverlayManager, PerfMonitorUpdateListener {
|
||||
private var initialized: Boolean = false
|
||||
private var enabled: Boolean = false
|
||||
private var hasInteractionData: Boolean = false
|
||||
private var interactionDialog: Dialog? = null
|
||||
private var buttonDialog: Dialog? = null
|
||||
private var durationLabel: TextView? = null
|
||||
internal class PerfMonitorOverlayView(
|
||||
private val context: Context,
|
||||
private val onButtonPress: () -> Unit,
|
||||
) {
|
||||
private var hidden: Boolean = true
|
||||
private var hasEventData: Boolean = false
|
||||
private val metricsDialog: Dialog
|
||||
private val toolbarDialog: Dialog
|
||||
private val tooltipDialog: Dialog
|
||||
private lateinit var buttonLabel: TextView
|
||||
private lateinit var recordingStateLabel: TextView
|
||||
private lateinit var durationLabel: TextView
|
||||
private lateinit var tooltipLabel: TextView
|
||||
private var ttl: Int = 0
|
||||
private var hideAfterTimeoutHandler: Handler? = null
|
||||
|
||||
override fun enable() {
|
||||
UiThreadUtil.runOnUiThread {
|
||||
enabled = true
|
||||
if (hasInteractionData) {
|
||||
showOverlay()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun disable() {
|
||||
UiThreadUtil.runOnUiThread {
|
||||
enabled = false
|
||||
hideOverlay()
|
||||
}
|
||||
}
|
||||
|
||||
override fun reset() {
|
||||
UiThreadUtil.runOnUiThread {
|
||||
hasInteractionData = false
|
||||
hideOverlay()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onRecordingStateChanged(state: TracingState) {
|
||||
// recordingState = state
|
||||
// view?.updateRecordingState(state)
|
||||
}
|
||||
|
||||
override fun onNewFocusedEvent(data: PerfMonitorUpdateListener.LongTaskEventData) {
|
||||
UiThreadUtil.runOnUiThread {
|
||||
ensureInitialized()
|
||||
durationLabel?.text = String.format(Locale.US, "%d ms", data.durationMs)
|
||||
durationLabel?.setTextColor(getDurationHighlightColor(data.responsivenessScore))
|
||||
hasInteractionData = true
|
||||
ttl = data.ttl
|
||||
|
||||
hideAfterTimeoutHandler?.removeCallbacksAndMessages(null)
|
||||
|
||||
if (enabled) {
|
||||
showOverlay()
|
||||
|
||||
// Schedule hiding overlay after ttl milliseconds
|
||||
if (ttl > 0) {
|
||||
if (hideAfterTimeoutHandler == null) {
|
||||
hideAfterTimeoutHandler = Handler(Looper.getMainLooper())
|
||||
}
|
||||
hideAfterTimeoutHandler?.postDelayed({ hideOverlay() }, ttl.toLong())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun ensureInitialized() {
|
||||
if (initialized) {
|
||||
return
|
||||
}
|
||||
val context = contextSupplier.get() ?: return
|
||||
init {
|
||||
DisplayMetricsHolder.initDisplayMetricsIfNotInitialized(context)
|
||||
createDialog(context)
|
||||
createButton(context)
|
||||
initialized = true
|
||||
tooltipDialog = createTooltipDialog()
|
||||
metricsDialog = createMetricsDialog()
|
||||
toolbarDialog = createToolbarDialog()
|
||||
}
|
||||
|
||||
private fun showOverlay() {
|
||||
interactionDialog?.show()
|
||||
buttonDialog?.show()
|
||||
fun show() {
|
||||
toolbarDialog.show()
|
||||
tooltipDialog.show()
|
||||
if (hasEventData) {
|
||||
toolbarDialog.window?.decorView?.post { updateMetricsDialogPosition() }
|
||||
metricsDialog.show()
|
||||
}
|
||||
hidden = false
|
||||
}
|
||||
|
||||
private fun hideOverlay() {
|
||||
interactionDialog?.hide()
|
||||
buttonDialog?.hide()
|
||||
fun hide() {
|
||||
metricsDialog.hide()
|
||||
toolbarDialog.hide()
|
||||
tooltipDialog.hide()
|
||||
hidden = true
|
||||
}
|
||||
|
||||
private fun createDialog(context: Context) {
|
||||
val containerLayout = createInnerLayout(context)
|
||||
fun resetState() {
|
||||
hasEventData = false
|
||||
metricsDialog.hide()
|
||||
}
|
||||
|
||||
fun updateFocusedEvent(data: PerfMonitorUpdateListener.LongTaskEventData) {
|
||||
durationLabel.text = String.format(Locale.US, "%d ms", data.durationMs)
|
||||
durationLabel.setTextColor(getDurationHighlightColor(data.responsivenessScore))
|
||||
hasEventData = true
|
||||
ttl = data.ttl
|
||||
|
||||
hideAfterTimeoutHandler?.removeCallbacksAndMessages(null)
|
||||
|
||||
if (!hidden) {
|
||||
metricsDialog.show()
|
||||
|
||||
// Schedule hiding metrics overlay after ttl milliseconds
|
||||
if (ttl > 0) {
|
||||
if (hideAfterTimeoutHandler == null) {
|
||||
hideAfterTimeoutHandler = Handler(Looper.getMainLooper())
|
||||
}
|
||||
hideAfterTimeoutHandler?.postDelayed({ metricsDialog.hide() }, ttl.toLong())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun updateRecordingState(state: TracingState) {
|
||||
recordingStateLabel.text =
|
||||
when (state) {
|
||||
TracingState.ENABLEDINBACKGROUNDMODE -> "Profiling: ON"
|
||||
TracingState.DISABLED -> "Profiling: OFF"
|
||||
TracingState.ENABLEDINCDPMODE -> "Profiling: DISABLED"
|
||||
}
|
||||
buttonLabel.text =
|
||||
when (state) {
|
||||
TracingState.ENABLEDINBACKGROUNDMODE -> "Open ↗️"
|
||||
TracingState.DISABLED -> "Start"
|
||||
TracingState.ENABLEDINCDPMODE -> ""
|
||||
}
|
||||
tooltipLabel.text =
|
||||
when (state) {
|
||||
TracingState.ENABLEDINBACKGROUNDMODE -> "Dev Menu > Finish performance trace"
|
||||
TracingState.DISABLED -> "Dev Menu > Start performance trace"
|
||||
TracingState.ENABLEDINCDPMODE -> ""
|
||||
}
|
||||
if (state == TracingState.ENABLEDINCDPMODE) {
|
||||
tooltipDialog.hide()
|
||||
} else {
|
||||
tooltipDialog.show()
|
||||
}
|
||||
|
||||
toolbarDialog.window?.decorView?.post { updateMetricsDialogPosition() }
|
||||
}
|
||||
|
||||
private fun createMetricsDialog(): Dialog {
|
||||
val containerLayout = createInnerLayout()
|
||||
val longTaskLabel =
|
||||
TextView(context).apply {
|
||||
textSize = TEXT_SIZE_PRIMARY
|
||||
@@ -138,7 +141,7 @@ internal class PerfMonitorOverlayViewManager(
|
||||
containerLayout.addView(durationLabel)
|
||||
|
||||
val dialog =
|
||||
createAnchoredDialog(context, dpToPx(140f), dpToPx(16f)).apply {
|
||||
createAnchoredDialog(getMetricsDialogOffsetX(), dpToPx(16f)).apply {
|
||||
setContentView(containerLayout)
|
||||
}
|
||||
dialog.window?.apply {
|
||||
@@ -151,30 +154,25 @@ internal class PerfMonitorOverlayViewManager(
|
||||
}
|
||||
}
|
||||
|
||||
this.interactionDialog = dialog
|
||||
return dialog
|
||||
}
|
||||
|
||||
fun updateRecordingState(state: TracingState) {}
|
||||
|
||||
private fun createButton(context: Context) {
|
||||
val buttonInner = createInnerLayout(context)
|
||||
buttonInner.addView(
|
||||
private fun createToolbarDialog(): Dialog {
|
||||
val buttonInner = createInnerLayout()
|
||||
recordingStateLabel =
|
||||
TextView(context).apply {
|
||||
text = "Analyze"
|
||||
textSize = TEXT_SIZE_PRIMARY
|
||||
setTextColor(Color.WHITE)
|
||||
typeface = TYPEFACE_BOLD
|
||||
}
|
||||
)
|
||||
buttonInner.addView(
|
||||
buttonInner.addView(recordingStateLabel)
|
||||
buttonLabel =
|
||||
TextView(context).apply {
|
||||
text = "cmd + A"
|
||||
textSize = TEXT_SIZE_ACCESSORY
|
||||
setTextColor(Color.WHITE)
|
||||
alpha = 0.7f
|
||||
textSize = TEXT_SIZE_PRIMARY
|
||||
setTextColor(COLOR_TEXT_BLUE)
|
||||
typeface = TYPEFACE_BOLD
|
||||
}
|
||||
)
|
||||
buttonInner.addView(buttonLabel)
|
||||
val buttonView =
|
||||
LinearLayout(context).apply {
|
||||
orientation = LinearLayout.VERTICAL
|
||||
@@ -185,19 +183,43 @@ internal class PerfMonitorOverlayViewManager(
|
||||
dpToPx(8f).toInt(),
|
||||
)
|
||||
addView(buttonInner)
|
||||
setOnClickListener { inspectorTarget?.pauseAndAnalyzeBackgroundTrace() }
|
||||
setOnClickListener { onButtonPress() }
|
||||
}
|
||||
val dialog =
|
||||
createAnchoredDialog(context, dpToPx(0f), dpToPx(0f)).apply { setContentView(buttonView) }
|
||||
|
||||
val dialog = createAnchoredDialog(dpToPx(0f), dpToPx(0f)).apply { setContentView(buttonView) }
|
||||
dialog.window?.apply {
|
||||
attributes =
|
||||
attributes?.apply { flags = flags or WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE }
|
||||
}
|
||||
|
||||
this.buttonDialog = dialog
|
||||
return dialog
|
||||
}
|
||||
|
||||
private fun createAnchoredDialog(context: Context, offsetX: Float, offsetY: Float): Dialog {
|
||||
private fun createTooltipDialog(): Dialog {
|
||||
val containerLayout = createInnerLayout()
|
||||
tooltipLabel =
|
||||
TextView(context).apply {
|
||||
textSize = TEXT_SIZE_ACCESSORY
|
||||
setTextColor(Color.WHITE)
|
||||
}
|
||||
containerLayout.addView(tooltipLabel)
|
||||
|
||||
val dialog =
|
||||
createAnchoredDialog(dpToPx(16f), dpToPx(52f)).apply { setContentView(containerLayout) }
|
||||
dialog.window?.apply {
|
||||
attributes =
|
||||
attributes?.apply {
|
||||
flags =
|
||||
flags or
|
||||
WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE or
|
||||
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
|
||||
}
|
||||
}
|
||||
|
||||
return dialog
|
||||
}
|
||||
|
||||
private fun createAnchoredDialog(offsetX: Float, offsetY: Float): Dialog {
|
||||
val dialog =
|
||||
Dialog(context, R.style.NoAnimationDialog).apply {
|
||||
requestWindowFeature(Window.FEATURE_NO_TITLE)
|
||||
@@ -228,12 +250,12 @@ internal class PerfMonitorOverlayViewManager(
|
||||
return dialog
|
||||
}
|
||||
|
||||
private fun createInnerLayout(context: Context): LinearLayout {
|
||||
private fun createInnerLayout(): LinearLayout {
|
||||
return LinearLayout(context).apply {
|
||||
orientation = LinearLayout.HORIZONTAL
|
||||
gravity = Gravity.CENTER_VERTICAL
|
||||
val paddingHorizontal = dpToPx(14f).toInt()
|
||||
val paddingVertical = dpToPx(8f).toInt()
|
||||
val paddingVertical = dpToPx(7f).toInt()
|
||||
setPadding(paddingHorizontal, paddingVertical, paddingHorizontal, paddingVertical)
|
||||
layoutParams =
|
||||
LinearLayout.LayoutParams(
|
||||
@@ -256,10 +278,21 @@ internal class PerfMonitorOverlayViewManager(
|
||||
}
|
||||
}
|
||||
|
||||
private fun getMetricsDialogOffsetX(): Float {
|
||||
val toolbarWidth = toolbarDialog?.window?.decorView?.width ?: 0
|
||||
return toolbarWidth.toFloat()
|
||||
}
|
||||
|
||||
private fun updateMetricsDialogPosition() {
|
||||
metricsDialog?.window?.apply {
|
||||
attributes = attributes?.apply { x = getMetricsDialogOffsetX().toInt() }
|
||||
}
|
||||
}
|
||||
|
||||
private fun getDurationHighlightColor(responsivenessScore: Int): Int {
|
||||
return when (responsivenessScore) {
|
||||
3 -> COLOR_TEXT_RED
|
||||
2 -> COLOR_TEXT_YELLOW
|
||||
2 -> COLOR_TEXT_RED
|
||||
1 -> COLOR_TEXT_YELLOW
|
||||
else -> COLOR_TEXT_GREEN
|
||||
}
|
||||
}
|
||||
@@ -270,6 +303,7 @@ internal class PerfMonitorOverlayViewManager(
|
||||
private val COLOR_TEXT_GREEN = Color.parseColor("#4AEB2F")
|
||||
private val COLOR_TEXT_YELLOW = Color.parseColor("#FFAA00")
|
||||
private val COLOR_TEXT_RED = Color.parseColor("#FF0000")
|
||||
private val COLOR_TEXT_BLUE = Color.parseColor("#00B0FF")
|
||||
private val COLOR_OVERLAY_BORDER = Color.parseColor("#6C6C6C")
|
||||
private val TEXT_SIZE_PRIMARY = 13f
|
||||
private val TEXT_SIZE_ACCESSORY = 9f
|
||||
+1
-1
@@ -81,6 +81,6 @@ internal class ReactHostImplDevHelper(private val delegate: ReactHostImpl) :
|
||||
delegate.loadBundle(bundleLoader)
|
||||
|
||||
override fun getTracingState(): TracingState {
|
||||
return delegate.reactHostInspectorTarget?.tracingState() ?: TracingState.DISABLED
|
||||
return delegate.reactHostInspectorTarget?.getTracingState() ?: TracingState.ENABLEDINCDPMODE
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -43,7 +43,7 @@ internal class ReactHostInspectorTarget(reactHostImpl: ReactHostImpl) :
|
||||
|
||||
external fun tracingStateAsInt(): Int
|
||||
|
||||
fun tracingState(): TracingState {
|
||||
override fun getTracingState(): TracingState {
|
||||
return TracingState.entries[tracingStateAsInt()]
|
||||
}
|
||||
|
||||
|
||||
@@ -50,7 +50,8 @@ void PerfMonitorUpdateHandler::handlePerfMetricsUpdate(
|
||||
}
|
||||
|
||||
auto responsivenessScore = getInteractionScore(duration);
|
||||
auto ttl = responsivenessScore == InteractionResponsivenessScore::Poor
|
||||
auto ttl =
|
||||
responsivenessScore == InteractionResponsivenessScore::NeedsImprovement
|
||||
? BAD_EVENT_TTL
|
||||
: DEFAULT_TTL;
|
||||
|
||||
|
||||
+2
-1
@@ -47,9 +47,10 @@ Pod::Spec.new do |s|
|
||||
add_rncore_dependency(s)
|
||||
|
||||
s.dependency "React-domnativemodule"
|
||||
s.dependency "React-featureflagsnativemodule"
|
||||
s.dependency "React-microtasksnativemodule"
|
||||
s.dependency "React-idlecallbacksnativemodule"
|
||||
s.dependency "React-webperformancenativemodule"
|
||||
add_dependency(s, "React-RCTFBReactNativeSpec")
|
||||
add_dependency(s, "React-featureflags")
|
||||
add_dependency(s, "React-featureflagsnativemodule")
|
||||
end
|
||||
|
||||
+9
@@ -131,9 +131,18 @@ NativePerformance::NativePerformance(std::shared_ptr<CallInvoker> jsInvoker)
|
||||
: NativePerformanceCxxSpec(std::move(jsInvoker)) {}
|
||||
|
||||
HighResTimeStamp NativePerformance::now(jsi::Runtime& /*rt*/) {
|
||||
// This is not spec-compliant, as this is the duration from system boot to
|
||||
// now, instead of from app startup to now.
|
||||
// This should be carefully changed eventually.
|
||||
return HighResTimeStamp::now();
|
||||
}
|
||||
|
||||
HighResDuration NativePerformance::timeOrigin(jsi::Runtime& /*rt*/) {
|
||||
// This is not spec-compliant, as this is an approximation from Unix epoch to
|
||||
// system boot, instead of a precise duration from Unix epoch to app startup.
|
||||
return HighResTimeStamp::unsafeOriginFromUnixTimeStamp();
|
||||
}
|
||||
|
||||
void NativePerformance::reportMark(
|
||||
jsi::Runtime& rt,
|
||||
const std::string& name,
|
||||
|
||||
+3
@@ -88,6 +88,9 @@ class NativePerformance : public NativePerformanceCxxSpec<NativePerformance> {
|
||||
// https://www.w3.org/TR/hr-time-3/#now-method
|
||||
HighResTimeStamp now(jsi::Runtime& rt);
|
||||
|
||||
// https://www.w3.org/TR/hr-time-3/#timeorigin-attribute
|
||||
HighResDuration timeOrigin(jsi::Runtime& rt);
|
||||
|
||||
#pragma mark - User Timing Level 3 functions (https://w3c.github.io/user-timing/)
|
||||
|
||||
void reportMark(
|
||||
|
||||
+2
@@ -45,12 +45,14 @@ Pod::Spec.new do |s|
|
||||
|
||||
s.dependency "React-jsi"
|
||||
s.dependency "React-jsiexecutor"
|
||||
s.dependency "React-cxxreact"
|
||||
|
||||
depend_on_js_engine(s)
|
||||
add_rn_third_party_dependencies(s)
|
||||
add_rncore_dependency(s)
|
||||
|
||||
s.dependency "ReactCommon/turbomodule/core"
|
||||
|
||||
add_dependency(s, "React-RCTFBReactNativeSpec")
|
||||
add_dependency(s, "React-performancetimeline")
|
||||
add_dependency(s, "React-runtimeexecutor", :additional_framework_paths => ["platform/ios"])
|
||||
|
||||
@@ -27,10 +27,10 @@ std::optional<double> DynamicEventPayload::extractValue(
|
||||
auto dynamic = payload_;
|
||||
for (auto& key : path) {
|
||||
auto type = dynamic.type();
|
||||
if ((type == folly::dynamic::Type::OBJECT ||
|
||||
type == folly::dynamic::Type::ARRAY) &&
|
||||
!dynamic.empty()) {
|
||||
if (type == folly::dynamic::Type::OBJECT && !dynamic.empty()) {
|
||||
dynamic = folly::dynamic(dynamic[key]);
|
||||
} else if (type == folly::dynamic::Type::ARRAY && !dynamic.empty()) {
|
||||
dynamic = folly::dynamic(dynamic[std::stoi(key)]);
|
||||
}
|
||||
}
|
||||
if (dynamic.type() == folly::dynamic::Type::DOUBLE) {
|
||||
|
||||
@@ -201,6 +201,11 @@ class HighResTimeStamp {
|
||||
return HighResTimeStamp(chronoNow());
|
||||
}
|
||||
|
||||
static HighResDuration unsafeOriginFromUnixTimeStamp() noexcept {
|
||||
static auto origin = computeUnsafeOriginFromUnixTimeStamp();
|
||||
return origin;
|
||||
}
|
||||
|
||||
static constexpr HighResTimeStamp min() noexcept {
|
||||
return HighResTimeStamp(std::chrono::steady_clock::time_point::min());
|
||||
}
|
||||
@@ -285,6 +290,13 @@ class HighResTimeStamp {
|
||||
|
||||
std::chrono::steady_clock::time_point chronoTimePoint_;
|
||||
|
||||
static HighResDuration computeUnsafeOriginFromUnixTimeStamp() noexcept {
|
||||
auto systemNow = std::chrono::system_clock::now();
|
||||
auto steadyNow = std::chrono::steady_clock::now();
|
||||
return HighResDuration(
|
||||
systemNow.time_since_epoch() - steadyNow.time_since_epoch());
|
||||
}
|
||||
|
||||
#ifdef REACT_NATIVE_DEBUG
|
||||
static std::function<std::chrono::steady_clock::time_point()>&
|
||||
getTimeStampProvider() {
|
||||
|
||||
@@ -199,11 +199,11 @@ declare interface EventCounts {
|
||||
}
|
||||
|
||||
declare class Performance {
|
||||
+eventCounts: EventCounts;
|
||||
+timeOrigin: DOMHighResTimeStamp;
|
||||
|
||||
clearMarks(name?: string): void;
|
||||
|
||||
clearMeasures(name?: string): void;
|
||||
|
||||
eventCounts: EventCounts;
|
||||
getEntries: (
|
||||
options?: PerformanceEntryFilterOptions,
|
||||
) => Array<PerformanceEntry>;
|
||||
@@ -215,7 +215,7 @@ declare class Performance {
|
||||
startMarkOrOptions?: string | PerformanceMeasureOptions,
|
||||
endMark?: string,
|
||||
): PerformanceMeasure;
|
||||
now: () => DOMHighResTimeStamp;
|
||||
now(): DOMHighResTimeStamp;
|
||||
toJSON(): string;
|
||||
}
|
||||
|
||||
|
||||
+98
-98
@@ -1,6 +1,6 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`execute test-app "RCTAppDependencyProvider.h" should match snapshot 1`] = `
|
||||
exports[`execute test-app "ReactAppDependencyProvider/RCTAppDependencyProvider.h" should match snapshot 1`] = `
|
||||
"/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
@@ -29,7 +29,7 @@ NS_ASSUME_NONNULL_END
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`execute test-app "RCTAppDependencyProvider.mm" should match snapshot 1`] = `
|
||||
exports[`execute test-app "ReactAppDependencyProvider/RCTAppDependencyProvider.mm" should match snapshot 1`] = `
|
||||
"/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
@@ -73,7 +73,45 @@ exports[`execute test-app "RCTAppDependencyProvider.mm" should match snapshot 1`
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`execute test-app "RCTModuleProviders.h" should match snapshot 1`] = `
|
||||
exports[`execute test-app "ReactAppDependencyProvider/ReactAppDependencyProvider.podspec" should match snapshot 1`] = `
|
||||
"# 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.
|
||||
|
||||
version = \\"1000.0.0\\"
|
||||
source = { :git => 'https://github.com/facebook/react-native.git' }
|
||||
if version == '1000.0.0'
|
||||
# This is an unpublished version, use the latest commit hash of the react-native repo, which we’re presumably in.
|
||||
source[:commit] = \`git rev-parse HEAD\`.strip if system(\\"git rev-parse --git-dir > /dev/null 2>&1\\")
|
||||
else
|
||||
source[:tag] = \\"v#{version}\\"
|
||||
end
|
||||
|
||||
Pod::Spec.new do |s|
|
||||
s.name = \\"ReactAppDependencyProvider\\"
|
||||
s.version = version
|
||||
s.summary = \\"The third party dependency provider for the app\\"
|
||||
s.homepage = \\"https://reactnative.dev/\\"
|
||||
s.documentation_url = \\"https://reactnative.dev/\\"
|
||||
s.license = \\"MIT\\"
|
||||
s.author = \\"Meta Platforms, Inc. and its affiliates\\"
|
||||
s.platforms = min_supported_versions
|
||||
s.source = source
|
||||
s.source_files = \\"**/RCTAppDependencyProvider.{h,mm}\\"
|
||||
|
||||
# This guard prevent to install the dependencies when we run \`pod install\` in the old architecture.
|
||||
s.pod_target_xcconfig = {
|
||||
\\"CLANG_CXX_LANGUAGE_STANDARD\\" => rct_cxx_language_standard(),
|
||||
\\"DEFINES_MODULE\\" => \\"YES\\"
|
||||
}
|
||||
|
||||
s.dependency \\"ReactCodegen\\"
|
||||
end
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`execute test-app "ReactCodegen/RCTModuleProviders.h" should match snapshot 1`] = `
|
||||
"/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
@@ -93,7 +131,7 @@ exports[`execute test-app "RCTModuleProviders.h" should match snapshot 1`] = `
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`execute test-app "RCTModuleProviders.mm" should match snapshot 1`] = `
|
||||
exports[`execute test-app "ReactCodegen/RCTModuleProviders.mm" should match snapshot 1`] = `
|
||||
"/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
@@ -159,7 +197,7 @@ exports[`execute test-app "RCTModuleProviders.mm" should match snapshot 1`] = `
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`execute test-app "RCTModulesConformingToProtocolsProvider.h" should match snapshot 1`] = `
|
||||
exports[`execute test-app "ReactCodegen/RCTModulesConformingToProtocolsProvider.h" should match snapshot 1`] = `
|
||||
"/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
@@ -181,7 +219,7 @@ exports[`execute test-app "RCTModulesConformingToProtocolsProvider.h" should mat
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`execute test-app "RCTModulesConformingToProtocolsProvider.mm" should match snapshot 1`] = `
|
||||
exports[`execute test-app "ReactCodegen/RCTModulesConformingToProtocolsProvider.mm" should match snapshot 1`] = `
|
||||
"/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
@@ -248,7 +286,7 @@ exports[`execute test-app "RCTModulesConformingToProtocolsProvider.mm" should ma
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`execute test-app "RCTThirdPartyComponentsProvider.h" should match snapshot 1`] = `
|
||||
exports[`execute test-app "ReactCodegen/RCTThirdPartyComponentsProvider.h" should match snapshot 1`] = `
|
||||
"/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
@@ -268,7 +306,7 @@ exports[`execute test-app "RCTThirdPartyComponentsProvider.h" should match snaps
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`execute test-app "RCTThirdPartyComponentsProvider.mm" should match snapshot 1`] = `
|
||||
exports[`execute test-app "ReactCodegen/RCTThirdPartyComponentsProvider.mm" should match snapshot 1`] = `
|
||||
"/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
@@ -303,7 +341,7 @@ exports[`execute test-app "RCTThirdPartyComponentsProvider.mm" should match snap
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`execute test-app "RCTUnstableModulesRequiringMainQueueSetupProvider.h" should match snapshot 1`] = `
|
||||
exports[`execute test-app "ReactCodegen/RCTUnstableModulesRequiringMainQueueSetupProvider.h" should match snapshot 1`] = `
|
||||
"/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
@@ -321,7 +359,7 @@ exports[`execute test-app "RCTUnstableModulesRequiringMainQueueSetupProvider.h"
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`execute test-app "RCTUnstableModulesRequiringMainQueueSetupProvider.mm" should match snapshot 1`] = `
|
||||
exports[`execute test-app "ReactCodegen/RCTUnstableModulesRequiringMainQueueSetupProvider.mm" should match snapshot 1`] = `
|
||||
"/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
@@ -355,45 +393,7 @@ exports[`execute test-app "RCTUnstableModulesRequiringMainQueueSetupProvider.mm"
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`execute test-app "ReactAppDependencyProvider.podspec" should match snapshot 1`] = `
|
||||
"# 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.
|
||||
|
||||
version = \\"1000.0.0\\"
|
||||
source = { :git => 'https://github.com/facebook/react-native.git' }
|
||||
if version == '1000.0.0'
|
||||
# This is an unpublished version, use the latest commit hash of the react-native repo, which we’re presumably in.
|
||||
source[:commit] = \`git rev-parse HEAD\`.strip if system(\\"git rev-parse --git-dir > /dev/null 2>&1\\")
|
||||
else
|
||||
source[:tag] = \\"v#{version}\\"
|
||||
end
|
||||
|
||||
Pod::Spec.new do |s|
|
||||
s.name = \\"ReactAppDependencyProvider\\"
|
||||
s.version = version
|
||||
s.summary = \\"The third party dependency provider for the app\\"
|
||||
s.homepage = \\"https://reactnative.dev/\\"
|
||||
s.documentation_url = \\"https://reactnative.dev/\\"
|
||||
s.license = \\"MIT\\"
|
||||
s.author = \\"Meta Platforms, Inc. and its affiliates\\"
|
||||
s.platforms = min_supported_versions
|
||||
s.source = source
|
||||
s.source_files = \\"**/RCTAppDependencyProvider.{h,mm}\\"
|
||||
|
||||
# This guard prevent to install the dependencies when we run \`pod install\` in the old architecture.
|
||||
s.pod_target_xcconfig = {
|
||||
\\"CLANG_CXX_LANGUAGE_STANDARD\\" => rct_cxx_language_standard(),
|
||||
\\"DEFINES_MODULE\\" => \\"YES\\"
|
||||
}
|
||||
|
||||
s.dependency \\"ReactCodegen\\"
|
||||
end
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`execute test-app "ReactCodegen.podspec" should match snapshot 1`] = `
|
||||
exports[`execute test-app "ReactCodegen/ReactCodegen.podspec" should match snapshot 1`] = `
|
||||
"# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under the MIT license found in the
|
||||
@@ -507,7 +507,7 @@ end
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`execute test-app-legacy "RCTAppDependencyProvider.h" should match snapshot 1`] = `
|
||||
exports[`execute test-app-legacy "ReactAppDependencyProvider/RCTAppDependencyProvider.h" should match snapshot 1`] = `
|
||||
"/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
@@ -536,7 +536,7 @@ NS_ASSUME_NONNULL_END
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`execute test-app-legacy "RCTAppDependencyProvider.mm" should match snapshot 1`] = `
|
||||
exports[`execute test-app-legacy "ReactAppDependencyProvider/RCTAppDependencyProvider.mm" should match snapshot 1`] = `
|
||||
"/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
@@ -580,7 +580,45 @@ exports[`execute test-app-legacy "RCTAppDependencyProvider.mm" should match snap
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`execute test-app-legacy "RCTModuleProviders.h" should match snapshot 1`] = `
|
||||
exports[`execute test-app-legacy "ReactAppDependencyProvider/ReactAppDependencyProvider.podspec" should match snapshot 1`] = `
|
||||
"# 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.
|
||||
|
||||
version = \\"1000.0.0\\"
|
||||
source = { :git => 'https://github.com/facebook/react-native.git' }
|
||||
if version == '1000.0.0'
|
||||
# This is an unpublished version, use the latest commit hash of the react-native repo, which we’re presumably in.
|
||||
source[:commit] = \`git rev-parse HEAD\`.strip if system(\\"git rev-parse --git-dir > /dev/null 2>&1\\")
|
||||
else
|
||||
source[:tag] = \\"v#{version}\\"
|
||||
end
|
||||
|
||||
Pod::Spec.new do |s|
|
||||
s.name = \\"ReactAppDependencyProvider\\"
|
||||
s.version = version
|
||||
s.summary = \\"The third party dependency provider for the app\\"
|
||||
s.homepage = \\"https://reactnative.dev/\\"
|
||||
s.documentation_url = \\"https://reactnative.dev/\\"
|
||||
s.license = \\"MIT\\"
|
||||
s.author = \\"Meta Platforms, Inc. and its affiliates\\"
|
||||
s.platforms = min_supported_versions
|
||||
s.source = source
|
||||
s.source_files = \\"**/RCTAppDependencyProvider.{h,mm}\\"
|
||||
|
||||
# This guard prevent to install the dependencies when we run \`pod install\` in the old architecture.
|
||||
s.pod_target_xcconfig = {
|
||||
\\"CLANG_CXX_LANGUAGE_STANDARD\\" => rct_cxx_language_standard(),
|
||||
\\"DEFINES_MODULE\\" => \\"YES\\"
|
||||
}
|
||||
|
||||
s.dependency \\"ReactCodegen\\"
|
||||
end
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`execute test-app-legacy "ReactCodegen/RCTModuleProviders.h" should match snapshot 1`] = `
|
||||
"/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
@@ -600,7 +638,7 @@ exports[`execute test-app-legacy "RCTModuleProviders.h" should match snapshot 1`
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`execute test-app-legacy "RCTModuleProviders.mm" should match snapshot 1`] = `
|
||||
exports[`execute test-app-legacy "ReactCodegen/RCTModuleProviders.mm" should match snapshot 1`] = `
|
||||
"/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
@@ -657,7 +695,7 @@ exports[`execute test-app-legacy "RCTModuleProviders.mm" should match snapshot 1
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`execute test-app-legacy "RCTModulesConformingToProtocolsProvider.h" should match snapshot 1`] = `
|
||||
exports[`execute test-app-legacy "ReactCodegen/RCTModulesConformingToProtocolsProvider.h" should match snapshot 1`] = `
|
||||
"/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
@@ -679,7 +717,7 @@ exports[`execute test-app-legacy "RCTModulesConformingToProtocolsProvider.h" sho
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`execute test-app-legacy "RCTModulesConformingToProtocolsProvider.mm" should match snapshot 1`] = `
|
||||
exports[`execute test-app-legacy "ReactCodegen/RCTModulesConformingToProtocolsProvider.mm" should match snapshot 1`] = `
|
||||
"/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
@@ -737,7 +775,7 @@ exports[`execute test-app-legacy "RCTModulesConformingToProtocolsProvider.mm" sh
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`execute test-app-legacy "RCTThirdPartyComponentsProvider.h" should match snapshot 1`] = `
|
||||
exports[`execute test-app-legacy "ReactCodegen/RCTThirdPartyComponentsProvider.h" should match snapshot 1`] = `
|
||||
"/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
@@ -757,7 +795,7 @@ exports[`execute test-app-legacy "RCTThirdPartyComponentsProvider.h" should matc
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`execute test-app-legacy "RCTThirdPartyComponentsProvider.mm" should match snapshot 1`] = `
|
||||
exports[`execute test-app-legacy "ReactCodegen/RCTThirdPartyComponentsProvider.mm" should match snapshot 1`] = `
|
||||
"/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
@@ -791,7 +829,7 @@ exports[`execute test-app-legacy "RCTThirdPartyComponentsProvider.mm" should mat
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`execute test-app-legacy "RCTUnstableModulesRequiringMainQueueSetupProvider.h" should match snapshot 1`] = `
|
||||
exports[`execute test-app-legacy "ReactCodegen/RCTUnstableModulesRequiringMainQueueSetupProvider.h" should match snapshot 1`] = `
|
||||
"/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
@@ -809,7 +847,7 @@ exports[`execute test-app-legacy "RCTUnstableModulesRequiringMainQueueSetupProvi
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`execute test-app-legacy "RCTUnstableModulesRequiringMainQueueSetupProvider.mm" should match snapshot 1`] = `
|
||||
exports[`execute test-app-legacy "ReactCodegen/RCTUnstableModulesRequiringMainQueueSetupProvider.mm" should match snapshot 1`] = `
|
||||
"/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
@@ -834,45 +872,7 @@ exports[`execute test-app-legacy "RCTUnstableModulesRequiringMainQueueSetupProvi
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`execute test-app-legacy "ReactAppDependencyProvider.podspec" should match snapshot 1`] = `
|
||||
"# 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.
|
||||
|
||||
version = \\"1000.0.0\\"
|
||||
source = { :git => 'https://github.com/facebook/react-native.git' }
|
||||
if version == '1000.0.0'
|
||||
# This is an unpublished version, use the latest commit hash of the react-native repo, which we’re presumably in.
|
||||
source[:commit] = \`git rev-parse HEAD\`.strip if system(\\"git rev-parse --git-dir > /dev/null 2>&1\\")
|
||||
else
|
||||
source[:tag] = \\"v#{version}\\"
|
||||
end
|
||||
|
||||
Pod::Spec.new do |s|
|
||||
s.name = \\"ReactAppDependencyProvider\\"
|
||||
s.version = version
|
||||
s.summary = \\"The third party dependency provider for the app\\"
|
||||
s.homepage = \\"https://reactnative.dev/\\"
|
||||
s.documentation_url = \\"https://reactnative.dev/\\"
|
||||
s.license = \\"MIT\\"
|
||||
s.author = \\"Meta Platforms, Inc. and its affiliates\\"
|
||||
s.platforms = min_supported_versions
|
||||
s.source = source
|
||||
s.source_files = \\"**/RCTAppDependencyProvider.{h,mm}\\"
|
||||
|
||||
# This guard prevent to install the dependencies when we run \`pod install\` in the old architecture.
|
||||
s.pod_target_xcconfig = {
|
||||
\\"CLANG_CXX_LANGUAGE_STANDARD\\" => rct_cxx_language_standard(),
|
||||
\\"DEFINES_MODULE\\" => \\"YES\\"
|
||||
}
|
||||
|
||||
s.dependency \\"ReactCodegen\\"
|
||||
end
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`execute test-app-legacy "ReactCodegen.podspec" should match snapshot 1`] = `
|
||||
exports[`execute test-app-legacy "ReactCodegen/ReactCodegen.podspec" should match snapshot 1`] = `
|
||||
"# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under the MIT license found in the
|
||||
|
||||
+12
-12
@@ -42,18 +42,18 @@ const packageJson = JSON.stringify({
|
||||
});
|
||||
|
||||
[
|
||||
'RCTAppDependencyProvider.h',
|
||||
'RCTAppDependencyProvider.mm',
|
||||
'RCTModuleProviders.h',
|
||||
'RCTModuleProviders.mm',
|
||||
'RCTModulesConformingToProtocolsProvider.h',
|
||||
'RCTModulesConformingToProtocolsProvider.mm',
|
||||
'RCTThirdPartyComponentsProvider.h',
|
||||
'RCTThirdPartyComponentsProvider.mm',
|
||||
'ReactAppDependencyProvider.podspec',
|
||||
'ReactCodegen.podspec',
|
||||
'RCTUnstableModulesRequiringMainQueueSetupProvider.h',
|
||||
'RCTUnstableModulesRequiringMainQueueSetupProvider.mm',
|
||||
'ReactAppDependencyProvider/RCTAppDependencyProvider.h',
|
||||
'ReactAppDependencyProvider/RCTAppDependencyProvider.mm',
|
||||
'ReactCodegen/RCTModuleProviders.h',
|
||||
'ReactCodegen/RCTModuleProviders.mm',
|
||||
'ReactCodegen/RCTModulesConformingToProtocolsProvider.h',
|
||||
'ReactCodegen/RCTModulesConformingToProtocolsProvider.mm',
|
||||
'ReactCodegen/RCTThirdPartyComponentsProvider.h',
|
||||
'ReactCodegen/RCTThirdPartyComponentsProvider.mm',
|
||||
'ReactAppDependencyProvider/ReactAppDependencyProvider.podspec',
|
||||
'ReactCodegen/ReactCodegen.podspec',
|
||||
'ReactCodegen/RCTUnstableModulesRequiringMainQueueSetupProvider.h',
|
||||
'ReactCodegen/RCTUnstableModulesRequiringMainQueueSetupProvider.mm',
|
||||
].forEach(file => {
|
||||
it(`"${file}" should match snapshot`, () => {
|
||||
const generatedFileDir = path.join(outputDir, 'build/generated/ios');
|
||||
|
||||
+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.
|
||||
*
|
||||
* @flow strict-local
|
||||
* @format
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
const {TEMPLATES_FOLDER_PATH} = require('./constants');
|
||||
const {codegenLog} = require('./utils');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const PACKAGE_SWIFT_TEMPLATE_PATH = path.join(
|
||||
TEMPLATES_FOLDER_PATH,
|
||||
'Package.swift.template',
|
||||
);
|
||||
|
||||
function generatePackageSwift(
|
||||
projectRoot /*: string */,
|
||||
outputDir /*: string */,
|
||||
reactNativePath /*: string */,
|
||||
) {
|
||||
const fullOutputPath = path.join(projectRoot, outputDir);
|
||||
fs.mkdirSync(outputDir, {recursive: true});
|
||||
// Generate PAckage.swift File
|
||||
codegenLog('Generating Package.swift');
|
||||
const templateH = fs
|
||||
.readFileSync(PACKAGE_SWIFT_TEMPLATE_PATH, 'utf8')
|
||||
.replace(
|
||||
/{reactNativePath}/,
|
||||
path.relative(fullOutputPath, reactNativePath),
|
||||
);
|
||||
const finalPathH = path.join(outputDir, 'Package.swift');
|
||||
fs.writeFileSync(finalPathH, templateH);
|
||||
codegenLog(`Generated artifact: ${finalPathH}`);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
generatePackageSwift,
|
||||
};
|
||||
+26
-12
@@ -22,6 +22,7 @@ const {
|
||||
} = require('./generateAppDependencyProvider');
|
||||
const {generateCustomURLHandlers} = require('./generateCustomURLHandlers');
|
||||
const {generateNativeCode} = require('./generateNativeCode');
|
||||
const {generatePackageSwift} = require('./generatePackageSwift');
|
||||
const {generateRCTModuleProviders} = require('./generateRCTModuleProviders');
|
||||
const {
|
||||
generateRCTThirdPartyComponents,
|
||||
@@ -37,6 +38,7 @@ const {
|
||||
codegenLog,
|
||||
findCodegenEnabledLibraries,
|
||||
findDisabledLibrariesByPlatform,
|
||||
findReactNativeRootPath,
|
||||
pkgJsonIncludesGeneratedCode,
|
||||
readPkgJsonInDirectory,
|
||||
readReactNativeConfig,
|
||||
@@ -99,7 +101,6 @@ function execute(
|
||||
|
||||
if (codegenEnabledLibraries.length === 0) {
|
||||
codegenLog('No codegen-enabled libraries found.', true);
|
||||
return;
|
||||
}
|
||||
|
||||
let platforms =
|
||||
@@ -114,10 +115,6 @@ function execute(
|
||||
({name}) => !disabledLibraries.includes(name),
|
||||
);
|
||||
|
||||
if (!libraries.length) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const outputPath = computeOutputPath(
|
||||
projectRoot,
|
||||
baseOutputPath,
|
||||
@@ -125,10 +122,15 @@ function execute(
|
||||
platform,
|
||||
);
|
||||
|
||||
const reactCodegenOutputPath =
|
||||
platform === 'android'
|
||||
? outputPath
|
||||
: path.join(outputPath, 'ReactCodegen');
|
||||
|
||||
if (runReactNativeCodegen) {
|
||||
const schemaInfos = generateSchemaInfos(libraries);
|
||||
generateNativeCode(
|
||||
outputPath,
|
||||
reactCodegenOutputPath,
|
||||
schemaInfos.filter(schemaInfo =>
|
||||
mustGenerateNativeCode(projectRoot, schemaInfo),
|
||||
),
|
||||
@@ -139,20 +141,32 @@ function execute(
|
||||
|
||||
if (source === 'app' && platform !== 'android') {
|
||||
// These components are only required by apps, not by libraries and are Apple specific.
|
||||
generateRCTThirdPartyComponents(libraries, outputPath);
|
||||
generateRCTModuleProviders(projectRoot, pkgJson, libraries, outputPath);
|
||||
generateCustomURLHandlers(libraries, outputPath);
|
||||
generateRCTThirdPartyComponents(libraries, reactCodegenOutputPath);
|
||||
generateRCTModuleProviders(
|
||||
projectRoot,
|
||||
pkgJson,
|
||||
libraries,
|
||||
reactCodegenOutputPath,
|
||||
);
|
||||
generateCustomURLHandlers(libraries, reactCodegenOutputPath);
|
||||
generateUnstableModulesRequiringMainQueueSetupProvider(
|
||||
libraries,
|
||||
outputPath,
|
||||
reactCodegenOutputPath,
|
||||
);
|
||||
generateAppDependencyProvider(
|
||||
path.join(outputPath, 'ReactAppDependencyProvider'),
|
||||
);
|
||||
generateAppDependencyProvider(outputPath);
|
||||
generateReactCodegenPodspec(
|
||||
projectRoot,
|
||||
pkgJson,
|
||||
outputPath,
|
||||
reactCodegenOutputPath,
|
||||
baseOutputPath,
|
||||
);
|
||||
generatePackageSwift(
|
||||
projectRoot,
|
||||
outputPath,
|
||||
findReactNativeRootPath(projectRoot),
|
||||
);
|
||||
}
|
||||
|
||||
cleanupEmptyFilesAndFolders(outputPath);
|
||||
|
||||
@@ -461,6 +461,17 @@ function findDisabledLibrariesByPlatform(
|
||||
);
|
||||
}
|
||||
|
||||
function findReactNativeRootPath(projectRoot /* : string */) /* : string */ {
|
||||
const reactNativePackageJsonPath = require.resolve(
|
||||
path.join('react-native', 'package.json'),
|
||||
{
|
||||
paths: [projectRoot],
|
||||
},
|
||||
);
|
||||
|
||||
return path.dirname(reactNativePackageJsonPath);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
buildCodegenIfNeeded,
|
||||
pkgJsonIncludesGeneratedCode,
|
||||
@@ -474,4 +485,5 @@ module.exports = {
|
||||
parseiOSAnnotations,
|
||||
readReactNativeConfig,
|
||||
findDisabledLibrariesByPlatform,
|
||||
findReactNativeRootPath,
|
||||
};
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
// swift-tools-version: 6.1
|
||||
// The swift-tools-version declares the minimum version of Swift required to build this package.
|
||||
|
||||
import PackageDescription
|
||||
|
||||
let package = Package(
|
||||
name: "React-GeneratedCode",
|
||||
platforms: [.iOS(.v15), .macCatalyst(SupportedPlatform.MacCatalystVersion.v13)],
|
||||
products: [
|
||||
// Products define the executables and libraries a package produces, making them visible to other packages.
|
||||
.library(
|
||||
name: "ReactCodegen",
|
||||
targets: ["ReactCodegen"]),
|
||||
.library(
|
||||
name: "ReactAppDependencyProvider",
|
||||
targets: ["ReactAppDependencyProvider"]),
|
||||
],
|
||||
dependencies: [
|
||||
.package(name: "React", path: "{reactNativePath}")
|
||||
],
|
||||
targets: [
|
||||
// Targets are the basic building blocks of a package, defining a module or a test suite.
|
||||
// Targets can depend on other targets in this package and products from dependencies.
|
||||
.target(
|
||||
name: "ReactCodegen",
|
||||
dependencies: ["React"],
|
||||
path: "ReactCodegen",
|
||||
exclude: ["ReactCodegen.podspec"],
|
||||
publicHeadersPath: ".",
|
||||
cSettings: [
|
||||
.headerSearchPath("headers")
|
||||
],
|
||||
cxxSettings: [
|
||||
.headerSearchPath("headers"),
|
||||
.unsafeFlags(["-std=c++20"]),
|
||||
],
|
||||
linkerSettings: [
|
||||
.linkedFramework("Foundation")
|
||||
]
|
||||
),
|
||||
.target(
|
||||
name: "ReactAppDependencyProvider",
|
||||
dependencies: ["ReactCodegen"],
|
||||
path: "ReactAppDependencyProvider",
|
||||
exclude: ["ReactAppDependencyProvider.podspec"],
|
||||
publicHeadersPath: ".",
|
||||
cSettings: [
|
||||
.headerSearchPath("headers"),
|
||||
],
|
||||
cxxSettings: [
|
||||
.headerSearchPath("headers"),
|
||||
.unsafeFlags(["-std=c++20"]),
|
||||
],
|
||||
linkerSettings: [
|
||||
.linkedFramework("Foundation")
|
||||
]
|
||||
)
|
||||
]
|
||||
)
|
||||
@@ -24,7 +24,8 @@ require_relative './cocoapods/rncore.rb'
|
||||
# Importing to expose use_native_modules!
|
||||
require_relative './cocoapods/autolinking.rb'
|
||||
|
||||
$CODEGEN_OUTPUT_DIR = 'build/generated/ios'
|
||||
$CODEGEN_OUTPUT_DIR = 'build/generated/ios/ReactCodegen'
|
||||
$APP_DEPENDENCY_PROVIDER_OUTPUT_DIR = 'build/generated/ios/ReactAppDependencyProvider'
|
||||
$CODEGEN_COMPONENT_DIR = 'react/renderer/components'
|
||||
$CODEGEN_MODULE_DIR = '.'
|
||||
|
||||
@@ -200,7 +201,7 @@ def use_react_native! (
|
||||
end
|
||||
|
||||
pod 'ReactCodegen', :path => $CODEGEN_OUTPUT_DIR, :modular_headers => true
|
||||
pod 'ReactAppDependencyProvider', :path => $CODEGEN_OUTPUT_DIR, :modular_headers => true
|
||||
pod 'ReactAppDependencyProvider', :path => $APP_DEPENDENCY_PROVIDER_OUTPUT_DIR, :modular_headers => true
|
||||
# Not needed, but run_codegen expects this to be set.
|
||||
folly_config = get_folly_config()
|
||||
run_codegen!(
|
||||
|
||||
-1
@@ -4,7 +4,6 @@
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @fantom_react_fb_flags enableEagerAlternateStateNodeCleanup:true
|
||||
* @flow strict-local
|
||||
* @format
|
||||
*/
|
||||
|
||||
@@ -63,6 +63,7 @@ const cachedReportMeasure = NativePerformance.reportMeasure;
|
||||
const cachedGetMarkTime = NativePerformance.getMarkTime;
|
||||
const cachedNativeClearMarks = NativePerformance.clearMarks;
|
||||
const cachedNativeClearMeasures = NativePerformance.clearMeasures;
|
||||
let cachedTimeOrigin: ?DOMHighResTimeStamp;
|
||||
|
||||
const MARK_OPTIONS_REUSABLE_OBJECT: PerformanceMarkOptions = {
|
||||
startTime: 0,
|
||||
@@ -139,6 +140,24 @@ export default class Performance {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the high resolution timestamp that is used as the baseline for
|
||||
* performance-related timestamps.
|
||||
* https://developer.mozilla.org/en-US/docs/Web/API/Performance/timeOrigin
|
||||
*/
|
||||
get timeOrigin(): DOMHighResTimeStamp {
|
||||
if (cachedTimeOrigin == null) {
|
||||
if (NativePerformance.timeOrigin) {
|
||||
cachedTimeOrigin = NativePerformance?.timeOrigin();
|
||||
} else {
|
||||
// Very naive polyfill.
|
||||
cachedTimeOrigin = Date.now() - getCurrentTimeStamp();
|
||||
}
|
||||
}
|
||||
|
||||
return cachedTimeOrigin;
|
||||
}
|
||||
|
||||
mark(
|
||||
markName: string,
|
||||
markOptions?: PerformanceMarkOptions,
|
||||
|
||||
+33
@@ -22,4 +22,37 @@ describe('Performance', () => {
|
||||
return new PerformanceEntry();
|
||||
}).toThrow("Failed to construct 'PerformanceEntry': Illegal constructor");
|
||||
});
|
||||
|
||||
describe('now', () => {
|
||||
it('provides increasing timestamps since boot time', () => {
|
||||
const first = performance.now();
|
||||
const second = performance.now();
|
||||
const third = performance.now();
|
||||
|
||||
expect(typeof first).toBe('number');
|
||||
expect(typeof second).toBe('number');
|
||||
expect(typeof third).toBe('number');
|
||||
|
||||
expect(first).toBeGreaterThan(0);
|
||||
expect(second).toBeGreaterThan(first);
|
||||
expect(third).toBeGreaterThan(second);
|
||||
});
|
||||
});
|
||||
|
||||
describe('timeOrigin', () => {
|
||||
it('allows moving timestamps to Unix epoch', () => {
|
||||
// We need to truncate timestamps because `Date.now()` only provides
|
||||
// integer millisecond precision.
|
||||
const adjustedMonotonicTime = Math.trunc(
|
||||
performance.now() + performance.timeOrigin,
|
||||
);
|
||||
const wallTime = Date.now();
|
||||
const adjustedMonotonicTimeAfter = Math.trunc(
|
||||
performance.now() + performance.timeOrigin,
|
||||
);
|
||||
|
||||
expect(wallTime).toBeGreaterThanOrEqual(adjustedMonotonicTime);
|
||||
expect(adjustedMonotonicTimeAfter).toBeGreaterThanOrEqual(wallTime);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
+2
@@ -54,6 +54,8 @@ export type PerformanceObserverInit = {
|
||||
|
||||
export interface Spec extends TurboModule {
|
||||
+now: () => number;
|
||||
+timeOrigin?: () => number;
|
||||
|
||||
+reportMark: (name: string, startTime: number, entry: mixed) => void;
|
||||
+reportMeasure: (
|
||||
name: string,
|
||||
|
||||
@@ -44,3 +44,26 @@ configure<com.facebook.react.ReactSettingsExtension> {
|
||||
lockFiles = files("yarn.lock"),
|
||||
)
|
||||
}
|
||||
|
||||
// Gradle properties defined in `gradle.properties` are not inherited by
|
||||
// included builds, see https://github.com/gradle/gradle/issues/2534.
|
||||
// This is a workaround to read the configuration from the consuming project,
|
||||
// and apply relevant properties to the :react-native project.
|
||||
buildscript {
|
||||
val properties = java.util.Properties()
|
||||
val propertiesToInherit = listOf("hermesV1Enabled", "react.hermesV1Enabled")
|
||||
|
||||
try {
|
||||
file("../../android/gradle.properties").inputStream().use { properties.load(it) }
|
||||
|
||||
gradle.rootProject {
|
||||
propertiesToInherit.forEach { property ->
|
||||
if (properties.containsKey(property)) {
|
||||
gradle.rootProject.extra.set(property, properties.getProperty(property))
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
// fail silently
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user