refactor callback system into unified MMKVHandler across all platforms

Replace 4 separate static function pointers (LogHandler, ErrorHandler,
ContentChangeHandler, ContentLoadedHandler) with a single MMKVHandler
abstract class in Core C++. Update all 6 platform wrappers (iOS, Android,
OHOS, Python, Golang, Flutter) to use adapter classes bridging to the new
unified handler. Add onMMKVContentLoadSuccessfully callback to Android,
OHOS, Flutter, Python and Golang where it was previously missing.
This commit is contained in:
guoling
2026-03-18 12:40:05 +08:00
parent d90f664a2e
commit 9348a93f26
33 changed files with 917 additions and 671 deletions
+67 -73
View File
@@ -61,26 +61,47 @@ static MMBuffer pyBytes2MMBuffer(const py::bytes &bytes) {
static function<void(MMKVLogLevel level, const char *file, int line, const char *function, const string &message)>
g_logHandler = nullptr;
static void MyLogHandler(MMKVLogLevel level, const char *file, int line, const char *function, const string &message) {
if (g_logHandler) {
g_logHandler(level, file, line, function, message);
}
}
static function<MMKVRecoverStrategic(const string &mmapID, MMKVErrorType errorType)> g_errorHandler = nullptr;
static MMKVRecoverStrategic MyErrorHandler(const string &mmapID, MMKVErrorType errorType) {
if (g_errorHandler) {
return g_errorHandler(mmapID, errorType);
}
return OnErrorDiscard;
}
static function<void(const string &mmapID)> g_contentHandler = nullptr;
static void MyContentChangeHandler(const std::string &mmapID) {
if (g_contentHandler) {
g_contentHandler(mmapID);
static function<void(const string &mmapID)> g_contentLoadedHandler = nullptr;
// C++ handler that bridges to Python callbacks
class PyMMKVHandler : public mmkv::MMKVHandler {
public:
void mmkvLog(MMKVLogLevel level, const char *file, int line, const char *function, MMKVLog_t message) override {
if (g_logHandler) {
g_logHandler(level, file, line, function, message);
}
}
}
MMKVRecoverStrategic onMMKVCRCCheckFail(const std::string &mmapID) override {
if (g_errorHandler) {
return g_errorHandler(mmapID, MMKVErrorType::MMKVCRCCheckFail);
}
return OnErrorDiscard;
}
MMKVRecoverStrategic onMMKVFileLengthError(const std::string &mmapID) override {
if (g_errorHandler) {
return g_errorHandler(mmapID, MMKVErrorType::MMKVFileLength);
}
return OnErrorDiscard;
}
void onContentChangedByOuterProcess(const std::string &mmapID) override {
if (g_contentHandler) {
g_contentHandler(mmapID);
}
}
void onMMKVContentLoadSuccessfully(const std::string &mmapID) override {
if (g_contentLoadedHandler) {
g_contentLoadedHandler(mmapID);
}
}
};
static PyMMKVHandler g_pyHandler;
PYBIND11_MODULE(mmkv, m) {
m.doc() = "An efficient, small key-value storage framework developed by WeChat Team.";
@@ -207,7 +228,7 @@ PYBIND11_MODULE(mmkv, m) {
[](const MMKVPath_t &rootDir, MMKVLogLevel logLevel, decltype(g_logHandler) logHandler) {
if (logHandler) {
g_logHandler = std::move(logHandler);
MMKV::initializeMMKV(rootDir, logLevel, MyLogHandler);
MMKV::initializeMMKV(rootDir, logLevel, &g_pyHandler);
} else {
MMKV::initializeMMKV(rootDir, logLevel, nullptr);
}
@@ -380,69 +401,41 @@ PYBIND11_MODULE(mmkv, m) {
clsMMKV.def_static("rootDir", &MMKV::getRootDir, "get the root directory of MMKV");
// log callback handler
clsMMKV.def_static(
"registerLogHandler",
[](decltype(g_logHandler) callback) {
g_logHandler = std::move(callback);
MMKV::registerLogHandler(MyLogHandler);
},
"call this method to redirect MMKV's log,\n"
"must call MMKV.unRegisterLogHandler() or MMKV.onExit() before exit\n"
"Parameters:\n"
" log_handler: (logLevel: mmkv.MMKVLogLevel, file: str, line: int, function: str, message: str) -> None",
py::arg("log_handler"));
clsMMKV.def_static(
"unRegisterLogHandler",
[] {
g_logHandler = nullptr;
MMKV::unRegisterLogHandler();
},
"If you have registered a log handler, you must call this method or MMKV.onExit() before exit. "
"Otherwise your app/script won't exit properly.");
// error callback handler
clsMMKV.def_static(
"registerErrorHandler",
[](decltype(g_errorHandler) callback) {
g_errorHandler = std::move(callback);
MMKV::registerErrorHandler(MyErrorHandler);
},
"call this method to handle MMKV failure,\n"
"must call MMKV.unRegisterErrorHandler() or MMKV.onExit() before exit\n"
"Parameters:\n"
" error_handler: (mmapID: str, errorType: mmkv.MMKVErrorType) -> mmkv.MMKVRecoverStrategic",
py::arg("error_handler"));
clsMMKV.def_static(
"unRegisterErrorHandler",
[] {
g_errorHandler = nullptr;
MMKV::unRegisterErrorHandler();
},
"If you have registered an error handler, you must call this method or MMKV.onExit() before exit. "
"Otherwise your app/script won't exit properly.");
// content change callback handler
// unified callback handler
clsMMKV.def("checkContentChanged", &MMKV::checkContentChanged, "check if content been changed by other process");
clsMMKV.def_static(
"registerContentChangeHandler",
[](decltype(g_contentHandler) callback) {
g_contentHandler = std::move(callback);
MMKV::registerContentChangeHandler(MyContentChangeHandler);
"registerHandler",
[](decltype(g_logHandler) logHandler,
decltype(g_errorHandler) errorHandler,
decltype(g_contentHandler) contentChangeHandler,
decltype(g_contentLoadedHandler) contentLoadedHandler) {
g_logHandler = logHandler ? std::move(logHandler) : nullptr;
g_errorHandler = errorHandler ? std::move(errorHandler) : nullptr;
g_contentHandler = contentChangeHandler ? std::move(contentChangeHandler) : nullptr;
g_contentLoadedHandler = contentLoadedHandler ? std::move(contentLoadedHandler) : nullptr;
MMKV::registerHandler(&g_pyHandler);
},
"register a content change handler,\n"
"get notified when an MMKV instance has been changed by other process (not guarantee real-time notification),\n"
"must call MMKV.unRegisterContentChangeHandler() or MMKV.onExit() before exit\n"
"register a unified callback handler for MMKV,\n"
"must call MMKV.unRegisterHandler() or MMKV.onExit() before exit\n"
"Parameters:\n"
" content_change_handler: (mmapID: str) -> None",
py::arg("content_change_handler"));
" log_handler: (logLevel: mmkv.MMKVLogLevel, file: str, line: int, function: str, message: str) -> None\n"
" error_handler: (mmapID: str, errorType: mmkv.MMKVErrorType) -> mmkv.MMKVRecoverStrategic\n"
" content_change_handler: (mmapID: str) -> None\n"
" content_loaded_handler: (mmapID: str) -> None",
py::arg("log_handler") = nullptr,
py::arg("error_handler") = nullptr,
py::arg("content_change_handler") = nullptr,
py::arg("content_loaded_handler") = nullptr);
clsMMKV.def_static(
"unRegisterContentChangeHandler",
"unRegisterHandler",
[] {
g_logHandler = nullptr;
g_errorHandler = nullptr;
g_contentHandler = nullptr;
MMKV::unRegisterContentChangeHandler();
g_contentLoadedHandler = nullptr;
MMKV::unRegisterHandler();
},
"If you have registered a content change handler, you must call this method or MMKV.onExit() before exit. "
"If you have registered a handler, you must call this method or MMKV.onExit() before exit. "
"Otherwise your app/script won't exit properly.");
clsMMKV.def_static(
@@ -452,6 +445,7 @@ PYBIND11_MODULE(mmkv, m) {
g_logHandler = nullptr;
g_errorHandler = nullptr;
g_contentHandler = nullptr;
g_contentLoadedHandler = nullptr;
},
"call this method before exit, especially if you have registered any callback handlers");