Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multiple version checking #4914

Merged
merged 35 commits into from
Sep 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
2987693
init
tjzel Aug 10, 2023
4e0c7ed
androidele
tjzel Aug 10, 2023
d2ab1e9
invertio
tjzel Aug 10, 2023
f4e02fc
renamele
tjzel Aug 10, 2023
0a71101
hmmm... bugs...
tjzel Aug 10, 2023
4fbba50
init
tjzel Aug 10, 2023
9fc54c5
Merge branch 'main' into @tjzel/troubleshooting
tjzel Aug 10, 2023
4311419
remove future
tjzel Aug 10, 2023
80edeeb
sharebale pls
tjzel Aug 10, 2023
ba3861c
test trobule
tjzel Aug 11, 2023
99982f0
url validator lets goooo 🧨
tjzel Aug 11, 2023
3c551d6
fix urls
tjzel Aug 11, 2023
ba149e3
self-review
tjzel Aug 16, 2023
5a58f09
mergele to trobuleshooting
tjzel Aug 16, 2023
6f38b70
fix CI
tjzel Aug 16, 2023
65ca4aa
remove old checker
tjzel Aug 18, 2023
c5c4d67
mergele to trobuleshooting
tjzel Aug 23, 2023
4a107e0
actually...
tjzel Aug 24, 2023
4a86f30
Merge branch 'main' into @tjzel/version-checker
tjzel Aug 24, 2023
bf20b6a
cpp eats java
tjzel Aug 25, 2023
7413264
no more drafties
tjzel Aug 25, 2023
dd68a13
patch matching for js version
tjzel Aug 25, 2023
3fc88aa
Merge branch 'main' into @tjzel/version-checker
tjzel Aug 25, 2023
78d1bbd
mergele main
tjzel Aug 28, 2023
35ba611
huh
tjzel Aug 28, 2023
848916f
ok
tjzel Aug 28, 2023
6d174f7
review changes
tjzel Aug 30, 2023
bd5f532
version checker
tjzel Sep 7, 2023
cc6c399
mergele main
tjzel Sep 7, 2023
87afd30
review changes
tjzel Sep 14, 2023
12b6180
mergele main
tjzel Sep 26, 2023
2b5e2fa
trobuleshouting
tjzel Sep 26, 2023
cfe6749
remove whitespace
tjzel Sep 26, 2023
b8e5081
trobuleshouting
tjzel Sep 26, 2023
10dfb4b
final touches
tjzel Sep 26, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions Common/cpp/ReanimatedRuntime/RNRuntimeDecorator.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#include "RNRuntimeDecorator.h"
#ifdef DEBUG
#include "ReanimatedVersion.h"
#endif // DEBUG

namespace reanimated {

Expand Down Expand Up @@ -29,8 +31,9 @@ void RNRuntimeDecorator::decorate(
#endif // RCT_NEW_ARCH_ENABLED
rnRuntime.global().setProperty(rnRuntime, "_IS_FABRIC", isFabric);

auto version = getReanimatedVersionString(rnRuntime);
rnRuntime.global().setProperty(rnRuntime, "_REANIMATED_VERSION_CPP", version);
#ifdef DEBUG
checkJSVersion(rnRuntime);
#endif // DEBUG

rnRuntime.global().setProperty(
rnRuntime, "_REANIMATED_IS_REDUCED_MOTION", isReducedMotion);
Expand Down
60 changes: 58 additions & 2 deletions Common/cpp/Tools/ReanimatedVersion.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
#include "ReanimatedVersion.h"
#include <regex>
#include <string>

#ifdef REANIMATED_VERSION
#define STRINGIZE(x) #x
Expand All @@ -10,8 +12,62 @@ using namespace facebook;

namespace reanimated {

jsi::String getReanimatedVersionString(jsi::Runtime &rt) {
return jsi::String::createFromUtf8(rt, REANIMATED_VERSION_STRING);
std::string getReanimatedCppVersion() {
return std::string(REANIMATED_VERSION_STRING);
}

// This function is pretty much a copy of
// `src/reanimated2/platform-specific/checkVersion.ts`.
#ifdef DEBUG
bool matchVersion(const std::string &version1, const std::string &version2) {
std::regex pattern("^\\d+\\.\\d+\\.\\d+$");
if (std::regex_match(version1, pattern) &&
std::regex_match(version2, pattern)) {
auto majorPattern = std::regex("^\\d+");
auto major1 = std::regex_search(version1, majorPattern);
auto major2 = std::regex_search(version2, majorPattern);
if (major1 != major2) {
return false;
}
auto minorPattern = std::regex("\\.\\d+\\.");
auto minor1 = std::regex_search(version1, minorPattern);
auto minor2 = std::regex_search(version2, minorPattern);
if (minor1 != minor2) {
return false;
}
return true;
} else {
return version1 == version2;
}
}

void checkJSVersion(jsi::Runtime &rnRuntime) {
auto cppVersion = getReanimatedCppVersion();

auto maybeJSVersion =
rnRuntime.global().getProperty(rnRuntime, "_REANIMATED_VERSION_JS");
if (maybeJSVersion.isUndefined()) {
throw std::runtime_error(
std::string(
"[Reanimated] C++ side failed to resolve JavaScript code version\n") +
"See `https://docs.swmansion.com/react-native-reanimated/docs/guides/troubleshooting#c-side-failed-to-resolve-javascript-code-version` for more details.");
}

auto jsVersion = maybeJSVersion.asString(rnRuntime).utf8(rnRuntime);

if (!matchVersion(cppVersion, jsVersion)) {
throw std::runtime_error(
std::string(
"[Reanimated] Mismatch between C++ code version and JavaScript code version (") +
cppVersion + " vs. " + jsVersion + " respectively).\n" +
"See `https://docs.swmansion.com/react-native-reanimated/docs/guides/troubleshooting#mismatch-between-c-code-version-and-javascript-code-version` for more details.");
}

rnRuntime.global().setProperty(
rnRuntime,
"_REANIMATED_VERSION_CPP",
jsi::String::createFromUtf8(rnRuntime, cppVersion));
}
#endif // DEBUG

}; // namespace reanimated
10 changes: 8 additions & 2 deletions Common/cpp/Tools/ReanimatedVersion.h
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
#pragma once

#include <jsi/jsi.h>
#include <string>

using namespace facebook;

namespace reanimated {

jsi::String getReanimatedVersionString(jsi::Runtime &rt);
std::string getReanimatedCppVersion();

};
#ifdef DEBUG
tjzel marked this conversation as resolved.
Show resolved Hide resolved
bool matchVersion(const std::string &, const std::string &);
void checkJSVersion(jsi::Runtime &);
#endif // DEBUG

}; // namespace reanimated
1 change: 0 additions & 1 deletion RNReanimated.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ require_relative './scripts/reanimated_utils'

reanimated_package_json = JSON.parse(File.read(File.join(__dir__, "package.json")))
config = find_config()
assert_no_multiple_instances(config)
assert_latest_react_native_with_new_architecture(config, reanimated_package_json)
assert_minimal_react_native_version(config)

tjzel marked this conversation as resolved.
Show resolved Hide resolved
Expand Down
60 changes: 2 additions & 58 deletions android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -112,14 +112,6 @@ def getPlaygroundAppName() { // only for the development
return playgroundAppName
}

def shouldAssertNoMultipleInstances() {
if (rootProject.hasProperty("disableMultipleInstancesCheck")) {
return rootProject.property("disableMultipleInstancesCheck") != "true"
} else {
return true
}
}

def getReanimatedVersion() {
def inputFile = file(projectDir.path + '/../package.json')
def json = new JsonSlurper().parseText(inputFile.text)
Expand Down Expand Up @@ -267,6 +259,7 @@ android {
versionCode 1
versionName "1.0"
buildConfigField("boolean", "IS_NEW_ARCHITECTURE_ENABLED", IS_NEW_ARCHITECTURE_ENABLED.toString())
buildConfigField("String", "REANIMATED_VERSION_JAVA", "\"${REANIMATED_VERSION}\"")
tomekzaw marked this conversation as resolved.
Show resolved Hide resolved
externalNativeBuild {
cmake {
arguments "-DANDROID_STL=c++_shared",
Expand Down Expand Up @@ -385,55 +378,6 @@ android {
}
}

abstract class NoMultipleInstancesAssertionTask extends DefaultTask {
@Inject abstract ObjectFactory getObjectFactory()

@Input abstract Property<File> getProjectDirFile()
@Input abstract Property<File> getRootDirFile()
@Input abstract Property<Boolean> getShouldCheck()

def findReanimatedInstancesForPath(String path) {
return objectFactory.fileTree().from(path)
.include("**/react-native-reanimated/package.json")
.exclude("**/.yarn/**")
.exclude({ Files.isSymbolicLink(it.getFile().toPath()) })
.findAll()
}

@TaskAction
def check() {
if (shouldCheck.get()) {
// Assert there are no multiple installations of Reanimated
Set<File> files

if (projectDirFile.get().parent.contains(rootDirFile.get().parent)) {
// standard app
files = findReanimatedInstancesForPath(rootDirFile.get().parent + "/node_modules")
} else {
// monorepo
files = findReanimatedInstancesForPath(rootDirFile.get().parent + "/node_modules")
files.addAll(
findReanimatedInstancesForPath(projectDirFile.get().parentFile.parent)
)
}

if (files.size() > 1) {
String parsedLocation = files.stream().map({
File file -> "- " + file.toString().replace("/package.json", "")
}).collect().join("\n")
String exceptionMessage = "\n[Reanimated] Multiple versions of Reanimated were detected in `build.gradle`. See `https://docs.swmansion.com/react-native-reanimated/docs/guides/troubleshooting/#multiple-versions-of-reanimated-were-detected` for more details.\n\nConflict between: \n" + parsedLocation + "\n"
throw new GradleException(exceptionMessage)
}
}
}
}

tasks.register('assertNoMultipleInstances', NoMultipleInstancesAssertionTask) {
shouldCheck = shouldAssertNoMultipleInstances()
rootDirFile = rootDir
projectDirFile = projectDir
}

def assertLatestReactNativeWithNewArchitecture = task assertLatestReactNativeWithNewArchitectureTask {
onlyIf { IS_NEW_ARCHITECTURE_ENABLED && REANIMATED_MAJOR_VERSION == 3 && REACT_NATIVE_MINOR_VERSION < 72 }
doFirst {
Expand Down Expand Up @@ -465,7 +409,7 @@ task prepareHeadersForPrefab(type: Copy) {
}

tasks.preBuild {
dependsOn assertNoMultipleInstances, assertLatestReactNativeWithNewArchitecture, assertMinimalReactNativeVersion
dependsOn assertLatestReactNativeWithNewArchitecture, assertMinimalReactNativeVersion
}

task cleanCmakeCache() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ public NativeProxy(ReactApplicationContext context) {
fabricUIManager);
prepareLayoutAnimations(LayoutAnimations);
installJSIBindings();
if (BuildConfig.DEBUG) {
checkCppVersion();
}
}

private native HybridData initHybrid(
Expand Down
46 changes: 46 additions & 0 deletions android/src/main/cpp/NativeProxy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@
#include "RNRuntimeDecorator.h"
#include "ReanimatedJSIUtils.h"
#include "ReanimatedRuntime.h"
#ifdef DEBUG
#include "ReanimatedVersion.h"
#endif // DEBUG
#include "WorkletRuntime.h"
#include "WorkletRuntimeCollector.h"

Expand Down Expand Up @@ -101,12 +104,55 @@ jni::local_ref<NativeProxy::jhybriddata> NativeProxy::initHybrid(
/**/);
}

#ifdef DEBUG
void NativeProxy::checkJavaVersion(jsi::Runtime &rnRuntime) {
std::string javaVersion;
try {
javaVersion =
getJniMethod<jstring()>("getReanimatedJavaVersion")(javaPart_.get())
->toStdString();
} catch (std::exception &) {
throw std::runtime_error(
std::string(
"[Reanimated] C++ side failed to resolve Java code version.\n") +
"See `https://docs.swmansion.com/react-native-reanimated/docs/guides/troubleshooting#c-side-failed-to-resolve-java-code-version` for more details.");
}
tjzel marked this conversation as resolved.
Show resolved Hide resolved

auto cppVersion = getReanimatedCppVersion();
if (cppVersion != javaVersion) {
throw std::runtime_error(
std::string(
"[Reanimated] Mismatch between C++ code version and Java code version (") +
cppVersion + " vs. " + javaVersion + " respectively).\n" +
"See `https://docs.swmansion.com/react-native-reanimated/docs/guides/troubleshooting#mismatch-between-c-code-version-and-java-code-version` for more details.");
}
}

void NativeProxy::injectCppVersion() {
auto cppVersion = getReanimatedCppVersion();
try {
static const auto method =
getJniMethod<void(jni::local_ref<JString>)>("setCppVersion");
method(javaPart_.get(), make_jstring(cppVersion));
} catch (std::exception &) {
throw std::runtime_error(
std::string(
"[Reanimated] C++ side failed to resolve Java code version (injection).\n") +
tjzel marked this conversation as resolved.
Show resolved Hide resolved
"See `https://docs.swmansion.com/react-native-reanimated/docs/guides/troubleshooting#c-side-failed-to-resolve-java-code-version` for more details.");
}
}
#endif // DEBUG

void NativeProxy::installJSIBindings() {
jsi::Runtime &rnRuntime = *rnRuntime_;
WorkletRuntimeCollector::install(rnRuntime);
auto isReducedMotion = getIsReducedMotion();
RNRuntimeDecorator::decorate(
rnRuntime, nativeReanimatedModule_, isReducedMotion);
#ifdef DEBUG
checkJavaVersion(rnRuntime);
injectCppVersion();
#endif // DEBUG

registerEventHandler();
setupLayoutAnimations();
Expand Down
4 changes: 4 additions & 0 deletions android/src/main/cpp/NativeProxy.h
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,10 @@ class NativeProxy : public jni::HybridClass<NativeProxy> {
jsi::Runtime *rnRuntime_;
std::shared_ptr<NativeReanimatedModule> nativeReanimatedModule_;
jni::global_ref<LayoutAnimations::javaobject> layoutAnimations_;
#ifdef DEBUG
void checkJavaVersion(jsi::Runtime &);
void injectCppVersion();
#endif // DEBUG
#ifdef RCT_NEW_ARCH_ENABLED
// removed temporarily, event listener mechanism needs to be fixed on RN side
// std::shared_ptr<facebook::react::Scheduler> reactScheduler_;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import com.facebook.soloader.SoLoader;
import com.swmansion.common.GestureHandlerStateManager;
import com.swmansion.reanimated.AndroidUIScheduler;
import com.swmansion.reanimated.BuildConfig;
import com.swmansion.reanimated.NativeProxy;
import com.swmansion.reanimated.NodesManager;
import com.swmansion.reanimated.ReanimatedModule;
Expand Down Expand Up @@ -44,6 +45,7 @@ public abstract class NativeProxyCommon {
private ReanimatedKeyboardEventListener reanimatedKeyboardEventListener;
private Long firstUptime = SystemClock.uptimeMillis();
private boolean slowAnimationsEnabled = false;
protected String cppVersion = null;

protected NativeProxyCommon(ReactApplicationContext context) {
mAndroidUIScheduler = new AndroidUIScheduler(context);
Expand Down Expand Up @@ -97,6 +99,37 @@ public void requestRender(AnimationFrameCallback callback) {
mNodesManager.postOnAnimation(callback);
}

@DoNotStrip
public String getReanimatedJavaVersion() {
return BuildConfig.REANIMATED_VERSION_JAVA;
}

@DoNotStrip
@SuppressWarnings("unused")
tjzel marked this conversation as resolved.
Show resolved Hide resolved
// It turns out it's pretty difficult to set a member of a class
// instance through JNI so we decided to use a setter instead.
protected void setCppVersion(String version) {
cppVersion = version;
tjzel marked this conversation as resolved.
Show resolved Hide resolved
}

protected void checkCppVersion() {
if (cppVersion == null) {
throw new RuntimeException(
"[Reanimated] Java side failed to resolve C++ code version. "
+ "See https://docs.swmansion.com/react-native-reanimated/docs/guides/troubleshooting#java-side-failed-to-resolve-c-code-version for more information.");
}
String javaVersion = getReanimatedJavaVersion();
if (!cppVersion.equals(javaVersion)) {
throw new RuntimeException(
"[Reanimated] Mismatch between Java code version and C++ code version ("
+ javaVersion
+ " vs. "
+ cppVersion
+ " respectively). See "
+ "https://docs.swmansion.com/react-native-reanimated/docs/guides/troubleshooting#mismatch-between-java-code-version-and-c-code-version for more information.");
}
}

@DoNotStrip
public void updateProps(int viewTag, Map<String, Object> props) {
mNodesManager.updateProps(viewTag, props);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ public NativeProxy(ReactApplicationContext context) {
messageQueueThread);
prepareLayoutAnimations(LayoutAnimations);
installJSIBindings();
if (BuildConfig.DEBUG) {
checkCppVersion();
}
}

private native HybridData initHybrid(
Expand Down
Loading