diff --git a/.github/workflows/build_and_test.yml b/.github/workflows/build_and_test.yml index f4340c3e7..749596999 100644 --- a/.github/workflows/build_and_test.yml +++ b/.github/workflows/build_and_test.yml @@ -9,6 +9,9 @@ on: jobs: build: runs-on: ubuntu-latest + env: + ORG_GRADLE_PROJECT_signingKey: ${{ secrets.GPG_SIGNING_KEY }} + ORG_GRADLE_PROJECT_signingPassword: ${{ secrets.GPG_SIGNING_PASSWORD }} steps: - uses: actions/checkout@v4 @@ -91,6 +94,13 @@ jobs: name: archive path: archive + - name: Extract archive + run: | + mv archive/dist dist + mv archive/dist.unstripped dist.unstripped + rmdir archive + shell: bash + - name: 🍺 Install Maestro run: | curl -Ls "https://get.maestro.mobile.dev" | bash @@ -115,6 +125,20 @@ jobs: target: google_apis working-directory: test script: | - mv ../archive/dist ../dist npx expo run:android --variant release --no-bundler + adb logcat -c + set +e maestro test maestro.yaml + STATUS=$? + adb logcat -d > adb.log + exit $STATUS + + - name: Upload failed artifacts + if: failure() + uses: actions/upload-artifact@v4 + with: + name: failure_artifacts + path: | + $HOME/.maestro/tests/**/* + test/android/app/build/outputs/apk/release/app-release.apk + test/adb.log diff --git a/.gitignore b/.gitignore index 6841f050f..e681316ab 100644 --- a/.gitignore +++ b/.gitignore @@ -20,6 +20,7 @@ package-lock.json bin/ gen/ out/ +.cxx/ # Gradle files .gradle/ diff --git a/lib/android-jsc/build.gradle b/lib/android-jsc/build.gradle deleted file mode 100644 index 1b1cd40b9..000000000 --- a/lib/android-jsc/build.gradle +++ /dev/null @@ -1,65 +0,0 @@ -apply plugin: 'com.android.library' -apply plugin: 'maven-publish' - -def distDir = project.findProperty("distDir") ?: "" -def jniLibsDir = project.findProperty("jniLibsDir") ?: "" -def revision = project.findProperty("revision") ?: "".replaceAll("\\s", "") -def i18n = project.findProperty("i18n") ?: "" - -if (!distDir) throw new RuntimeException("expecting --project-prop distDir=??? but was empty") -if (!jniLibsDir) throw new RuntimeException("expecting --project-prop jniLibsDir=??? but was empty") -if (!revision) throw new RuntimeException("expecting --project-prop revision=??? but was empty") -if (!i18n) throw new RuntimeException("expecting --project-prop i18n=??? but was empty") - -android { - namespace 'org.webkit.androidjsc' - compileSdkVersion 35 - - defaultConfig { - minSdkVersion 24 - targetSdkVersion 34 - versionCode 1 - versionName "1.0" - } - - sourceSets { - main { - jniLibs.srcDirs = ["${jniLibsDir}"] - } - } - - packagingOptions { - doNotStrip "**/libjsc.so" - } - - publishing { - singleVariant("release") { - } - } -} - -dependencies {} - -project.group = "org.webkit" -def artifactName = Boolean.valueOf(i18n) ? "android-jsc-intl" : "android-jsc" -project.version = "r${revision}" - -afterEvaluate { - publishing { - publications { - release(MavenPublication) { - from components.release - pom { - name = "android-jsc" - artifactId = artifactName - packaging = "aar" - } - } - } - repositories { - maven { - url = "file://${distDir}" - } - } - } -} diff --git a/lib/cppruntime/build.gradle b/lib/cppruntime/build.gradle index 1c5727049..9a4593212 100644 --- a/lib/cppruntime/build.gradle +++ b/lib/cppruntime/build.gradle @@ -3,14 +3,14 @@ apply plugin: 'maven-publish' def distDir = project.findProperty("distDir") ?: "" def jniLibsDir = project.findProperty("jniLibsDir") ?: "" -def revision = project.findProperty("revision") ?: "".replaceAll("\\s", "") +def version = project.findProperty("version") ?: "".replaceAll("\\s", "") if (!distDir) throw new RuntimeException("expecting --project-prop distDir=??? but was empty") if (!jniLibsDir) throw new RuntimeException("expecting --project-prop jniLibsDir=??? but was empty") -if (!revision) throw new RuntimeException("expecting --project-prop revision=??? but was empty") +if (!version) throw new RuntimeException("expecting --project-prop version=??? but was empty") android { - namespace 'org.webkit.androidjsc_cppruntime' + namespace 'io.github.react_native_community.jscandroid_cppruntime' compileSdkVersion 35 defaultConfig { @@ -34,8 +34,8 @@ android { dependencies {} -project.group = "org.webkit" -project.version = "r${revision}" +project.group = "io.github.react-native-community" +project.version = "${version}" afterEvaluate { publishing { @@ -43,8 +43,8 @@ afterEvaluate { release(MavenPublication) { from components.release pom { - name = "android-jsc" - artifactId = "android-jsc-cppruntime" + name = "jsc-android" + artifactId = "jsc-android-cppruntime" packaging = "aar" } } diff --git a/lib/android-jsc/.gitignore b/lib/jsc-android/.gitignore similarity index 100% rename from lib/android-jsc/.gitignore rename to lib/jsc-android/.gitignore diff --git a/lib/jsc-android/CMakeLists.txt b/lib/jsc-android/CMakeLists.txt new file mode 100644 index 000000000..9277f16f7 --- /dev/null +++ b/lib/jsc-android/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 3.13) +set(CMAKE_VERBOSE_MAKEFILE on) +project(jsc-android) + +add_library(jsc SHARED empty.cpp) + +set(OUTPUT_SRC "${PREBUILT_LIBS_DIR}/${ANDROID_ABI}/libjsc.so") +set(OUTPUT_DST "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/libjsc.so") + +add_custom_command( + TARGET jsc POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different + ${OUTPUT_SRC} + ${OUTPUT_DST} + COMMENT "Overwriting ${OUTPUT_SRC} to ${OUTPUT_DST}" +) diff --git a/lib/jsc-android/build.gradle b/lib/jsc-android/build.gradle new file mode 100644 index 000000000..9b98c0ea1 --- /dev/null +++ b/lib/jsc-android/build.gradle @@ -0,0 +1,123 @@ +apply plugin: 'com.android.library' +apply plugin: 'maven-publish' +apply plugin: 'signing' + +def distDir = project.findProperty("distDir") ?: "" +def jniLibsDir = project.findProperty("jniLibsDir") ?: "" +def headersDir = project.findProperty("headersDir") ?: "${distDir}/include" +def version = project.findProperty("version") ?: "".replaceAll("\\s", "") +def i18n = project.findProperty("i18n") ?: "" + +def signingKey = project.findProperty('signingKey') +def signingPassword = project.findProperty('signingPassword') + +if (!distDir) throw new RuntimeException("expecting --project-prop distDir=??? but was empty") +if (!jniLibsDir) throw new RuntimeException("expecting --project-prop jniLibsDir=??? but was empty") +if (!version) throw new RuntimeException("expecting --project-prop version=??? but was empty") +if (!i18n) throw new RuntimeException("expecting --project-prop i18n=??? but was empty") + +android { + namespace 'io.github.react_native_community.jscandroid' + compileSdkVersion 35 + + defaultConfig { + minSdkVersion 24 + targetSdkVersion 34 + versionCode 1 + versionName "1.0" + + externalNativeBuild { + cmake { + arguments '-DANDROID_STL=c++_shared', + "-DPREBUILT_LIBS_DIR=${jniLibsDir}" + targets 'jsc' + } + } + } + + externalNativeBuild { + cmake { + path 'CMakeLists.txt' + } + } + + packagingOptions { + doNotStrip '**/libjsc.so' + pickFirst '**/libjsc.so' + + excludes += [ + '**/libc++_shared.so', + ] + } + + buildFeatures { + prefabPublishing true + } + + prefab { + jsc { + headers file(headersDir).absolutePath + } + } + + publishing { + singleVariant("release") { + } + } +} + +dependencies {} + +project.group = "io.github.react-native-community" +def artifactName = Boolean.valueOf(i18n) ? "jsc-android-intl" : "jsc-android" +project.version = "${version}" + +afterEvaluate { + publishing { + publications { + release(MavenPublication) { + from components.release + pom { + name = artifactName + artifactId = artifactName + description = 'Pre-build version of JavaScriptCore to be used by React Native apps' + url = 'https://github.com/react-native-community/jsc-android-buildscripts' + + developers { + developer { + id = 'react-native-community' + name = 'React Native Community' + } + } + + licenses { + license { + name = 'BSD-2-Clause' + url = 'https://github.com/react-native-community/jsc-android-buildscripts/blob/main/LICENSE' + distribution = 'repo' + } + } + + scm { + url = 'https://github.com/react-native-community/jsc-android-buildscripts.git' + connection = 'scm:git:https://github.com/react-native-community/jsc-android-buildscripts.git' + developerConnection = 'scm:git:git@github.com:react-native-community/jsc-android-buildscripts.git' + } + } + } + } + + repositories { + maven { + url = "file://${distDir}" + } + } + + if (signingKey && signingPassword) { + signing { + useInMemoryPgpKeys(signingKey, signingPassword) + sign publishing.publications.release + } + } + } +} diff --git a/lib/jsc-android/empty.cpp b/lib/jsc-android/empty.cpp new file mode 100644 index 000000000..e69de29bb diff --git a/lib/android-jsc/src/main/AndroidManifest.xml b/lib/jsc-android/src/main/AndroidManifest.xml similarity index 100% rename from lib/android-jsc/src/main/AndroidManifest.xml rename to lib/jsc-android/src/main/AndroidManifest.xml diff --git a/lib/settings.gradle b/lib/settings.gradle index baa5c84a9..629654b98 100644 --- a/lib/settings.gradle +++ b/lib/settings.gradle @@ -1,4 +1,4 @@ rootProject.name = 'JavaScriptCore Lib' -include ':android-jsc' +include ':jsc-android' include ':cppruntime' diff --git a/measure/android/build.gradle b/measure/android/build.gradle index 943e57834..f58f33e9e 100644 --- a/measure/android/build.gradle +++ b/measure/android/build.gradle @@ -6,7 +6,7 @@ ext { JSC_VERSION = jscAAR ? file(file(jscAAR).getParent()).getName() : "" def i18nProp = project.findProperty("i18n") - JSC_NAME = Boolean.valueOf(i18nProp) ? "android-jsc-intl" : "android-jsc" + JSC_NAME = Boolean.valueOf(i18nProp) ? "jsc-android-intl" : "jsc-android" isIDE = System.getProperties()['idea.platform.prefix'] != null } @@ -18,7 +18,7 @@ if (!isIDE && JSC_VERSION) { configurations.all { resolutionStrategy { eachDependency { DependencyResolveDetails details -> - if (details.requested.name == 'android-jsc') { + if (details.requested.name == 'jsc-android') { details.useTarget group: details.requested.group, name: JSC_NAME, version: JSC_VERSION } } @@ -43,7 +43,7 @@ buildscript { allprojects { repositories { - // this tells gradle where android-jsc resides + // this tells gradle where jsc-android resides maven { url JSC_DIR } diff --git a/scripts/start.sh b/scripts/start.sh index 6a7855e33..f03eb65cc 100755 --- a/scripts/start.sh +++ b/scripts/start.sh @@ -79,12 +79,14 @@ createAAR() { local distDir=$2 local jniLibsDir=$3 local i18n=$4 + local headersDir=${distDir}/include printf "\n\n\t\t===================== create aar :${target}: =====================\n\n" cd $ROOTDIR/lib ./gradlew clean :${target}:publish \ --project-prop distDir="${distDir}" \ --project-prop jniLibsDir="${jniLibsDir}" \ - --project-prop revision="$REVISION" \ + --project-prop headersDir="${headersDir}" \ + --project-prop version="${npm_package_version}" \ --project-prop i18n="${i18n}" cd $ROOTDIR } @@ -104,19 +106,19 @@ export I18N=true prep compile -export DISTDIR=${ROOTDIR}/dist printf "\n\n\t\t===================== create stripped distributions =====================\n\n" -createAAR "android-jsc" ${DISTDIR} ${INSTALL_DIR_I18N_false} "false" -createAAR "android-jsc" ${DISTDIR} ${INSTALL_DIR_I18N_true} "true" -createAAR "cppruntime" ${DISTDIR} ${INSTALL_CPPRUNTIME_DIR} "false" +export DISTDIR=${ROOTDIR}/dist copyHeaders ${DISTDIR} +createAAR "jsc-android" ${DISTDIR} ${INSTALL_DIR_I18N_false} "false" +createAAR "jsc-android" ${DISTDIR} ${INSTALL_DIR_I18N_true} "true" +createAAR "cppruntime" ${DISTDIR} ${INSTALL_CPPRUNTIME_DIR} "false" printf "\n\n\t\t===================== create unstripped distributions =====================\n\n" export DISTDIR=${ROOTDIR}/dist.unstripped -createAAR "android-jsc" ${DISTDIR} ${INSTALL_UNSTRIPPED_DIR_I18N_false} "false" -createAAR "android-jsc" ${DISTDIR} ${INSTALL_UNSTRIPPED_DIR_I18N_true} "true" -createAAR "cppruntime" ${DISTDIR} ${INSTALL_CPPRUNTIME_DIR} "false" copyHeaders ${DISTDIR} +createAAR "jsc-android" ${DISTDIR} ${INSTALL_UNSTRIPPED_DIR_I18N_false} "false" +createAAR "jsc-android" ${DISTDIR} ${INSTALL_UNSTRIPPED_DIR_I18N_true} "true" +createAAR "cppruntime" ${DISTDIR} ${INSTALL_CPPRUNTIME_DIR} "false" npm run info diff --git a/test/app.json b/test/app.json index baa2d92f4..f5f33baf4 100644 --- a/test/app.json +++ b/test/app.json @@ -26,6 +26,7 @@ "web": { "favicon": "./assets/favicon.png" }, - "jsEngine": "jsc" + "jsEngine": "jsc", + "plugins": ["./plugins/withJscAndroid"] } } diff --git a/test/package.json b/test/package.json index 9fd0e6c6b..7f2b3de63 100644 --- a/test/package.json +++ b/test/package.json @@ -6,8 +6,7 @@ "start": "expo start", "android": "expo run:android", "ios": "expo run:ios", - "web": "expo start --web", - "postinstall": "rm -rf node_modules/jsc-android/dist && cd node_modules/jsc-android && ln -s ../../../dist" + "web": "expo start --web" }, "dependencies": { "expo": "~52.0.7", diff --git a/test/plugins/withJscAndroid.js b/test/plugins/withJscAndroid.js new file mode 100644 index 000000000..63c864fa4 --- /dev/null +++ b/test/plugins/withJscAndroid.js @@ -0,0 +1,79 @@ +const assert = require('assert'); +const { + withAppBuildGradle, + withProjectBuildGradle, +} = require('expo/config-plugins'); + +const withJscAndroidAppBuildGradle = (config) => { + return withAppBuildGradle(config, (config) => { + assert(config.modResults.language === 'groovy'); + if ( + !config.modResults.contents.match( + /@generated withJscAndroidAppBuildGradle/ + ) + ) { + const code = ` +// [begin] @generated withJscAndroidAppBuildGradle +afterEvaluate { + project.rootProject.allprojects { + // Remove original mavenCentral added by RNGP + repositories.removeIf { repo -> + repo instanceof MavenArtifactRepository && repo.url.toString().contains('https://repo.maven.apache.org/maven2') + } + + repositories { + maven { + // Local dist maven repo + url("\${rootDir}/../../dist") + } + + mavenCentral { + content { + excludeGroup('org.webkit') + excludeGroup('io.github.react-native-community') + } + } + } + } + + configurations.all { + resolutionStrategy.dependencySubstitution { + substitute(module('org.webkit:android-jsc')) + .using(module('io.github.react-native-community:jsc-android:+')) + } + } +} +// [end] @generated withJscAndroidAppBuildGradle +`; + config.modResults.contents += code; + } + return config; + }); +}; + +const withJscAndroidProjectBuildGradle = (config) => { + return withProjectBuildGradle(config, (config) => { + assert(config.modResults.language === 'groovy'); + const code = ` + mavenCentral { + content { + excludeGroup('org.webkit') + excludeGroup('io.github.react-native-community') + } + } +`; + config.modResults.contents = config.modResults.contents.replace( + /^(\s+)(mavenCentral\(\))(\s*)$/gm, + code + ); + return config; + }); +}; + +const withJscAndroid = (config) => { + config = withJscAndroidAppBuildGradle(config); + config = withJscAndroidProjectBuildGradle(config); + return config; +}; + +module.exports = withJscAndroid;