mirror of
https://github.com/wgh136/flutter_qjs.git
synced 2025-09-27 13:27:24 +00:00
fix js memory leak.
This commit is contained in:
@@ -3,8 +3,12 @@
|
|||||||
* @Author: ekibun
|
* @Author: ekibun
|
||||||
* @Date: 2020-08-08 08:16:50
|
* @Date: 2020-08-08 08:16:50
|
||||||
* @LastEditors: ekibun
|
* @LastEditors: ekibun
|
||||||
* @LastEditTime: 2020-08-20 14:55:13
|
* @LastEditTime: 2020-08-25 18:12:51
|
||||||
-->
|
-->
|
||||||
|
## 0.0.3
|
||||||
|
|
||||||
|
* fix js memory leak.
|
||||||
|
|
||||||
## 0.0.2
|
## 0.0.2
|
||||||
|
|
||||||
* update example.
|
* update example.
|
||||||
|
@@ -32,7 +32,7 @@ android {
|
|||||||
main.java.srcDirs += 'src/main/kotlin'
|
main.java.srcDirs += 'src/main/kotlin'
|
||||||
}
|
}
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
minSdkVersion 21
|
minSdkVersion 16
|
||||||
externalNativeBuild {
|
externalNativeBuild {
|
||||||
cmake {
|
cmake {
|
||||||
cppFlags "-std=c++17"
|
cppFlags "-std=c++17"
|
||||||
|
@@ -23,7 +23,7 @@ add_library( # Sets the name of the library.
|
|||||||
# quickjs
|
# quickjs
|
||||||
set(QUICK_JS_LIB_DIR ../../../../cxx/quickjs)
|
set(QUICK_JS_LIB_DIR ../../../../cxx/quickjs)
|
||||||
file (STRINGS "${QUICK_JS_LIB_DIR}/VERSION" QUICKJS_VERSION)
|
file (STRINGS "${QUICK_JS_LIB_DIR}/VERSION" QUICKJS_VERSION)
|
||||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DCONFIG_VERSION=\\\"${QUICKJS_VERSION}\\\"")
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DDUMP_LEAKS -DCONFIG_VERSION=\\\"${QUICKJS_VERSION}\\\"")
|
||||||
target_sources(${JNI_LIB_NAME} PUBLIC
|
target_sources(${JNI_LIB_NAME} PUBLIC
|
||||||
${QUICK_JS_LIB_DIR}/cutils.c
|
${QUICK_JS_LIB_DIR}/cutils.c
|
||||||
${QUICK_JS_LIB_DIR}/libregexp.c
|
${QUICK_JS_LIB_DIR}/libregexp.c
|
||||||
|
@@ -3,7 +3,7 @@
|
|||||||
* @Author: ekibun
|
* @Author: ekibun
|
||||||
* @Date: 2020-08-16 11:08:23
|
* @Date: 2020-08-16 11:08:23
|
||||||
* @LastEditors: ekibun
|
* @LastEditors: ekibun
|
||||||
* @LastEditTime: 2020-08-20 13:09:08
|
* @LastEditTime: 2020-08-25 18:06:08
|
||||||
*/
|
*/
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
@@ -45,10 +45,15 @@ namespace qjs
|
|||||||
JSValue array = JS_NewArray(ctx);
|
JSValue array = JS_NewArray(ctx);
|
||||||
auto buf = env->GetDoubleArrayElements((jdoubleArray)val, 0);
|
auto buf = env->GetDoubleArrayElements((jdoubleArray)val, 0);
|
||||||
for (uint32_t i = 0; i < size; i++)
|
for (uint32_t i = 0; i < size; i++)
|
||||||
|
{
|
||||||
|
auto atom = JS_NewAtomUInt32(ctx, i);
|
||||||
JS_DefinePropertyValue(
|
JS_DefinePropertyValue(
|
||||||
ctx, array, JS_NewAtomUInt32(ctx, i),
|
ctx, array, atom,
|
||||||
JS_NewFloat64(ctx, buf[i]),
|
JS_NewFloat64(ctx, buf[i]),
|
||||||
JS_PROP_C_W_E);
|
JS_PROP_C_W_E);
|
||||||
|
JS_FreeAtom(ctx, atom);
|
||||||
|
}
|
||||||
|
|
||||||
return array;
|
return array;
|
||||||
}
|
}
|
||||||
else if (className.compare("java.lang.Boolean") == 0)
|
else if (className.compare("java.lang.Boolean") == 0)
|
||||||
@@ -82,10 +87,15 @@ namespace qjs
|
|||||||
JSValue array = JS_NewArray(ctx);
|
JSValue array = JS_NewArray(ctx);
|
||||||
cache[val] = array;
|
cache[val] = array;
|
||||||
for (uint32_t i = 0; i < size; i++)
|
for (uint32_t i = 0; i < size; i++)
|
||||||
|
{
|
||||||
|
auto atom = JS_NewAtomUInt32(ctx, i);
|
||||||
JS_DefinePropertyValue(
|
JS_DefinePropertyValue(
|
||||||
ctx, array, JS_NewAtomUInt32(ctx, i),
|
ctx, array, atom,
|
||||||
javaToJs(ctx, env, env->GetObjectArrayElement(list, i), cache),
|
javaToJs(ctx, env, env->GetObjectArrayElement(list, i), cache),
|
||||||
JS_PROP_C_W_E);
|
JS_PROP_C_W_E);
|
||||||
|
JS_FreeAtom(ctx, atom);
|
||||||
|
}
|
||||||
|
|
||||||
return array;
|
return array;
|
||||||
}
|
}
|
||||||
else if (className.compare("java.util.HashMap") == 0)
|
else if (className.compare("java.util.HashMap") == 0)
|
||||||
@@ -119,10 +129,14 @@ namespace qjs
|
|||||||
{
|
{
|
||||||
// 读取一条数据
|
// 读取一条数据
|
||||||
jobject entryObj = env->CallObjectMethod(iteratorObj, nextMID);
|
jobject entryObj = env->CallObjectMethod(iteratorObj, nextMID);
|
||||||
|
auto atomvalue = javaToJs(ctx, env, env->CallObjectMethod(entryObj, getKeyMID), cache);
|
||||||
|
auto atom = JS_ValueToAtom(ctx, atomvalue);
|
||||||
JS_DefinePropertyValue(
|
JS_DefinePropertyValue(
|
||||||
ctx, obj, JS_ValueToAtom(ctx, javaToJs(ctx, env, env->CallObjectMethod(entryObj, getKeyMID), cache)),
|
ctx, obj, atom,
|
||||||
javaToJs(ctx, env, env->CallObjectMethod(entryObj, getValueMID), cache),
|
javaToJs(ctx, env, env->CallObjectMethod(entryObj, getValueMID), cache),
|
||||||
JS_PROP_C_W_E);
|
JS_PROP_C_W_E);
|
||||||
|
JS_FreeAtom(ctx, atom);
|
||||||
|
JS_FreeValue(ctx, atomvalue);
|
||||||
}
|
}
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
@@ -158,7 +172,7 @@ namespace qjs
|
|||||||
if (JS_IsFunction(val.ctx, val.v))
|
if (JS_IsFunction(val.ctx, val.v))
|
||||||
{
|
{
|
||||||
std::map<jobject, jobject> retMap;
|
std::map<jobject, jobject> retMap;
|
||||||
retMap[env->NewStringUTF("__js_function__")] = jniWrapPrimity<jlong>(env, (int64_t) new JSValue{JS_DupValue(val.ctx, val.v)});
|
retMap[env->NewStringUTF("__js_function__")] = jniWrapPrimity<jlong>(env, (int64_t) new JSValue{js_add_ref(val)});
|
||||||
return jniWrapMap(env, retMap);
|
return jniWrapMap(env, retMap);
|
||||||
}
|
}
|
||||||
else if (JS_IsArray(val.ctx, val.v) > 0)
|
else if (JS_IsArray(val.ctx, val.v) > 0)
|
||||||
|
@@ -3,9 +3,10 @@
|
|||||||
* @Author: ekibun
|
* @Author: ekibun
|
||||||
* @Date: 2020-08-09 18:16:11
|
* @Date: 2020-08-09 18:16:11
|
||||||
* @LastEditors: ekibun
|
* @LastEditors: ekibun
|
||||||
* @LastEditTime: 2020-08-16 19:00:06
|
* @LastEditTime: 2020-08-25 16:00:46
|
||||||
*/
|
*/
|
||||||
#include "java_js_wrapper.hpp"
|
#include "java_js_wrapper.hpp"
|
||||||
|
#include "android/log.h"
|
||||||
|
|
||||||
JNIEnv *getEnv(JavaVM *gJvm)
|
JNIEnv *getEnv(JavaVM *gJvm)
|
||||||
{
|
{
|
||||||
@@ -109,7 +110,7 @@ Java_soko_ekibun_flutter_1qjs_JniBridge_close(
|
|||||||
jobject thiz,
|
jobject thiz,
|
||||||
jlong engine)
|
jlong engine)
|
||||||
{
|
{
|
||||||
delete (qjs::Engine *)engine;
|
delete ((qjs::Engine *)engine);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" JNIEXPORT void JNICALL
|
extern "C" JNIEXPORT void JNICALL
|
||||||
@@ -136,8 +137,8 @@ Java_soko_ekibun_flutter_1qjs_JniBridge_call(
|
|||||||
callargs[i] = qjs::javaToJs(ctx.ctx, env, env->GetObjectArrayElement(array, i));
|
callargs[i] = qjs::javaToJs(ctx.ctx, env, env->GetObjectArrayElement(array, i));
|
||||||
}
|
}
|
||||||
jvm->DetachCurrentThread();
|
jvm->DetachCurrentThread();
|
||||||
qjs::JSValue ret = JS_Call(ctx.ctx, *function, ctx.global(), (int)argscount, callargs);
|
qjs::JSValue ret = qjs::call_handler(ctx.ctx, *function, (int)argscount, callargs);
|
||||||
qjs::JS_FreeValue(ctx.ctx, *function);
|
delete[] callargs;
|
||||||
if (qjs::JS_IsException(ret))
|
if (qjs::JS_IsException(ret))
|
||||||
throw qjs::exception{};
|
throw qjs::exception{};
|
||||||
return qjs::Value{ctx.ctx, ret};
|
return qjs::Value{ctx.ctx, ret};
|
||||||
|
@@ -21,7 +21,7 @@ class FlutterQjsPlugin: FlutterPlugin, MethodCallHandler {
|
|||||||
|
|
||||||
override fun onAttachedToEngine(flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
|
override fun onAttachedToEngine(flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
|
||||||
applicationContext = flutterPluginBinding.applicationContext
|
applicationContext = flutterPluginBinding.applicationContext
|
||||||
val channel = MethodChannel(flutterPluginBinding.binaryMessenger, "soko.ekibun.flutter_qjs")
|
channel = MethodChannel(flutterPluginBinding.binaryMessenger, "soko.ekibun.flutter_qjs")
|
||||||
channel.setMethodCallHandler(this)
|
channel.setMethodCallHandler(this)
|
||||||
channelwrapper = MethodChannelWrapper(handler, channel)
|
channelwrapper = MethodChannelWrapper(handler, channel)
|
||||||
}
|
}
|
||||||
@@ -37,13 +37,13 @@ class FlutterQjsPlugin: FlutterPlugin, MethodCallHandler {
|
|||||||
val name: String = call.argument<String>("name")!!
|
val name: String = call.argument<String>("name")!!
|
||||||
JniBridge.instance.evaluate(engine, script, name, ResultWrapper(handler, result))
|
JniBridge.instance.evaluate(engine, script, name, ResultWrapper(handler, result))
|
||||||
} else if (call.method == "call") {
|
} else if (call.method == "call") {
|
||||||
println(call.arguments<Map<*, *>>());
|
|
||||||
val engine: Long = call.argument<Long>("engine")!!
|
val engine: Long = call.argument<Long>("engine")!!
|
||||||
val function: Long = call.argument<Long>("function")!!
|
val function: Long = call.argument<Long>("function")!!
|
||||||
val args: List<Any> = call.argument<List<Any>>("arguments")!!
|
val args: List<Any> = call.argument<List<Any>>("arguments")!!
|
||||||
JniBridge.instance.call(engine, function, args, ResultWrapper(handler, result))
|
JniBridge.instance.call(engine, function, args, ResultWrapper(handler, result))
|
||||||
} else if (call.method == "close") {
|
} else if (call.method == "close") {
|
||||||
val engine: Long = call.argument<Long>("engine")!!
|
val engine: Long = call.arguments<Long>()
|
||||||
|
println(engine)
|
||||||
JniBridge.instance.close(engine)
|
JniBridge.instance.close(engine)
|
||||||
result.success(null)
|
result.success(null)
|
||||||
} else {
|
} else {
|
||||||
|
@@ -3,7 +3,7 @@
|
|||||||
* @Author: ekibun
|
* @Author: ekibun
|
||||||
* @Date: 2020-08-07 13:55:52
|
* @Date: 2020-08-07 13:55:52
|
||||||
* @LastEditors: ekibun
|
* @LastEditors: ekibun
|
||||||
* @LastEditTime: 2020-08-20 13:09:52
|
* @LastEditTime: 2020-08-25 16:07:29
|
||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "quickjs/quickjspp.hpp"
|
#include "quickjs/quickjspp.hpp"
|
||||||
@@ -17,7 +17,7 @@ namespace std
|
|||||||
{
|
{
|
||||||
size_t operator()(const qjs::Value &key) const
|
size_t operator()(const qjs::Value &key) const
|
||||||
{
|
{
|
||||||
return (size_t) JS_VALUE_GET_PTR(key.v);
|
return (size_t)JS_VALUE_GET_PTR(key.v);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
} // namespace std
|
} // namespace std
|
||||||
@@ -46,12 +46,30 @@ namespace qjs
|
|||||||
JSValue reject;
|
JSValue reject;
|
||||||
} JSOSFuture;
|
} JSOSFuture;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
struct list_head link;
|
||||||
|
JSValue ref;
|
||||||
|
} JSOSRef;
|
||||||
|
|
||||||
typedef struct JSThreadState
|
typedef struct JSThreadState
|
||||||
{
|
{
|
||||||
struct list_head os_future; /* list of JSOSFuture.link */
|
struct list_head os_future;
|
||||||
|
struct list_head os_ref;
|
||||||
DartChannel channel;
|
DartChannel channel;
|
||||||
} JSThreadState;
|
} JSThreadState;
|
||||||
|
|
||||||
|
JSValue js_add_ref(Value val)
|
||||||
|
{
|
||||||
|
JSRuntime *rt = JS_GetRuntime(val.ctx);
|
||||||
|
JSThreadState *ts = (JSThreadState *)JS_GetRuntimeOpaque(rt);
|
||||||
|
JSOSRef *th;
|
||||||
|
th = (JSOSRef *)js_mallocz(val.ctx, sizeof(*th));
|
||||||
|
th->ref = JS_DupValue(val.ctx, val.v);
|
||||||
|
list_add_tail(&th->link, &ts->os_ref);
|
||||||
|
return th->ref;
|
||||||
|
}
|
||||||
|
|
||||||
static JSValue js_add_future(Value resolve, Value reject, std::promise<JSFutureReturn> *promise)
|
static JSValue js_add_future(Value resolve, Value reject, std::promise<JSFutureReturn> *promise)
|
||||||
{
|
{
|
||||||
JSRuntime *rt = JS_GetRuntime(resolve.ctx);
|
JSRuntime *rt = JS_GetRuntime(resolve.ctx);
|
||||||
@@ -91,6 +109,21 @@ namespace qjs
|
|||||||
return js_add_future(resolve, reject, ts->channel(name, args));
|
return js_add_future(resolve, reject, ts->channel(name, args));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void unlink_ref(JSRuntime *rt, JSOSRef *th)
|
||||||
|
{
|
||||||
|
if (th->link.prev)
|
||||||
|
{
|
||||||
|
list_del(&th->link);
|
||||||
|
th->link.prev = th->link.next = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void free_ref(JSRuntime *rt, JSOSRef *th)
|
||||||
|
{
|
||||||
|
JS_FreeValueRT(rt, th->ref);
|
||||||
|
js_free_rt(rt, th);
|
||||||
|
}
|
||||||
|
|
||||||
static void unlink_future(JSRuntime *rt, JSOSFuture *th)
|
static void unlink_future(JSRuntime *rt, JSOSFuture *th)
|
||||||
{
|
{
|
||||||
if (th->link.prev)
|
if (th->link.prev)
|
||||||
@@ -117,6 +150,7 @@ namespace qjs
|
|||||||
}
|
}
|
||||||
memset(ts, 0, sizeof(*ts));
|
memset(ts, 0, sizeof(*ts));
|
||||||
init_list_head(&ts->os_future);
|
init_list_head(&ts->os_future);
|
||||||
|
init_list_head(&ts->os_ref);
|
||||||
ts->channel = channel;
|
ts->channel = channel;
|
||||||
|
|
||||||
JS_SetRuntimeOpaque(rt, ts);
|
JS_SetRuntimeOpaque(rt, ts);
|
||||||
@@ -135,12 +169,18 @@ namespace qjs
|
|||||||
unlink_future(rt, th);
|
unlink_future(rt, th);
|
||||||
free_future(rt, th);
|
free_future(rt, th);
|
||||||
}
|
}
|
||||||
|
list_for_each_safe(el, el1, &ts->os_ref)
|
||||||
|
{
|
||||||
|
JSOSRef *th = list_entry(el, JSOSRef, link);
|
||||||
|
unlink_ref(rt, th);
|
||||||
|
free_ref(rt, th);
|
||||||
|
}
|
||||||
ts->channel = nullptr;
|
ts->channel = nullptr;
|
||||||
free(ts);
|
free(ts);
|
||||||
JS_SetRuntimeOpaque(rt, NULL); /* fail safe */
|
JS_SetRuntimeOpaque(rt, NULL); /* fail safe */
|
||||||
}
|
}
|
||||||
|
|
||||||
static void call_handler(JSContext *ctx, JSValueConst func, int count, JSValue *argv)
|
static JSValue call_handler(JSContext *ctx, JSValueConst func, int count, JSValue *argv)
|
||||||
{
|
{
|
||||||
JSValue ret, func1;
|
JSValue ret, func1;
|
||||||
/* 'func' might be destroyed when calling itself (if it frees the
|
/* 'func' might be destroyed when calling itself (if it frees the
|
||||||
@@ -148,9 +188,9 @@ namespace qjs
|
|||||||
func1 = JS_DupValue(ctx, func);
|
func1 = JS_DupValue(ctx, func);
|
||||||
ret = JS_Call(ctx, func1, JS_UNDEFINED, count, argv);
|
ret = JS_Call(ctx, func1, JS_UNDEFINED, count, argv);
|
||||||
JS_FreeValue(ctx, func1);
|
JS_FreeValue(ctx, func1);
|
||||||
if (JS_IsException(ret))
|
for (int i = 0; i < count; ++i)
|
||||||
throw exception{};
|
JS_FreeValue(ctx, argv[i]);
|
||||||
JS_FreeValue(ctx, ret);
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int js_dart_poll(JSContext *ctx)
|
static int js_dart_poll(JSContext *ctx)
|
||||||
@@ -182,9 +222,10 @@ namespace qjs
|
|||||||
th->reject = JS_UNDEFINED;
|
th->reject = JS_UNDEFINED;
|
||||||
unlink_future(rt, th);
|
unlink_future(rt, th);
|
||||||
free_future(rt, th);
|
free_future(rt, th);
|
||||||
call_handler(ctx, argv.count < 0 ? reject : resolve, abs(argv.count), argv.argv);
|
JSValue ret = call_handler(ctx, argv.count < 0 ? reject : resolve, abs(argv.count), argv.argv);
|
||||||
for (int i = 0; i < abs(argv.count); ++i)
|
if (qjs::JS_IsException(ret))
|
||||||
JS_FreeValue(ctx, argv.argv[i]);
|
throw qjs::exception{};
|
||||||
|
JS_FreeValue(ctx, ret);
|
||||||
JS_FreeValue(ctx, resolve);
|
JS_FreeValue(ctx, resolve);
|
||||||
JS_FreeValue(ctx, reject);
|
JS_FreeValue(ctx, reject);
|
||||||
delete argv.argv;
|
delete argv.argv;
|
||||||
|
@@ -37,6 +37,12 @@
|
|||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(__ANDROID__)
|
||||||
|
#include <android/log.h>
|
||||||
|
#undef printf
|
||||||
|
#define printf(...) __android_log_print(ANDROID_LOG_INFO, "qjs", __VA_ARGS__)
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
#include <WinSock2.h>
|
#include <WinSock2.h>
|
||||||
|
|
||||||
|
@@ -39,7 +39,7 @@ android {
|
|||||||
defaultConfig {
|
defaultConfig {
|
||||||
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
|
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
|
||||||
applicationId "soko.ekibun.example"
|
applicationId "soko.ekibun.example"
|
||||||
minSdkVersion 21
|
minSdkVersion 16
|
||||||
targetSdkVersion 28
|
targetSdkVersion 28
|
||||||
versionCode flutterVersionCode.toInteger()
|
versionCode flutterVersionCode.toInteger()
|
||||||
versionName flutterVersionName
|
versionName flutterVersionName
|
||||||
|
@@ -3,7 +3,7 @@
|
|||||||
* @Author: ekibun
|
* @Author: ekibun
|
||||||
* @Date: 2020-08-08 08:16:51
|
* @Date: 2020-08-08 08:16:51
|
||||||
* @LastEditors: ekibun
|
* @LastEditors: ekibun
|
||||||
* @LastEditTime: 2020-08-20 14:42:10
|
* @LastEditTime: 2020-08-24 22:26:03
|
||||||
*/
|
*/
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'dart:typed_data';
|
import 'dart:typed_data';
|
||||||
@@ -109,7 +109,7 @@ class _TestPageState extends State<TestPage> {
|
|||||||
FlatButton(
|
FlatButton(
|
||||||
child: Text("close engine"),
|
child: Text("close engine"),
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
if (engine != null) return;
|
if (engine == null) return;
|
||||||
await engine.destroy();
|
await engine.destroy();
|
||||||
engine = null;
|
engine = null;
|
||||||
}),
|
}),
|
||||||
|
@@ -75,7 +75,7 @@ packages:
|
|||||||
path: ".."
|
path: ".."
|
||||||
relative: true
|
relative: true
|
||||||
source: path
|
source: path
|
||||||
version: "0.0.2"
|
version: "0.0.3"
|
||||||
flutter_test:
|
flutter_test:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description: flutter
|
description: flutter
|
||||||
|
@@ -1 +1 @@
|
|||||||
5
|
6
|
||||||
|
@@ -34,7 +34,7 @@ add_dependencies(flutter flutter_assemble)
|
|||||||
|
|
||||||
# === Wrapper ===
|
# === Wrapper ===
|
||||||
list(APPEND CPP_WRAPPER_SOURCES_CORE
|
list(APPEND CPP_WRAPPER_SOURCES_CORE
|
||||||
"engine_method_result.cc"
|
"core_implementations.cc"
|
||||||
"standard_codec.cc"
|
"standard_codec.cc"
|
||||||
)
|
)
|
||||||
list(TRANSFORM CPP_WRAPPER_SOURCES_CORE PREPEND "${WRAPPER_ROOT}/")
|
list(TRANSFORM CPP_WRAPPER_SOURCES_CORE PREPEND "${WRAPPER_ROOT}/")
|
||||||
|
@@ -1,5 +1,7 @@
|
|||||||
#include "flutter_window.h"
|
#include "flutter_window.h"
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
#include "flutter/generated_plugin_registrant.h"
|
#include "flutter/generated_plugin_registrant.h"
|
||||||
|
|
||||||
FlutterWindow::FlutterWindow(RunLoop* run_loop,
|
FlutterWindow::FlutterWindow(RunLoop* run_loop,
|
||||||
@@ -34,3 +36,19 @@ void FlutterWindow::OnDestroy() {
|
|||||||
|
|
||||||
Win32Window::OnDestroy();
|
Win32Window::OnDestroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LRESULT
|
||||||
|
FlutterWindow::MessageHandler(HWND hwnd, UINT const message,
|
||||||
|
WPARAM const wparam,
|
||||||
|
LPARAM const lparam) noexcept {
|
||||||
|
// Give Flutter, including plugins, an opporutunity to handle window messages.
|
||||||
|
if (flutter_controller_) {
|
||||||
|
std::optional<LRESULT> result =
|
||||||
|
flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam,
|
||||||
|
lparam);
|
||||||
|
if (result) {
|
||||||
|
return *result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Win32Window::MessageHandler(hwnd, message, wparam, lparam);
|
||||||
|
}
|
||||||
|
@@ -4,11 +4,11 @@
|
|||||||
#include <flutter/dart_project.h>
|
#include <flutter/dart_project.h>
|
||||||
#include <flutter/flutter_view_controller.h>
|
#include <flutter/flutter_view_controller.h>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#include "run_loop.h"
|
#include "run_loop.h"
|
||||||
#include "win32_window.h"
|
#include "win32_window.h"
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
// A window that does nothing but host a Flutter view.
|
// A window that does nothing but host a Flutter view.
|
||||||
class FlutterWindow : public Win32Window {
|
class FlutterWindow : public Win32Window {
|
||||||
public:
|
public:
|
||||||
@@ -22,6 +22,8 @@ class FlutterWindow : public Win32Window {
|
|||||||
// Win32Window:
|
// Win32Window:
|
||||||
bool OnCreate() override;
|
bool OnCreate() override;
|
||||||
void OnDestroy() override;
|
void OnDestroy() override;
|
||||||
|
LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam,
|
||||||
|
LPARAM const lparam) noexcept override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// The run loop driving events for this window.
|
// The run loop driving events for this window.
|
||||||
|
@@ -154,13 +154,6 @@ Win32Window::MessageHandler(HWND hwnd,
|
|||||||
UINT const message,
|
UINT const message,
|
||||||
WPARAM const wparam,
|
WPARAM const wparam,
|
||||||
LPARAM const lparam) noexcept {
|
LPARAM const lparam) noexcept {
|
||||||
auto window =
|
|
||||||
reinterpret_cast<Win32Window*>(GetWindowLongPtr(hwnd, GWLP_USERDATA));
|
|
||||||
|
|
||||||
if (window == nullptr) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (message) {
|
switch (message) {
|
||||||
case WM_DESTROY:
|
case WM_DESTROY:
|
||||||
window_handle_ = nullptr;
|
window_handle_ = nullptr;
|
||||||
|
@@ -38,14 +38,14 @@ class FlutterJs {
|
|||||||
destroy() async {
|
destroy() async {
|
||||||
if (_engine != null) {
|
if (_engine != null) {
|
||||||
await _FlutterJs.instance._channel
|
await _FlutterJs.instance._channel
|
||||||
.invokeMethod("close", {"engine": _engine});
|
.invokeMethod("close", _engine);
|
||||||
_engine = null;
|
_engine = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Evaluate js script.
|
/// Evaluate js script.
|
||||||
Future<dynamic> evaluate(String command, String name) async {
|
Future<dynamic> evaluate(String command, String name) async {
|
||||||
_ensureEngine();
|
await _ensureEngine();
|
||||||
var arguments = {"engine": _engine, "script": command, "name": name};
|
var arguments = {"engine": _engine, "script": command, "name": name};
|
||||||
return _FlutterJs.instance._wrapFunctionArguments(
|
return _FlutterJs.instance._wrapFunctionArguments(
|
||||||
await _FlutterJs.instance._channel.invokeMethod("evaluate", arguments),
|
await _FlutterJs.instance._channel.invokeMethod("evaluate", arguments),
|
||||||
@@ -62,7 +62,6 @@ class _FlutterJs {
|
|||||||
Map<dynamic, JsMethodHandler>();
|
Map<dynamic, JsMethodHandler>();
|
||||||
_FlutterJs._internal() {
|
_FlutterJs._internal() {
|
||||||
_channel.setMethodCallHandler((call) async {
|
_channel.setMethodCallHandler((call) async {
|
||||||
print(call.arguments);
|
|
||||||
var engine = call.arguments["engine"];
|
var engine = call.arguments["engine"];
|
||||||
var args = call.arguments["args"];
|
var args = call.arguments["args"];
|
||||||
if (methodHandlers[engine] == null) return call.noSuchMethod(null);
|
if (methodHandlers[engine] == null) return call.noSuchMethod(null);
|
||||||
|
@@ -10,6 +10,7 @@ add_library(libquickjs SHARED
|
|||||||
)
|
)
|
||||||
project(libquickjs LANGUAGES C)
|
project(libquickjs LANGUAGES C)
|
||||||
target_compile_options(libquickjs PRIVATE "-DCONFIG_VERSION=\"${QUICKJS_VERSION}\"")
|
target_compile_options(libquickjs PRIVATE "-DCONFIG_VERSION=\"${QUICKJS_VERSION}\"")
|
||||||
|
target_compile_options(libquickjs PRIVATE "-DDUMP_LEAKS")
|
||||||
|
|
||||||
set(PROJECT_NAME "flutter_qjs")
|
set(PROJECT_NAME "flutter_qjs")
|
||||||
project(${PROJECT_NAME} LANGUAGES CXX)
|
project(${PROJECT_NAME} LANGUAGES CXX)
|
||||||
|
@@ -3,7 +3,7 @@
|
|||||||
* @Author: ekibun
|
* @Author: ekibun
|
||||||
* @Date: 2020-08-14 21:45:02
|
* @Date: 2020-08-14 21:45:02
|
||||||
* @LastEditors: ekibun
|
* @LastEditors: ekibun
|
||||||
* @LastEditTime: 2020-08-20 13:09:21
|
* @LastEditTime: 2020-08-25 18:11:19
|
||||||
*/
|
*/
|
||||||
#include "../cxx/js_engine.hpp"
|
#include "../cxx/js_engine.hpp"
|
||||||
#include <flutter_linux/flutter_linux.h>
|
#include <flutter_linux/flutter_linux.h>
|
||||||
@@ -37,9 +37,14 @@ namespace qjs
|
|||||||
auto size = (uint32_t)fl_value_get_length(val);
|
auto size = (uint32_t)fl_value_get_length(val);
|
||||||
JSValue array = JS_NewArray(ctx);
|
JSValue array = JS_NewArray(ctx);
|
||||||
for (uint32_t i = 0; i < size; ++i)
|
for (uint32_t i = 0; i < size; ++i)
|
||||||
|
{
|
||||||
|
auto atom = JS_NewAtomUInt32(ctx, i);
|
||||||
JS_DefinePropertyValue(
|
JS_DefinePropertyValue(
|
||||||
ctx, array, JS_NewAtomUInt32(ctx, i), JS_NewFloat64(ctx, buf[i]),
|
ctx, array, atom, JS_NewFloat64(ctx, buf[i]),
|
||||||
JS_PROP_C_W_E);
|
JS_PROP_C_W_E);
|
||||||
|
JS_FreeAtom(ctx, atom);
|
||||||
|
}
|
||||||
|
|
||||||
return array;
|
return array;
|
||||||
}
|
}
|
||||||
case FL_VALUE_TYPE_LIST:
|
case FL_VALUE_TYPE_LIST:
|
||||||
@@ -47,10 +52,14 @@ namespace qjs
|
|||||||
auto size = (uint32_t)fl_value_get_length(val);
|
auto size = (uint32_t)fl_value_get_length(val);
|
||||||
JSValue array = JS_NewArray(ctx);
|
JSValue array = JS_NewArray(ctx);
|
||||||
for (uint32_t i = 0; i < size; ++i)
|
for (uint32_t i = 0; i < size; ++i)
|
||||||
|
{
|
||||||
|
auto atom = JS_NewAtomUInt32(ctx, i);
|
||||||
JS_DefinePropertyValue(
|
JS_DefinePropertyValue(
|
||||||
ctx, array, JS_NewAtomUInt32(ctx, i),
|
ctx, array, atom,
|
||||||
dartToJs(ctx, fl_value_get_list_value(val, i)),
|
dartToJs(ctx, fl_value_get_list_value(val, i)),
|
||||||
JS_PROP_C_W_E);
|
JS_PROP_C_W_E);
|
||||||
|
JS_FreeAtom(ctx, atom);
|
||||||
|
}
|
||||||
return array;
|
return array;
|
||||||
}
|
}
|
||||||
case FL_VALUE_TYPE_MAP:
|
case FL_VALUE_TYPE_MAP:
|
||||||
@@ -58,11 +67,16 @@ namespace qjs
|
|||||||
auto size = (uint32_t)fl_value_get_length(val);
|
auto size = (uint32_t)fl_value_get_length(val);
|
||||||
JSValue obj = JS_NewObject(ctx);
|
JSValue obj = JS_NewObject(ctx);
|
||||||
for (uint32_t i = 0; i < size; ++i)
|
for (uint32_t i = 0; i < size; ++i)
|
||||||
|
{
|
||||||
|
auto atomvalue = dartToJs(ctx, fl_value_get_map_key(val, i));
|
||||||
|
auto atom = JS_ValueToAtom(ctx, atomvalue);
|
||||||
JS_DefinePropertyValue(
|
JS_DefinePropertyValue(
|
||||||
ctx, obj,
|
ctx, obj, atom,
|
||||||
JS_ValueToAtom(ctx, dartToJs(ctx, fl_value_get_map_key(val, i))),
|
|
||||||
dartToJs(ctx, fl_value_get_map_value(val, i)),
|
dartToJs(ctx, fl_value_get_map_value(val, i)),
|
||||||
JS_PROP_C_W_E);
|
JS_PROP_C_W_E);
|
||||||
|
JS_FreeAtom(ctx, atom);
|
||||||
|
JS_FreeValue(ctx, atomvalue);
|
||||||
|
}
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@@ -93,7 +107,7 @@ namespace qjs
|
|||||||
if (JS_IsFunction(val.ctx, val.v))
|
if (JS_IsFunction(val.ctx, val.v))
|
||||||
{
|
{
|
||||||
FlValue *retMap = fl_value_new_map();
|
FlValue *retMap = fl_value_new_map();
|
||||||
fl_value_set_string_take(retMap, "__js_function__", fl_value_new_int((int64_t) new JSValue{JS_DupValue(val.ctx, val.v)}));
|
fl_value_set_string_take(retMap, "__js_function__", fl_value_new_int((int64_t) new JSValue{js_add_ref(val)}));
|
||||||
return retMap;
|
return retMap;
|
||||||
}
|
}
|
||||||
else if (JS_IsArray(val.ctx, val.v) > 0)
|
else if (JS_IsArray(val.ctx, val.v) > 0)
|
||||||
|
@@ -3,7 +3,7 @@
|
|||||||
* @Author: ekibun
|
* @Author: ekibun
|
||||||
* @Date: 2020-08-17 21:37:11
|
* @Date: 2020-08-17 21:37:11
|
||||||
* @LastEditors: ekibun
|
* @LastEditors: ekibun
|
||||||
* @LastEditTime: 2020-08-18 23:22:08
|
* @LastEditTime: 2020-08-25 16:07:02
|
||||||
*/
|
*/
|
||||||
#include "include/flutter_qjs/flutter_qjs_plugin.h"
|
#include "include/flutter_qjs/flutter_qjs_plugin.h"
|
||||||
|
|
||||||
@@ -112,8 +112,8 @@ static void flutter_qjs_plugin_handle_method_call(
|
|||||||
{
|
{
|
||||||
callargs[i] = qjs::dartToJs(ctx.ctx, fl_value_get_list_value(arguments, i));
|
callargs[i] = qjs::dartToJs(ctx.ctx, fl_value_get_list_value(arguments, i));
|
||||||
}
|
}
|
||||||
qjs::JSValue ret = JS_Call(ctx.ctx, *function, qjs::JSValue{qjs::JSValueUnion{0}, qjs::JS_TAG_UNDEFINED}, (int)argscount, callargs);
|
qjs::JSValue ret = qjs::call_handler(ctx.ctx, *function, (int)argscount, callargs);
|
||||||
qjs::JS_FreeValue(ctx.ctx, *function);
|
delete[] callargs;
|
||||||
if (qjs::JS_IsException(ret))
|
if (qjs::JS_IsException(ret))
|
||||||
throw qjs::exception{};
|
throw qjs::exception{};
|
||||||
return qjs::Value{ctx.ctx, ret};
|
return qjs::Value{ctx.ctx, ret};
|
||||||
@@ -128,6 +128,13 @@ static void flutter_qjs_plugin_handle_method_call(
|
|||||||
g_object_unref(pmethod_call);
|
g_object_unref(pmethod_call);
|
||||||
}});
|
}});
|
||||||
}
|
}
|
||||||
|
else if (strcmp(method, "close") == 0)
|
||||||
|
{
|
||||||
|
qjs::Engine *engine = (qjs::Engine *)fl_value_get_int(fl_method_call_get_args(method_call));
|
||||||
|
delete engine;
|
||||||
|
g_autoptr(FlMethodResponse) response = FL_METHOD_RESPONSE(fl_method_success_response_new(fl_value_new_null()));
|
||||||
|
fl_method_call_respond(method_call, response, nullptr);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
g_autoptr(FlMethodResponse) response = FL_METHOD_RESPONSE(fl_method_not_implemented_response_new());
|
g_autoptr(FlMethodResponse) response = FL_METHOD_RESPONSE(fl_method_not_implemented_response_new());
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
name: flutter_qjs
|
name: flutter_qjs
|
||||||
description: This plugin is a simple js engine for flutter using the `quickjs` project. Plugin currently supports Windows, Linux, and Android.
|
description: This plugin is a simple js engine for flutter using the `quickjs` project. Plugin currently supports Windows, Linux, and Android.
|
||||||
version: 0.0.2
|
version: 0.0.3
|
||||||
homepage: https://github.com/ekibun/flutter_qjs
|
homepage: https://github.com/ekibun/flutter_qjs
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
|
@@ -11,6 +11,7 @@ add_library(libquickjs STATIC
|
|||||||
)
|
)
|
||||||
project(libquickjs LANGUAGES C)
|
project(libquickjs LANGUAGES C)
|
||||||
target_compile_options(libquickjs PRIVATE "-DCONFIG_VERSION=\"${QUICKJS_VERSION}\"")
|
target_compile_options(libquickjs PRIVATE "-DCONFIG_VERSION=\"${QUICKJS_VERSION}\"")
|
||||||
|
target_compile_options(libquickjs PRIVATE "-DDUMP_LEAKS")
|
||||||
|
|
||||||
set(PROJECT_NAME "flutter_qjs")
|
set(PROJECT_NAME "flutter_qjs")
|
||||||
project(${PROJECT_NAME} LANGUAGES CXX)
|
project(${PROJECT_NAME} LANGUAGES CXX)
|
||||||
|
@@ -3,7 +3,7 @@
|
|||||||
* @Author: ekibun
|
* @Author: ekibun
|
||||||
* @Date: 2020-08-14 21:45:02
|
* @Date: 2020-08-14 21:45:02
|
||||||
* @LastEditors: ekibun
|
* @LastEditors: ekibun
|
||||||
* @LastEditTime: 2020-08-20 13:06:24
|
* @LastEditTime: 2020-08-25 18:08:45
|
||||||
*/
|
*/
|
||||||
#include "../cxx/js_engine.hpp"
|
#include "../cxx/js_engine.hpp"
|
||||||
#include <flutter/standard_method_codec.h>
|
#include <flutter/standard_method_codec.h>
|
||||||
@@ -46,9 +46,13 @@ namespace qjs
|
|||||||
JSValue array = JS_NewArray(ctx);
|
JSValue array = JS_NewArray(ctx);
|
||||||
auto size = (uint32_t)buf.size();
|
auto size = (uint32_t)buf.size();
|
||||||
for (uint32_t i = 0; i < size; ++i)
|
for (uint32_t i = 0; i < size; ++i)
|
||||||
|
{
|
||||||
|
auto atom = JS_NewAtomUInt32(ctx, i);
|
||||||
JS_DefinePropertyValue(
|
JS_DefinePropertyValue(
|
||||||
ctx, array, JS_NewAtomUInt32(ctx, i), JS_NewFloat64(ctx, buf[i]),
|
ctx, array, atom, JS_NewFloat64(ctx, buf[i]),
|
||||||
JS_PROP_C_W_E);
|
JS_PROP_C_W_E);
|
||||||
|
JS_FreeAtom(ctx, atom);
|
||||||
|
}
|
||||||
return array;
|
return array;
|
||||||
}
|
}
|
||||||
if (std::holds_alternative<flutter::EncodableList>(val))
|
if (std::holds_alternative<flutter::EncodableList>(val))
|
||||||
@@ -57,9 +61,14 @@ namespace qjs
|
|||||||
JSValue array = JS_NewArray(ctx);
|
JSValue array = JS_NewArray(ctx);
|
||||||
auto size = (uint32_t)list.size();
|
auto size = (uint32_t)list.size();
|
||||||
for (uint32_t i = 0; i < size; i++)
|
for (uint32_t i = 0; i < size; i++)
|
||||||
|
{
|
||||||
|
auto atom = JS_NewAtomUInt32(ctx, i);
|
||||||
JS_DefinePropertyValue(
|
JS_DefinePropertyValue(
|
||||||
ctx, array, JS_NewAtomUInt32(ctx, i), dartToJs(ctx, list[i]),
|
ctx, array, atom, dartToJs(ctx, list[i]),
|
||||||
JS_PROP_C_W_E);
|
JS_PROP_C_W_E);
|
||||||
|
JS_FreeAtom(ctx, atom);
|
||||||
|
}
|
||||||
|
|
||||||
return array;
|
return array;
|
||||||
}
|
}
|
||||||
if (std::holds_alternative<flutter::EncodableMap>(val))
|
if (std::holds_alternative<flutter::EncodableMap>(val))
|
||||||
@@ -67,9 +76,16 @@ namespace qjs
|
|||||||
auto map = std::get<flutter::EncodableMap>(val);
|
auto map = std::get<flutter::EncodableMap>(val);
|
||||||
JSValue obj = JS_NewObject(ctx);
|
JSValue obj = JS_NewObject(ctx);
|
||||||
for (auto iter = map.begin(); iter != map.end(); ++iter)
|
for (auto iter = map.begin(); iter != map.end(); ++iter)
|
||||||
|
{
|
||||||
|
auto atomvalue = dartToJs(ctx, iter->first);
|
||||||
|
auto atom = JS_ValueToAtom(ctx, atomvalue);
|
||||||
JS_DefinePropertyValue(
|
JS_DefinePropertyValue(
|
||||||
ctx, obj, JS_ValueToAtom(ctx, dartToJs(ctx, iter->first)), dartToJs(ctx, iter->second),
|
ctx, obj, atom, dartToJs(ctx, iter->second),
|
||||||
JS_PROP_C_W_E);
|
JS_PROP_C_W_E);
|
||||||
|
JS_FreeAtom(ctx, atom);
|
||||||
|
JS_FreeValue(ctx, atomvalue);
|
||||||
|
}
|
||||||
|
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
return JS_UNDEFINED;
|
return JS_UNDEFINED;
|
||||||
@@ -100,7 +116,7 @@ namespace qjs
|
|||||||
if (JS_IsFunction(val.ctx, val.v))
|
if (JS_IsFunction(val.ctx, val.v))
|
||||||
{
|
{
|
||||||
flutter::EncodableMap retMap;
|
flutter::EncodableMap retMap;
|
||||||
retMap[std::string("__js_function__")] = (int64_t) new JSValue{JS_DupValue(val.ctx, val.v)};
|
retMap[std::string("__js_function__")] = (int64_t) new JSValue{js_add_ref(val)};
|
||||||
return retMap;
|
return retMap;
|
||||||
}
|
}
|
||||||
else if (JS_IsArray(val.ctx, val.v) > 0)
|
else if (JS_IsArray(val.ctx, val.v) > 0)
|
||||||
|
@@ -151,8 +151,8 @@ namespace
|
|||||||
{
|
{
|
||||||
callargs[i] = qjs::dartToJs(ctx.ctx, arguments[i]);
|
callargs[i] = qjs::dartToJs(ctx.ctx, arguments[i]);
|
||||||
}
|
}
|
||||||
qjs::JSValue ret = JS_Call(ctx.ctx, *function, ctx.global().v, (int)argscount, callargs);
|
qjs::JSValue ret = qjs::call_handler(ctx.ctx, *function, (int)argscount, callargs);
|
||||||
qjs::JS_FreeValue(ctx.ctx, *function);
|
delete[] callargs;
|
||||||
if (qjs::JS_IsException(ret))
|
if (qjs::JS_IsException(ret))
|
||||||
throw qjs::exception{};
|
throw qjs::exception{};
|
||||||
return qjs::Value{ctx.ctx, ret};
|
return qjs::Value{ctx.ctx, ret};
|
||||||
|
Reference in New Issue
Block a user