Skip to content

Commit

Permalink
bump
Browse files Browse the repository at this point in the history
  • Loading branch information
sergeymild committed Mar 29, 2023
1 parent e4ca8a2 commit 226e963
Show file tree
Hide file tree
Showing 32 changed files with 10,994 additions and 154 deletions.
68 changes: 57 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,71 @@
# react-native-jsi-bridge

React Native JSI library for communicate between js and native code via jsi
React Native JSI library for communicate between js and native code via jsi skipping the react-native bridge which improve performance and skips data serialization/deserialization.

## Installation

```sh
npm install react-native-jsi-bridge
#add to package.json
"react-native-jsi-bridge":"sergeymild/react-native-jsi-bridge#0.71.0"
# after that make yarn install
# and npx pod-install
```

## Usage
## Usage JS

```js
import { multiply } from 'react-native-jsi-bridge';
on js side just import `import { JsiBridge } from 'react-native-jsi-bridge'`
and subscribe on events which will be fired from native code.
```typescript
import { JsiBridge } from 'react-native-jsi-bridge';

// ...
// for subscribe
JsiBridge.on('eventNameInJsCode', (data: string) => {

const result = await multiply(3, 7);
})

// for unsubscribe
JsiBridge.off('eventNameInJsCode')
```

For send event to native code
```typescript
// send event to native code
JsiBridge.emit('eventNameInNativeCode', JSON.stringify({user: "withNamr"}))
```

## Usage Native Java

On native side (Java/Kotlin)
```java

// for subscribe
JsiBridge.on('eventNameInNativeCode', someObjectSerializedToString -> {

})

// for unsubscribe
JsiBridge.off('eventNameInNativeCode')

// send event to js code
JsiBridge.emit('eventNameInJsCode', someObjectSerializedToString)
```

## Usage Native Objective-c

On native side
```
#import "JsiBridgeEmitter.h"
// for subscribe
[[JsiBridgeEmitter shared] on:@"eventNameInNativeCode" with:^(NSString *data) {
// some logic
}];
// for unsubscribe
[[JsiBridgeEmitter shared] off:@"eventNameInNativeCode"];
// send event to js code
[[JsiBridgeEmitter shared] emit:@"eventNameInJsCode" with:@"someObjectSerializedToString"];
```

## Contributing
Expand All @@ -25,7 +75,3 @@ See the [contributing guide](CONTRIBUTING.md) to learn how to contribute to the
## License

MIT

---

Made with [create-react-native-library](https://github.com/callstack/react-native-builder-bob)
47 changes: 47 additions & 0 deletions android/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
cmake_minimum_required(VERSION 3.10)

set (PACKAGE_NAME "jsiBridge")

set (CMAKE_VERBOSE_MAKEFILE ON)
set (CMAKE_CXX_STANDARD 17)

set (BUILD_DIR ${CMAKE_SOURCE_DIR}/build)

include("${REACT_NATIVE_DIR}/ReactAndroid/cmake-utils/folly-flags.cmake")
add_compile_options(${folly_FLAGS})

# Consume shared libraries and headers from prefabs
find_package(fbjni REQUIRED CONFIG)
find_package(ReactAndroid REQUIRED CONFIG)

add_library(
${PACKAGE_NAME}
SHARED
src/main/cpp/JsiBridge.cpp
)

# includes

target_include_directories(
${PACKAGE_NAME}
PRIVATE
"${REACT_NATIVE_DIR}/ReactAndroid/src/main/jni/react/turbomodule"
"${REACT_NATIVE_DIR}/ReactCommon"
"${REACT_NATIVE_DIR}/ReactCommon/callinvoker"
"src/main/cpp"
)

find_library(
LOG_LIB
log
)

message(WARNING "${PACKAGE_NAME} linking: CMAKE_CURRENT_SOURCE_DIR=${ANDROID_ABI}")
target_link_libraries(
${PACKAGE_NAME}
${LOG_LIB}
ReactAndroid::jsi
ReactAndroid::reactnativejni
fbjni::fbjni
android
)
88 changes: 88 additions & 0 deletions android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,74 @@ def getExtOrIntegerDefault(name) {
return rootProject.ext.has(name) ? rootProject.ext.get(name) : (project.properties["JsiBridge_" + name]).toInteger()
}

def safeExtGet(prop, fallback) {
rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
}

def reactNativeArchitectures() {
def value = project.getProperties().get("reactNativeArchitectures")
return value ? value.split(",") : ["armeabi-v7a", "arm64-v8a"]
}

def resolveReactNativeDirectory() {
def reactNativeLocation = safeExtGet("REACT_NATIVE_NODE_MODULES_DIR", null)
if (reactNativeLocation != null) {
return file(reactNativeLocation)
}

// monorepo workaround
// react-native can be hoisted or in project's own node_modules
def reactNativeFromProjectNodeModules = file("${rootProject.projectDir}/../node_modules/react-native")
if (reactNativeFromProjectNodeModules.exists()) {
return reactNativeFromProjectNodeModules
}

throw new GradleException(
"[Reanimated] Unable to resolve react-native location in " +
"node_modules. You should project extension property (in app/build.gradle) " +
"`REACT_NATIVE_NODE_MODULES_DIR` with path to react-native."
)
}

def reactNativeRootDir = resolveReactNativeDirectory()

android {
buildFeatures {
prefab true
}
compileSdkVersion getExtOrIntegerDefault("compileSdkVersion")
ndkVersion getExtOrDefault('ndkVersion')

defaultConfig {
minSdkVersion getExtOrIntegerDefault("minSdkVersion")
targetSdkVersion getExtOrIntegerDefault("targetSdkVersion")
buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString()

externalNativeBuild {
cmake {
cppFlags "-fexceptions", "-frtti", "-std=c++1y", "-DONANDROID"
abiFilters "armeabi-v7a", "arm64-v8a"
arguments '-DANDROID_STL=c++_shared',
"-DREACT_NATIVE_DIR=${reactNativeRootDir.path}",
"-DANDROID_CPP_FEATURES=rtti exceptions",
'-DANDROID_ARM_NEON=TRUE'
}
}
ndk {
abiFilters (*reactNativeArchitectures())
}
}

dexOptions {
javaMaxHeapSize "4g"
}

externalNativeBuild {
cmake {
path "CMakeLists.txt"
}
}

buildTypes {
release {
minifyEnabled false
Expand All @@ -53,6 +113,34 @@ android {
targetCompatibility JavaVersion.VERSION_1_8
}

packagingOptions {
// Exclude all Libraries that are already present in the user's app (through React Native or by him installing REA)
excludes = [
"META-INF",
"META-INF/**",
"**/libc++_shared.so",
"**/libfbjni.so",
"**/libjsi.so",
"**/libfolly_json.so",
"**/libfolly_runtime.so",
"**/libglog.so",
"**/libhermes.so",
"**/libhermes-executor-debug.so",
"**/libhermes_executor.so",
"**/libreactnativejni.so",
"**/libturbomodulejsijni.so",
"**/libreact_nativemodule_core.so",
"**/libjscexecutor.so",
"**/libv8executor.so",
]
exclude "META-INF/**"
}

configurations {
extractHeaders
extractJNI
}

}

repositories {
Expand Down
137 changes: 137 additions & 0 deletions android/src/main/cpp/JsiBridge.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
//
// Created by Sergei Golishnikov on 08/03/2022.
//

#include "JsiBridge.h"

#include <utility>
#include "iostream"

using namespace facebook;
using namespace facebook::jni;

using TSelf = local_ref<HybridClass<JsiBridge>::jhybriddata>;

JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *) {
return facebook::jni::initialize(vm, [] {
JsiBridge::registerNatives();
});
}

// JNI binding
void JsiBridge::registerNatives() {
__android_log_print(ANDROID_LOG_VERBOSE, "πŸ˜‡", "registerNatives");
registerHybrid({
makeNativeMethod("initHybrid",
JsiBridge::initHybrid),
makeNativeMethod("installJSIBindings",
JsiBridge::installJSIBindings),
makeNativeMethod("emitJs",
JsiBridge::emitJs),
});
}

JsiBridge::JsiBridge(
jni::alias_ref<JsiBridge::javaobject> jThis,
jsi::Runtime *rt,
std::shared_ptr<facebook::react::CallInvoker> jsCallInvoker)
: javaPart_(jni::make_global(jThis)),
runtime_(rt),
jsCallInvoker_(std::move(jsCallInvoker)) {}

// JNI init
TSelf JsiBridge::initHybrid(
alias_ref<jhybridobject> jThis,
jlong jsContext,
jni::alias_ref<facebook::react::CallInvokerHolder::javaobject>
jsCallInvokerHolder) {

__android_log_write(ANDROID_LOG_INFO, "πŸ₯²", "initHybrid...");
auto jsCallInvoker = jsCallInvokerHolder->cthis()->getCallInvoker();
return makeCxxInstance(jThis, (jsi::Runtime *) jsContext, jsCallInvoker);
}

void JsiBridge::emitJs(jstring name, jstring data) {
__android_log_print(ANDROID_LOG_VERBOSE, "πŸ˜‡", "emit");

auto stdName = jni::make_local(name)->toStdString();
auto stdData = jni::make_local(data)->toStdString();

if (jsListeners_.find(stdName) != jsListeners_.end()) {
jsCallInvoker_->invokeAsync([=, d = stdData]() {
jsListeners_[stdName]->call(*runtime_,jsi::String::createFromUtf8(*runtime_, d));
});
}
}

void JsiBridge::installJSIBindings() {
__android_log_print(ANDROID_LOG_VERBOSE, "πŸ˜‡", "installJSIBindings");

auto registerCallback = jsi::Function::createFromHostFunction(
*runtime_,
jsi::PropNameID::forUtf8(*runtime_, "registerCallback"),
2,
[=](jsi::Runtime &runtime,
const jsi::Value &thisArg,
const jsi::Value *args,
size_t count) -> jsi::Value {


auto name = args[0].asString(runtime).utf8(runtime);

__android_log_print(ANDROID_LOG_VERBOSE, "πŸ˜‡", "registerCallback %s", name.c_str());

auto callback = args[1].asObject(runtime).asFunction(runtime);
jsListeners_[name] = std::make_shared<jsi::Function>(std::move(callback));
return jsi::Value::undefined();
});

auto removeCallback = jsi::Function::createFromHostFunction(
*runtime_,
jsi::PropNameID::forUtf8(*runtime_, "removeCallback"),
1,
[=](jsi::Runtime &runtime,
const jsi::Value &thisArg,
const jsi::Value *args,
size_t count) -> jsi::Value {

auto name = args[0].asString(runtime).utf8(runtime);

__android_log_print(ANDROID_LOG_VERBOSE, "πŸ˜‡", "removeCallback %s", name.c_str());

jsListeners_.erase(name);
return jsi::Value::undefined();
});


auto emit = jsi::Function::createFromHostFunction(
*runtime_,
jsi::PropNameID::forUtf8(*runtime_, "emit"),
2,
[=](jsi::Runtime &runtime,
const jsi::Value &thisArg,
const jsi::Value *args,
size_t count) -> jsi::Value {

auto name = args[0].asString(runtime).utf8(runtime);
auto data = args[1].asString(runtime).utf8(runtime);
auto localData = jni::make_jstring(data);
auto localName = jni::make_jstring(name);

__android_log_print(ANDROID_LOG_VERBOSE, "πŸ˜‡", "emit %s", name.c_str());

auto method = javaPart_->getClass()->getMethod<void(jni::local_ref<jstring>, jni::local_ref<jstring>)>(
"emitNative");
method(javaPart_.get(), localName, localData);
return jsi::Value::undefined();
});



jsi::Object _jsiBridge = jsi::Object(*runtime_);
_jsiBridge.setProperty(*runtime_, "registerCallback", std::move(registerCallback));
_jsiBridge.setProperty(*runtime_, "removeCallback", std::move(removeCallback));
_jsiBridge.setProperty(*runtime_, "emit", std::move(emit));
runtime_->global().setProperty(*runtime_, "_JsiBridge", std::move(_jsiBridge));

}
Loading

0 comments on commit 226e963

Please sign in to comment.