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