Skip to content

Commit

Permalink
feat: Create Android base
Browse files Browse the repository at this point in the history
  • Loading branch information
mrousavy committed Aug 21, 2023
1 parent bb2a4d9 commit eb17c00
Show file tree
Hide file tree
Showing 5 changed files with 128 additions and 28 deletions.
41 changes: 33 additions & 8 deletions android/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,15 +1,40 @@
cmake_minimum_required(VERSION 3.4.1)
project(VisionCameraTflite)
cmake_minimum_required(VERSION 3.9.0)

set (CMAKE_VERBOSE_MAKEFILE ON)
set (CMAKE_CXX_STANDARD 11)
set (PACKAGE_NAME "VisionCameraTflite")
set (CMAKE_CXX_STANDARD 17)

add_library(cpp
SHARED
../cpp/vision-camera-tflite.cpp
cpp-adapter.cpp
find_package(ReactAndroid REQUIRED CONFIG)
find_package(fbjni REQUIRED CONFIG)

add_library(
${PACKAGE_NAME}
SHARED
../cpp/jsi/Promise.cpp
../cpp/jsi/TypedArray.cpp
../cpp/TensorflowPlugin.cpp
../cpp/TensorHelpers.cpp
src/main/cpp/Tflite.cpp
)

# Specifies a path to native header files.
include_directories(
../cpp
target_include_directories(
${PACKAGE_NAME}
PRIVATE
"../cpp"
"src/main/cpp"
"${NODE_MODULES_DIR}/react-native/ReactCommon"
"${NODE_MODULES_DIR}/react-native/ReactCommon/callinvoker"
"${NODE_MODULES_DIR}/react-native/ReactAndroid/src/main/jni/react/turbomodule" # <-- CallInvokerHolder JNI wrapper
)

set_target_properties(${PACKAGE_NAME} PROPERTIES LINKER_LANGUAGE CXX)

target_link_libraries(
${PACKAGE_NAME}
android # <-- log
ReactAndroid::jsi # <-- jsi.h
ReactAndroid::reactnativejni # <-- CallInvokerImpl
fbjni::fbjni # <-- fbjni.h
)
29 changes: 28 additions & 1 deletion android/build.gradle
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import java.nio.file.Paths

buildscript {
repositories {
google()
mavenCentral()
}

dependencies {
classpath "com.android.tools.build:gradle:7.2.1"
classpath "com.android.tools.build:gradle:7.2.2"
}
}

Expand All @@ -30,16 +32,37 @@ def getExtOrIntegerDefault(name) {
return rootProject.ext.has(name) ? rootProject.ext.get(name) : (project.properties["Tflite_" + name]).toInteger()
}

static def findNodeModules(baseDir) {
def basePath = baseDir.toPath().normalize()
// Node's module resolution algorithm searches up to the root directory,
// after which the base path will be null
while (basePath) {
def nodeModulesPath = Paths.get(basePath.toString(), "node_modules")
def reactNativePath = Paths.get(nodeModulesPath.toString(), "react-native")
if (nodeModulesPath.toFile().exists() && reactNativePath.toFile().exists()) {
return nodeModulesPath.toString()
}
basePath = basePath.getParent()
}
throw new GradleException("vision-camera-tflite: Failed to find node_modules/ path!")
}

def nodeModules = findNodeModules(projectDir)

android {
ndkVersion getExtOrDefault("ndkVersion")
compileSdkVersion getExtOrIntegerDefault("compileSdkVersion")
namespace "com.tflite"

defaultConfig {
minSdkVersion getExtOrIntegerDefault("minSdkVersion")
targetSdkVersion getExtOrIntegerDefault("targetSdkVersion")
buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString()
externalNativeBuild {
cmake {
arguments "-DANDROID_STL=c++_shared",
"-DNODE_MODULES_DIR=${nodeModules}",
"-DIS_NEW_ARCHITECTURE_ENABLED=${isNewArchitectureEnabled()}"
cppFlags "-O2 -frtti -fexceptions -Wall -fstack-protector-all"
abiFilters "x86", "x86_64", "armeabi-v7a", "arm64-v8a"
}
Expand All @@ -56,6 +79,10 @@ android {
}
}

buildFeatures {
prefab true
}

lintOptions {
disable "GradleCompatible"
}
Expand Down
8 changes: 0 additions & 8 deletions android/cpp-adapter.cpp

This file was deleted.

38 changes: 38 additions & 0 deletions android/src/main/cpp/Tflite.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#include <jni.h>
#include <jsi/jsi.h>
#include <fbjni/fbjni.h>

#include "TensorflowPlugin.h"
#include <ReactCommon/CallInvoker.h>
#include <ReactCommon/CallInvokerHolder.h>

using namespace facebook;

class TfliteModule: jni::JavaClass<TfliteModule> {
public:
static constexpr auto kJavaDescriptor = "Lcom/tflite/TfliteModule;";

static bool nativeInstall(jlong runtimePtr, jni::alias_ref<facebook::react::CallInvokerHolder::javaobject> jsCallInvokerHolder) {
auto runtime = reinterpret_cast<jsi::Runtime*>(runtimePtr);
if (runtime == nullptr) {
// Runtime was null!
return false;
}
auto jsCallInvoker = jsCallInvokerHolder->cthis()->getCallInvoker();

return true;
}

static void registerNatives() {
javaClassStatic()->registerNatives({
makeNativeMethod("nativeInstall", nativeInstall);
});
}
};

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

40 changes: 29 additions & 11 deletions android/src/main/java/com/tflite/TfliteModule.java
Original file line number Diff line number Diff line change
@@ -1,16 +1,21 @@
package com.tflite;

import android.util.Log;

import androidx.annotation.NonNull;

import com.facebook.react.bridge.JavaScriptContextHolder;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.module.annotations.ReactModule;
import com.facebook.react.turbomodule.core.CallInvokerHolderImpl;

/** @noinspection JavaJniMissingFunction*/
@ReactModule(name = TfliteModule.NAME)
public class TfliteModule extends ReactContextBaseJavaModule {
public static final String NAME = "Tflite";
public static final String NAME = "vision-camera-tflite";

public TfliteModule(ReactApplicationContext reactContext) {
super(reactContext);
Expand All @@ -22,16 +27,29 @@ public String getName() {
return NAME;
}

static {
System.loadLibrary("cpp");
@ReactMethod(isBlockingSynchronousMethod = true)
public boolean install() {
try {
Log.i(NAME, "Loading C++ library...");
System.loadLibrary("vision-camera-tflite");

JavaScriptContextHolder jsContext = getReactApplicationContext().getJavaScriptContextHolder();
CallInvokerHolderImpl callInvoker = (CallInvokerHolderImpl) getReactApplicationContext().getCatalystInstance().getJSCallInvokerHolder();

Log.i(NAME, "Installing JSI Bindings for VisionCamera Tflite plugin...");
boolean successful = nativeInstall(jsContext.get(), callInvoker);
if (successful) {
Log.i(NAME, "Successfully installed JSI Bindings!");
return true;
} else {
Log.e(NAME, "Failed to install JSI Bindings for VisionCamera Tflite plugin!");
return false;
}
} catch (Exception exception) {
Log.e(NAME, "Failed to install JSI Bindings!", exception);
return false;
}
}

private static native double nativeMultiply(double a, double b);

// Example method
// See https://reactnative.dev/docs/native-modules-android
@ReactMethod
public void multiply(double a, double b, Promise promise) {
promise.resolve(nativeMultiply(a, b));
}
private static native boolean nativeInstall(long jsiPtr, CallInvokerHolderImpl jsCallInvoker);
}

0 comments on commit eb17c00

Please sign in to comment.