Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
CaiMuCheng committed Jan 25, 2024
0 parents commit e974a86
Show file tree
Hide file tree
Showing 706 changed files with 221,619 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Auto detect text files and perform LF normalization
* text=auto
30 changes: 30 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Gradle files
.gradle/
build/

# Local configuration file (sdk path, etc)
local.properties

# Log/OS Files
*.log

# Android Studio generated files and folders
captures/
.externalNativeBuild/
.cxx/
*.apk
output.json

# IntelliJ
*.iml
.idea/

# Keystore files
*.jks
*.keystore

# Google Services (e.g. APIs or Firebase)
google-services.json

# Android Profiling
*.hprof
373 changes: 373 additions & 0 deletions LICENSE

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# NodeJava
Run NodeJS on Android with Java API
1 change: 1 addition & 0 deletions app/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
57 changes: 57 additions & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
@file:Suppress("UnstableApiUsage")

plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.jetbrains.kotlin.android)
}

android {
namespace = "com.mucheng.nodejava"
compileSdk = 34

defaultConfig {
applicationId = "com.mucheng.nodejava"
minSdk = 21
targetSdk = 34
versionCode = 1
versionName = "1.0"

testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
externalNativeBuild {
cmake {
cppFlags += "-std=c++17"
arguments += "-DANDROID_STL=c++_shared"
}
}
ndk {
//noinspection ChromeOsAbiSupport
abiFilters += setOf("arm64-v8a")
}
}

buildTypes {
release {
isMinifyEnabled = false
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = "1.8"
}
externalNativeBuild {
cmake {
path = file("src/main/cpp/CMakeLists.txt")
version = "3.22.1"
}
}
}

dependencies {
}
21 changes: 21 additions & 0 deletions app/proguard-rules.pro
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html

# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}

# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable

# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
20 changes: 20 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

<application
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@android:style/Theme.Material.Light.DarkActionBar"
android:roundIcon="@mipmap/ic_launcher_round">
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>

</manifest>
Empty file added app/src/main/assets/nodeJava.js
Empty file.
52 changes: 52 additions & 0 deletions app/src/main/cpp/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html.
# For more examples on how to use CMake, see https://github.com/android/ndk-samples.

# Sets the minimum CMake version required for this project.
cmake_minimum_required(VERSION 3.22.1)

# Declares the project name. The project name can be accessed via ${ PROJECT_NAME},
# Since this is the top level CMakeLists.txt, the project name is also accessible
# with ${CMAKE_PROJECT_NAME} (both CMake variables are in-sync within the top level
# build script scope).
project("nodejava")
set(CMAKE_CXX_STANDARD 17)
# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.
#
# In this top level CMakeLists.txt, ${CMAKE_PROJECT_NAME} is used to define
# the target library name; in the sub-module's CMakeLists.txt, ${PROJECT_NAME}
# is preferred for the same purpose.
#
# In order to load a library into your app from Java/Kotlin, you must call
# System.loadLibrary() and pass the name of the library defined here;
# for GameActivity/NativeActivity derived applications, the same library name must be
# used in the AndroidManifest.xml file.
add_library(${CMAKE_PROJECT_NAME} SHARED
# List C/C++ source files with relative paths to this CMakeLists.txt.
main.cpp
Util.cpp
Isolate.cpp
Context.cpp
)

target_include_directories(${CMAKE_PROJECT_NAME} PUBLIC
${CMAKE_SOURCE_DIR}
${CMAKE_SOURCE_DIR}/include
${CMAKE_SOURCE_DIR}/include/node
)

add_library(node SHARED IMPORTED)
set_target_properties(node PROPERTIES IMPORTED_LOCATION
${CMAKE_SOURCE_DIR}/natives/${CMAKE_ANDROID_ARCH_ABI}/libnode.so)

# Specifies libraries CMake should link to your target library. You
# can link libraries from various origins, such as libraries defined in this
# build script, prebuilt third-party libraries, or Android system libraries.
target_link_libraries(${CMAKE_PROJECT_NAME}
node
# List libraries link to the target library
android
log)
157 changes: 157 additions & 0 deletions app/src/main/cpp/Context.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
#include "Context.h"
#include "Isolate.h"
#include "Util.h"
#include "main.h"
#include "log.h"
#include <jni.h>

Context::Context(Isolate *isolate) {
this->isolate = isolate;

SETUP_ISOLATE_CLASS();
self.Reset(isolate->self, node::NewContext(isolate->self));

environment = node::CreateEnvironment(
isolate->isolateData,
self.Get(isolate->self),
Main::initializationResult->args(),
Main::initializationResult->exec_args(),
node::EnvironmentFlags::kOwnsProcessState
);
}

void Context::To(jobject instance, Context *self) {
Util::SetPtr(instance, "contextPtr", self);
}

Context *Context::From(jobject instance) {
return Util::GetPtrCast<Context *>(instance, "contextPtr");
}

extern "C"
JNIEXPORT void JNICALL
Java_com_mucheng_nodejava_core_Context_nativeCreateContext(JNIEnv *env, jobject thiz,
jlong isolatePtr) {
Isolate *isolate = Util::Cast<Isolate *>(isolatePtr);
Context *context = new Context(isolate);
Context::To(thiz, context);
}
extern "C"
JNIEXPORT void JNICALL
Java_com_mucheng_nodejava_core_Context_nativeLoadEnvironment(JNIEnv *env, jobject thiz,
jstring source) {
Context *context = Context::From(thiz);
Isolate *isolate = context->isolate;

SETUP_ISOLATE_CLASS();
SETUP_CONTEXT_CLASS();

v8::TryCatch tryCatch(isolate->self);
SetProcessExitHandler(context->environment, [](node::Environment *environment, int exitCode) {
Stop(environment, node::StopFlags::kDoNotTerminateIsolate);
LOGE("Process ExitCode: %d", exitCode);
});

v8::MaybeLocal<v8::Value> result;
if (source == nullptr) {
result = LoadEnvironment(context->environment,
[&](const node::StartExecutionCallbackInfo &info) -> v8::MaybeLocal<v8::Value> {
v8::EscapableHandleScope escapableHandleScope(isolate->self);
return escapableHandleScope.Escape(
v8::Undefined(isolate->self));
});
} else {
result = LoadEnvironment(context->environment, Util::JavaStr2CStr(source));
}

if (result.IsEmpty()) {
if (tryCatch.HasCaught()) {
v8::MaybeLocal<v8::Value> stackTrace = v8::TryCatch::StackTrace(
context->self.Get(isolate->self), tryCatch.Exception());
if (stackTrace.IsEmpty()) {
LOGE("Uncaught Environment Error: %s",
*v8::String::Utf8Value(isolate->self, tryCatch.Exception()));
} else {
Util::ThrowNodeException(
*v8::String::Utf8Value(isolate->self, stackTrace.ToLocalChecked()));
}
}
return;
}
}

extern "C"
JNIEXPORT jboolean JNICALL
Java_com_mucheng_nodejava_core_Context_nativeSpinEventLoop(JNIEnv *env, jobject thiz) {
Context *context = Context::From(thiz);
return SpinEventLoop(context->environment).FromMaybe(1) == 0;
}

extern "C"
JNIEXPORT void JNICALL
Java_com_mucheng_nodejava_core_Context_nativeStop(JNIEnv *env, jobject thiz) {
Context *context = Context::From(thiz);
Stop(context->environment, node::StopFlags::kDoNotTerminateIsolate);
}

extern "C"
JNIEXPORT void JNICALL
Java_com_mucheng_nodejava_core_Context_nativeEmitProcessExit(JNIEnv *env, jobject thiz) {
Context *context = Context::From(thiz);
EmitProcessExit(context->environment);
}

extern "C"
JNIEXPORT void JNICALL
Java_com_mucheng_nodejava_core_Context_nativeEvaluateScript(JNIEnv *env, jobject thiz,
jstring script) {
Context *context = Context::From(thiz);
Isolate *isolate = context->isolate;

SETUP_ISOLATE_CLASS();
SETUP_CONTEXT_CLASS();

v8::TryCatch tryCatch(isolate->self);
SetProcessExitHandler(context->environment, [](node::Environment *environment, int exitCode) {
Stop(environment, node::StopFlags::kDoNotTerminateIsolate);
LOGE("Process ExitCode: %d", exitCode);
});

v8::MaybeLocal<v8::Script> compiling = v8::Script::Compile(context->self.Get(isolate->self),
v8::String::NewFromUtf8(
isolate->self,
Util::JavaStr2CStr(
script)).ToLocalChecked());
if (compiling.IsEmpty()) {
if (tryCatch.HasCaught()) {
v8::MaybeLocal<v8::Value> stackTrace = v8::TryCatch::StackTrace(
context->self.Get(isolate->self), tryCatch.Exception());
if (stackTrace.IsEmpty()) {
LOGE("Uncaught Compiling Error: %s",
*v8::String::Utf8Value(isolate->self, tryCatch.Exception()));
} else {
Util::ThrowScriptCompilingException(
*v8::String::Utf8Value(isolate->self, stackTrace.ToLocalChecked()));
}
}
return;
}

v8::MaybeLocal<v8::Value> running = compiling.ToLocalChecked()->Run(
context->self.Get(isolate->self));

if (running.IsEmpty()) {
if (tryCatch.HasCaught()) {
v8::MaybeLocal<v8::Value> stackTrace = v8::TryCatch::StackTrace(
context->self.Get(isolate->self), tryCatch.Exception());
if (stackTrace.IsEmpty()) {
LOGE("Uncaught Runtime Error: %s",
*v8::String::Utf8Value(isolate->self, tryCatch.Exception()));
} else {
Util::ThrowScriptRuntimeException(
*v8::String::Utf8Value(isolate->self, stackTrace.ToLocalChecked()));
}
}
return;
}
}
23 changes: 23 additions & 0 deletions app/src/main/cpp/Context.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#ifndef NODEJAVA_CONTEXT_H
#define NODEJAVA_CONTEXT_H

#include "Isolate.h"
#include <jni.h>

#define SETUP_CONTEXT_CLASS() v8::Context::Scope contextScope(context->self.Get(isolate->self));

class Context {
public:
Isolate *isolate;
node::Environment *environment;
v8::Persistent<v8::Context> self;

Context(Isolate *isolate);

static void To(jobject instance, Context *self);

static Context *From(jobject instance);
};


#endif //NODEJAVA_CONTEXT_H
Loading

0 comments on commit e974a86

Please sign in to comment.