diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json index c8a4e87..075a3e0 100644 --- a/.vscode/c_cpp_properties.json +++ b/.vscode/c_cpp_properties.json @@ -3,7 +3,8 @@ { "name": "Win32", "includePath": [ - "${workspaceFolder}/example/windows/flutter/ephemeral/cpp_client_wrapper/include/**" + "${workspaceFolder}/windows/**", + "${workspaceFolder}/example/windows/**" ], "defines": [ "_DEBUG", @@ -17,7 +18,7 @@ "intelliSenseMode": "msvc-x64" }, { - "name": "Linux", + "name": "Android", "includePath": [ "C:/Users/ekibun/AppData/Local/Android/Sdk/ndk/21.3.6528147/toolchains/llvm/prebuilt/windows-x86_64/sysroot/usr/include" ], @@ -31,6 +32,24 @@ "cStandard": "c11", "cppStandard": "c++17", "intelliSenseMode": "gcc-x64" + }, + { + "name": "Linux", + "includePath": [ + "${workspaceFolder}/linux/**", + "${workspaceFolder}/example/linux/**", + "/usr/include/**" + ], + "defines": [ + "_DEBUG", + "UNICODE", + "_UNICODE" + ], + "windowsSdkVersion": "10.0.18362.0", + "compilerPath": "/usr/bin/clang++", + "cStandard": "c11", + "cppStandard": "c++17", + "intelliSenseMode": "gcc-x64" } ], "version": 4 diff --git a/.vscode/settings.json b/.vscode/settings.json index f40bb0d..bb163bf 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -100,7 +100,8 @@ "cinttypes": "cpp", "typeindex": "cpp", "__functional_03": "cpp", - "compare": "cpp" + "compare": "cpp", + "any": "cpp" }, "java.configuration.updateBuildConfiguration": "interactive" } \ No newline at end of file diff --git a/example/lib/main.dart b/example/lib/main.dart index fbef0d3..9f3700a 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -3,7 +3,7 @@ * @Author: ekibun * @Date: 2020-08-08 08:16:51 * @LastEditors: ekibun - * @LastEditTime: 2020-08-08 17:50:30 + * @LastEditTime: 2020-08-17 21:46:10 */ import 'package:flutter/material.dart'; diff --git a/example/lib/test.dart b/example/lib/test.dart index 308083c..4f6afb8 100644 --- a/example/lib/test.dart +++ b/example/lib/test.dart @@ -3,7 +3,7 @@ * @Author: ekibun * @Date: 2020-07-18 23:28:55 * @LastEditors: ekibun - * @LastEditTime: 2020-08-15 16:39:07 + * @LastEditTime: 2020-08-17 21:52:14 */ import 'package:dio/dio.dart'; import 'package:flutter/material.dart'; @@ -24,7 +24,7 @@ class _TestPageState extends State { Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - title: Text("JS 引擎功能测试"), + title: Text("JS engine test"), ), body: SingleChildScrollView( padding: const EdgeInsets.all(16), @@ -36,7 +36,7 @@ class _TestPageState extends State { child: Row( children: [ FlatButton( - child: Text("初始化引擎"), + child: Text("create engine"), onPressed: () async { if (engine != null) return; engine = FlutterJs(); @@ -56,10 +56,10 @@ class _TestPageState extends State { }); }), FlatButton( - child: Text("运行"), + child: Text("evaluate"), onPressed: () async { if (engine == null) { - print("请先初始化引擎"); + print("please create engine first"); return; } try { @@ -70,7 +70,7 @@ class _TestPageState extends State { setState(() {}); }), FlatButton( - child: Text("释放引擎"), + child: Text("close engine"), onPressed: () async { if (engine != null) return; await engine.destroy(); @@ -90,7 +90,7 @@ class _TestPageState extends State { ), ), SizedBox(height: 16), - Text("运行结果:"), + Text("result:"), SizedBox(height: 16), Container( width: double.infinity, diff --git a/lib/flutter_qjs.dart b/lib/flutter_qjs.dart index 1990c92..cfe4d68 100644 --- a/lib/flutter_qjs.dart +++ b/lib/flutter_qjs.dart @@ -3,7 +3,7 @@ * @Author: ekibun * @Date: 2020-08-08 08:29:09 * @LastEditors: ekibun - * @LastEditTime: 2020-08-16 19:10:47 + * @LastEditTime: 2020-08-17 23:31:55 */ import 'dart:async'; import 'dart:io'; @@ -66,6 +66,7 @@ class FlutterJs { ensureEngine() async { if (_engine == null) { _engine = await _FlutterJs.instance._channel.invokeMethod("createEngine"); + print(_engine); } } @@ -83,7 +84,7 @@ class FlutterJs { Future evaluate(String command, String name) async { ensureEngine(); - var arguments = {"engine": _engine, "script": command, "name": command}; + var arguments = {"engine": _engine, "script": command, "name": ""}; return _FlutterJs.instance._wrapFunctionArguments( await _FlutterJs.instance._channel.invokeMethod("evaluate", arguments), _engine); } diff --git a/linux/CMakeLists.txt b/linux/CMakeLists.txt index 2aafd98..97ca317 100644 --- a/linux/CMakeLists.txt +++ b/linux/CMakeLists.txt @@ -7,6 +7,20 @@ set(PLUGIN_NAME "${PROJECT_NAME}_plugin") add_library(${PLUGIN_NAME} SHARED "${PLUGIN_NAME}.cc" ) + +# quickjs +set(QUICK_JS_LIB_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../cxx/quickjspp) +file (STRINGS "${QUICK_JS_LIB_DIR}/quickjs/VERSION" QUICKJS_VERSION) +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DCONFIG_VERSION=\\\"${QUICKJS_VERSION}\\\"") +add_library(libquickjs SHARED + ${QUICK_JS_LIB_DIR}/quickjs/cutils.c + ${QUICK_JS_LIB_DIR}/quickjs/libregexp.c + ${QUICK_JS_LIB_DIR}/quickjs/libunicode.c + ${QUICK_JS_LIB_DIR}/quickjs/quickjs.h + ${QUICK_JS_LIB_DIR}/quickjs/quickjs.c +) +project(libquickjs LANGUAGES C) + apply_standard_settings(${PLUGIN_NAME}) set_target_properties(${PLUGIN_NAME} PROPERTIES CXX_VISIBILITY_PRESET hidden) @@ -14,7 +28,7 @@ target_compile_definitions(${PLUGIN_NAME} PRIVATE FLUTTER_PLUGIN_IMPL) target_include_directories(${PLUGIN_NAME} INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/include") target_link_libraries(${PLUGIN_NAME} PRIVATE flutter) -target_link_libraries(${PLUGIN_NAME} PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/../cxx/libquickjs.so") +target_link_libraries(${PLUGIN_NAME} PRIVATE libquickjs) target_link_libraries(${PLUGIN_NAME} PRIVATE PkgConfig::GTK) # List of absolute paths to libraries that should be bundled with the plugin diff --git a/linux/dart_js_wrapper.hpp b/linux/dart_js_wrapper.hpp index 921e954..9fdcf08 100644 --- a/linux/dart_js_wrapper.hpp +++ b/linux/dart_js_wrapper.hpp @@ -3,12 +3,10 @@ * @Author: ekibun * @Date: 2020-08-14 21:45:02 * @LastEditors: ekibun - * @LastEditTime: 2020-08-15 15:42:55 + * @LastEditTime: 2020-08-17 22:43:20 */ #include "../cxx/js_engine.hpp" -// #include #include -#include namespace std { diff --git a/linux/flutter_qjs_plugin.cc b/linux/flutter_qjs_plugin.cc index 3fb4ed1..6c6f5d3 100644 --- a/linux/flutter_qjs_plugin.cc +++ b/linux/flutter_qjs_plugin.cc @@ -1,3 +1,10 @@ +/* + * @Description: + * @Author: ekibun + * @Date: 2020-08-17 21:37:11 + * @LastEditors: ekibun + * @LastEditTime: 2020-08-18 00:57:10 + */ #include "include/flutter_qjs/flutter_qjs_plugin.h" #include @@ -16,30 +23,80 @@ struct _FlutterQjsPlugin G_DEFINE_TYPE(FlutterQjsPlugin, flutter_qjs_plugin, g_object_get_type()) +g_autoptr(FlMethodChannel) channel = nullptr; + +std::promise *invokeChannelMethod(std::string name, qjs::Value args, qjs::Engine *engine) +{ + auto promise = new std::promise(); + return promise; +} + // Called when a method call is received from Flutter. static void flutter_qjs_plugin_handle_method_call( FlutterQjsPlugin *self, FlMethodCall *method_call) { - g_autoptr(FlMethodResponse) response = nullptr; - const gchar *method = fl_method_call_get_name(method_call); - if (strcmp(method, "getPlatformVersion") == 0) + if (strcmp(method, "createEngine") == 0) { - struct utsname uname_data = {}; - uname(&uname_data); - g_autofree gchar *version = g_strdup_printf("Linux %s", uname_data.version); - g_autoptr(FlValue) result = fl_value_new_string(version); - response = FL_METHOD_RESPONSE(fl_method_success_response_new(result)); + qjs::Engine *engine = new qjs::Engine(invokeChannelMethod); + g_warning("engine %ld", engine); + g_autoptr(FlMethodResponse) response = FL_METHOD_RESPONSE(fl_method_success_response_new(fl_value_new_int((int64_t)engine))); + fl_method_call_respond(method_call, response, nullptr); + // g_autoptr(GError) error = nullptr; + // if (!fl_method_call_respond(method_call, response, &error)) + // g_warning("Failed to send method call response: %s", error->message); + } + else if (strcmp(method, "evaluate") == 0) + { + FlValue *args = fl_method_call_get_args(method_call); + qjs::Engine *engine = nullptr; + std::string script, name; + for (int i = 0; i < 3; ++i) + { + FlValue *key = fl_value_get_map_key(args, i); + const gchar *keychar = fl_value_to_string(key); + if (strcmp(keychar, "engine") == 0) + { + engine = (qjs::Engine *)fl_value_get_int(fl_value_get_map_value(args, i)); + } + if (strcmp(keychar, "script") == 0) + { + script = fl_value_get_string(fl_value_get_map_value(args, i)); + } + if (strcmp(keychar, "name") == 0) + { + name = fl_value_get_string(fl_value_get_map_value(args, i)); + } + } + auto pmethod_call = g_object_ref(method_call); + g_warning("engine %ld; script: %s; name: %s", (int64_t)engine, script.c_str(), name.c_str()); + engine->commit(qjs::EngineTask{ + [script, name](qjs::Context &ctx) { + return ctx.eval(script, name.c_str(), JS_EVAL_TYPE_GLOBAL); + }, + [pmethod_call](qjs::Value resolve) { + g_warning("%s", fl_value_to_string(qjs::jsToDart(resolve))); + g_autoptr(FlMethodResponse) response = FL_METHOD_RESPONSE(fl_method_success_response_new(qjs::jsToDart(resolve))); + fl_method_call_respond((FlMethodCall *)pmethod_call, response, nullptr); + g_object_unref(pmethod_call); + }, + [pmethod_call](qjs::Value reject) { + fl_method_call_respond_error((FlMethodCall *)pmethod_call, "FlutterJSException", qjs::getStackTrack(reject).c_str(), nullptr, nullptr); + g_object_unref(pmethod_call); + }}); + // g_autoptr(FlMethodResponse) response = FL_METHOD_RESPONSE(fl_method_success_response_new(args)); + // fl_method_call_respond(method_call, response, nullptr); + // g_autoptr(GError) error = nullptr; + // if (!fl_method_call_respond(method_call, response, &error)) + // g_warning("Failed to send method call response: %s", error->message); } - else { - response = FL_METHOD_RESPONSE(fl_method_not_implemented_response_new()); + g_autoptr(FlMethodResponse) response = FL_METHOD_RESPONSE(fl_method_not_implemented_response_new()); + fl_method_call_respond(method_call, response, nullptr); } - - fl_method_call_respond(method_call, response, nullptr); } static void flutter_qjs_plugin_dispose(GObject *object) @@ -67,9 +124,9 @@ void flutter_qjs_plugin_register_with_registrar(FlPluginRegistrar *registrar) g_object_new(flutter_qjs_plugin_get_type(), nullptr)); g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new(); - g_autoptr(FlMethodChannel) channel = + channel = fl_method_channel_new(fl_plugin_registrar_get_messenger(registrar), - "flutter_qjs", + "soko.ekibun.flutter_qjs", FL_METHOD_CODEC(codec)); fl_method_channel_set_method_call_handler(channel, method_call_cb, g_object_ref(plugin), diff --git a/windows/flutter_qjs_plugin.cpp b/windows/flutter_qjs_plugin.cpp index bda4428..78d577b 100644 --- a/windows/flutter_qjs_plugin.cpp +++ b/windows/flutter_qjs_plugin.cpp @@ -129,9 +129,11 @@ namespace [presult](qjs::Value resolve) { flutter::EncodableValue response = qjs::jsToDart(resolve); presult->Success(&response); + delete presult; }, [presult](qjs::Value reject) { presult->Error("FlutterJSException", qjs::getStackTrack(reject)); + delete presult; }}); } else if (method_call.method_name().compare("call") == 0)