diff --git a/packages/gradle-plugin/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/tasks/internal/PrepareJSCTask.kt b/packages/gradle-plugin/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/tasks/internal/PrepareJSCTask.kt deleted file mode 100644 index 9b6913df88fa29..00000000000000 --- a/packages/gradle-plugin/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/tasks/internal/PrepareJSCTask.kt +++ /dev/null @@ -1,50 +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.tasks.internal - -import java.io.File -import org.gradle.api.DefaultTask -import org.gradle.api.file.DirectoryProperty -import org.gradle.api.provider.Property -import org.gradle.api.tasks.* - -/** - * A task that takes care of unbundling JSC and preparing it for be consumed by the Android NDK. - * Specifically it will unbundle shared libs, headers and will copy over the Makefile from - * `src/main/jni/third-party/jsc/` - */ -abstract class PrepareJSCTask : DefaultTask() { - - @get:Input abstract val jscPackagePath: Property - - @get:OutputDirectory abstract val outputDir: DirectoryProperty - - @TaskAction - fun taskAction() { - if (!jscPackagePath.isPresent || jscPackagePath.orNull == null) { - error("Could not find the jsc-android npm package") - } - val jscDist = File(jscPackagePath.get(), "dist") - if (!jscDist.exists()) { - error("The jsc-android npm package is missing its \"dist\" directory") - } - val jscAAR = - project.fileTree(jscDist).matching { it.include("**/android-jsc/**/*.aar") }.singleFile - val soFiles = project.zipTree(jscAAR).matching { it.include("**/*.so") } - val headerFiles = project.fileTree(jscDist).matching { it.include("**/include/*.h") } - - project.copy { it -> - it.from(soFiles) - it.from(headerFiles) - it.from(project.file("src/main/jni/third-party/jsc/CMakeLists.txt")) - it.filesMatching("**/*.h") { it.path = "JavaScriptCore/${it.name}" } - it.includeEmptyDirs = false - it.into(outputDir) - } - } -} diff --git a/packages/gradle-plugin/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/utils/DependencyUtils.kt b/packages/gradle-plugin/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/utils/DependencyUtils.kt index 2a2f242c31ca26..ca6e2c6ceb08fd 100644 --- a/packages/gradle-plugin/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/utils/DependencyUtils.kt +++ b/packages/gradle-plugin/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/utils/DependencyUtils.kt @@ -47,14 +47,11 @@ internal object DependencyUtils { repo.content { it.excludeGroup("com.facebook.react") } } } - // Android JSC is installed from npm - mavenRepoFromURI(File(reactNativeDir, "../jsc-android/dist").toURI()) { repo -> - repo.content { it.includeGroup("org.webkit") } - } repositories.google { repo -> repo.content { // We don't want to fetch JSC or React from Google it.excludeGroup("org.webkit") + it.excludeGroup("io.github.react-native-community") it.excludeGroup("com.facebook.react") } } @@ -62,6 +59,7 @@ internal object DependencyUtils { repo.content { // We don't want to fetch JSC or React from JitPack it.excludeGroup("org.webkit") + it.excludeGroup("io.github.react-native-community") it.excludeGroup("com.facebook.react") } } diff --git a/packages/gradle-plugin/react-native-gradle-plugin/src/test/kotlin/com/facebook/react/tasks/internal/PrepareJSCTaskTest.kt b/packages/gradle-plugin/react-native-gradle-plugin/src/test/kotlin/com/facebook/react/tasks/internal/PrepareJSCTaskTest.kt deleted file mode 100644 index e4767c05e89f84..00000000000000 --- a/packages/gradle-plugin/react-native-gradle-plugin/src/test/kotlin/com/facebook/react/tasks/internal/PrepareJSCTaskTest.kt +++ /dev/null @@ -1,129 +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.tasks.internal - -import com.facebook.react.tests.createProject -import com.facebook.react.tests.createTestTask -import com.facebook.react.tests.zipFiles -import java.io.* -import org.assertj.core.api.Assertions.assertThat -import org.assertj.core.api.Assertions.assertThatThrownBy -import org.junit.Rule -import org.junit.Test -import org.junit.rules.TemporaryFolder - -class PrepareJSCTaskTest { - - @get:Rule val tempFolder = TemporaryFolder() - - @Test - fun prepareJSCTask_withMissingPackage_fails() { - val task = createTestTask() - - assertThatThrownBy { task.taskAction() }.isInstanceOf(IllegalStateException::class.java) - } - - @Test - fun prepareJSCTask_withNullPackage_fails() { - val task = createTestTask { it.jscPackagePath.set(null as String?) } - - assertThatThrownBy { task.taskAction() }.isInstanceOf(IllegalStateException::class.java) - } - - @Test - fun prepareJSCTask_withMissingDistFolder_fails() { - val task = - createTestTask { it.jscPackagePath.set(tempFolder.root.absolutePath) } - - assertThatThrownBy { task.taskAction() }.isInstanceOf(IllegalStateException::class.java) - } - - @Test - fun prepareJSCTask_ignoresEmptyDirs() { - prepareInputFolder() - val output = tempFolder.newFolder("output") - File(tempFolder.root, "dist/just/an/empty/folders/").apply { mkdirs() } - - val task = - createTestTask { - it.jscPackagePath.set(tempFolder.root.absolutePath) - it.outputDir.set(output) - } - - task.taskAction() - - assertThat(File(output, "just/an/empty/folders/")).doesNotExist() - } - - @Test - fun prepareJSCTask_copiesSoFiles() { - val soFile = tempFolder.newFile("libsomething.so") - prepareInputFolder(aarContent = listOf(soFile)) - val output = tempFolder.newFolder("output") - - val task = - createTestTask { - it.jscPackagePath.set(tempFolder.root.absolutePath) - it.outputDir.set(output) - } - - task.taskAction() - - assertThat(output.listFiles()?.first()?.name).isEqualTo("libsomething.so") - } - - @Test - fun prepareJSCTask_copiesHeaderFilesToCorrectFolder() { - prepareInputFolder() - File(tempFolder.root, "dist/include/justaheader.h").apply { - parentFile.mkdirs() - createNewFile() - } - val output = tempFolder.newFolder("output") - - val task = - createTestTask { - it.jscPackagePath.set(tempFolder.root.absolutePath) - it.outputDir.set(output) - } - - task.taskAction() - - assertThat(File(output, "JavaScriptCore/justaheader.h")).exists() - } - - @Test - fun prepareJSCTask_copiesCMakefile() { - val project = createProject() - prepareInputFolder() - File(project.projectDir, "src/main/jni/third-party/jsc/CMakeLists.txt").apply { - parentFile.mkdirs() - createNewFile() - } - val output = tempFolder.newFolder("output") - - val task = - createTestTask(project = project) { - it.jscPackagePath.set(tempFolder.root.absolutePath) - it.outputDir.set(output) - } - - task.taskAction() - - assertThat(File(output, "CMakeLists.txt")).exists() - } - - private fun prepareInputFolder(aarContent: List = listOf(tempFolder.newFile())) { - val dist = tempFolder.newFolder("dist") - File(dist, "android-jsc/android-library.aar").apply { - parentFile.mkdirs() - createNewFile() - } - zipFiles(File(dist, "android-jsc/android-library.aar"), aarContent) - } -} diff --git a/packages/gradle-plugin/react-native-gradle-plugin/src/test/kotlin/com/facebook/react/utils/DependencyUtilsTest.kt b/packages/gradle-plugin/react-native-gradle-plugin/src/test/kotlin/com/facebook/react/utils/DependencyUtilsTest.kt index a0a116263f12d3..9cd9323d2c37ac 100644 --- a/packages/gradle-plugin/react-native-gradle-plugin/src/test/kotlin/com/facebook/react/utils/DependencyUtilsTest.kt +++ b/packages/gradle-plugin/react-native-gradle-plugin/src/test/kotlin/com/facebook/react/utils/DependencyUtilsTest.kt @@ -56,23 +56,6 @@ class DependencyUtilsTest { .isNotNull() } - @Test - fun configureRepositories_containsJscLocalMavenRepo() { - val projectFolder = tempFolder.newFolder() - val reactNativeDir = tempFolder.newFolder("react-native") - val jscAndroidDir = tempFolder.newFolder("jsc-android") - val repositoryURI = URI.create("file://${jscAndroidDir}/dist") - val project = createProject(projectFolder) - - configureRepositories(project, reactNativeDir) - - assertThat( - project.repositories.firstOrNull { - it is MavenArtifactRepository && it.url == repositoryURI - }) - .isNotNull() - } - @Test fun configureRepositories_containsMavenCentral() { val repositoryURI = URI.create("https://repo.maven.apache.org/maven2/") diff --git a/packages/helloworld/android/app/build.gradle b/packages/helloworld/android/app/build.gradle index 7230ac0356fcab..4eaf707ac339f3 100644 --- a/packages/helloworld/android/app/build.gradle +++ b/packages/helloworld/android/app/build.gradle @@ -81,14 +81,14 @@ def enableProguardInReleaseBuilds = false * The preferred build flavor of JavaScriptCore (JSC) * * For example, to use the international variant, you can use: - * `def jscFlavor = 'org.webkit:android-jsc-intl:+'` + * `def jscFlavor = "io.github.react-native-community:jsc-android-intl:2026004.+"` * * The international variant includes ICU i18n library and necessary data * allowing to use e.g. `Date.toLocaleString` and `String.localeCompare` that * give correct results when using with locales other than en-US. Note that * this variant is about 6MiB larger per architecture than default. */ -def jscFlavor = 'org.webkit:android-jsc:+' +def jscFlavor = "io.github.react-native-community:jsc-android:2026004.+" android { ndkVersion rootProject.ext.ndkVersion diff --git a/packages/react-native/ReactAndroid/build.gradle.kts b/packages/react-native/ReactAndroid/build.gradle.kts index d2b0769a367611..11476c0354ad37 100644 --- a/packages/react-native/ReactAndroid/build.gradle.kts +++ b/packages/react-native/ReactAndroid/build.gradle.kts @@ -396,13 +396,6 @@ val prepareGlog by outputDir.set(File(thirdPartyNdkDir, "glog")) } -// Create Android native library module based on jsc from npm -val prepareJSC by - tasks.registering(PrepareJSCTask::class) { - jscPackagePath.set(findNodeModulePath(projectDir, "jsc-android")) - outputDir = project.layout.buildDirectory.dir("third-party-ndk/jsc") - } - val prepareKotlinBuildScriptModel by tasks.registering { // This task is run when Gradle Sync is running. @@ -577,7 +570,6 @@ android { prepareFolly, prepareGlog, prepareGtest, - prepareJSC, preparePrefab) tasks.getByName("generateCodegenSchemaFromJavaScript").dependsOn(buildCodegenCLI) prepareKotlinBuildScriptModel.dependsOn("preBuild") @@ -664,9 +656,10 @@ dependencies { compileOnly(libs.javax.annotation.api) api(libs.javax.inject) - // It's up to the consumer to decide if hermes should be included or not. - // Therefore hermes-engine is a compileOnly dependency. + // It's up to the consumer to decide if hermes/jsc should be included or not. + // Therefore hermes-engine and jsc are compileOnly dependencies. compileOnly(project(":packages:react-native:ReactAndroid:hermes-engine")) + compileOnly(libs.jsc.android) testImplementation(libs.junit) testImplementation(libs.assertj) diff --git a/packages/react-native/ReactAndroid/src/main/jni/CMakeLists.txt b/packages/react-native/ReactAndroid/src/main/jni/CMakeLists.txt index c88061c56288b6..eb1b6d9301a0da 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/CMakeLists.txt +++ b/packages/react-native/ReactAndroid/src/main/jni/CMakeLists.txt @@ -43,7 +43,9 @@ endfunction() # Third-party prefabs find_package(hermes-engine REQUIRED CONFIG) find_package(fbjni REQUIRED CONFIG) +find_package(jsc-android REQUIRED CONFIG) add_library(fbjni ALIAS fbjni::fbjni) +add_library(jsc ALIAS jsc-android::jsc) # Third-party downloaded targets add_react_third_party_ndk_subdir(glog) @@ -52,7 +54,6 @@ add_react_third_party_ndk_subdir(double-conversion) add_react_third_party_ndk_subdir(fast_float) add_react_third_party_ndk_subdir(fmt) add_react_third_party_ndk_subdir(folly) -add_react_third_party_ndk_subdir(jsc) add_react_third_party_ndk_subdir(googletest) # Common targets diff --git a/packages/react-native/ReactAndroid/src/main/jni/third-party/jsc/CMakeLists.txt b/packages/react-native/ReactAndroid/src/main/jni/third-party/jsc/CMakeLists.txt deleted file mode 100644 index 4f72ace845ce36..00000000000000 --- a/packages/react-native/ReactAndroid/src/main/jni/third-party/jsc/CMakeLists.txt +++ /dev/null @@ -1,15 +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. - -cmake_minimum_required(VERSION 3.13) -set(CMAKE_VERBOSE_MAKEFILE on) - -add_library(jsc SHARED IMPORTED GLOBAL) -set_target_properties(jsc - PROPERTIES - IMPORTED_LOCATION - ${CMAKE_CURRENT_SOURCE_DIR}/jni/${ANDROID_ABI}/libjsc.so) - -target_include_directories(jsc INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) diff --git a/packages/react-native/gradle/libs.versions.toml b/packages/react-native/gradle/libs.versions.toml index 195527fc60f323..03351e484a26bd 100644 --- a/packages/react-native/gradle/libs.versions.toml +++ b/packages/react-native/gradle/libs.versions.toml @@ -21,6 +21,7 @@ fresco = "3.5.0" infer-annotation = "0.18.0" javax-annotation-api = "1.3.2" javax-inject = "1" +jsc-android = "2026004.0.1" jsr305 = "3.0.2" junit = "4.13.2" kotlin = "2.0.21" @@ -66,6 +67,7 @@ okhttp3 = { module = "com.squareup.okhttp3:okhttp", version.ref = "okhttp" } okio = { module = "com.squareup.okio:okio", version.ref = "okio" } javax-inject = { module = "javax.inject:javax.inject", version.ref = "javax-inject" } javax-annotation-api = { module = "javax.annotation:javax.annotation-api", version.ref = "javax-annotation-api" } +jsc-android = { module = "io.github.react-native-community:jsc-android", version.ref = "jsc-android" } junit = {module = "junit:junit", version.ref = "junit" } assertj = {module = "org.assertj:assertj-core", version.ref = "assertj" } diff --git a/packages/react-native/package.json b/packages/react-native/package.json index 6481bbaf55fa71..63f156c0b7190d 100644 --- a/packages/react-native/package.json +++ b/packages/react-native/package.json @@ -128,7 +128,6 @@ "glob": "^7.1.1", "invariant": "^2.2.4", "jest-environment-node": "^29.6.3", - "jsc-android": "^250231.0.0", "memoize-one": "^5.0.0", "metro-runtime": "^0.81.0", "metro-source-map": "^0.81.0", diff --git a/packages/rn-tester/android/app/build.gradle.kts b/packages/rn-tester/android/app/build.gradle.kts index 703d6387ed6656..d7d263c303f865 100644 --- a/packages/rn-tester/android/app/build.gradle.kts +++ b/packages/rn-tester/android/app/build.gradle.kts @@ -72,9 +72,9 @@ val enableProguardInReleaseBuilds = true /** * The preferred build flavor of JavaScriptCore (JSC) For example, to use the international variant, - * you can use: `def jscFlavor = 'org.webkit:android-jsc-intl:+'` + * you can use: `def jscFlavor = "io.github.react-native-community:jsc-android-intl:2026004.+"` */ -val jscFlavor = "org.webkit:android-jsc:+" +val jscFlavor = "io.github.react-native-community:jsc-android:2026004.+" /** This allows to customized the CMake version used for compiling RN Tester. */ val cmakeVersion = @@ -86,13 +86,6 @@ fun reactNativeArchitectures(): List { return value?.toString()?.split(",") ?: listOf("armeabi-v7a", "x86", "x86_64", "arm64-v8a") } -repositories { - maven { - url = rootProject.file("node_modules/jsc-android/dist").toURI() - content { includeGroup("org.webkit") } - } -} - android { compileSdk = libs.versions.compileSdk.get().toInt() buildToolsVersion = libs.versions.buildTools.get() diff --git a/yarn.lock b/yarn.lock index e424b377d278a3..483036ad85d022 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5899,11 +5899,6 @@ jsbn@~0.1.0: resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" integrity sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg== -jsc-android@^250231.0.0: - version "250231.0.0" - resolved "https://registry.yarnpkg.com/jsc-android/-/jsc-android-250231.0.0.tgz#91720f8df382a108872fa4b3f558f33ba5e95262" - integrity sha512-rS46PvsjYmdmuz1OAWXY/1kCYG7pnf1TBqeTiOJr1iDz7s5DLxxC9n/ZMknLDxzYzNVfI7R95MH10emSSG1Wuw== - jsc-safe-url@^0.2.2: version "0.2.4" resolved "https://registry.yarnpkg.com/jsc-safe-url/-/jsc-safe-url-0.2.4.tgz#141c14fbb43791e88d5dc64e85a374575a83477a"