parent
7ed7033716
commit
43515d8058
@ -0,0 +1,35 @@ |
||||
package io.openim.flutter_openim_sdk |
||||
|
||||
import androidx.annotation.NonNull |
||||
|
||||
import io.flutter.embedding.engine.plugins.FlutterPlugin |
||||
import io.flutter.plugin.common.MethodCall |
||||
import io.flutter.plugin.common.MethodChannel |
||||
import io.flutter.plugin.common.MethodChannel.MethodCallHandler |
||||
import io.flutter.plugin.common.MethodChannel.Result |
||||
|
||||
/** FlutterOpenimSdkPlugin */ |
||||
class FlutterOpenimSdkPlugin: FlutterPlugin, MethodCallHandler { |
||||
/// The MethodChannel that will the communication between Flutter and native Android |
||||
/// |
||||
/// This local reference serves to register the plugin with the Flutter Engine and unregister it |
||||
/// when the Flutter Engine is detached from the Activity |
||||
private lateinit var channel : MethodChannel |
||||
|
||||
override fun onAttachedToEngine(flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) { |
||||
channel = MethodChannel(flutterPluginBinding.binaryMessenger, "flutter_openim_sdk") |
||||
channel.setMethodCallHandler(this) |
||||
} |
||||
|
||||
override fun onMethodCall(call: MethodCall, result: Result) { |
||||
if (call.method == "getPlatformVersion") { |
||||
result.success("Android ${android.os.Build.VERSION.RELEASE}") |
||||
} else { |
||||
result.notImplemented() |
||||
} |
||||
} |
||||
|
||||
override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) { |
||||
channel.setMethodCallHandler(null) |
||||
} |
||||
} |
@ -0,0 +1,27 @@ |
||||
package io.openim.flutter_openim_sdk |
||||
|
||||
import io.flutter.plugin.common.MethodCall |
||||
import io.flutter.plugin.common.MethodChannel |
||||
import kotlin.test.Test |
||||
import org.mockito.Mockito |
||||
|
||||
/* |
||||
* This demonstrates a simple unit test of the Kotlin portion of this plugin's implementation. |
||||
* |
||||
* Once you have built the plugin's example app, you can run these tests from the command |
||||
* line by running `./gradlew testDebugUnitTest` in the `example/android/` directory, or |
||||
* you can run them directly from IDEs that support JUnit such as Android Studio. |
||||
*/ |
||||
|
||||
internal class FlutterOpenimSdkPluginTest { |
||||
@Test |
||||
fun onMethodCall_getPlatformVersion_returnsExpectedValue() { |
||||
val plugin = FlutterOpenimSdkPlugin() |
||||
|
||||
val call = MethodCall("getPlatformVersion", null) |
||||
val mockResult: MethodChannel.Result = Mockito.mock(MethodChannel.Result::class.java) |
||||
plugin.onMethodCall(call, mockResult) |
||||
|
||||
Mockito.verify(mockResult).success("Android " + android.os.Build.VERSION.RELEASE) |
||||
} |
||||
} |
Binary file not shown.
@ -0,0 +1,5 @@ |
||||
package io.openim.flutter_openim_sdk_example |
||||
|
||||
import io.flutter.embedding.android.FlutterActivity |
||||
|
||||
class MainActivity: FlutterActivity() |
@ -0,0 +1,25 @@ |
||||
// This is a basic Flutter integration test. |
||||
// |
||||
// Since integration tests run in a full Flutter application, they can interact |
||||
// with the host side of a plugin implementation, unlike Dart unit tests. |
||||
// |
||||
// For more information about Flutter integration tests, please see |
||||
// https://flutter.dev/to/integration-testing |
||||
|
||||
|
||||
import 'package:flutter_test/flutter_test.dart'; |
||||
import 'package:integration_test/integration_test.dart'; |
||||
|
||||
import 'package:flutter_openim_sdk/flutter_openim_sdk.dart'; |
||||
|
||||
void main() { |
||||
IntegrationTestWidgetsFlutterBinding.ensureInitialized(); |
||||
|
||||
testWidgets('getPlatformVersion test', (WidgetTester tester) async { |
||||
final FlutterOpenimSdk plugin = FlutterOpenimSdk(); |
||||
final String? version = await plugin.getPlatformVersion(); |
||||
// The version string depends on the host platform running the test, so |
||||
// just assert that some non-empty string is returned. |
||||
expect(version?.isNotEmpty, true); |
||||
}); |
||||
} |
@ -0,0 +1,17 @@ |
||||
flutter/ephemeral/ |
||||
|
||||
# Visual Studio user-specific files. |
||||
*.suo |
||||
*.user |
||||
*.userosscache |
||||
*.sln.docstates |
||||
|
||||
# Visual Studio build-related files. |
||||
x64/ |
||||
x86/ |
||||
|
||||
# Visual Studio cache files |
||||
# files ending in .cache can be ignored |
||||
*.[Cc]ache |
||||
# but keep track of directories ending in .cache |
||||
!*.[Cc]ache/ |
@ -0,0 +1,110 @@ |
||||
# Project-level configuration. |
||||
cmake_minimum_required(VERSION 3.14) |
||||
project(flutter_openim_sdk_example LANGUAGES CXX) |
||||
|
||||
# The name of the executable created for the application. Change this to change |
||||
# the on-disk name of your application. |
||||
set(BINARY_NAME "flutter_openim_sdk_example") |
||||
|
||||
# Explicitly opt in to modern CMake behaviors to avoid warnings with recent |
||||
# versions of CMake. |
||||
cmake_policy(VERSION 3.14...3.25) |
||||
|
||||
# Define build configuration option. |
||||
get_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) |
||||
if(IS_MULTICONFIG) |
||||
set(CMAKE_CONFIGURATION_TYPES "Debug;Profile;Release" |
||||
CACHE STRING "" FORCE) |
||||
else() |
||||
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) |
||||
set(CMAKE_BUILD_TYPE "Debug" CACHE |
||||
STRING "Flutter build mode" FORCE) |
||||
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS |
||||
"Debug" "Profile" "Release") |
||||
endif() |
||||
endif() |
||||
# Define settings for the Profile build mode. |
||||
set(CMAKE_EXE_LINKER_FLAGS_PROFILE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}") |
||||
set(CMAKE_SHARED_LINKER_FLAGS_PROFILE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE}") |
||||
set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_RELEASE}") |
||||
set(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS_RELEASE}") |
||||
|
||||
# Use Unicode for all projects. |
||||
add_definitions(-DUNICODE -D_UNICODE) |
||||
|
||||
# Compilation settings that should be applied to most targets. |
||||
# |
||||
# Be cautious about adding new options here, as plugins use this function by |
||||
# default. In most cases, you should add new options to specific targets instead |
||||
# of modifying this function. |
||||
function(APPLY_STANDARD_SETTINGS TARGET) |
||||
target_compile_features(${TARGET} PUBLIC cxx_std_17) |
||||
target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100") |
||||
target_compile_options(${TARGET} PRIVATE /EHsc) |
||||
target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0") |
||||
target_compile_definitions(${TARGET} PRIVATE "$<$<CONFIG:Debug>:_DEBUG>") |
||||
endfunction() |
||||
|
||||
# Flutter library and tool build rules. |
||||
set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") |
||||
add_subdirectory(${FLUTTER_MANAGED_DIR}) |
||||
|
||||
# Application build; see runner/CMakeLists.txt. |
||||
add_subdirectory("runner") |
||||
|
||||
# Enable the test target. |
||||
set(include_flutter_openim_sdk_tests TRUE) |
||||
|
||||
# Generated plugin build rules, which manage building the plugins and adding |
||||
# them to the application. |
||||
include(flutter/generated_plugins.cmake) |
||||
|
||||
|
||||
# === Installation === |
||||
# Support files are copied into place next to the executable, so that it can |
||||
# run in place. This is done instead of making a separate bundle (as on Linux) |
||||
# so that building and running from within Visual Studio will work. |
||||
set(BUILD_BUNDLE_DIR "$<TARGET_FILE_DIR:${BINARY_NAME}>") |
||||
# Make the "install" step default, as it's required to run. |
||||
set(CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD 1) |
||||
if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) |
||||
set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) |
||||
endif() |
||||
|
||||
set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") |
||||
set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}") |
||||
|
||||
install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" |
||||
COMPONENT Runtime) |
||||
|
||||
install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" |
||||
COMPONENT Runtime) |
||||
|
||||
install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" |
||||
COMPONENT Runtime) |
||||
|
||||
if(PLUGIN_BUNDLED_LIBRARIES) |
||||
install(FILES "${PLUGIN_BUNDLED_LIBRARIES}" |
||||
DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" |
||||
COMPONENT Runtime) |
||||
endif() |
||||
|
||||
# Copy the native assets provided by the build.dart from all packages. |
||||
set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/windows/") |
||||
install(DIRECTORY "${NATIVE_ASSETS_DIR}" |
||||
DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" |
||||
COMPONENT Runtime) |
||||
|
||||
# Fully re-copy the assets directory on each build to avoid having stale files |
||||
# from a previous install. |
||||
set(FLUTTER_ASSET_DIR_NAME "flutter_assets") |
||||
install(CODE " |
||||
file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") |
||||
" COMPONENT Runtime) |
||||
install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" |
||||
DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) |
||||
|
||||
# Install the AOT library on non-Debug builds only. |
||||
install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" |
||||
CONFIGURATIONS Profile;Release |
||||
COMPONENT Runtime) |
@ -0,0 +1,109 @@ |
||||
# This file controls Flutter-level build steps. It should not be edited. |
||||
cmake_minimum_required(VERSION 3.14) |
||||
|
||||
set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") |
||||
|
||||
# Configuration provided via flutter tool. |
||||
include(${EPHEMERAL_DIR}/generated_config.cmake) |
||||
|
||||
# TODO: Move the rest of this into files in ephemeral. See |
||||
# https://github.com/flutter/flutter/issues/57146. |
||||
set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper") |
||||
|
||||
# Set fallback configurations for older versions of the flutter tool. |
||||
if (NOT DEFINED FLUTTER_TARGET_PLATFORM) |
||||
set(FLUTTER_TARGET_PLATFORM "windows-x64") |
||||
endif() |
||||
|
||||
# === Flutter Library === |
||||
set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll") |
||||
|
||||
# Published to parent scope for install step. |
||||
set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) |
||||
set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) |
||||
set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) |
||||
set(AOT_LIBRARY "${PROJECT_DIR}/build/windows/app.so" PARENT_SCOPE) |
||||
|
||||
list(APPEND FLUTTER_LIBRARY_HEADERS |
||||
"flutter_export.h" |
||||
"flutter_windows.h" |
||||
"flutter_messenger.h" |
||||
"flutter_plugin_registrar.h" |
||||
"flutter_texture_registrar.h" |
||||
) |
||||
list(TRANSFORM FLUTTER_LIBRARY_HEADERS PREPEND "${EPHEMERAL_DIR}/") |
||||
add_library(flutter INTERFACE) |
||||
target_include_directories(flutter INTERFACE |
||||
"${EPHEMERAL_DIR}" |
||||
) |
||||
target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}.lib") |
||||
add_dependencies(flutter flutter_assemble) |
||||
|
||||
# === Wrapper === |
||||
list(APPEND CPP_WRAPPER_SOURCES_CORE |
||||
"core_implementations.cc" |
||||
"standard_codec.cc" |
||||
) |
||||
list(TRANSFORM CPP_WRAPPER_SOURCES_CORE PREPEND "${WRAPPER_ROOT}/") |
||||
list(APPEND CPP_WRAPPER_SOURCES_PLUGIN |
||||
"plugin_registrar.cc" |
||||
) |
||||
list(TRANSFORM CPP_WRAPPER_SOURCES_PLUGIN PREPEND "${WRAPPER_ROOT}/") |
||||
list(APPEND CPP_WRAPPER_SOURCES_APP |
||||
"flutter_engine.cc" |
||||
"flutter_view_controller.cc" |
||||
) |
||||
list(TRANSFORM CPP_WRAPPER_SOURCES_APP PREPEND "${WRAPPER_ROOT}/") |
||||
|
||||
# Wrapper sources needed for a plugin. |
||||
add_library(flutter_wrapper_plugin STATIC |
||||
${CPP_WRAPPER_SOURCES_CORE} |
||||
${CPP_WRAPPER_SOURCES_PLUGIN} |
||||
) |
||||
apply_standard_settings(flutter_wrapper_plugin) |
||||
set_target_properties(flutter_wrapper_plugin PROPERTIES |
||||
POSITION_INDEPENDENT_CODE ON) |
||||
set_target_properties(flutter_wrapper_plugin PROPERTIES |
||||
CXX_VISIBILITY_PRESET hidden) |
||||
target_link_libraries(flutter_wrapper_plugin PUBLIC flutter) |
||||
target_include_directories(flutter_wrapper_plugin PUBLIC |
||||
"${WRAPPER_ROOT}/include" |
||||
) |
||||
add_dependencies(flutter_wrapper_plugin flutter_assemble) |
||||
|
||||
# Wrapper sources needed for the runner. |
||||
add_library(flutter_wrapper_app STATIC |
||||
${CPP_WRAPPER_SOURCES_CORE} |
||||
${CPP_WRAPPER_SOURCES_APP} |
||||
) |
||||
apply_standard_settings(flutter_wrapper_app) |
||||
target_link_libraries(flutter_wrapper_app PUBLIC flutter) |
||||
target_include_directories(flutter_wrapper_app PUBLIC |
||||
"${WRAPPER_ROOT}/include" |
||||
) |
||||
add_dependencies(flutter_wrapper_app flutter_assemble) |
||||
|
||||
# === Flutter tool backend === |
||||
# _phony_ is a non-existent file to force this command to run every time, |
||||
# since currently there's no way to get a full input/output list from the |
||||
# flutter tool. |
||||
set(PHONY_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/_phony_") |
||||
set_source_files_properties("${PHONY_OUTPUT}" PROPERTIES SYMBOLIC TRUE) |
||||
add_custom_command( |
||||
OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} |
||||
${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN} |
||||
${CPP_WRAPPER_SOURCES_APP} |
||||
${PHONY_OUTPUT} |
||||
COMMAND ${CMAKE_COMMAND} -E env |
||||
${FLUTTER_TOOL_ENVIRONMENT} |
||||
"${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat" |
||||
${FLUTTER_TARGET_PLATFORM} $<CONFIG> |
||||
VERBATIM |
||||
) |
||||
add_custom_target(flutter_assemble DEPENDS |
||||
"${FLUTTER_LIBRARY}" |
||||
${FLUTTER_LIBRARY_HEADERS} |
||||
${CPP_WRAPPER_SOURCES_CORE} |
||||
${CPP_WRAPPER_SOURCES_PLUGIN} |
||||
${CPP_WRAPPER_SOURCES_APP} |
||||
) |
@ -0,0 +1,14 @@ |
||||
//
|
||||
// Generated file. Do not edit.
|
||||
//
|
||||
|
||||
// clang-format off
|
||||
|
||||
#include "generated_plugin_registrant.h" |
||||
|
||||
#include <flutter_openim_sdk/flutter_openim_sdk_plugin.h> |
||||
|
||||
void RegisterPlugins(flutter::PluginRegistry* registry) { |
||||
FlutterOpenimSdkPluginRegisterWithRegistrar( |
||||
registry->GetRegistrarForPlugin("FlutterOpenimSdkPlugin")); |
||||
} |
@ -0,0 +1,15 @@ |
||||
//
|
||||
// Generated file. Do not edit.
|
||||
//
|
||||
|
||||
// clang-format off
|
||||
|
||||
#ifndef GENERATED_PLUGIN_REGISTRANT_ |
||||
#define GENERATED_PLUGIN_REGISTRANT_ |
||||
|
||||
#include <flutter/plugin_registry.h> |
||||
|
||||
// Registers Flutter plugins.
|
||||
void RegisterPlugins(flutter::PluginRegistry* registry); |
||||
|
||||
#endif // GENERATED_PLUGIN_REGISTRANT_
|
@ -0,0 +1,24 @@ |
||||
# |
||||
# Generated file, do not edit. |
||||
# |
||||
|
||||
list(APPEND FLUTTER_PLUGIN_LIST |
||||
flutter_openim_sdk |
||||
) |
||||
|
||||
list(APPEND FLUTTER_FFI_PLUGIN_LIST |
||||
) |
||||
|
||||
set(PLUGIN_BUNDLED_LIBRARIES) |
||||
|
||||
foreach(plugin ${FLUTTER_PLUGIN_LIST}) |
||||
add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin}) |
||||
target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) |
||||
list(APPEND PLUGIN_BUNDLED_LIBRARIES $<TARGET_FILE:${plugin}_plugin>) |
||||
list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) |
||||
endforeach(plugin) |
||||
|
||||
foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) |
||||
add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin}) |
||||
list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) |
||||
endforeach(ffi_plugin) |
@ -0,0 +1,40 @@ |
||||
cmake_minimum_required(VERSION 3.14) |
||||
project(runner LANGUAGES CXX) |
||||
|
||||
# Define the application target. To change its name, change BINARY_NAME in the |
||||
# top-level CMakeLists.txt, not the value here, or `flutter run` will no longer |
||||
# work. |
||||
# |
||||
# Any new source files that you add to the application should be added here. |
||||
add_executable(${BINARY_NAME} WIN32 |
||||
"flutter_window.cpp" |
||||
"main.cpp" |
||||
"utils.cpp" |
||||
"win32_window.cpp" |
||||
"${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" |
||||
"Runner.rc" |
||||
"runner.exe.manifest" |
||||
) |
||||
|
||||
# Apply the standard set of build settings. This can be removed for applications |
||||
# that need different build settings. |
||||
apply_standard_settings(${BINARY_NAME}) |
||||
|
||||
# Add preprocessor definitions for the build version. |
||||
target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION=\"${FLUTTER_VERSION}\"") |
||||
target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MAJOR=${FLUTTER_VERSION_MAJOR}") |
||||
target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MINOR=${FLUTTER_VERSION_MINOR}") |
||||
target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_PATCH=${FLUTTER_VERSION_PATCH}") |
||||
target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_BUILD=${FLUTTER_VERSION_BUILD}") |
||||
|
||||
# Disable Windows macros that collide with C++ standard library functions. |
||||
target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX") |
||||
|
||||
# Add dependency libraries and include directories. Add any application-specific |
||||
# dependencies here. |
||||
target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app) |
||||
target_link_libraries(${BINARY_NAME} PRIVATE "dwmapi.lib") |
||||
target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") |
||||
|
||||
# Run the Flutter tool portions of the build. This must not be removed. |
||||
add_dependencies(${BINARY_NAME} flutter_assemble) |
@ -0,0 +1,121 @@ |
||||
// Microsoft Visual C++ generated resource script. |
||||
// |
||||
#pragma code_page(65001) |
||||
#include "resource.h" |
||||
|
||||
#define APSTUDIO_READONLY_SYMBOLS |
||||
///////////////////////////////////////////////////////////////////////////// |
||||
// |
||||
// Generated from the TEXTINCLUDE 2 resource. |
||||
// |
||||
#include "winres.h" |
||||
|
||||
///////////////////////////////////////////////////////////////////////////// |
||||
#undef APSTUDIO_READONLY_SYMBOLS |
||||
|
||||
///////////////////////////////////////////////////////////////////////////// |
||||
// English (United States) resources |
||||
|
||||
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) |
||||
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US |
||||
|
||||
#ifdef APSTUDIO_INVOKED |
||||
///////////////////////////////////////////////////////////////////////////// |
||||
// |
||||
// TEXTINCLUDE |
||||
// |
||||
|
||||
1 TEXTINCLUDE |
||||
BEGIN |
||||
"resource.h\0" |
||||
END |
||||
|
||||
2 TEXTINCLUDE |
||||
BEGIN |
||||
"#include ""winres.h""\r\n" |
||||
"\0" |
||||
END |
||||
|
||||
3 TEXTINCLUDE |
||||
BEGIN |
||||
"\r\n" |
||||
"\0" |
||||
END |
||||
|
||||
#endif // APSTUDIO_INVOKED |
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////// |
||||
// |
||||
// Icon |
||||
// |
||||
|
||||
// Icon with lowest ID value placed first to ensure application icon |
||||
// remains consistent on all systems. |
||||
IDI_APP_ICON ICON "resources\\app_icon.ico" |
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////// |
||||
// |
||||
// Version |
||||
// |
||||
|
||||
#if defined(FLUTTER_VERSION_MAJOR) && defined(FLUTTER_VERSION_MINOR) && defined(FLUTTER_VERSION_PATCH) && defined(FLUTTER_VERSION_BUILD) |
||||
#define VERSION_AS_NUMBER FLUTTER_VERSION_MAJOR,FLUTTER_VERSION_MINOR,FLUTTER_VERSION_PATCH,FLUTTER_VERSION_BUILD |
||||
#else |
||||
#define VERSION_AS_NUMBER 1,0,0,0 |
||||
#endif |
||||
|
||||
#if defined(FLUTTER_VERSION) |
||||
#define VERSION_AS_STRING FLUTTER_VERSION |
||||
#else |
||||
#define VERSION_AS_STRING "1.0.0" |
||||
#endif |
||||
|
||||
VS_VERSION_INFO VERSIONINFO |
||||
FILEVERSION VERSION_AS_NUMBER |
||||
PRODUCTVERSION VERSION_AS_NUMBER |
||||
FILEFLAGSMASK VS_FFI_FILEFLAGSMASK |
||||
#ifdef _DEBUG |
||||
FILEFLAGS VS_FF_DEBUG |
||||
#else |
||||
FILEFLAGS 0x0L |
||||
#endif |
||||
FILEOS VOS__WINDOWS32 |
||||
FILETYPE VFT_APP |
||||
FILESUBTYPE 0x0L |
||||
BEGIN |
||||
BLOCK "StringFileInfo" |
||||
BEGIN |
||||
BLOCK "040904e4" |
||||
BEGIN |
||||
VALUE "CompanyName", "io.openim" "\0" |
||||
VALUE "FileDescription", "flutter_openim_sdk_example" "\0" |
||||
VALUE "FileVersion", VERSION_AS_STRING "\0" |
||||
VALUE "InternalName", "flutter_openim_sdk_example" "\0" |
||||
VALUE "LegalCopyright", "Copyright (C) 2025 io.openim. All rights reserved." "\0" |
||||
VALUE "OriginalFilename", "flutter_openim_sdk_example.exe" "\0" |
||||
VALUE "ProductName", "flutter_openim_sdk_example" "\0" |
||||
VALUE "ProductVersion", VERSION_AS_STRING "\0" |
||||
END |
||||
END |
||||
BLOCK "VarFileInfo" |
||||
BEGIN |
||||
VALUE "Translation", 0x409, 1252 |
||||
END |
||||
END |
||||
|
||||
#endif // English (United States) resources |
||||
///////////////////////////////////////////////////////////////////////////// |
||||
|
||||
|
||||
|
||||
#ifndef APSTUDIO_INVOKED |
||||
///////////////////////////////////////////////////////////////////////////// |
||||
// |
||||
// Generated from the TEXTINCLUDE 3 resource. |
||||
// |
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////// |
||||
#endif // not APSTUDIO_INVOKED |
@ -0,0 +1,71 @@ |
||||
#include "flutter_window.h" |
||||
|
||||
#include <optional> |
||||
|
||||
#include "flutter/generated_plugin_registrant.h" |
||||
|
||||
FlutterWindow::FlutterWindow(const flutter::DartProject& project) |
||||
: project_(project) {} |
||||
|
||||
FlutterWindow::~FlutterWindow() {} |
||||
|
||||
bool FlutterWindow::OnCreate() { |
||||
if (!Win32Window::OnCreate()) { |
||||
return false; |
||||
} |
||||
|
||||
RECT frame = GetClientArea(); |
||||
|
||||
// The size here must match the window dimensions to avoid unnecessary surface
|
||||
// creation / destruction in the startup path.
|
||||
flutter_controller_ = std::make_unique<flutter::FlutterViewController>( |
||||
frame.right - frame.left, frame.bottom - frame.top, project_); |
||||
// Ensure that basic setup of the controller was successful.
|
||||
if (!flutter_controller_->engine() || !flutter_controller_->view()) { |
||||
return false; |
||||
} |
||||
RegisterPlugins(flutter_controller_->engine()); |
||||
SetChildContent(flutter_controller_->view()->GetNativeWindow()); |
||||
|
||||
flutter_controller_->engine()->SetNextFrameCallback([&]() { |
||||
this->Show(); |
||||
}); |
||||
|
||||
// Flutter can complete the first frame before the "show window" callback is
|
||||
// registered. The following call ensures a frame is pending to ensure the
|
||||
// window is shown. It is a no-op if the first frame hasn't completed yet.
|
||||
flutter_controller_->ForceRedraw(); |
||||
|
||||
return true; |
||||
} |
||||
|
||||
void FlutterWindow::OnDestroy() { |
||||
if (flutter_controller_) { |
||||
flutter_controller_ = nullptr; |
||||
} |
||||
|
||||
Win32Window::OnDestroy(); |
||||
} |
||||
|
||||
LRESULT |
||||
FlutterWindow::MessageHandler(HWND hwnd, UINT const message, |
||||
WPARAM const wparam, |
||||
LPARAM const lparam) noexcept { |
||||
// Give Flutter, including plugins, an opportunity to handle window messages.
|
||||
if (flutter_controller_) { |
||||
std::optional<LRESULT> result = |
||||
flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam, |
||||
lparam); |
||||
if (result) { |
||||
return *result; |
||||
} |
||||
} |
||||
|
||||
switch (message) { |
||||
case WM_FONTCHANGE: |
||||
flutter_controller_->engine()->ReloadSystemFonts(); |
||||
break; |
||||
} |
||||
|
||||
return Win32Window::MessageHandler(hwnd, message, wparam, lparam); |
||||
} |
@ -0,0 +1,33 @@ |
||||
#ifndef RUNNER_FLUTTER_WINDOW_H_ |
||||
#define RUNNER_FLUTTER_WINDOW_H_ |
||||
|
||||
#include <flutter/dart_project.h> |
||||
#include <flutter/flutter_view_controller.h> |
||||
|
||||
#include <memory> |
||||
|
||||
#include "win32_window.h" |
||||
|
||||
// A window that does nothing but host a Flutter view.
|
||||
class FlutterWindow : public Win32Window { |
||||
public: |
||||
// Creates a new FlutterWindow hosting a Flutter view running |project|.
|
||||
explicit FlutterWindow(const flutter::DartProject& project); |
||||
virtual ~FlutterWindow(); |
||||
|
||||
protected: |
||||
// Win32Window:
|
||||
bool OnCreate() override; |
||||
void OnDestroy() override; |
||||
LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam, |
||||
LPARAM const lparam) noexcept override; |
||||
|
||||
private: |
||||
// The project to run.
|
||||
flutter::DartProject project_; |
||||
|
||||
// The Flutter instance hosted by this window.
|
||||
std::unique_ptr<flutter::FlutterViewController> flutter_controller_; |
||||
}; |
||||
|
||||
#endif // RUNNER_FLUTTER_WINDOW_H_
|
@ -0,0 +1,43 @@ |
||||
#include <flutter/dart_project.h> |
||||
#include <flutter/flutter_view_controller.h> |
||||
#include <windows.h> |
||||
|
||||
#include "flutter_window.h" |
||||
#include "utils.h" |
||||
|
||||
int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, |
||||
_In_ wchar_t *command_line, _In_ int show_command) { |
||||
// Attach to console when present (e.g., 'flutter run') or create a
|
||||
// new console when running with a debugger.
|
||||
if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) { |
||||
CreateAndAttachConsole(); |
||||
} |
||||
|
||||
// Initialize COM, so that it is available for use in the library and/or
|
||||
// plugins.
|
||||
::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); |
||||
|
||||
flutter::DartProject project(L"data"); |
||||
|
||||
std::vector<std::string> command_line_arguments = |
||||
GetCommandLineArguments(); |
||||
|
||||
project.set_dart_entrypoint_arguments(std::move(command_line_arguments)); |
||||
|
||||
FlutterWindow window(project); |
||||
Win32Window::Point origin(10, 10); |
||||
Win32Window::Size size(1280, 720); |
||||
if (!window.Create(L"flutter_openim_sdk_example", origin, size)) { |
||||
return EXIT_FAILURE; |
||||
} |
||||
window.SetQuitOnClose(true); |
||||
|
||||
::MSG msg; |
||||
while (::GetMessage(&msg, nullptr, 0, 0)) { |
||||
::TranslateMessage(&msg); |
||||
::DispatchMessage(&msg); |
||||
} |
||||
|
||||
::CoUninitialize(); |
||||
return EXIT_SUCCESS; |
||||
} |
@ -0,0 +1,16 @@ |
||||
//{{NO_DEPENDENCIES}}
|
||||
// Microsoft Visual C++ generated include file.
|
||||
// Used by Runner.rc
|
||||
//
|
||||
#define IDI_APP_ICON 101 |
||||
|
||||
// Next default values for new objects
|
||||
//
|
||||
#ifdef APSTUDIO_INVOKED |
||||
#ifndef APSTUDIO_READONLY_SYMBOLS |
||||
#define _APS_NEXT_RESOURCE_VALUE 102 |
||||
#define _APS_NEXT_COMMAND_VALUE 40001 |
||||
#define _APS_NEXT_CONTROL_VALUE 1001 |
||||
#define _APS_NEXT_SYMED_VALUE 101 |
||||
#endif |
||||
#endif |
After Width: | Height: | Size: 33 KiB |
@ -0,0 +1,14 @@ |
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> |
||||
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> |
||||
<application xmlns="urn:schemas-microsoft-com:asm.v3"> |
||||
<windowsSettings> |
||||
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2</dpiAwareness> |
||||
</windowsSettings> |
||||
</application> |
||||
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1"> |
||||
<application> |
||||
<!-- Windows 10 and Windows 11 --> |
||||
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/> |
||||
</application> |
||||
</compatibility> |
||||
</assembly> |
@ -0,0 +1,65 @@ |
||||
#include "utils.h" |
||||
|
||||
#include <flutter_windows.h> |
||||
#include <io.h> |
||||
#include <stdio.h> |
||||
#include <windows.h> |
||||
|
||||
#include <iostream> |
||||
|
||||
void CreateAndAttachConsole() { |
||||
if (::AllocConsole()) { |
||||
FILE *unused; |
||||
if (freopen_s(&unused, "CONOUT$", "w", stdout)) { |
||||
_dup2(_fileno(stdout), 1); |
||||
} |
||||
if (freopen_s(&unused, "CONOUT$", "w", stderr)) { |
||||
_dup2(_fileno(stdout), 2); |
||||
} |
||||
std::ios::sync_with_stdio(); |
||||
FlutterDesktopResyncOutputStreams(); |
||||
} |
||||
} |
||||
|
||||
std::vector<std::string> GetCommandLineArguments() { |
||||
// Convert the UTF-16 command line arguments to UTF-8 for the Engine to use.
|
||||
int argc; |
||||
wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc); |
||||
if (argv == nullptr) { |
||||
return std::vector<std::string>(); |
||||
} |
||||
|
||||
std::vector<std::string> command_line_arguments; |
||||
|
||||
// Skip the first argument as it's the binary name.
|
||||
for (int i = 1; i < argc; i++) { |
||||
command_line_arguments.push_back(Utf8FromUtf16(argv[i])); |
||||
} |
||||
|
||||
::LocalFree(argv); |
||||
|
||||
return command_line_arguments; |
||||
} |
||||
|
||||
std::string Utf8FromUtf16(const wchar_t* utf16_string) { |
||||
if (utf16_string == nullptr) { |
||||
return std::string(); |
||||
} |
||||
unsigned int target_length = ::WideCharToMultiByte( |
||||
CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, |
||||
-1, nullptr, 0, nullptr, nullptr) |
||||
-1; // remove the trailing null character
|
||||
int input_length = (int)wcslen(utf16_string); |
||||
std::string utf8_string; |
||||
if (target_length == 0 || target_length > utf8_string.max_size()) { |
||||
return utf8_string; |
||||
} |
||||
utf8_string.resize(target_length); |
||||
int converted_length = ::WideCharToMultiByte( |
||||
CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, |
||||
input_length, utf8_string.data(), target_length, nullptr, nullptr); |
||||
if (converted_length == 0) { |
||||
return std::string(); |
||||
} |
||||
return utf8_string; |
||||
} |
@ -0,0 +1,19 @@ |
||||
#ifndef RUNNER_UTILS_H_ |
||||
#define RUNNER_UTILS_H_ |
||||
|
||||
#include <string> |
||||
#include <vector> |
||||
|
||||
// Creates a console for the process, and redirects stdout and stderr to
|
||||
// it for both the runner and the Flutter library.
|
||||
void CreateAndAttachConsole(); |
||||
|
||||
// Takes a null-terminated wchar_t* encoded in UTF-16 and returns a std::string
|
||||
// encoded in UTF-8. Returns an empty std::string on failure.
|
||||
std::string Utf8FromUtf16(const wchar_t* utf16_string); |
||||
|
||||
// Gets the command line arguments passed in as a std::vector<std::string>,
|
||||
// encoded in UTF-8. Returns an empty std::vector<std::string> on failure.
|
||||
std::vector<std::string> GetCommandLineArguments(); |
||||
|
||||
#endif // RUNNER_UTILS_H_
|
@ -0,0 +1,288 @@ |
||||
#include "win32_window.h" |
||||
|
||||
#include <dwmapi.h> |
||||
#include <flutter_windows.h> |
||||
|
||||
#include "resource.h" |
||||
|
||||
namespace { |
||||
|
||||
/// Window attribute that enables dark mode window decorations.
|
||||
///
|
||||
/// Redefined in case the developer's machine has a Windows SDK older than
|
||||
/// version 10.0.22000.0.
|
||||
/// See: https://docs.microsoft.com/windows/win32/api/dwmapi/ne-dwmapi-dwmwindowattribute
|
||||
#ifndef DWMWA_USE_IMMERSIVE_DARK_MODE |
||||
#define DWMWA_USE_IMMERSIVE_DARK_MODE 20 |
||||
#endif |
||||
|
||||
constexpr const wchar_t kWindowClassName[] = L"FLUTTER_RUNNER_WIN32_WINDOW"; |
||||
|
||||
/// Registry key for app theme preference.
|
||||
///
|
||||
/// A value of 0 indicates apps should use dark mode. A non-zero or missing
|
||||
/// value indicates apps should use light mode.
|
||||
constexpr const wchar_t kGetPreferredBrightnessRegKey[] = |
||||
L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize"; |
||||
constexpr const wchar_t kGetPreferredBrightnessRegValue[] = L"AppsUseLightTheme"; |
||||
|
||||
// The number of Win32Window objects that currently exist.
|
||||
static int g_active_window_count = 0; |
||||
|
||||
using EnableNonClientDpiScaling = BOOL __stdcall(HWND hwnd); |
||||
|
||||
// Scale helper to convert logical scaler values to physical using passed in
|
||||
// scale factor
|
||||
int Scale(int source, double scale_factor) { |
||||
return static_cast<int>(source * scale_factor); |
||||
} |
||||
|
||||
// Dynamically loads the |EnableNonClientDpiScaling| from the User32 module.
|
||||
// This API is only needed for PerMonitor V1 awareness mode.
|
||||
void EnableFullDpiSupportIfAvailable(HWND hwnd) { |
||||
HMODULE user32_module = LoadLibraryA("User32.dll"); |
||||
if (!user32_module) { |
||||
return; |
||||
} |
||||
auto enable_non_client_dpi_scaling = |
||||
reinterpret_cast<EnableNonClientDpiScaling*>( |
||||
GetProcAddress(user32_module, "EnableNonClientDpiScaling")); |
||||
if (enable_non_client_dpi_scaling != nullptr) { |
||||
enable_non_client_dpi_scaling(hwnd); |
||||
} |
||||
FreeLibrary(user32_module); |
||||
} |
||||
|
||||
} // namespace
|
||||
|
||||
// Manages the Win32Window's window class registration.
|
||||
class WindowClassRegistrar { |
||||
public: |
||||
~WindowClassRegistrar() = default; |
||||
|
||||
// Returns the singleton registrar instance.
|
||||
static WindowClassRegistrar* GetInstance() { |
||||
if (!instance_) { |
||||
instance_ = new WindowClassRegistrar(); |
||||
} |
||||
return instance_; |
||||
} |
||||
|
||||
// Returns the name of the window class, registering the class if it hasn't
|
||||
// previously been registered.
|
||||
const wchar_t* GetWindowClass(); |
||||
|
||||
// Unregisters the window class. Should only be called if there are no
|
||||
// instances of the window.
|
||||
void UnregisterWindowClass(); |
||||
|
||||
private: |
||||
WindowClassRegistrar() = default; |
||||
|
||||
static WindowClassRegistrar* instance_; |
||||
|
||||
bool class_registered_ = false; |
||||
}; |
||||
|
||||
WindowClassRegistrar* WindowClassRegistrar::instance_ = nullptr; |
||||
|
||||
const wchar_t* WindowClassRegistrar::GetWindowClass() { |
||||
if (!class_registered_) { |
||||
WNDCLASS window_class{}; |
||||
window_class.hCursor = LoadCursor(nullptr, IDC_ARROW); |
||||
window_class.lpszClassName = kWindowClassName; |
||||
window_class.style = CS_HREDRAW | CS_VREDRAW; |
||||
window_class.cbClsExtra = 0; |
||||
window_class.cbWndExtra = 0; |
||||
window_class.hInstance = GetModuleHandle(nullptr); |
||||
window_class.hIcon = |
||||
LoadIcon(window_class.hInstance, MAKEINTRESOURCE(IDI_APP_ICON)); |
||||
window_class.hbrBackground = 0; |
||||
window_class.lpszMenuName = nullptr; |
||||
window_class.lpfnWndProc = Win32Window::WndProc; |
||||
RegisterClass(&window_class); |
||||
class_registered_ = true; |
||||
} |
||||
return kWindowClassName; |
||||
} |
||||
|
||||
void WindowClassRegistrar::UnregisterWindowClass() { |
||||
UnregisterClass(kWindowClassName, nullptr); |
||||
class_registered_ = false; |
||||
} |
||||
|
||||
Win32Window::Win32Window() { |
||||
++g_active_window_count; |
||||
} |
||||
|
||||
Win32Window::~Win32Window() { |
||||
--g_active_window_count; |
||||
Destroy(); |
||||
} |
||||
|
||||
bool Win32Window::Create(const std::wstring& title, |
||||
const Point& origin, |
||||
const Size& size) { |
||||
Destroy(); |
||||
|
||||
const wchar_t* window_class = |
||||
WindowClassRegistrar::GetInstance()->GetWindowClass(); |
||||
|
||||
const POINT target_point = {static_cast<LONG>(origin.x), |
||||
static_cast<LONG>(origin.y)}; |
||||
HMONITOR monitor = MonitorFromPoint(target_point, MONITOR_DEFAULTTONEAREST); |
||||
UINT dpi = FlutterDesktopGetDpiForMonitor(monitor); |
||||
double scale_factor = dpi / 96.0; |
||||
|
||||
HWND window = CreateWindow( |
||||
window_class, title.c_str(), WS_OVERLAPPEDWINDOW, |
||||
Scale(origin.x, scale_factor), Scale(origin.y, scale_factor), |
||||
Scale(size.width, scale_factor), Scale(size.height, scale_factor), |
||||
nullptr, nullptr, GetModuleHandle(nullptr), this); |
||||
|
||||
if (!window) { |
||||
return false; |
||||
} |
||||
|
||||
UpdateTheme(window); |
||||
|
||||
return OnCreate(); |
||||
} |
||||
|
||||
bool Win32Window::Show() { |
||||
return ShowWindow(window_handle_, SW_SHOWNORMAL); |
||||
} |
||||
|
||||
// static
|
||||
LRESULT CALLBACK Win32Window::WndProc(HWND const window, |
||||
UINT const message, |
||||
WPARAM const wparam, |
||||
LPARAM const lparam) noexcept { |
||||
if (message == WM_NCCREATE) { |
||||
auto window_struct = reinterpret_cast<CREATESTRUCT*>(lparam); |
||||
SetWindowLongPtr(window, GWLP_USERDATA, |
||||
reinterpret_cast<LONG_PTR>(window_struct->lpCreateParams)); |
||||
|
||||
auto that = static_cast<Win32Window*>(window_struct->lpCreateParams); |
||||
EnableFullDpiSupportIfAvailable(window); |
||||
that->window_handle_ = window; |
||||
} else if (Win32Window* that = GetThisFromHandle(window)) { |
||||
return that->MessageHandler(window, message, wparam, lparam); |
||||
} |
||||
|
||||
return DefWindowProc(window, message, wparam, lparam); |
||||
} |
||||
|
||||
LRESULT |
||||
Win32Window::MessageHandler(HWND hwnd, |
||||
UINT const message, |
||||
WPARAM const wparam, |
||||
LPARAM const lparam) noexcept { |
||||
switch (message) { |
||||
case WM_DESTROY: |
||||
window_handle_ = nullptr; |
||||
Destroy(); |
||||
if (quit_on_close_) { |
||||
PostQuitMessage(0); |
||||
} |
||||
return 0; |
||||
|
||||
case WM_DPICHANGED: { |
||||
auto newRectSize = reinterpret_cast<RECT*>(lparam); |
||||
LONG newWidth = newRectSize->right - newRectSize->left; |
||||
LONG newHeight = newRectSize->bottom - newRectSize->top; |
||||
|
||||
SetWindowPos(hwnd, nullptr, newRectSize->left, newRectSize->top, newWidth, |
||||
newHeight, SWP_NOZORDER | SWP_NOACTIVATE); |
||||
|
||||
return 0; |
||||
} |
||||
case WM_SIZE: { |
||||
RECT rect = GetClientArea(); |
||||
if (child_content_ != nullptr) { |
||||
// Size and position the child window.
|
||||
MoveWindow(child_content_, rect.left, rect.top, rect.right - rect.left, |
||||
rect.bottom - rect.top, TRUE); |
||||
} |
||||
return 0; |
||||
} |
||||
|
||||
case WM_ACTIVATE: |
||||
if (child_content_ != nullptr) { |
||||
SetFocus(child_content_); |
||||
} |
||||
return 0; |
||||
|
||||
case WM_DWMCOLORIZATIONCOLORCHANGED: |
||||
UpdateTheme(hwnd); |
||||
return 0; |
||||
} |
||||
|
||||
return DefWindowProc(window_handle_, message, wparam, lparam); |
||||
} |
||||
|
||||
void Win32Window::Destroy() { |
||||
OnDestroy(); |
||||
|
||||
if (window_handle_) { |
||||
DestroyWindow(window_handle_); |
||||
window_handle_ = nullptr; |
||||
} |
||||
if (g_active_window_count == 0) { |
||||
WindowClassRegistrar::GetInstance()->UnregisterWindowClass(); |
||||
} |
||||
} |
||||
|
||||
Win32Window* Win32Window::GetThisFromHandle(HWND const window) noexcept { |
||||
return reinterpret_cast<Win32Window*>( |
||||
GetWindowLongPtr(window, GWLP_USERDATA)); |
||||
} |
||||
|
||||
void Win32Window::SetChildContent(HWND content) { |
||||
child_content_ = content; |
||||
SetParent(content, window_handle_); |
||||
RECT frame = GetClientArea(); |
||||
|
||||
MoveWindow(content, frame.left, frame.top, frame.right - frame.left, |
||||
frame.bottom - frame.top, true); |
||||
|
||||
SetFocus(child_content_); |
||||
} |
||||
|
||||
RECT Win32Window::GetClientArea() { |
||||
RECT frame; |
||||
GetClientRect(window_handle_, &frame); |
||||
return frame; |
||||
} |
||||
|
||||
HWND Win32Window::GetHandle() { |
||||
return window_handle_; |
||||
} |
||||
|
||||
void Win32Window::SetQuitOnClose(bool quit_on_close) { |
||||
quit_on_close_ = quit_on_close; |
||||
} |
||||
|
||||
bool Win32Window::OnCreate() { |
||||
// No-op; provided for subclasses.
|
||||
return true; |
||||
} |
||||
|
||||
void Win32Window::OnDestroy() { |
||||
// No-op; provided for subclasses.
|
||||
} |
||||
|
||||
void Win32Window::UpdateTheme(HWND const window) { |
||||
DWORD light_mode; |
||||
DWORD light_mode_size = sizeof(light_mode); |
||||
LSTATUS result = RegGetValue(HKEY_CURRENT_USER, kGetPreferredBrightnessRegKey, |
||||
kGetPreferredBrightnessRegValue, |
||||
RRF_RT_REG_DWORD, nullptr, &light_mode, |
||||
&light_mode_size); |
||||
|
||||
if (result == ERROR_SUCCESS) { |
||||
BOOL enable_dark_mode = light_mode == 0; |
||||
DwmSetWindowAttribute(window, DWMWA_USE_IMMERSIVE_DARK_MODE, |
||||
&enable_dark_mode, sizeof(enable_dark_mode)); |
||||
} |
||||
} |
@ -0,0 +1,102 @@ |
||||
#ifndef RUNNER_WIN32_WINDOW_H_ |
||||
#define RUNNER_WIN32_WINDOW_H_ |
||||
|
||||
#include <windows.h> |
||||
|
||||
#include <functional> |
||||
#include <memory> |
||||
#include <string> |
||||
|
||||
// A class abstraction for a high DPI-aware Win32 Window. Intended to be
|
||||
// inherited from by classes that wish to specialize with custom
|
||||
// rendering and input handling
|
||||
class Win32Window { |
||||
public: |
||||
struct Point { |
||||
unsigned int x; |
||||
unsigned int y; |
||||
Point(unsigned int x, unsigned int y) : x(x), y(y) {} |
||||
}; |
||||
|
||||
struct Size { |
||||
unsigned int width; |
||||
unsigned int height; |
||||
Size(unsigned int width, unsigned int height) |
||||
: width(width), height(height) {} |
||||
}; |
||||
|
||||
Win32Window(); |
||||
virtual ~Win32Window(); |
||||
|
||||
// Creates a win32 window with |title| that is positioned and sized using
|
||||
// |origin| and |size|. New windows are created on the default monitor. Window
|
||||
// sizes are specified to the OS in physical pixels, hence to ensure a
|
||||
// consistent size this function will scale the inputted width and height as
|
||||
// as appropriate for the default monitor. The window is invisible until
|
||||
// |Show| is called. Returns true if the window was created successfully.
|
||||
bool Create(const std::wstring& title, const Point& origin, const Size& size); |
||||
|
||||
// Show the current window. Returns true if the window was successfully shown.
|
||||
bool Show(); |
||||
|
||||
// Release OS resources associated with window.
|
||||
void Destroy(); |
||||
|
||||
// Inserts |content| into the window tree.
|
||||
void SetChildContent(HWND content); |
||||
|
||||
// Returns the backing Window handle to enable clients to set icon and other
|
||||
// window properties. Returns nullptr if the window has been destroyed.
|
||||
HWND GetHandle(); |
||||
|
||||
// If true, closing this window will quit the application.
|
||||
void SetQuitOnClose(bool quit_on_close); |
||||
|
||||
// Return a RECT representing the bounds of the current client area.
|
||||
RECT GetClientArea(); |
||||
|
||||
protected: |
||||
// Processes and route salient window messages for mouse handling,
|
||||
// size change and DPI. Delegates handling of these to member overloads that
|
||||
// inheriting classes can handle.
|
||||
virtual LRESULT MessageHandler(HWND window, |
||||
UINT const message, |
||||
WPARAM const wparam, |
||||
LPARAM const lparam) noexcept; |
||||
|
||||
// Called when CreateAndShow is called, allowing subclass window-related
|
||||
// setup. Subclasses should return false if setup fails.
|
||||
virtual bool OnCreate(); |
||||
|
||||
// Called when Destroy is called.
|
||||
virtual void OnDestroy(); |
||||
|
||||
private: |
||||
friend class WindowClassRegistrar; |
||||
|
||||
// OS callback called by message pump. Handles the WM_NCCREATE message which
|
||||
// is passed when the non-client area is being created and enables automatic
|
||||
// non-client DPI scaling so that the non-client area automatically
|
||||
// responds to changes in DPI. All other messages are handled by
|
||||
// MessageHandler.
|
||||
static LRESULT CALLBACK WndProc(HWND const window, |
||||
UINT const message, |
||||
WPARAM const wparam, |
||||
LPARAM const lparam) noexcept; |
||||
|
||||
// Retrieves a class instance pointer for |window|
|
||||
static Win32Window* GetThisFromHandle(HWND const window) noexcept; |
||||
|
||||
// Update the window frame's theme to match the system theme.
|
||||
static void UpdateTheme(HWND const window); |
||||
|
||||
bool quit_on_close_ = false; |
||||
|
||||
// window handle for top level window.
|
||||
HWND window_handle_ = nullptr; |
||||
|
||||
// window handle for hosted content.
|
||||
HWND child_content_ = nullptr; |
||||
}; |
||||
|
||||
#endif // RUNNER_WIN32_WINDOW_H_
|
@ -0,0 +1,38 @@ |
||||
.idea/ |
||||
.vagrant/ |
||||
.sconsign.dblite |
||||
.svn/ |
||||
|
||||
.DS_Store |
||||
*.swp |
||||
profile |
||||
|
||||
DerivedData/ |
||||
build/ |
||||
GeneratedPluginRegistrant.h |
||||
GeneratedPluginRegistrant.m |
||||
|
||||
.generated/ |
||||
|
||||
*.pbxuser |
||||
*.mode1v3 |
||||
*.mode2v3 |
||||
*.perspectivev3 |
||||
|
||||
!default.pbxuser |
||||
!default.mode1v3 |
||||
!default.mode2v3 |
||||
!default.perspectivev3 |
||||
|
||||
xcuserdata |
||||
|
||||
*.moved-aside |
||||
|
||||
*.pyc |
||||
*sync/ |
||||
Icon? |
||||
.tags* |
||||
|
||||
/Flutter/Generated.xcconfig |
||||
/Flutter/ephemeral/ |
||||
/Flutter/flutter_export_environment.sh |
@ -0,0 +1,17 @@ |
||||
flutter/ |
||||
|
||||
# Visual Studio user-specific files. |
||||
*.suo |
||||
*.user |
||||
*.userosscache |
||||
*.sln.docstates |
||||
|
||||
# Visual Studio build-related files. |
||||
x64/ |
||||
x86/ |
||||
|
||||
# Visual Studio cache files |
||||
# files ending in .cache can be ignored |
||||
*.[Cc]ache |
||||
# but keep track of directories ending in .cache |
||||
!*.[Cc]ache/ |
@ -0,0 +1,105 @@ |
||||
# The Flutter tooling requires that developers have a version of Visual Studio |
||||
# installed that includes CMake 3.14 or later. You should not increase this |
||||
# version, as doing so will cause the plugin to fail to compile for some |
||||
# customers of the plugin. |
||||
cmake_minimum_required(VERSION 3.14) |
||||
|
||||
# Project-level configuration. |
||||
set(PROJECT_NAME "flutter_openim_sdk") |
||||
project(${PROJECT_NAME} LANGUAGES CXX) |
||||
|
||||
# Explicitly opt in to modern CMake behaviors to avoid warnings with recent |
||||
# versions of CMake. |
||||
cmake_policy(VERSION 3.14...3.25) |
||||
|
||||
# This value is used when generating builds using this plugin, so it must |
||||
# not be changed |
||||
set(PLUGIN_NAME "flutter_openim_sdk_plugin") |
||||
set(PCH_HEADER_FILE ${CMAKE_CURRENT_LIST_DIR}/src/common/stable.h) |
||||
|
||||
# third_party_libs |
||||
include_directories("${CMAKE_CURRENT_SOURCE_DIR}/third_party/alog/include") |
||||
link_directories("${CMAKE_CURRENT_SOURCE_DIR}/third_party/alog/lib/x64/${CMAKE_BUILD_TYPE}") |
||||
|
||||
FILE(GLOB SELF_TEMP_SRC_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} src/*.cpp src/*.h) |
||||
source_group(src FILES ${SELF_TEMP_SRC_FILES}) |
||||
list(APPEND NIM_CORE_SOURCES ${SELF_TEMP_SRC_FILES}) |
||||
|
||||
FILE(GLOB SELF_TEMP_SRC_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} src/common/*.cpp src/common/*.h) |
||||
source_group(src/common FILES ${SELF_TEMP_SRC_FILES}) |
||||
list(APPEND NIM_CORE_SOURCES ${SELF_TEMP_SRC_FILES}) |
||||
|
||||
FILE(GLOB SELF_TEMP_SRC_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} src/common/services/*.cpp src/common/services/*.h) |
||||
source_group(src/common/services FILES ${SELF_TEMP_SRC_FILES}) |
||||
list(APPEND NIM_CORE_SOURCES ${SELF_TEMP_SRC_FILES}) |
||||
|
||||
FILE(GLOB SELF_TEMP_SRC_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} src/common/utils/*.cpp src/common/utils/*.h src/common/utils/*.hpp) |
||||
source_group(src/common/utils FILES ${SELF_TEMP_SRC_FILES}) |
||||
list(APPEND NIM_CORE_SOURCES ${SELF_TEMP_SRC_FILES}) |
||||
|
||||
FILE(GLOB SELF_TEMP_SRC_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} src/utils/*.cpp src/utils/*.h) |
||||
source_group(src/utils FILES ${SELF_TEMP_SRC_FILES}) |
||||
list(APPEND NIM_CORE_SOURCES ${SELF_TEMP_SRC_FILES}) |
||||
|
||||
FILE(GLOB SELF_TEMP_SRC_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} src/utils/dump/*.cpp src/utils/dump/*.h) |
||||
source_group(src/utils/dump FILES ${SELF_TEMP_SRC_FILES}) |
||||
list(APPEND NIM_CORE_SOURCES ${SELF_TEMP_SRC_FILES}) |
||||
|
||||
# Any new source files that you add to the plugin should be added here. |
||||
list(APPEND PLUGIN_SOURCES |
||||
${CMAKE_CURRENT_LIST_DIR}/flutter_openim_sdk_plugin.cpp |
||||
) |
||||
|
||||
add_library(${PLUGIN_NAME} SHARED |
||||
${PLUGIN_SOURCES} |
||||
${NIM_CORE_SOURCES} |
||||
) |
||||
target_precompile_headers(${PLUGIN_NAME} PRIVATE ${PCH_HEADER_FILE}) |
||||
target_link_libraries(${PLUGIN_NAME} PRIVATE yx_alog) |
||||
|
||||
# Apply a standard set of build settings that are configured in the |
||||
# application-level CMakeLists.txt. This can be removed for plugins that want |
||||
# full control over build settings. |
||||
apply_standard_settings(${PLUGIN_NAME}) |
||||
|
||||
# Symbols are hidden by default to reduce the chance of accidental conflicts |
||||
# between plugins. This should not be removed; any symbols that should be |
||||
# exported should be explicitly exported with the FLUTTER_PLUGIN_EXPORT macro. |
||||
set_target_properties(${PLUGIN_NAME} PROPERTIES |
||||
CXX_VISIBILITY_PRESET hidden) |
||||
target_compile_definitions(${PLUGIN_NAME} PRIVATE FLUTTER_PLUGIN_IMPL) |
||||
target_compile_options(${PLUGIN_NAME} PRIVATE /W4 /WX- /wd4100 /wd4267 /wd4189 /wd4244 /wd4996 /bigobj /utf-8) |
||||
|
||||
target_include_directories(${PLUGIN_NAME} PUBLIC |
||||
"${CMAKE_CURRENT_LIST_DIR}/include" |
||||
"${CMAKE_CURRENT_LIST_DIR}/" |
||||
"${CMAKE_CURRENT_LIST_DIR}/openlib/x64/include" |
||||
) |
||||
|
||||
target_link_libraries(${PLUGIN_NAME} PRIVATE |
||||
flutter |
||||
flutter_wrapper_plugin |
||||
${CMAKE_CURRENT_LIST_DIR}/openlib/x64/libopenimsdk.lib |
||||
) |
||||
|
||||
|
||||
|
||||
file(GLOB flutter_openim_sdk_bundled_libraries |
||||
"${CMAKE_CURRENT_LIST_DIR}/openlib/x64/*.dll" |
||||
) |
||||
|
||||
file(GLOB LIBRARY_FILES "${CMAKE_CURRENT_LIST_DIR}/openlib/x64/*") |
||||
foreach(LIB_FILE ${LIBRARY_FILES}) |
||||
if(LIB_FILE MATCHES "cacert\.pem") |
||||
# 添加库文件路径到变量 |
||||
list(APPEND flutter_openim_sdk_bundled_libraries ${LIB_FILE}) |
||||
endif() |
||||
endforeach() |
||||
|
||||
set(flutter_openim_sdk_bundled_libraries ${flutter_openim_sdk_bundled_libraries} PARENT_SCOPE) |
||||
|
||||
|
||||
|
||||
#install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/openlib/libopenimsdk.dll |
||||
# DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" |
||||
#) |
@ -0,0 +1,104 @@ |
||||
#include "include/flutter_openim_sdk/flutter_openim_sdk_plugin.h" |
||||
|
||||
// This must be included before many other Windows headers.
|
||||
#include <windows.h> |
||||
|
||||
// For getPlatformVersion; remove unless needed for your plugin implementation.
|
||||
#include <VersionHelpers.h> |
||||
|
||||
#include <flutter/method_channel.h> |
||||
#include <flutter/plugin_registrar_windows.h> |
||||
#include <flutter/standard_method_codec.h> |
||||
|
||||
#include <memory> |
||||
#include <sstream> |
||||
#include "src/MethodCallHandlerImpl.h" |
||||
#include "src/common/stable.h" |
||||
|
||||
|
||||
class FlutterOpenimSdkPlugin : public flutter::Plugin { |
||||
public: |
||||
static void RegisterWithRegistrar(flutter::PluginRegistrarWindows *registrar); |
||||
|
||||
FlutterOpenimSdkPlugin(); |
||||
|
||||
virtual ~FlutterOpenimSdkPlugin(); |
||||
|
||||
// Disallow copy and assign.
|
||||
FlutterOpenimSdkPlugin(const FlutterOpenimSdkPlugin &) = delete; |
||||
|
||||
FlutterOpenimSdkPlugin &operator=(const FlutterOpenimSdkPlugin &) = delete; |
||||
|
||||
// Called when a method is called on this plugin's channel from Dart.
|
||||
void HandleMethodCall( |
||||
const flutter::MethodCall <flutter::EncodableValue> &method_call, |
||||
std::unique_ptr <flutter::MethodResult<flutter::EncodableValue>> result); |
||||
|
||||
public: |
||||
std::unique_ptr<MethodCallHandlerImpl> m_channel; |
||||
}; |
||||
|
||||
//std::string ws2s(const std::wstring& wstr) {
|
||||
// using convert_typeX = std::codecvt_utf8<wchar_t>;
|
||||
// std::wstring_convert<convert_typeX, wchar_t> converterX;
|
||||
// return converterX.to_bytes(wstr);
|
||||
//}
|
||||
|
||||
// static
|
||||
void FlutterOpenimSdkPlugin::RegisterWithRegistrar( |
||||
flutter::PluginRegistrarWindows *registrar) { |
||||
|
||||
//std::string filePath = ws2s(_wgetenv(L"LOCALAPPDATA"));
|
||||
std::string filePath = std::getenv("LOCALAPPDATA"); |
||||
std::string filePathApp; |
||||
if (!filePath.empty()) { |
||||
filePath.append("/OpenIM/OpenimPlugin"); |
||||
} else { |
||||
std::cout << "log filePath empty!" << std::endl; |
||||
} |
||||
filePathApp = filePath; |
||||
filePathApp.append("/app"); |
||||
std::cout << "log filePath: " << filePathApp.c_str() << std::endl; |
||||
ALog::CreateInstance(filePathApp, "nim_core_plugin", Info); |
||||
ALog::GetInstance()->setShortFileName(true); |
||||
YXLOG(Info) << "===================start===================" << YXLOGEnd; |
||||
YXLOG_API(Info) << "RegisterWithRegistrar, logPath: " << filePathApp |
||||
<< YXLOGEnd; |
||||
//InitDumpInfo("");
|
||||
|
||||
NimCore::getInstance()->setLogDir(filePath); |
||||
|
||||
auto plugin = std::make_unique<FlutterOpenimSdkPlugin>(); |
||||
auto channel = plugin->m_channel->startListening(registrar); |
||||
channel->SetMethodCallHandler( |
||||
[plugin_pointer = plugin.get()](const auto &call, auto result) { |
||||
plugin_pointer->HandleMethodCall(call, std::move(result)); |
||||
}); |
||||
|
||||
|
||||
registrar->AddPlugin(std::move(plugin)); |
||||
} |
||||
|
||||
FlutterOpenimSdkPlugin::FlutterOpenimSdkPlugin() { |
||||
m_channel = std::make_unique<MethodCallHandlerImpl>(); |
||||
} |
||||
|
||||
FlutterOpenimSdkPlugin::~FlutterOpenimSdkPlugin() { |
||||
m_channel.reset(nullptr); |
||||
} |
||||
|
||||
|
||||
|
||||
|
||||
void FlutterOpenimSdkPlugin::HandleMethodCall( |
||||
const flutter::MethodCall <flutter::EncodableValue> &method_call, |
||||
std::unique_ptr <flutter::MethodResult<flutter::EncodableValue>> result) { |
||||
m_channel->onMethodCall(method_call, std::move(result)); |
||||
} |
||||
|
||||
|
||||
void FlutterOpenimSdkPluginRegisterWithRegistrar(FlutterDesktopPluginRegistrarRef registrar) { |
||||
FlutterOpenimSdkPlugin::RegisterWithRegistrar( |
||||
flutter::PluginRegistrarManager::GetInstance() |
||||
->GetRegistrar<flutter::PluginRegistrarWindows>(registrar)); |
||||
} |
@ -0,0 +1,24 @@ |
||||
#ifndef FLUTTER_PLUGIN_FLUTTER_OPENIM_SDK_PLUGIN_H_ |
||||
#define FLUTTER_PLUGIN_FLUTTER_OPENIM_SDK_PLUGIN_H_ |
||||
|
||||
#include <flutter/plugin_registrar_windows.h> |
||||
#include <flutter_plugin_registrar.h> |
||||
|
||||
#ifdef FLUTTER_PLUGIN_IMPL |
||||
#define FLUTTER_PLUGIN_EXPORT __declspec(dllexport) |
||||
#else |
||||
#define FLUTTER_PLUGIN_EXPORT __declspec(dllimport) |
||||
#endif |
||||
|
||||
#if defined(__cplusplus) |
||||
extern "C" { |
||||
#endif |
||||
|
||||
FLUTTER_PLUGIN_EXPORT void FlutterOpenimSdkPluginRegisterWithRegistrar( |
||||
FlutterDesktopPluginRegistrarRef registrar); |
||||
|
||||
#if defined(__cplusplus) |
||||
} // extern "C"
|
||||
#endif |
||||
|
||||
#endif // FLUTTER_PLUGIN_FLUTTER_OPENIM_SDK_PLUGIN_H_
|
@ -0,0 +1,46 @@ |
||||
// Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
// Use of this source code is governed by a MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "FLTConvert.h" |
||||
|
||||
Convert::Convert() {} |
||||
|
||||
std::string Convert::getStringFormMapForLog( |
||||
const flutter::EncodableMap* arguments) const { |
||||
if (!arguments) { |
||||
return ""; |
||||
} |
||||
|
||||
// todo
|
||||
return ""; |
||||
} |
||||
|
||||
void Convert::getLogList(const std::string& strLog, |
||||
std::list<std::string>& listLog) const { |
||||
listLog.clear(); |
||||
int num = 15 * 1024; // 分割定长大小
|
||||
int len = strLog.length(); // 字符串长度
|
||||
int end = num; |
||||
for (int start = 0; start < len;) { |
||||
if (end > len) // 针对最后一个分割串
|
||||
{ |
||||
listLog.emplace_back( |
||||
strLog.substr(start, len - start)); // 最后一个字符串的原始部分
|
||||
break; |
||||
} |
||||
listLog.emplace_back( |
||||
strLog.substr(start, num)); // 从0开始,分割num位字符串
|
||||
start = end; |
||||
end = end + num; |
||||
} |
||||
} |
||||
|
||||
std::string Convert::getStringFormListForLog( |
||||
const flutter::EncodableList* arguments) const { |
||||
if (!arguments) { |
||||
return ""; |
||||
} |
||||
|
||||
return ""; |
||||
} |
@ -0,0 +1,29 @@ |
||||
// Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
// Use of this source code is governed by a MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef FLTCONVERT_H |
||||
#define FLTCONVERT_H |
||||
|
||||
#include <string> |
||||
#include <unordered_map> |
||||
|
||||
#include "common/FLTService.h" |
||||
#include "common/utils/singleton.h" |
||||
|
||||
class Convert { |
||||
public: |
||||
SINGLETONG(Convert) |
||||
|
||||
std::string getStringFormMapForLog( |
||||
const flutter::EncodableMap* arguments) const; |
||||
void getLogList(const std::string& strLog, |
||||
std::list<std::string>& listLog) const; |
||||
std::string getStringFormListForLog( |
||||
const flutter::EncodableList* arguments) const; |
||||
|
||||
private: |
||||
Convert(); |
||||
}; |
||||
|
||||
#endif // FLTCONVERT_H
|
@ -0,0 +1,45 @@ |
||||
// Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
// Use of this source code is governed by a MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "MethodCallHandlerImpl.h" |
||||
|
||||
#include <flutter/method_channel.h> |
||||
#include <flutter/plugin_registrar_windows.h> |
||||
#include <flutter/standard_method_codec.h> |
||||
|
||||
#include <memory> |
||||
|
||||
#include "NimCore.h" |
||||
|
||||
MethodCallHandlerImpl::MethodCallHandlerImpl() {} |
||||
|
||||
void MethodCallHandlerImpl::onMethodCall( |
||||
const flutter::MethodCall <flutter::EncodableValue> &method_call, |
||||
std::shared_ptr <flutter::MethodResult<flutter::EncodableValue>> result) { |
||||
const auto *arguments = |
||||
std::get_if<flutter::EncodableMap>(method_call.arguments()); |
||||
if (arguments) { |
||||
NimCore::getInstance()->onMethodCall(method_call.method_name(), arguments, |
||||
result); |
||||
} else { |
||||
if (result) { |
||||
result->NotImplemented(); |
||||
} |
||||
} |
||||
} |
||||
|
||||
flutter::MethodChannel <flutter::EncodableValue> * |
||||
MethodCallHandlerImpl::startListening(flutter::PluginRegistrar *registrar) { |
||||
m_methodChannel = |
||||
std::make_unique < flutter::MethodChannel < flutter::EncodableValue >> ( |
||||
registrar->messenger(), "flutter_openim_sdk", |
||||
&flutter::StandardMethodCodec::GetInstance()); |
||||
|
||||
NimCore::getInstance()->setMethodChannel(m_methodChannel.get()); |
||||
return m_methodChannel.get(); |
||||
} |
||||
|
||||
void MethodCallHandlerImpl::stopListening() { |
||||
NimCore::getInstance()->setMethodChannel(nullptr); |
||||
} |
@ -0,0 +1,34 @@ |
||||
// Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
// Use of this source code is governed by a MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef METHODCALLHANDLERIMPL_H |
||||
#define METHODCALLHANDLERIMPL_H |
||||
|
||||
#include <flutter/method_channel.h> |
||||
#include <flutter/plugin_registrar_windows.h> |
||||
#include <flutter/standard_method_codec.h> |
||||
|
||||
#include <memory> |
||||
|
||||
#include "NimCore.h" |
||||
|
||||
class MethodCallHandlerImpl { |
||||
public: |
||||
MethodCallHandlerImpl(); |
||||
|
||||
void onMethodCall( |
||||
const flutter::MethodCall<flutter::EncodableValue>& method_call, |
||||
std::shared_ptr<flutter::MethodResult<flutter::EncodableValue>> result); |
||||
|
||||
flutter::MethodChannel<flutter::EncodableValue>* startListening( |
||||
flutter::PluginRegistrar* registrar); |
||||
|
||||
void stopListening(); |
||||
|
||||
private: |
||||
std::unique_ptr<flutter::MethodChannel<flutter::EncodableValue>> |
||||
m_methodChannel; |
||||
}; |
||||
|
||||
#endif // METHODCALLHANDLERIMPL_H
|
@ -0,0 +1,252 @@ |
||||
// Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
// Use of this source code is governed by a MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "NimCore.h" |
||||
|
||||
#include <flutter/encodable_value.h> |
||||
#include <flutter/method_channel.h> |
||||
#include <flutter/plugin_registrar_windows.h> |
||||
#include <flutter/standard_method_codec.h> |
||||
|
||||
#include "FLTConvert.h" |
||||
|
||||
#include "common/services/IMManager.h" |
||||
|
||||
|
||||
const std::string kFLTNimCoreService = "serviceName"; |
||||
|
||||
NimCore::NimCore() { regService(); } |
||||
|
||||
NimCore::~NimCore() {} |
||||
|
||||
void NimCore::regService() { |
||||
addService(new IMManagerService()); |
||||
|
||||
} |
||||
|
||||
void NimCore::cleanService() { |
||||
// m_services.clear();
|
||||
|
||||
} |
||||
|
||||
void NimCore::addService(FLTService* service) { |
||||
m_services[service->getServiceName()] = service; |
||||
} |
||||
|
||||
// FLTMessageService* NimCore::getFLTMessageService() const {
|
||||
// return dynamic_cast<FLTMessageService*>(getService("MessageService"));
|
||||
// }
|
||||
|
||||
FLTService* NimCore::getService(const std::string& serviceName) const { |
||||
auto service = m_services.find(serviceName); |
||||
if (m_services.end() == service) { |
||||
return nullptr; |
||||
} |
||||
|
||||
return service->second; |
||||
} |
||||
|
||||
void NimCore::onMethodCall( |
||||
const std::string& method, const flutter::EncodableMap* arguments, |
||||
std::shared_ptr<flutter::MethodResult<flutter::EncodableValue>> result) { |
||||
if (nullptr == arguments) { |
||||
if (result) { |
||||
result->NotImplemented(); |
||||
} |
||||
return; |
||||
} |
||||
|
||||
auto serviceName_iter = |
||||
arguments->find(flutter::EncodableValue("ManagerName")); |
||||
if (serviceName_iter != arguments->end() && |
||||
!serviceName_iter->second.IsNull()) { |
||||
std::string serviceName = std::get<std::string>(serviceName_iter->second); |
||||
auto* service = getService(serviceName); |
||||
if (service) { |
||||
std::shared_ptr<MockMethodResult> mockResult = |
||||
std::make_shared<MockMethodResult>(serviceName, method, result); |
||||
YXLOG_API(Info) << "mn: " << method << ", args: " |
||||
<< Convert::getInstance()->getStringFormMapForLog( |
||||
arguments) |
||||
<< YXLOGEnd; |
||||
service->onMethodCalled(method, arguments, mockResult); |
||||
return; |
||||
} |
||||
} else { |
||||
YXLOG_API(Warn) << "sn not found, mn: " << method << YXLOGEnd; |
||||
} |
||||
|
||||
if (result) { |
||||
result->NotImplemented(); |
||||
} |
||||
} |
||||
|
||||
void NimCore::invokeMethod(const std::string& method, |
||||
const flutter::EncodableMap& arguments) { |
||||
if (m_channel) { |
||||
m_channel->InvokeMethod( |
||||
method, std::make_unique<flutter::EncodableValue>(arguments)); |
||||
} |
||||
} |
||||
|
||||
template <typename T> |
||||
class InterResult : public flutter::MethodResult<T> { |
||||
protected: |
||||
void SuccessInternal(const T* result) override { |
||||
if (result != nullptr) { |
||||
NimCore::getInstance()->invokeCallback(flutter::EncodableValue(*result)); |
||||
} else { |
||||
NimCore::getInstance()->invokeCallback(std::nullopt); |
||||
} |
||||
} |
||||
|
||||
// Implementation of the public interface, to be provided by subclasses.
|
||||
void ErrorInternal(const std::string& error_code, |
||||
const std::string& error_message, |
||||
const T* error_details) override {} |
||||
|
||||
// Implementation of the public interface, to be provided by subclasses.
|
||||
void NotImplementedInternal() override {} |
||||
}; |
||||
|
||||
void NimCore::invokeMethod(const std::string& eventName, |
||||
const flutter::EncodableMap& arguments, |
||||
const InvokeMehtodCallback& callback) { |
||||
invokeCallback = callback; |
||||
if (m_channel) { |
||||
m_channel->InvokeMethod( |
||||
eventName, std::make_unique<flutter::EncodableValue>(arguments), |
||||
std::make_unique<InterResult<flutter::EncodableValue>>()); |
||||
} |
||||
} |
||||
|
||||
void NimCore::setMethodChannel(NimMethodChannel* channel) { |
||||
m_channel = channel; |
||||
} |
||||
|
||||
NimCore::NimMethodChannel* NimCore::getMethodChannel() { return m_channel; } |
||||
|
||||
void NimCore::setAppkey(const std::string& appkey) { m_appKey = appkey; } |
||||
|
||||
std::string NimCore::getAppkey() const { return m_appKey; } |
||||
|
||||
void NimCore::setLogDir(const std::string& logDir) { m_logDir = logDir; } |
||||
|
||||
std::string NimCore::getLogDir() const { return m_logDir; } |
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
MockMethodResult::MockMethodResult( |
||||
const std::string serviceName, const std::string methodName, |
||||
std::shared_ptr<flutter::MethodResult<flutter::EncodableValue>> result) |
||||
: m_serviceName(serviceName), |
||||
m_methodName(methodName), |
||||
m_result(std::move(result)) {} |
||||
|
||||
void MockMethodResult::ErrorInternal(const std::string& error_code, |
||||
const std::string& error_message, |
||||
const flutter::EncodableValue* details) { |
||||
YXLOG_API(Warn) << "cb error, sn: " << m_serviceName |
||||
<< ", mn: " << m_methodName << ", error_code: " << error_code |
||||
<< ", error_msg: " << error_message |
||||
<< ", details: " << getStringFormEncodableValue(details) |
||||
<< YXLOGEnd; |
||||
if (m_result) m_result->Success(*details); |
||||
// //失败情况下, 也调用success接口,避免dart层抛出异常
|
||||
// m_result->Error(error_code, error_message, *details);
|
||||
} |
||||
|
||||
void MockMethodResult::NotImplementedInternal() { |
||||
YXLOG_API(Warn) << "cb notImplemented, sn: " << m_serviceName |
||||
<< ", mn: " << m_methodName << YXLOGEnd; |
||||
if (m_result) m_result->NotImplemented(); |
||||
} |
||||
|
||||
void MockMethodResult::SuccessInternal(const flutter::EncodableValue* result) { |
||||
std::string strLog; |
||||
strLog.append("cb succ, sn: ") |
||||
.append(m_serviceName) |
||||
.append(", mn: ") |
||||
.append(m_methodName) |
||||
.append(", result: ") |
||||
.append(getStringFormEncodableValue(result)); |
||||
std::list<std::string> logList; |
||||
Convert::getInstance()->getLogList(strLog, logList); |
||||
for (auto& it : logList) { |
||||
YXLOG_API(Info) << it << YXLOGEnd; |
||||
} |
||||
|
||||
if (m_result) m_result->Success(*result); |
||||
} |
||||
|
||||
std::string MockMethodResult::getStringFormEncodableValue( |
||||
const flutter::EncodableValue* value) const { |
||||
if (!value) { |
||||
return ""; |
||||
} |
||||
|
||||
std::string result; |
||||
if (auto it = std::get_if<bool>(value); it) { |
||||
result = *it ? "true" : "false"; |
||||
} else if (auto it1 = std::get_if<int32_t>(value); it1) { |
||||
result = std::to_string(*it1); |
||||
} else if (auto it2 = std::get_if<int64_t>(value); it2) { |
||||
result = std::to_string(*it2); |
||||
} else if (auto it3 = std::get_if<double>(value); it3) { |
||||
result = std::to_string(*it3); |
||||
} else if (auto it4 = std::get_if<std::string>(value); it4) { |
||||
result = *it4; |
||||
} else if (auto it5 = std::get_if<std::vector<uint8_t>>(value); it5) { |
||||
result.append("["); |
||||
bool bFirst = true; |
||||
for (auto& it5Tmp : *it5) { |
||||
if (!bFirst) { |
||||
result.append(","); |
||||
} |
||||
result.append(std::to_string(it5Tmp)); |
||||
bFirst = false; |
||||
} |
||||
result.append("]"); |
||||
} else if (auto it6 = std::get_if<std::vector<int32_t>>(value); it6) { |
||||
result.append("["); |
||||
bool bFirst = true; |
||||
for (auto& it6Tmp : *it6) { |
||||
if (!bFirst) { |
||||
result.append(","); |
||||
} |
||||
result.append(std::to_string(it6Tmp)); |
||||
bFirst = false; |
||||
} |
||||
result.append("]"); |
||||
} else if (auto it7 = std::get_if<std::vector<int64_t>>(value); it7) { |
||||
result.append("["); |
||||
bool bFirst = true; |
||||
for (auto& it7Tmp : *it7) { |
||||
if (!bFirst) { |
||||
result.append(","); |
||||
} |
||||
result.append(std::to_string(it7Tmp)); |
||||
bFirst = false; |
||||
} |
||||
result.append("]"); |
||||
} else if (auto it8 = std::get_if<std::vector<double>>(value); it8) { |
||||
result.append("["); |
||||
bool bFirst = true; |
||||
for (auto& it8Tmp : *it8) { |
||||
if (!bFirst) { |
||||
result.append(","); |
||||
} |
||||
result.append(std::to_string(it8Tmp)); |
||||
bFirst = false; |
||||
} |
||||
result.append("]"); |
||||
} else if (auto it9 = std::get_if<EncodableList>(value); it9) { |
||||
result = Convert::getInstance()->getStringFormListForLog(it9); |
||||
} else if (auto it10 = std::get_if<EncodableMap>(value); it10) { |
||||
result = Convert::getInstance()->getStringFormMapForLog(it10); |
||||
} else { |
||||
// wjzh
|
||||
} |
||||
|
||||
return result; |
||||
} |
@ -0,0 +1,105 @@ |
||||
// Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
// Use of this source code is governed by a MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef NIMCORE_H |
||||
#define NIMCORE_H |
||||
|
||||
#include <flutter/encodable_value.h> |
||||
#include <flutter/method_channel.h> |
||||
#include <flutter/plugin_registrar_windows.h> |
||||
#include <flutter/standard_method_codec.h> |
||||
|
||||
class FLTService; |
||||
|
||||
class FLTAuthService; |
||||
|
||||
class FLTMessageService; |
||||
|
||||
class NimCore { |
||||
public: |
||||
using NimMethodChannel = flutter::MethodChannel<flutter::EncodableValue>; |
||||
|
||||
public: |
||||
SINGLETONG(NimCore) |
||||
|
||||
private: |
||||
NimCore(); |
||||
|
||||
~NimCore(); |
||||
|
||||
public: |
||||
using InvokeMehtodCallback = |
||||
std::function<void(const std::optional <flutter::EncodableValue> &)>; |
||||
|
||||
InvokeMehtodCallback invokeCallback; |
||||
|
||||
void regService(); |
||||
|
||||
void cleanService(); |
||||
|
||||
void addService(FLTService *service); |
||||
|
||||
// FLTAuthService* getFLTAuthService() const;
|
||||
// FLTMessageService* getFLTMessageService() const;
|
||||
FLTService *getService(const std::string &serviceName) const; |
||||
|
||||
void onMethodCall( |
||||
const std::string &method, const flutter::EncodableMap *arguments, |
||||
std::shared_ptr <flutter::MethodResult<flutter::EncodableValue>> result); |
||||
|
||||
void invokeMethod(const std::string &method, |
||||
const flutter::EncodableMap &arguments); |
||||
|
||||
void invokeMethod(const std::string &eventName, |
||||
const flutter::EncodableMap &arguments, |
||||
const InvokeMehtodCallback &callback); |
||||
|
||||
void setMethodChannel(NimMethodChannel *channel); |
||||
|
||||
NimMethodChannel *getMethodChannel(); |
||||
|
||||
public: |
||||
void setAppkey(const std::string &appkey); |
||||
|
||||
std::string getAppkey() const; |
||||
|
||||
void setLogDir(const std::string &logDir); |
||||
|
||||
std::string getLogDir() const; |
||||
|
||||
std::string getAccountId() const; |
||||
|
||||
private: |
||||
std::unordered_map<std::string, FLTService *> m_services; |
||||
NimMethodChannel *m_channel = nullptr; |
||||
std::string m_appKey = ""; |
||||
std::string m_logDir; |
||||
}; |
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
class MockMethodResult : public flutter::MethodResult<> { |
||||
public: |
||||
MockMethodResult( |
||||
const std::string serviceName, const std::string methodName, |
||||
std::shared_ptr <flutter::MethodResult<flutter::EncodableValue>> result); |
||||
|
||||
virtual void ErrorInternal(const std::string &error_code, |
||||
const std::string &error_message, |
||||
const flutter::EncodableValue *details) override; |
||||
|
||||
virtual void NotImplementedInternal() override; |
||||
|
||||
virtual void SuccessInternal(const flutter::EncodableValue *result) override; |
||||
|
||||
private: |
||||
std::string getStringFormEncodableValue( |
||||
const flutter::EncodableValue *value) const; |
||||
|
||||
private: |
||||
std::string m_serviceName; |
||||
std::string m_methodName; |
||||
std::shared_ptr <flutter::MethodResult<flutter::EncodableValue>> m_result; |
||||
}; |
||||
|
||||
#endif // NIMCORE
|
@ -0,0 +1,65 @@ |
||||
// Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
// Use of this source code is governed by a MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "FLTService.h" |
||||
|
||||
#include "../FLTConvert.h" |
||||
|
||||
std::string FLTService::getServiceName() const { return m_serviceName; } |
||||
|
||||
void notifyEvent(const std::string& eventName, |
||||
flutter::EncodableMap& arguments) { |
||||
arguments.insert(std::make_pair(flutter::EncodableValue("serviceName"), |
||||
flutter::EncodableValue(""))); |
||||
std::string strLog; |
||||
strLog.append("en: ") |
||||
.append(eventName) |
||||
.append(", args: ") |
||||
.append(Convert::getInstance()->getStringFormMapForLog(&arguments)); |
||||
std::list<std::string> logList; |
||||
Convert::getInstance()->getLogList(strLog, logList); |
||||
for (auto& it : logList) { |
||||
YXLOG_API(Info) << it << YXLOGEnd; |
||||
} |
||||
NimCore::getInstance()->invokeMethod(eventName, arguments); |
||||
YXLOG_API(Info) << "notifyEvent invoke completation." << YXLOGEnd; |
||||
} |
||||
|
||||
//void FLTService::notifyEvent(const std::string& eventName,
|
||||
// flutter::EncodableMap& arguments,
|
||||
// const NimCore::InvokeMehtodCallback& callback) {
|
||||
// arguments.insert(std::make_pair(flutter::EncodableValue("serviceName"),
|
||||
// flutter::EncodableValue(m_serviceName)));
|
||||
// std::string strLog;
|
||||
// strLog.append("en: ")
|
||||
// .append(eventName)
|
||||
// .append(", args: ")
|
||||
// .append(Convert::getInstance()->getStringFormMapForLog(&arguments));
|
||||
// std::list<std::string> logList;
|
||||
// Convert::getInstance()->getLogList(strLog, logList);
|
||||
// for (auto& it : logList) {
|
||||
// YXLOG_API(Info) << it << YXLOGEnd;
|
||||
// }
|
||||
// NimCore::getInstance()->invokeMethod(eventName, arguments, callback);
|
||||
// YXLOG_API(Info) << "notifyEvent invoke completation." << YXLOGEnd;
|
||||
//}
|
||||
|
||||
void FLTService::notifyEventEx(const std::string& serviceName, |
||||
const std::string& eventName, |
||||
flutter::EncodableMap& arguments) { |
||||
arguments.insert(std::make_pair(flutter::EncodableValue("serviceName"), |
||||
flutter::EncodableValue(serviceName))); |
||||
std::string strLog; |
||||
strLog.append("en: ") |
||||
.append(eventName) |
||||
.append(", args: ") |
||||
.append(Convert::getInstance()->getStringFormMapForLog(&arguments)); |
||||
std::list<std::string> logList; |
||||
Convert::getInstance()->getLogList(strLog, logList); |
||||
for (auto& it : logList) { |
||||
YXLOG_API(Info) << it << YXLOGEnd; |
||||
} |
||||
NimCore::getInstance()->invokeMethod(eventName, arguments); |
||||
YXLOG_API(Info) << "notifyEventEx invoke completation." << YXLOGEnd; |
||||
} |
@ -0,0 +1,46 @@ |
||||
// Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
// Use of this source code is governed by a MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef FLTSERVICE_H |
||||
#define FLTSERVICE_H |
||||
|
||||
#include "../NimCore.h" |
||||
#include "NimResult.h" |
||||
#include "flutter/method_result.h" |
||||
|
||||
#define DECLARE_FUN(fun) \ |
||||
void fun(const flutter::EncodableMap* arguments, \
|
||||
FLTService::MethodResult result); |
||||
|
||||
void notifyEvent(const std::string& eventName, |
||||
flutter::EncodableMap& arguments); |
||||
|
||||
class FLTService { |
||||
public: |
||||
using MethodResult = |
||||
std::shared_ptr<flutter::MethodResult<flutter::EncodableValue>>; |
||||
|
||||
public: |
||||
virtual void onMethodCalled( |
||||
const std::string& method, const flutter::EncodableMap* arguments, |
||||
std::shared_ptr<flutter::MethodResult<flutter::EncodableValue>> |
||||
result) = 0; |
||||
|
||||
std::string getServiceName() const; |
||||
|
||||
|
||||
|
||||
//void notifyEvent(const std::string& eventName,
|
||||
// flutter::EncodableMap& arguments,
|
||||
// const NimCore::InvokeMehtodCallback& callback);
|
||||
|
||||
static void notifyEventEx(const std::string& serviceName, |
||||
const std::string& eventName, |
||||
flutter::EncodableMap& arguments); |
||||
|
||||
protected: |
||||
std::string m_serviceName; |
||||
}; |
||||
|
||||
#endif // FLTSERVICE_H
|
@ -0,0 +1,88 @@ |
||||
// Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
// Use of this source code is governed by a MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "NimResult.h" |
||||
|
||||
using namespace flutter; |
||||
|
||||
EncodableValue NimResult::getErrorResult(int code, const std::string& msg) { |
||||
EncodableMap result; |
||||
result.insert(std::make_pair(EncodableValue("code"), EncodableValue(code))); |
||||
result.insert( |
||||
std::make_pair(EncodableValue("errorDetails"), EncodableValue(msg))); |
||||
result.insert(std::make_pair(EncodableValue("data"), EncodableValue())); |
||||
return EncodableValue(result); |
||||
} |
||||
|
||||
EncodableValue NimResult::getErrorResult(int code, const std::string& msg, |
||||
const EncodableMap& data) { |
||||
EncodableMap result; |
||||
result.insert(std::make_pair(EncodableValue("code"), EncodableValue(code))); |
||||
result.insert( |
||||
std::make_pair(EncodableValue("errorDetails"), EncodableValue(msg))); |
||||
result.insert(std::make_pair(EncodableValue("data"), EncodableValue(data))); |
||||
return EncodableValue(result); |
||||
} |
||||
|
||||
EncodableValue NimResult::getSuccessResult() { |
||||
EncodableMap result; |
||||
result.insert(std::make_pair(EncodableValue("code"), EncodableValue(0))); |
||||
result.insert( |
||||
std::make_pair(EncodableValue("errorDetails"), EncodableValue(""))); |
||||
result.insert(std::make_pair(EncodableValue("data"), EncodableValue())); |
||||
return EncodableValue(result); |
||||
} |
||||
|
||||
EncodableValue NimResult::getSuccessResult(bool data) { |
||||
return getSuccessResult(EncodableValue(data)); |
||||
} |
||||
|
||||
EncodableValue NimResult::getSuccessResult(int32_t data) { |
||||
return getSuccessResult(EncodableValue(data)); |
||||
} |
||||
|
||||
EncodableValue NimResult::getSuccessResult(int64_t data) { |
||||
return getSuccessResult(EncodableValue(data)); |
||||
} |
||||
|
||||
EncodableValue NimResult::getSuccessResult(const std::string& data) { |
||||
return getSuccessResult(EncodableValue(data)); |
||||
} |
||||
|
||||
EncodableValue NimResult::getSuccessResult(const EncodableValue& data) { |
||||
EncodableMap result; |
||||
result.insert(std::make_pair(EncodableValue("code"), EncodableValue(0))); |
||||
result.insert( |
||||
std::make_pair(EncodableValue("errorDetails"), EncodableValue(""))); |
||||
result.insert(std::make_pair(EncodableValue("data"), data)); |
||||
return EncodableValue(result); |
||||
} |
||||
|
||||
EncodableValue NimResult::getSuccessResult(const EncodableMap& data) { |
||||
EncodableMap result; |
||||
result.insert(std::make_pair(EncodableValue("code"), EncodableValue(0))); |
||||
result.insert( |
||||
std::make_pair(EncodableValue("errorDetails"), EncodableValue(""))); |
||||
result.insert(std::make_pair(EncodableValue("data"), data)); |
||||
return EncodableValue(result); |
||||
} |
||||
|
||||
EncodableValue NimResult::getSuccessResult(const EncodableList& data) { |
||||
EncodableMap result; |
||||
result.insert(std::make_pair(EncodableValue("code"), EncodableValue(0))); |
||||
result.insert( |
||||
std::make_pair(EncodableValue("errorDetails"), EncodableValue(""))); |
||||
result.insert(std::make_pair(EncodableValue("data"), data)); |
||||
return EncodableValue(result); |
||||
} |
||||
|
||||
EncodableValue NimResult::getSuccessResult(const std::string& msg, |
||||
const EncodableMap& data) { |
||||
EncodableMap result; |
||||
result.insert(std::make_pair(EncodableValue("code"), EncodableValue(0))); |
||||
result.insert( |
||||
std::make_pair(EncodableValue("errorDetails"), EncodableValue(msg))); |
||||
result.insert(std::make_pair(EncodableValue("data"), EncodableValue(data))); |
||||
return EncodableValue(result); |
||||
} |
@ -0,0 +1,34 @@ |
||||
// Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
// Use of this source code is governed by a MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef NIMRESULT_H |
||||
#define NIMRESULT_H |
||||
|
||||
#include "flutter/encodable_value.h" |
||||
|
||||
using namespace flutter; |
||||
|
||||
class NimResult { |
||||
public: |
||||
static EncodableValue getErrorResult(int code, const std::string& msg); |
||||
static EncodableValue getErrorResult(int code, const std::string& msg, |
||||
const flutter::EncodableMap& data); |
||||
|
||||
static EncodableValue getSuccessResult(); |
||||
static EncodableValue getSuccessResult(bool data); |
||||
static EncodableValue getSuccessResult(int32_t data); |
||||
static EncodableValue getSuccessResult(int64_t data); |
||||
static EncodableValue getSuccessResult(const std::string& data); |
||||
static EncodableValue getSuccessResult(const flutter::EncodableValue& data); |
||||
static EncodableValue getSuccessResult(const flutter::EncodableMap& data); |
||||
static EncodableValue getSuccessResult(const flutter::EncodableList& data); |
||||
static EncodableValue getSuccessResult(const std::string& msg, |
||||
const flutter::EncodableMap& data); |
||||
}; |
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif // NIMRESULT_H
|
@ -0,0 +1,71 @@ |
||||
#include "ZegoDataUtils.h" |
||||
|
||||
bool zego_value_is_null(flutter::EncodableValue value) { return value.IsNull(); } |
||||
|
||||
int32_t zego_value_get_int(flutter::EncodableValue value) { |
||||
// dart 没有 int32_t int64_t 区分,这里处理了 int32 最高位为 1(负数)的 case
|
||||
return (int32_t)zego_value_get_long(value); |
||||
} |
||||
|
||||
int64_t zego_value_get_long(flutter::EncodableValue value) { return value.LongValue(); } |
||||
|
||||
bool zego_value_get_bool(flutter::EncodableValue value) { return std::get<bool>(value); } |
||||
|
||||
double zego_value_get_double(flutter::EncodableValue value) { return std::get<double>(value); } |
||||
|
||||
std::string zego_value_get_string(flutter::EncodableValue value) { |
||||
return std::get<std::string>(value); |
||||
} |
||||
|
||||
std::vector<float> zego_value_get_vector_float(flutter::EncodableValue value) { |
||||
return std::get<std::vector<float>>(value); |
||||
} |
||||
|
||||
std::vector<uint8_t> zego_value_get_vector_uint8(flutter::EncodableValue value) { |
||||
return std::get<std::vector<uint8_t>>(value); |
||||
} |
||||
|
||||
ZFMap zego_value_get_map(flutter::EncodableValue value) { return std::get<ZFMap>(value); } |
||||
|
||||
ZFArray zego_value_get_list(flutter::EncodableValue value) { return std::get<ZFArray>(value); } |
||||
|
||||
|
||||
// 将 EncodableValue 转换为 nlohmann::json
|
||||
nlohmann::json EncodableValueToJson(const flutter::EncodableValue& value) { |
||||
if (std::holds_alternative<bool>(value)) { |
||||
return std::get<bool>(value); |
||||
} else if (std::holds_alternative<int32_t>(value)) { |
||||
return std::get<int32_t>(value); |
||||
} else if (std::holds_alternative<int64_t>(value)) { |
||||
return std::get<int64_t>(value); |
||||
} else if (std::holds_alternative<double>(value)) { |
||||
return std::get<double>(value); |
||||
} else if (std::holds_alternative<std::string>(value)) { |
||||
return std::get<std::string>(value); |
||||
} else if (std::holds_alternative<flutter::EncodableList>(value)) { |
||||
nlohmann::json json_array = nlohmann::json::array(); |
||||
for (const auto& item : std::get<flutter::EncodableList>(value)) { |
||||
json_array.push_back(EncodableValueToJson(item)); |
||||
} |
||||
return json_array; |
||||
} else if (std::holds_alternative<flutter::EncodableMap>(value)) { |
||||
nlohmann::json json_object = nlohmann::json::object(); |
||||
for (const auto& pair : std::get<flutter::EncodableMap>(value)) { |
||||
std::string key = std::get<std::string>(pair.first); // 假设键是字符串
|
||||
json_object[key] = EncodableValueToJson(pair.second); |
||||
} |
||||
return json_object; |
||||
} |
||||
return nullptr; // 处理空值或不支持的类型
|
||||
} |
||||
|
||||
// 将 EncodableMap 转换为 JSON 字符串
|
||||
std::string map_2_json(const flutter::EncodableMap& map) { |
||||
nlohmann::json json_object = nlohmann::json::object(); |
||||
for (const auto& pair : map) { |
||||
std::string key = std::get<std::string>(pair.first); // 假设键是字符串
|
||||
json_object[key] = EncodableValueToJson(pair.second); |
||||
} |
||||
auto json_string = json_object.dump(); // 序列化为 JSON 字符串
|
||||
return json_string; // 序列化为 JSON 字符串
|
||||
} |
@ -0,0 +1,36 @@ |
||||
#pragma once |
||||
|
||||
#include <flutter/encodable_value.h> |
||||
#include <flutter/event_channel.h> |
||||
#include <memory> |
||||
#include "json.hpp" |
||||
|
||||
#define ZFValue(varName) flutter::EncodableValue(varName) |
||||
#define ZFMap flutter::EncodableMap |
||||
#define ZFArray flutter::EncodableList |
||||
|
||||
#define ZFArgument flutter::EncodableMap & |
||||
#define ZFResult std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>> |
||||
#define ZFEventSink std::unique_ptr<flutter::EventSink<flutter::EncodableValue>> |
||||
#define ZFMoveResult(result) std::shared_ptr<flutter::MethodResult<flutter::EncodableValue>>(std::move(result)) |
||||
|
||||
#define ZFPluginRegistrar flutter::PluginRegistrarWindows |
||||
#define ZFBinaryMessenger flutter::BinaryMessenger |
||||
#define ZFTextureRegistrar flutter::TextureRegistrar |
||||
|
||||
bool zego_value_is_null(flutter::EncodableValue value); |
||||
|
||||
int32_t zego_value_get_int(flutter::EncodableValue value); |
||||
int64_t zego_value_get_long(flutter::EncodableValue value); |
||||
bool zego_value_get_bool(flutter::EncodableValue value); |
||||
double zego_value_get_double(flutter::EncodableValue value); |
||||
std::string zego_value_get_string(flutter::EncodableValue value); |
||||
|
||||
std::vector<float> zego_value_get_vector_float(flutter::EncodableValue value); |
||||
std::vector<uint8_t> zego_value_get_vector_uint8(flutter::EncodableValue value); |
||||
ZFMap zego_value_get_map(flutter::EncodableValue value); |
||||
ZFArray zego_value_get_list(flutter::EncodableValue value); |
||||
std::string map_2_json(const flutter::EncodableMap& map); |
||||
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,70 @@ |
||||
#ifndef CONST_DEFINE_H |
||||
#define CONST_DEFINE_H |
||||
|
||||
enum class ConstDefine { |
||||
CONNECTING = 0, |
||||
CONNECT_SUCCESS, |
||||
CONNECT_FAILED, |
||||
KICKED_OFFLINE, |
||||
USER_TOKEN_EXPIRED, |
||||
JOINED_GROUP_ADDED, |
||||
JOINED_GROUP_DELETED, |
||||
GROUP_MEMBER_ADDED, |
||||
GROUP_MEMBER_DELETED, |
||||
GROUP_APPLICATION_ADDED, |
||||
GROUP_APPLICATION_DELETED, |
||||
GROUP_INFO_CHANGED, |
||||
GROUP_DISMISSED, |
||||
GROUP_MEMBER_INFO_CHANGED, |
||||
GROUP_APPLICATION_ACCEPTED, |
||||
GROUP_APPLICATION_REJECTED, |
||||
FRIEND_APPLICATION_ADDED, |
||||
FRIEND_APPLICATION_DELETED, |
||||
FRIEND_APPLICATION_ACCEPTED, |
||||
FRIEND_APPLICATION_REJECTED, |
||||
FRIEND_ADDED, |
||||
FRIEND_DELETED, |
||||
FRIEND_INFO_CHANGED, |
||||
BLACK_ADDED, |
||||
BLACK_DELETED, |
||||
SYNC_SERVER_START, |
||||
SYNC_SERVER_FINISH, |
||||
SYNC_SERVER_PROGRESS, |
||||
SYNC_SERVER_FAILED, |
||||
NEW_CONVERSATION, |
||||
CONVERSATION_CHANGED, |
||||
TOTAL_UNREAD_MESSAGE_COUNT_CHANGED, |
||||
RECV_NEW_MESSAGE, |
||||
RECV_C2C_READ_RECEIPT, |
||||
RECV_GROUP_READ_RECEIPT, |
||||
NEW_RECV_MESSAGE_REVOKED, |
||||
RECV_MESSAGE_EXTENSIONS_CHANGED, |
||||
RECV_MESSAGE_EXTENSIONS_DELETED, |
||||
RECV_MESSAGE_EXTENSIONS_ADDED, |
||||
RECV_OFFLINE_NEW_MESSAGE, |
||||
MSG_DELETED, |
||||
RECV_NEW_MESSAGES, |
||||
RECV_OFFLINE_NEW_MESSAGES, |
||||
SELF_INFO_UPDATED, |
||||
USER_STATUS_CHANGED, |
||||
RECV_CUSTOM_BUSINESS_MESSAGE, |
||||
MESSAGE_KV_INFO_CHANGED, |
||||
OPEN, |
||||
PART_SIZE, |
||||
HASH_PART_PROGRESS, |
||||
HASH_PART_COMPLETE, |
||||
UPLOAD_ID, |
||||
UPLOAD_PART_COMPLETE, |
||||
UPLOAD_COMPLETE, |
||||
COMPLETE, |
||||
CONVERSATION_USER_INPUT_STATUS_CHANGED, |
||||
RECV_ONLINE_ONLY_MESSAGE, |
||||
RECV_MESSAGE_EDIT, |
||||
USER_TOKEN_INVALID, |
||||
ON_PROGRESS |
||||
}; |
||||
|
||||
|
||||
|
||||
|
||||
#endif // EVENT_TYPES_H
|
@ -0,0 +1,339 @@ |
||||
// Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
// Use of this source code is governed by a MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "IMManager.h" |
||||
|
||||
#if defined(_WIN32) |
||||
#include <windows.h> |
||||
#endif |
||||
|
||||
#include "../NimResult.h" |
||||
#include <libopenimsdk.h> |
||||
#include "../ZegoDataUtils.h" |
||||
#include "ConstDefine.h" |
||||
|
||||
|
||||
IMManagerService::IMManagerService() { |
||||
m_serviceName = "imManager"; |
||||
|
||||
_im_manager_listener.onInitSdk = [](int state, char *msg) { |
||||
// friend added, handle friendInfo
|
||||
|
||||
flutter::EncodableMap arguments; |
||||
switch (ConstDefine(state)) { |
||||
case ConstDefine::CONNECTING: |
||||
arguments.insert(std::make_pair("type", "onConnecting")); |
||||
arguments.insert(std::make_pair("data", *msg)); |
||||
break; |
||||
case ConstDefine::CONNECT_SUCCESS: |
||||
arguments.insert(std::make_pair("type", "onConnectSuccess")); |
||||
arguments.insert(std::make_pair("data", *msg)); |
||||
break; |
||||
case ConstDefine::CONNECT_FAILED: |
||||
arguments.insert(std::make_pair("type", "onConnectFailed")); |
||||
arguments.insert(std::make_pair("data", *msg)); |
||||
break; |
||||
case ConstDefine::KICKED_OFFLINE: |
||||
arguments.insert(std::make_pair("type", "onKickedOffline")); |
||||
arguments.insert(std::make_pair("data", *msg)); |
||||
break; |
||||
case ConstDefine::USER_TOKEN_EXPIRED: |
||||
arguments.insert(std::make_pair("type", "onUserTokenExpired")); |
||||
arguments.insert(std::make_pair("data", *msg)); |
||||
break; |
||||
case ConstDefine::USER_TOKEN_INVALID: |
||||
arguments.insert(std::make_pair("type", "onUserTokenExpired")); |
||||
arguments.insert(std::make_pair("data", *msg)); |
||||
break; |
||||
} |
||||
notifyEvent("connectListener", arguments); |
||||
}; |
||||
|
||||
_im_manager_listener.baseCallBack = [](char *opid, int errCode, char *errMsg, char *msg) { |
||||
CallBaseCallBack(msg, errCode, errMsg, msg); |
||||
}; |
||||
|
||||
_im_manager_listener.uploadCallback = [](int state, char *msg) { |
||||
// upload progress
|
||||
|
||||
flutter::EncodableMap arguments; |
||||
switch (ConstDefine(state)) { |
||||
case ConstDefine::OPEN: |
||||
arguments.insert(std::make_pair("type", "onConnecting")); |
||||
arguments.insert(std::make_pair("data", *msg)); |
||||
break; |
||||
case ConstDefine::PART_SIZE: |
||||
arguments.insert(std::make_pair("type", "onConnectSuccess")); |
||||
arguments.insert(std::make_pair("data", *msg)); |
||||
break; |
||||
case ConstDefine::HASH_PART_PROGRESS: |
||||
arguments.insert(std::make_pair("type", "onConnectFailed")); |
||||
arguments.insert(std::make_pair("data", *msg)); |
||||
break; |
||||
case ConstDefine::HASH_PART_COMPLETE: |
||||
arguments.insert(std::make_pair("type", "onKickedOffline")); |
||||
arguments.insert(std::make_pair("data", *msg)); |
||||
break; |
||||
case ConstDefine::UPLOAD_ID: |
||||
arguments.insert(std::make_pair("type", "onUserTokenExpired")); |
||||
arguments.insert(std::make_pair("data", *msg)); |
||||
break; |
||||
case ConstDefine::UPLOAD_PART_COMPLETE: |
||||
arguments.insert(std::make_pair("type", "onUserTokenExpired")); |
||||
arguments.insert(std::make_pair("data", *msg)); |
||||
break; |
||||
case ConstDefine::UPLOAD_COMPLETE: |
||||
arguments.insert(std::make_pair("type", "onUserTokenExpired")); |
||||
arguments.insert(std::make_pair("data", *msg)); |
||||
break; |
||||
case ConstDefine::COMPLETE: |
||||
arguments.insert(std::make_pair("type", "onUserTokenExpired")); |
||||
arguments.insert(std::make_pair("data", *msg)); |
||||
break; |
||||
} |
||||
notifyEvent("uploadFileListener", arguments); |
||||
}; |
||||
} |
||||
|
||||
void IMManagerService::onMethodCalled( |
||||
const std::string &method, const flutter::EncodableMap *arguments, |
||||
std::shared_ptr<flutter::MethodResult<flutter::EncodableValue>> result) { |
||||
if (method == "initSDK") { |
||||
initializeSDK(arguments, result); |
||||
} else if (method == "unInitSDK") { |
||||
unInitSDK(arguments, result); |
||||
} else if (method == "login") { |
||||
login(arguments, result); |
||||
} else if (method == "logout") { |
||||
logout(arguments, result); |
||||
} else if (method == "getLoginStatus") { |
||||
getLoginStatus(arguments, result); |
||||
} else if (method == "uploadFile") { |
||||
uploadFile(arguments, result); |
||||
} else if (method == "uploadLogs") { |
||||
uploadLogs(arguments, result); |
||||
} else if (method == "logs") { |
||||
logs(arguments, result); |
||||
} else if (method == "updateFcmToken") { |
||||
updateFcmToken(arguments, result); |
||||
} else if (method == "setAppBackgroundStatus") { |
||||
setAppBackgroundStatus(arguments, result); |
||||
} else if (method == "networkStatusChanged") { |
||||
networkStatusChanged(arguments, result); |
||||
|
||||
} else { |
||||
result->NotImplemented(); |
||||
} |
||||
} |
||||
|
||||
|
||||
void IMManagerService::initializeSDK( |
||||
const flutter::EncodableMap *arguments, |
||||
std::shared_ptr<flutter::MethodResult<flutter::EncodableValue>> result) { |
||||
if (arguments) { |
||||
auto operationID = zego_value_get_string(arguments->at(ZFValue("operationID"))); |
||||
char *operationID_cs = const_cast<char *>(operationID.c_str()); |
||||
auto config = map_2_json(*arguments); |
||||
char *config_cs = const_cast<char *>(config.c_str()); |
||||
|
||||
|
||||
auto error = init_sdk(_im_manager_listener.onInitSdk, |
||||
operationID_cs, |
||||
config_cs); |
||||
if (error == 0) { |
||||
// handle error
|
||||
std::string msg = "IM init failed"; |
||||
result->Error("", "", |
||||
NimResult::getErrorResult(error, "")); |
||||
} else { |
||||
|
||||
result->Success(EncodableValue(error == 0)); |
||||
} |
||||
} |
||||
} |
||||
|
||||
|
||||
void IMManagerService::unInitSDK( |
||||
const flutter::EncodableMap *arguments, |
||||
std::shared_ptr<flutter::MethodResult<flutter::EncodableValue>> result) { |
||||
if (arguments) { |
||||
auto operationID = zego_value_get_string( |
||||
arguments->at(flutter::EncodableValue("operationID"))); |
||||
char *operationID_cs = const_cast<char *>(operationID.c_str()); |
||||
|
||||
un_init_sdk(operationID_cs); |
||||
|
||||
} else { |
||||
result->Error("INVALID_ARGUMENT", "Arguments cannot be null"); |
||||
} |
||||
} |
||||
|
||||
void IMManagerService::login( |
||||
const flutter::EncodableMap *arguments, |
||||
std::shared_ptr<flutter::MethodResult<flutter::EncodableValue>> result) { |
||||
if (arguments) { |
||||
auto operationID = zego_value_get_string( |
||||
arguments->at(flutter::EncodableValue("operationID"))); |
||||
auto userID = zego_value_get_string(arguments->at(flutter::EncodableValue("userID"))); |
||||
auto token = zego_value_get_string(arguments->at(flutter::EncodableValue("token"))); |
||||
char *operationID_cs = const_cast<char *>(operationID.c_str()); |
||||
char *userID_cs = const_cast<char *>(userID.c_str()); |
||||
char *token_cs = const_cast<char *>(token.c_str()); |
||||
|
||||
NewBaseCallBack(operationID, result); |
||||
|
||||
::login(_im_manager_listener.baseCallBack, operationID_cs, userID_cs, token_cs); |
||||
|
||||
} else { |
||||
result->Error("INVALID_ARGUMENT", "Arguments cannot be null"); |
||||
} |
||||
} |
||||
|
||||
void IMManagerService::logout( |
||||
const flutter::EncodableMap *arguments, |
||||
std::shared_ptr<flutter::MethodResult<flutter::EncodableValue>> result) { |
||||
if (arguments) { |
||||
auto operationID = zego_value_get_string( |
||||
arguments->at(flutter::EncodableValue("operationID"))); |
||||
char *operationID_cs = const_cast<char *>(operationID.c_str()); |
||||
NewBaseCallBack(operationID, result); |
||||
::logout(_im_manager_listener.baseCallBack, operationID_cs); |
||||
|
||||
} else { |
||||
result->Error("INVALID_ARGUMENT", "Arguments cannot be null"); |
||||
} |
||||
} |
||||
|
||||
void IMManagerService::getLoginStatus( |
||||
const flutter::EncodableMap *arguments, |
||||
std::shared_ptr<flutter::MethodResult<flutter::EncodableValue>> result) { |
||||
if (arguments) { |
||||
auto operationID = zego_value_get_string( |
||||
arguments->at(flutter::EncodableValue("operationID"))); |
||||
char *operationID_cs = const_cast<char *>(operationID.c_str()); |
||||
|
||||
int status = get_login_status(operationID_cs); |
||||
flutter::EncodableMap statusMap; |
||||
|
||||
result->Success(flutter::EncodableValue(status)); |
||||
} else { |
||||
result->Error("INVALID_ARGUMENT", "Arguments cannot be null"); |
||||
} |
||||
} |
||||
|
||||
void IMManagerService::uploadFile( |
||||
const flutter::EncodableMap *arguments, |
||||
std::shared_ptr<flutter::MethodResult<flutter::EncodableValue>> result) { |
||||
// if (arguments) {
|
||||
// auto operationID = zego_value_get_string(arguments->at(flutter::EncodableValue("operationID")));
|
||||
// auto id = zego_value_get_string(arguments->at(flutter::EncodableValue("id")));
|
||||
// auto fileInfo = map_2_json(*arguments);
|
||||
// char* operationID_cs = const_cast<char*>(operationID.c_str());
|
||||
// char* fileInfo_cs = const_cast<char*>(fileInfo.c_str());
|
||||
// uploadFileResult = result;
|
||||
// upload_file(_im_manager_listener.onUploadFile, operationID_cs, fileInfo_cs, _im_manager_listener.uploadCallback);
|
||||
// }
|
||||
// else {
|
||||
// result->Error("INVALID_ARGUMENT", "Arguments cannot be null");
|
||||
// }
|
||||
} |
||||
|
||||
void IMManagerService::uploadLogs( |
||||
const flutter::EncodableMap *arguments, |
||||
std::shared_ptr<flutter::MethodResult<flutter::EncodableValue>> result) { |
||||
// if (arguments) {
|
||||
// auto operationID = zego_value_get_string(
|
||||
// arguments->at(flutter::EncodableValue("operationID")));
|
||||
// auto line = zego_value_get_int(arguments->at(flutter::EncodableValue("line")));
|
||||
// auto ex = zego_value_get_string(arguments->at(flutter::EncodableValue("ex")));
|
||||
// char *operationID_cs = const_cast<char *>(operationID.c_str());
|
||||
// char *ex_cs = const_cast<char *>(ex.c_str());
|
||||
//
|
||||
// upload_logs(_im_manager_listener.onUploadLogs, operationID_cs, line, ex_cs);
|
||||
//
|
||||
// } else {
|
||||
// result->Error("INVALID_ARGUMENT", "Arguments cannot be null");
|
||||
// }
|
||||
} |
||||
|
||||
void IMManagerService::logs( |
||||
const flutter::EncodableMap *arguments, |
||||
std::shared_ptr<flutter::MethodResult<flutter::EncodableValue>> result) { |
||||
// if (arguments) {
|
||||
// auto operationID = zego_value_get_string(arguments->at(flutter::EncodableValue("operationID")));
|
||||
// auto logLevel = zego_value_get_int(arguments->at(flutter::EncodableValue("logLevel")));
|
||||
// auto file = zego_value_get_string(arguments->at(flutter::EncodableValue("file")));
|
||||
// auto line = zego_value_get_int(arguments->at(flutter::EncodableValue("line")));
|
||||
// auto msgs = zego_value_get_string(arguments->at(flutter::EncodableValue("msgs")));
|
||||
// auto err = zego_value_get_string(arguments->at(flutter::EncodableValue("err")));
|
||||
// auto keyAndValue = zego_value_get_string(arguments->at(flutter::EncodableValue("keyAndValue")));
|
||||
// char* operationID_cs = const_cast<char*>(operationID.c_str());
|
||||
// char* file_cs = const_cast<char*>(file.c_str());
|
||||
// char* msgs_cs = const_cast<char*>(msgs.c_str());
|
||||
// char* err_cs = const_cast<char*>(err.c_str());
|
||||
// char* keyAndValue_cs = const_cast<char*>(keyAndValue.c_str());
|
||||
//
|
||||
// auto error = logs(_im_manager_listener.onLogs, operationID_cs, logLevel, file_cs, line, msgs_cs, err_cs, keyAndValue_cs);
|
||||
// if (error != 0) {
|
||||
// std::string msg = "Logging failed";
|
||||
// result->Error("", "", NimResult::getErrorResult(error, msg));
|
||||
// }
|
||||
// else {
|
||||
// result->Success(NimResult::getSuccessResult());
|
||||
// }
|
||||
// }
|
||||
// else {
|
||||
// result->Error("INVALID_ARGUMENT", "Arguments cannot be null");
|
||||
// }
|
||||
} |
||||
|
||||
void IMManagerService::updateFcmToken( |
||||
const flutter::EncodableMap *arguments, |
||||
std::shared_ptr<flutter::MethodResult<flutter::EncodableValue>> result) { |
||||
if (arguments) { |
||||
auto operationID = zego_value_get_string( |
||||
arguments->at(flutter::EncodableValue("operationID"))); |
||||
auto fcmToken = zego_value_get_string(arguments->at(flutter::EncodableValue("fcmToken"))); |
||||
auto expireTime = zego_value_get_int(arguments->at(flutter::EncodableValue("expireTime"))); |
||||
char *operationID_cs = const_cast<char *>(operationID.c_str()); |
||||
char *fcmToken_cs = const_cast<char *>(fcmToken.c_str()); |
||||
NewBaseCallBack(operationID, result); |
||||
update_fcm_token(_im_manager_listener.baseCallBack, operationID_cs, fcmToken_cs, |
||||
expireTime); |
||||
} else { |
||||
result->Error("INVALID_ARGUMENT", "Arguments cannot be null"); |
||||
} |
||||
} |
||||
|
||||
void IMManagerService::setAppBackgroundStatus( |
||||
const flutter::EncodableMap *arguments, |
||||
std::shared_ptr<flutter::MethodResult<flutter::EncodableValue>> result) { |
||||
if (arguments) { |
||||
auto operationID = zego_value_get_string(arguments->at(flutter::EncodableValue("operationID"))); |
||||
auto isBackground = zego_value_get_bool(arguments->at(flutter::EncodableValue("isBackground"))); |
||||
char* operationID_cs = const_cast<char*>(operationID.c_str()); |
||||
NewBaseCallBack(operationID, result); |
||||
set_app_background_status(_im_manager_listener.baseCallBack, operationID_cs, isBackground); |
||||
|
||||
} |
||||
else { |
||||
result->Error("INVALID_ARGUMENT", "Arguments cannot be null"); |
||||
} |
||||
} |
||||
|
||||
void IMManagerService::networkStatusChanged( |
||||
const flutter::EncodableMap *arguments, |
||||
std::shared_ptr<flutter::MethodResult<flutter::EncodableValue>> result) { |
||||
if (arguments) { |
||||
auto operationID = zego_value_get_string(arguments->at(flutter::EncodableValue("operationID"))); |
||||
char* operationID_cs = const_cast<char*>(operationID.c_str()); |
||||
NewBaseCallBack(operationID, result); |
||||
network_status_changed(_im_manager_listener.baseCallBack, operationID_cs); |
||||
|
||||
} |
||||
else { |
||||
result->Error("INVALID_ARGUMENT", "Arguments cannot be null"); |
||||
} |
||||
} |
||||
|
@ -0,0 +1,75 @@ |
||||
// Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
// Use of this source code is governed by a MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef IMMANAGER_H |
||||
#define IMMANAGER_H |
||||
|
||||
#include "../FLTService.h" |
||||
#include "Listen.h" |
||||
|
||||
struct IMManagerServiceListener { |
||||
CB_I_S onInitSdk; |
||||
CB_S_I_S_S baseCallBack; |
||||
CB_I_S uploadCallback; |
||||
}; |
||||
|
||||
class IMManagerService : public FLTService { |
||||
public: |
||||
IMManagerService(); |
||||
virtual void onMethodCalled( |
||||
const std::string& method, const flutter::EncodableMap* arguments, |
||||
std::shared_ptr<flutter::MethodResult<flutter::EncodableValue>> result) |
||||
override; |
||||
|
||||
private: |
||||
void initializeSDK( |
||||
const flutter::EncodableMap* arguments, |
||||
std::shared_ptr<flutter::MethodResult<flutter::EncodableValue>> result); |
||||
|
||||
void unInitSDK( |
||||
const flutter::EncodableMap* arguments, |
||||
std::shared_ptr<flutter::MethodResult<flutter::EncodableValue>> result); |
||||
|
||||
void login( |
||||
const flutter::EncodableMap* arguments, |
||||
std::shared_ptr<flutter::MethodResult<flutter::EncodableValue>> result); |
||||
|
||||
void logout( |
||||
const flutter::EncodableMap* arguments, |
||||
std::shared_ptr<flutter::MethodResult<flutter::EncodableValue>> result); |
||||
|
||||
void getLoginStatus( |
||||
const flutter::EncodableMap* arguments, |
||||
std::shared_ptr<flutter::MethodResult<flutter::EncodableValue>> result); |
||||
|
||||
void uploadFile( |
||||
const flutter::EncodableMap* arguments, |
||||
std::shared_ptr<flutter::MethodResult<flutter::EncodableValue>> result); |
||||
|
||||
void uploadLogs( |
||||
const flutter::EncodableMap* arguments, |
||||
std::shared_ptr<flutter::MethodResult<flutter::EncodableValue>> result); |
||||
|
||||
void logs( |
||||
const flutter::EncodableMap* arguments, |
||||
std::shared_ptr<flutter::MethodResult<flutter::EncodableValue>> result); |
||||
|
||||
void updateFcmToken( |
||||
const flutter::EncodableMap* arguments, |
||||
std::shared_ptr<flutter::MethodResult<flutter::EncodableValue>> result); |
||||
|
||||
void setAppBackgroundStatus( |
||||
const flutter::EncodableMap* arguments, |
||||
std::shared_ptr<flutter::MethodResult<flutter::EncodableValue>> result); |
||||
|
||||
void networkStatusChanged( |
||||
const flutter::EncodableMap* arguments, |
||||
std::shared_ptr<flutter::MethodResult<flutter::EncodableValue>> result); |
||||
|
||||
IMManagerServiceListener _im_manager_listener; |
||||
}; |
||||
|
||||
|
||||
|
||||
#endif // IMMANAGER_H
|
@ -0,0 +1,20 @@ |
||||
#include "Listen.h" |
||||
#include <unordered_map> |
||||
|
||||
std::unordered_map <std::string, std::unique_ptr<BaseCallBack>> g_baseCallBackMap; |
||||
std::mutex g_baseCallBackMapMutex; |
||||
|
||||
void NewBaseCallBack(std::string opid, |
||||
std::shared_ptr <flutter::MethodResult<flutter::EncodableValue>> result) { |
||||
std::lock_guard <std::mutex> lock(g_baseCallBackMapMutex); |
||||
g_baseCallBackMap[opid] = std::make_unique<BaseCallBack>(result); |
||||
} |
||||
|
||||
void CallBaseCallBack(char *opid, int errCode, char *errMsg, char *msg) { |
||||
std::lock_guard <std::mutex> lock(g_baseCallBackMapMutex); |
||||
auto it = g_baseCallBackMap.find(std::string(opid)); |
||||
if (it != g_baseCallBackMap.end()) { |
||||
auto ctx = std::move(it->second); //unique_ptr
|
||||
ctx->HandleCallback(opid, errCode, errMsg, msg); |
||||
} |
||||
} |
@ -0,0 +1,58 @@ |
||||
#ifndef LISTEN_H |
||||
#define LISTEN_H |
||||
|
||||
#include <libopenimsdk.h> |
||||
#include "flutter/encodable_value.h" |
||||
#include "flutter/method_result.h" |
||||
|
||||
|
||||
|
||||
class BaseCallBack { |
||||
public: |
||||
BaseCallBack(std::shared_ptr<flutter::MethodResult<flutter::EncodableValue>> result) { |
||||
this->result = result; |
||||
} |
||||
|
||||
std::shared_ptr<flutter::MethodResult<flutter::EncodableValue>> result = nullptr; |
||||
|
||||
void HandleCallback(char* opid, int errCode, char* errMsg, char* msg) { |
||||
if (result == nullptr) { |
||||
return; |
||||
} |
||||
|
||||
if (errCode == 0) { |
||||
result->Success(flutter::EncodableValue(std::string(msg))); |
||||
} |
||||
else { |
||||
result->Error(std::to_string(errCode), std::string(errMsg), flutter::EncodableValue(std::string(msg))); |
||||
} |
||||
} |
||||
}; |
||||
|
||||
// 全局映射表
|
||||
extern std::unordered_map<std::string, std::unique_ptr<BaseCallBack>> g_baseCallBackMap; |
||||
extern std::mutex g_baseCallBackMapMutex; |
||||
|
||||
|
||||
void NewBaseCallBack(std::string opid, std::shared_ptr<flutter::MethodResult<flutter::EncodableValue>> result); |
||||
void CallBaseCallBack(char* opid, int errCode, char* errMsg, char* msg); |
||||
|
||||
|
||||
|
||||
//todo 没想好怎么实现
|
||||
class uploadFileCallBack { |
||||
public: |
||||
uploadFileCallBack(std::string id) { |
||||
this->id = id; |
||||
} |
||||
|
||||
std::string id = ""; |
||||
|
||||
void HandleCallback(char* opid, int errCode, char* errMsg, char* msg) { |
||||
|
||||
|
||||
} |
||||
}; |
||||
|
||||
|
||||
#endif |
@ -0,0 +1,311 @@ |
||||
/* |
||||
Using C++ template functions and recursion to initialize a function pointer pool, |
||||
combined with lambda expressions, this implementation manages function pointers, |
||||
achieving acquisition and release of pointers.All wrappers are used to convert |
||||
and map C++ functions to C functions, and with the use of indexed locking, |
||||
a thread-safe function pointer pool is implemented.For example, the wrapping |
||||
functions essentially map C++ functions to C functions. When a C function callback is triggered, |
||||
the function pointer pool, initialized through template recursion, locates the corresponding C++ function and invokes it. |
||||
*/ |
||||
|
||||
#define MAX_NUM_OF_CB_S 10 |
||||
#define MAX_NUM_OF_CB_I_S 10 |
||||
#define MAX_NUM_OF_CB_S_I_S_S 10 |
||||
#define MAX_NUM_OF_CB_S_I_S_S_I 10 |
||||
#define SLEEP_TIME_FOR_GET_INDEX 100 //ms |
||||
|
||||
// use recursive template to generate enough function pointer array |
||||
// and define c type function interface |
||||
// and define manager class to manage function pool |
||||
namespace { |
||||
CB_S* _fps_cb_s=new CB_S[MAX_NUM_OF_CB_S]; |
||||
CB_I_S* _fps_cb_i_s=new CB_I_S[MAX_NUM_OF_CB_I_S]; |
||||
CB_S_I_S_S* _fps_cb_s_i_s_s=new CB_S_I_S_S[MAX_NUM_OF_CB_S_I_S_S]; |
||||
CB_S_I_S_S_I* _fps_cb_s_i_s_s_i=new CB_S_I_S_S_I[MAX_NUM_OF_CB_S_I_S_S_I]; |
||||
// c type func interface call cpp function |
||||
std::function<void(const std::string&)>* _cpp_function_cb_s=new std::function<void(const std::string&)>[MAX_NUM_OF_CB_S]; |
||||
std::function<void(int,const std::string&)>* _cpp_function_cb_i_s=new std::function<void(int,const std::string&)>[MAX_NUM_OF_CB_I_S]; |
||||
std::function<void(const std::string&,int,const std::string&,const std::string&)>* _cpp_function_cb_s_i_s_s=new std::function<void(const std::string&,int,const std::string&,const std::string&)>[MAX_NUM_OF_CB_S_I_S_S]; |
||||
std::function<void(const std::string&,int,const std::string&,const std::string&,int)>* _cpp_function_cb_s_i_s_s_i=new std::function<void(const std::string&,int,const std::string&,const std::string&,int)>[MAX_NUM_OF_CB_S_I_S_S_I]; |
||||
|
||||
template<int N> |
||||
void _generate_cb_s(){ |
||||
_fps_cb_s[N]=[](char* c_str){ |
||||
_cpp_function_cb_s[N](std::string(c_str)); |
||||
}; |
||||
_generate_cb_s<N-1>(); |
||||
} |
||||
template<> |
||||
void _generate_cb_s<0>(){ |
||||
_fps_cb_s[0]=[](char* c_str){ |
||||
_cpp_function_cb_s[0](std::string(c_str)); |
||||
}; |
||||
} |
||||
|
||||
template<int N> |
||||
void _generate_cb_i_s(){ |
||||
_fps_cb_i_s[N]=[](int code,char* c_str){ |
||||
_cpp_function_cb_i_s[N](code,std::string(c_str)); |
||||
}; |
||||
_generate_cb_i_s<N-1>(); |
||||
} |
||||
template<> |
||||
void _generate_cb_i_s<0>(){ |
||||
_fps_cb_i_s[0]=[](int code,char* c_str){ |
||||
_cpp_function_cb_i_s[0](code,std::string(c_str)); |
||||
}; |
||||
} |
||||
template<int N> |
||||
void _generate_cb_s_i_s_s(){ |
||||
_fps_cb_s_i_s_s[N]=[](char* operationID,int code,char* c_str,char* c_str2){ |
||||
_cpp_function_cb_s_i_s_s[N](std::string(operationID),code,std::string(c_str),std::string(c_str2)); |
||||
}; |
||||
_generate_cb_s_i_s_s<N-1>(); |
||||
} |
||||
template<> |
||||
void _generate_cb_s_i_s_s<0>(){ |
||||
_fps_cb_s_i_s_s[0]=[](char* operationID,int code,char* c_str,char* c_str2){ |
||||
_cpp_function_cb_s_i_s_s[0](std::string(operationID),code,std::string(c_str),std::string(c_str2)); |
||||
}; |
||||
} |
||||
template<int N> |
||||
void _generate_cb_s_i_s_s_i(){ |
||||
_fps_cb_s_i_s_s_i[N]=[](char* operationID,int code,char* c_str,char* c_str2,int c_int){ |
||||
_cpp_function_cb_s_i_s_s_i[N](std::string(operationID),code,std::string(c_str),std::string(c_str2),c_int); |
||||
}; |
||||
_generate_cb_s_i_s_s_i<N-1>(); |
||||
} |
||||
template<> |
||||
void _generate_cb_s_i_s_s_i<0>(){ |
||||
_fps_cb_s_i_s_s_i[0]=[](char* operationID,int code,char* c_str,char* c_str2,int c_int){ |
||||
_cpp_function_cb_s_i_s_s_i[0](std::string(operationID),code,std::string(c_str),std::string(c_str2),c_int); |
||||
}; |
||||
} |
||||
|
||||
// init global function pointer array |
||||
void init(){ |
||||
_generate_cb_s<MAX_NUM_OF_CB_S-1>(); |
||||
_generate_cb_i_s<MAX_NUM_OF_CB_I_S-1>(); |
||||
_generate_cb_s_i_s_s<MAX_NUM_OF_CB_S_I_S_S-1>(); |
||||
_generate_cb_s_i_s_s_i<MAX_NUM_OF_CB_S_I_S_S_I-1>(); |
||||
} |
||||
// define sigle instance class to manage function pool |
||||
class FuncPoolManager{ |
||||
private: |
||||
// define a global bitmap, and support atomic operation, to manage cb_s pool |
||||
std::bitset<MAX_NUM_OF_CB_S> _cb_s_bitmap; |
||||
std::bitset<MAX_NUM_OF_CB_I_S> _cb_i_s_bitmap; |
||||
std::bitset<MAX_NUM_OF_CB_S_I_S_S> _cb_s_i_s_s_bitmap; |
||||
std::bitset<MAX_NUM_OF_CB_S_I_S_S_I> _cb_s_i_s_s_i_bitmap; |
||||
std::mutex _cb_s_mutex; |
||||
std::mutex _cb_i_s_mutex; |
||||
std::mutex _cb_s_i_s_s_mutex; |
||||
std::mutex _cb_s_i_s_s_i_mutex; |
||||
FuncPoolManager(){ |
||||
init(); |
||||
} |
||||
FuncPoolManager(const FuncPoolManager&){} |
||||
public: |
||||
static FuncPoolManager& get_instance(){ |
||||
static FuncPoolManager instance; |
||||
return instance; |
||||
} |
||||
// get a available cb_s function index |
||||
int get_cb_s_index(){ |
||||
std::lock_guard<std::mutex> lock(_cb_s_mutex); |
||||
int index=-1; |
||||
for(int i=0;i<_cb_s_bitmap.size();i++){ |
||||
if(_cb_s_bitmap[i]==0){ |
||||
_cb_s_bitmap[i]=1; |
||||
index=i; |
||||
break; |
||||
} |
||||
} |
||||
return index; |
||||
} |
||||
// get a available cb_i_s function index |
||||
int get_cb_i_s_index(){ |
||||
std::lock_guard<std::mutex> lock(_cb_i_s_mutex); |
||||
int index=-1; |
||||
for(int i=0;i<_cb_i_s_bitmap.size();i++){ |
||||
if(_cb_i_s_bitmap[i]==0){ |
||||
_cb_i_s_bitmap[i]=1; |
||||
index=i; |
||||
break; |
||||
} |
||||
} |
||||
return index; |
||||
} |
||||
// get a available cb_s_i_s_s function index |
||||
int get_cb_s_i_s_s_index(){ |
||||
std::lock_guard<std::mutex> lock(_cb_s_i_s_s_mutex); |
||||
int index=-1; |
||||
for(int i=0;i<_cb_s_i_s_s_bitmap.size();i++){ |
||||
if(_cb_s_i_s_s_bitmap[i]==0){ |
||||
_cb_s_i_s_s_bitmap[i]=1; |
||||
index=i; |
||||
break; |
||||
} |
||||
} |
||||
return index; |
||||
} |
||||
// get a available cb_s_i_s_s_i function index |
||||
int get_cb_s_i_s_s_i_index(){ |
||||
std::lock_guard<std::mutex> lock(_cb_s_i_s_s_i_mutex); |
||||
int index=-1; |
||||
for(int i=0;i<_cb_s_i_s_s_i_bitmap.size();i++){ |
||||
if(_cb_s_i_s_s_i_bitmap[i]==0){ |
||||
_cb_s_i_s_s_i_bitmap[i]=1; |
||||
index=i; |
||||
break; |
||||
} |
||||
} |
||||
return index; |
||||
} |
||||
// release a available cb_s function index |
||||
int release_cb_s_index(int index){ |
||||
std::lock_guard<std::mutex> lock(_cb_s_mutex); |
||||
if(index<0||index>=_cb_s_bitmap.size()){ |
||||
return -1; |
||||
} |
||||
_cpp_function_cb_s[index]=nullptr; |
||||
_cb_s_bitmap[index]=0; |
||||
return 0; |
||||
} |
||||
// release a available cb_i_s function index |
||||
int release_cb_i_s_index(int index){ |
||||
std::lock_guard<std::mutex> lock(_cb_i_s_mutex); |
||||
if(index<0||index>=_cb_i_s_bitmap.size()){ |
||||
return -1; |
||||
} |
||||
_cpp_function_cb_i_s[index]=nullptr; |
||||
_cb_i_s_bitmap[index]=0; |
||||
return 0; |
||||
} |
||||
// release a available cb_s_i_s_s function index |
||||
int release_cb_s_i_s_s_index(int index){ |
||||
std::lock_guard<std::mutex> lock(_cb_s_i_s_s_mutex); |
||||
if(index<0||index>=_cb_s_i_s_s_bitmap.size()){ |
||||
return -1; |
||||
} |
||||
_cpp_function_cb_s_i_s_s[index]=nullptr; |
||||
_cb_s_i_s_s_bitmap[index]=0; |
||||
return 0; |
||||
} |
||||
// release a available cb_s_i_s_s_i function index |
||||
int release_cb_s_i_s_s_i_index(int index){ |
||||
std::lock_guard<std::mutex> lock(_cb_s_i_s_s_i_mutex); |
||||
if(index<0||index>=_cb_s_i_s_s_i_bitmap.size()){ |
||||
return -1; |
||||
} |
||||
_cpp_function_cb_s_i_s_s_i[index]=nullptr; |
||||
_cb_s_i_s_s_i_bitmap[index]=0; |
||||
return 0; |
||||
} |
||||
}; |
||||
FuncPoolManager& instance=FuncPoolManager::get_instance(); |
||||
|
||||
// wrapper persistent function |
||||
// wrapp CB_S,if function pool is full,return nullptr |
||||
CB_S _wrapper_cpp_function(const std::function<void(const std::string&)>& cpp_function) { |
||||
int index=FuncPoolManager::get_instance().get_cb_s_index(); |
||||
while(index<0){ |
||||
std::this_thread::sleep_for(std::chrono::milliseconds(SLEEP_TIME_FOR_GET_INDEX)); |
||||
index=FuncPoolManager::get_instance().get_cb_s_index(); |
||||
} |
||||
_cpp_function_cb_s[index]=cpp_function; |
||||
return _fps_cb_s[index]; |
||||
} |
||||
// wrapp CB_I_S |
||||
CB_I_S _wrapper_cpp_function(const std::function<void(int,const std::string&)>& cpp_function) |
||||
{ |
||||
int index=FuncPoolManager::get_instance().get_cb_i_s_index(); |
||||
while(index<0){ |
||||
std::this_thread::sleep_for(std::chrono::milliseconds(SLEEP_TIME_FOR_GET_INDEX)); |
||||
index=FuncPoolManager::get_instance().get_cb_i_s_index(); |
||||
} |
||||
_cpp_function_cb_i_s[index]=cpp_function; |
||||
return _fps_cb_i_s[index]; |
||||
} |
||||
// wrapp CB_S_I_S_S |
||||
CB_S_I_S_S _wrapper_cpp_function(const std::function<void(const std::string&,int,const std::string&,const std::string&)>& cpp_function) |
||||
{ |
||||
int index=FuncPoolManager::get_instance().get_cb_s_i_s_s_index(); |
||||
while(index<0){ |
||||
std::this_thread::sleep_for(std::chrono::milliseconds(SLEEP_TIME_FOR_GET_INDEX)); |
||||
index=FuncPoolManager::get_instance().get_cb_s_i_s_s_index(); |
||||
} |
||||
_cpp_function_cb_s_i_s_s[index]=cpp_function; |
||||
return _fps_cb_s_i_s_s[index]; |
||||
} |
||||
// wrapp CB_S_I_S_S_I |
||||
CB_S_I_S_S_I _wrapper_cpp_function(const std::function<void(const std::string&,int,const std::string&,const std::string&,int)>& cpp_function) |
||||
{ |
||||
int index=FuncPoolManager::get_instance().get_cb_s_i_s_s_i_index(); |
||||
while(index<0){ |
||||
std::this_thread::sleep_for(std::chrono::milliseconds(SLEEP_TIME_FOR_GET_INDEX)); |
||||
index=FuncPoolManager::get_instance().get_cb_s_i_s_s_i_index(); |
||||
} |
||||
_cpp_function_cb_s_i_s_s_i[index]=cpp_function; |
||||
return _fps_cb_s_i_s_s_i[index]; |
||||
} |
||||
|
||||
// wrapp function to onetime function |
||||
CB_S _wrapper_callonce_cpp_function(const std::function<void(const std::string&)>& cpp_function) { |
||||
int index=FuncPoolManager::get_instance().get_cb_s_index(); |
||||
while(index<0){ |
||||
std::this_thread::sleep_for(std::chrono::milliseconds(SLEEP_TIME_FOR_GET_INDEX)); |
||||
index=FuncPoolManager::get_instance().get_cb_s_index(); |
||||
} |
||||
_cpp_function_cb_s[index]=[cpp_function,index](const std::string& str)->void { |
||||
cpp_function(str); |
||||
FuncPoolManager::get_instance().release_cb_s_index(index); |
||||
}; |
||||
return _fps_cb_s[index]; |
||||
} |
||||
|
||||
CB_I_S _wrapper_callonce_cpp_function(const std::function<void(int,const std::string&)>& cpp_function) |
||||
{ |
||||
int index=FuncPoolManager::get_instance().get_cb_i_s_index(); |
||||
while(index<0){ |
||||
std::this_thread::sleep_for(std::chrono::milliseconds(SLEEP_TIME_FOR_GET_INDEX)); |
||||
index=FuncPoolManager::get_instance().get_cb_i_s_index(); |
||||
} |
||||
_cpp_function_cb_i_s[index]=[cpp_function,index](int code,const std::string& str)->void { |
||||
cpp_function(code,str); |
||||
FuncPoolManager::get_instance().release_cb_i_s_index(index); |
||||
}; |
||||
return _fps_cb_i_s[index]; |
||||
} |
||||
|
||||
CB_S_I_S_S _wrapper_callonce_cpp_function(const std::function<void(const std::string&,int,const std::string&,const std::string&)>& cpp_function) |
||||
{ |
||||
int index=FuncPoolManager::get_instance().get_cb_s_i_s_s_index(); |
||||
while(index<0){ |
||||
std::this_thread::sleep_for(std::chrono::milliseconds(SLEEP_TIME_FOR_GET_INDEX)); |
||||
index=FuncPoolManager::get_instance().get_cb_s_i_s_s_index(); |
||||
} |
||||
_cpp_function_cb_s_i_s_s[index]=[cpp_function,index](const std::string& operationID,int code,const std::string& str,const std::string& str2)->void { |
||||
cpp_function(operationID,code,str,str2); |
||||
FuncPoolManager::get_instance().release_cb_s_i_s_s_index(index); |
||||
}; |
||||
return _fps_cb_s_i_s_s[index]; |
||||
} |
||||
|
||||
CB_S_I_S_S_I _wrapper_callonce_cpp_function(const std::function<void(const std::string&,int,const std::string&,const std::string&,int)>& cpp_function) |
||||
{ |
||||
int index=FuncPoolManager::get_instance().get_cb_s_i_s_s_i_index(); |
||||
// while loop util get a available index |
||||
while(index<0){ |
||||
std::this_thread::sleep_for(std::chrono::milliseconds(SLEEP_TIME_FOR_GET_INDEX)); |
||||
index=FuncPoolManager::get_instance().get_cb_s_i_s_s_i_index(); |
||||
} |
||||
_cpp_function_cb_s_i_s_s_i[index]=[cpp_function,index](const std::string& operationID,int code,const std::string& str,const std::string& str2,int c_int)->void { |
||||
cpp_function(operationID,code,str,str2,c_int); |
||||
FuncPoolManager::get_instance().release_cb_s_i_s_s_i_index(index); |
||||
}; |
||||
return _fps_cb_s_i_s_s_i[index]; |
||||
} |
||||
|
||||
} |
||||
|
@ -0,0 +1,40 @@ |
||||
// Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
// Use of this source code is governed by a MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef STABLE_H |
||||
#define STABLE_H |
||||
|
||||
#if defined __cplusplus |
||||
|
||||
// std
|
||||
#include <any> |
||||
#include <filesystem> |
||||
#include <functional> |
||||
#include <iostream> |
||||
#include <list> |
||||
#include <map> |
||||
#include <memory> |
||||
#include <mutex> |
||||
#include <optional> |
||||
#include <sstream> |
||||
#include <string> |
||||
#include <unordered_map> |
||||
#include <vector> |
||||
|
||||
|
||||
#ifdef _WIN32 |
||||
|
||||
#endif |
||||
#include "utils/singleton.h" |
||||
#include "utils/stringHash.hpp" |
||||
|
||||
// third parties
|
||||
#include "alog.h" |
||||
#define YXLOGEnd ALOGEnd |
||||
#define YXLOG(level) ALOG_DIY("nim_core_plugin", LogNormal, level) |
||||
#define YXLOG_API(level) ALOG_DIY("nim_core_plugin", LogApi, level) |
||||
|
||||
#endif |
||||
|
||||
#endif // STABLE_H
|
@ -0,0 +1,87 @@ |
||||
// Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
// Use of this source code is governed by a MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ALOGINSTANCE_H |
||||
#define ALOGINSTANCE_H |
||||
|
||||
#include <memory> |
||||
#include <string> |
||||
|
||||
#if defined(_WIN32) || defined(WIN32) || defined(_WIN64) |
||||
#define API_EXPORT |
||||
#else |
||||
#ifdef ALOG_API |
||||
#define API_EXPORT __attribute__((visibility("default"))) |
||||
#else |
||||
#define API_EXPORT |
||||
#endif |
||||
#endif |
||||
|
||||
typedef enum { Debug = 1, Info, Warn, Error, Fatal } ALogLevel; |
||||
|
||||
typedef enum { |
||||
LogNormal = 0, /**< 正常日志打印 */ |
||||
LogApi /**< API接口打印 */ |
||||
} ALogType; |
||||
|
||||
#define ALOGEnd ALog::ALogEnd() |
||||
#define ALOG(level) ALog().Init("", __FILE__, __LINE__, LogNormal, level) |
||||
#define ALOG_DIY(moduleName, type, level) \ |
||||
ALog().Init(moduleName, __FILE__, __LINE__, type, level) |
||||
|
||||
class API_EXPORT ALog { |
||||
public: |
||||
class ALogEnd {}; |
||||
|
||||
public: |
||||
ALog& Init(const char* module, const char* file, long line, ALogType type, |
||||
ALogLevel level); |
||||
ALog& operator<<(int value); |
||||
ALog& operator<<(unsigned int value); |
||||
ALog& operator<<(const std::string& value); |
||||
ALog& operator<<(const char* value); |
||||
ALog& operator<<(long long value); |
||||
ALog& operator<<(unsigned long long value); |
||||
ALog& operator<<(unsigned long value); |
||||
ALog& operator<<(float value); |
||||
ALog& operator<<(const unsigned char* value); |
||||
ALog& operator<<(void* value); |
||||
template <typename T> |
||||
ALog& operator<<(T* value) { |
||||
if (m_level >= m_minLevel) { |
||||
char strTmp[128] = {0}; |
||||
sprintf(strTmp, "%p", value); |
||||
m_strLog.append(strTmp); |
||||
} |
||||
return *this; |
||||
} |
||||
void operator<<(const ALog::ALogEnd& value); |
||||
|
||||
public: |
||||
static ALog* CreateInstance(const std::string& filePath, |
||||
const std::string& fileName, ALogLevel minLevel); |
||||
static ALog* GetInstance(); |
||||
static void DestoryInstance(); |
||||
ALog(); |
||||
~ALog(); |
||||
void setShortFileName(bool shortFileName = false); |
||||
|
||||
private: |
||||
explicit ALog(const std::string& file, const std::string& fileName, |
||||
ALogLevel minLevel); |
||||
void write(); |
||||
|
||||
private: |
||||
static std::unique_ptr<ALog> m_log; |
||||
static ALogLevel m_minLevel; |
||||
static bool m_shortFileName; |
||||
std::string m_strLog; |
||||
std::string m_strModule; |
||||
std::string m_strFile; |
||||
long m_line = 0; |
||||
ALogLevel m_level = Info; |
||||
ALogType m_type = LogNormal; |
||||
}; |
||||
|
||||
#endif // ALOGINSTANCE_H
|
@ -0,0 +1,14 @@ |
||||
// Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
// Use of this source code is governed by a MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ALog_verinfo_h |
||||
#define ALog_verinfo_h |
||||
|
||||
#define ALOG_REVISION "cfe9ad8" |
||||
#define ALOG_PATH "wjzh/feature/cpp" |
||||
#define ALOG_URL "" |
||||
#define ALOG_BUILD_TIME "2021-09-30 13:22:13" |
||||
#define ALOG_TAG "" |
||||
|
||||
#endif |
Loading…
Reference in new issue