Skip to content

Commit

Permalink
Create Java Part
Browse files Browse the repository at this point in the history
  • Loading branch information
mrousavy committed Feb 20, 2024
1 parent 6188bd7 commit ad36720
Show file tree
Hide file tree
Showing 12 changed files with 132 additions and 21 deletions.
18 changes: 10 additions & 8 deletions package/android/src/main/cpp/AndroidFilamentProxy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,18 @@ namespace margelo {

using namespace facebook;

explicit AndroidFilamentProxy::AndroidFilamentProxy(jni::alias_ref<JFilamentProxy> filamentProxy)
: _filamentProxy(jni::make_global(filamentProxy)) {}
AndroidFilamentProxy::AndroidFilamentProxy(jni::alias_ref<JFilamentProxy::javaobject> proxy)
: _proxy(jni::make_global(proxy)) {}

AndroidFilamentProxy::~AndroidFilamentProxy() {
// Hermes GC might destroy HostObjects on an arbitrary Thread which might not be
// connected to the JNI environment. To make sure fbjni can properly destroy
// the Java method, we connect to a JNI environment first.
jni::ThreadScope::WithClassLoader([&] { _filamentProxy.reset(); });
// Hermes GC might destroy HostObjects on an arbitrary Thread which might not be
// connected to the JNI environment. To make sure fbjni can properly destroy
// the Java method, we connect to a JNI environment first.
jni::ThreadScope::WithClassLoader([&] { _proxy.reset(); });
}

int AndroidFilamentProxy::loadModel(const std::string& path) {
return _proxy->loadModel(path);
int AndroidFilamentProxy::loadModel(const std::string &path) {
return _proxy->cthis()->loadModel(path);
}

} // namespace margelo
4 changes: 2 additions & 2 deletions package/android/src/main/cpp/AndroidFilamentProxy.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,15 @@ using namespace facebook;
*/
class AndroidFilamentProxy : public FilamentProxy {
public:
explicit AndroidFilamentProxy(jni::alias_ref<JFilamentProxy> filamentProxy);
explicit AndroidFilamentProxy(jni::alias_ref<JFilamentProxy::javaobject> filamentProxy);
~AndroidFilamentProxy();

private:
// TODO(hanno): implement
int loadModel(const std::string& path);

private:
jni::global_ref<JFilamentProxy> _proxy;
jni::global_ref<JFilamentProxy::javaobject> _proxy;
};

} // namespace margelo
7 changes: 6 additions & 1 deletion package/android/src/main/cpp/Filament.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
#include <fbjni/fbjni.h>
#include <jni.h>
#include "FilamentInstaller.h"
#include "JFilamentProxy.h"

JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void*) {
return facebook::jni::initialize(vm, [] { margelo::FilamentInstaller::registerNatives(); });
return facebook::jni::initialize(vm, [] {
margelo::FilamentInstaller::registerNatives();
margelo::JFilamentProxy::registerNatives();
});
}
20 changes: 20 additions & 0 deletions package/android/src/main/cpp/FilamentInstaller.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#include <jni.h>
#include <fbjni/fbjni.h>
#include <jsi/jsi.h>
#include "FilamentInstaller.h"
#include "AndroidFilamentProxy.h"

namespace margelo {

void FilamentInstaller::install(jni::alias_ref<jni::JClass> clazz,
jni::alias_ref<JFilamentProxy::javaobject> proxy) {
jsi::Runtime& runtime = proxy->cthis()->getRuntime();
std::shared_ptr<AndroidFilamentProxy> filamentProxy = std::make_shared<AndroidFilamentProxy>(proxy);
runtime.global().setProperty(runtime, "__filamentProxy", jsi::Object::createFromHostObject(runtime, filamentProxy));
}

void FilamentInstaller::registerNatives() {
javaClassStatic()->registerNatives({makeNativeMethod("install", FilamentInstaller::install)});
}

} // namespace margelo
3 changes: 2 additions & 1 deletion package/android/src/main/cpp/FilamentInstaller.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#include <fbjni/fbjni.h>
#include <jni.h>
#include "JFilamentProxy.h"

namespace margelo {

Expand All @@ -13,7 +14,7 @@ class FilamentInstaller : public jni::JavaClass<FilamentInstaller> {
public:
static auto constexpr kJavaDescriptor = "Lcom/margelo/filament/FilamentInstaller;";
static void registerNatives();
static void install(jni::alias_ref<jni::JClass> clazz, jni::alias_ref<JVisionCameraProxy::javaobject> proxy);
static void install(jni::alias_ref<jni::JClass> clazz, jni::alias_ref<JFilamentProxy::javaobject> proxy);
};

}; // namespace margelo
14 changes: 11 additions & 3 deletions package/android/src/main/cpp/java-bindings/JFilamentProxy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,24 @@ JFilamentProxy::~JFilamentProxy() {
}

int JFilamentProxy::loadModel(const std::string& path) {
static const auto method = javaClassLocal()->getMethod<jint(jstring)>("loadModel");
return method(_javaPart, make_jstring(path));
static const auto method = javaClassLocal()->getMethod<jint(jni::alias_ref<jstring>)>("loadModel");
return method(_javaPart, jni::make_jstring(path));
}

jsi::Runtime& JFilamentProxy::getRuntime() {
if (_runtime == nullptr) {
[[unlikely]];
throw std::runtime_error("JSI Runtime was null!");
}
return *_runtime;
}

void JFilamentProxy::registerNatives() {
registerHybrid({makeNativeMethod("initHybrid", JFilamentProxy::initHybrid)});
}

jni::local_ref<JFilamentProxy::jhybriddata>
JFilamentProxy::initHybrid(alias_ref<jhybridobject> jThis, jlong jsRuntimePointer,
JFilamentProxy::initHybrid(jni::alias_ref<jhybridobject> jThis, jlong jsRuntimePointer,
jni::alias_ref<facebook::react::CallInvokerHolder::javaobject> jsCallInvokerHolder) {
__android_log_write(ANDROID_LOG_INFO, TAG, "Initializing JFilamentProxy...");

Expand Down
2 changes: 2 additions & 0 deletions package/android/src/main/cpp/java-bindings/JFilamentProxy.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ class JFilamentProxy : public jni::HybridClass<JFilamentProxy> {
// TODO(hanno): implement
int loadModel(const std::string& path);

jsi::Runtime& getRuntime();

private:
friend HybridBase;
jni::global_ref<JFilamentProxy::javaobject> _javaPart;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.margelo.filament;

/** @noinspection JavaJniMissingFunction*/
public class FilamentInstaller {
public static native void install(FilamentProxy proxy);
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,42 @@
package com.margelo.filament;

import androidx.annotation.Keep;
import androidx.annotation.NonNull;

import com.facebook.jni.HybridData;
import com.facebook.proguard.annotations.DoNotStrip;
import com.facebook.react.bridge.JavaScriptContextHolder;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.turbomodule.core.CallInvokerHolderImpl;
import com.facebook.react.turbomodule.core.interfaces.CallInvokerHolder;

/** @noinspection JavaJniMissingFunction*/
class FilamentProxy {
/** @noinspection unused, FieldCanBeLocal */
@DoNotStrip
@Keep
private final HybridData hybridData;

FilamentProxy(@NonNull ReactApplicationContext context) {
JavaScriptContextHolder jsRuntimeHolder = context.getJavaScriptContextHolder();
if (jsRuntimeHolder == null) {
throw new RuntimeException("Failed to initialize react-native-filament: JSI Runtime Holder is null!");
}
Long runtimePointer = jsRuntimeHolder.get();
CallInvokerHolder callInvokerHolder = context.getCatalystInstance().getJSCallInvokerHolder();
if (!(callInvokerHolder instanceof CallInvokerHolderImpl)) {
throw new RuntimeException("Failed to initialize react-native-filament: JS Call Invoker is null!");
}
hybridData = initHybrid(runtimePointer, (CallInvokerHolderImpl) callInvokerHolder);
}

/** @noinspection unused*/
@DoNotStrip
@Keep
int loadModel(String path) {
// TODO(hanno): Implement Java part here
return 13;
}

private native HybridData initHybrid(Long jsRuntimePointer, CallInvokerHolderImpl callInvokerHolder);
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,31 @@

import android.graphics.Color;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.module.annotations.ReactModule;
import com.facebook.react.uimanager.ThemedReactContext;
import com.facebook.react.uimanager.annotations.ReactProp;

@ReactModule(name = FilamentViewManager.NAME)
public class FilamentViewManager extends FilamentViewManagerSpec<FilamentView> {

public static final String NAME = "FilamentView";
private final ReactApplicationContext context;
private FilamentProxy proxy = null;

FilamentViewManager(ReactApplicationContext context) {
this.context = context;
}

@Override
public String getName() {
public @NonNull String getName() {
return NAME;
}

@Override
public FilamentView createViewInstance(ThemedReactContext context) {
public @NonNull FilamentView createViewInstance(@NonNull ThemedReactContext context) {
return new FilamentView(context);
}

Expand All @@ -28,4 +35,25 @@ public FilamentView createViewInstance(ThemedReactContext context) {
public void setColor(FilamentView view, @Nullable String color) {
view.setBackgroundColor(Color.parseColor(color));
}

@Override
public void initialize() {
super.initialize();

if (proxy != null) {
try {
System.loadLibrary("RNFilament");
proxy = new FilamentProxy(context);
FilamentInstaller.install(proxy);
} catch (Throwable cause) {
throw new RuntimeException("Failed to initialize react-native-filament! Reason: " + cause.getMessage(), cause);
}
}
}

@Override
public void onCatalystInstanceDestroy() {
super.onCatalystInstanceDestroy();
proxy = null;
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@

package com.margelo.filament;

import androidx.annotation.NonNull;

import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
Expand All @@ -12,14 +14,14 @@

public class FilamentViewPackage implements ReactPackage {
@Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
public @NonNull List<ViewManager> createViewManagers(@NonNull ReactApplicationContext reactContext) {
List<ViewManager> viewManagers = new ArrayList<>();
viewManagers.add(new FilamentViewManager());
viewManagers.add(new FilamentViewManager(reactContext));
return viewManagers;
}

@Override
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
public @NonNull List<NativeModule> createNativeModules(@NonNull ReactApplicationContext reactContext) {
return Collections.emptyList();
}
}

0 comments on commit ad36720

Please sign in to comment.