Fix loading addon library from plugins

partially reverts c57e8b4618d1380c9d1bac3d70bb1a331961daf0
This commit is contained in:
Rocka 2025-09-22 23:26:24 +08:00
parent e48d07125c
commit 7d408e61ca
No known key found for this signature in database
GPG Key ID: 28031158FFDD6853
4 changed files with 195 additions and 4 deletions

View File

@ -44,7 +44,7 @@ add_library(pinyin-customphrase STATIC "${CHINESE_ADDONS_PINYIN_DIR}/customphras
target_include_directories(pinyin-customphrase INTERFACE "${CHINESE_ADDONS_PINYIN_DIR}")
target_link_libraries(pinyin-customphrase PRIVATE Fcitx5::Utils LibIME::Core)
add_library(native-lib SHARED native-lib.cpp)
add_library(native-lib SHARED native-lib.cpp androidaddonloader/androidaddonloader.cpp)
target_link_libraries(native-lib
log
libuv::uv_a

View File

@ -0,0 +1,102 @@
/*
* SPDX-License-Identifier: LGPL-2.1-or-later
* SPDX-FileCopyrightText: Copyright 2016-2016 CSSlayer <wengxt@gmail.com>
* SPDX-FileCopyrightText: Copyright 2023-2025 Fcitx5 for Android Contributors
* SPDX-FileComment: Modified from https://github.com/fcitx/fcitx5/blob/5.1.14/src/lib/fcitx/addonloader.cpp
*/
#include <exception>
#include <filesystem>
#include <memory>
#include <string>
#include <string_view>
#include <utility>
#include <vector>
#include <fcitx-utils/flags.h>
#include <fcitx-utils/library.h>
#include <fcitx-utils/log.h>
#include <fcitx-utils/standardpaths.h>
#include <fcitx-utils/stringutils.h>
#include <fcitx/addoninfo.h>
#include <fcitx/addoninstance.h>
#define FCITX_LIBRARY_SUFFIX ".so"
#include "androidaddonloader.h"
namespace fcitx {
AddonInstance *AndroidSharedLibraryLoader::load(const AddonInfo &info,
AddonManager *manager) {
auto iter = registry_.find(info.uniqueName());
if (iter == registry_.end()) {
std::vector<std::string> libnames =
stringutils::split(info.library(), ";");
if (libnames.empty()) {
FCITX_ERROR() << "Failed to parse Library field: " << info.library()
<< " for addon " << info.uniqueName();
return nullptr;
}
std::vector<Library> libraries;
for (std::string_view libname: libnames) {
Flags<LibraryLoadHint> flag = LibraryLoadHint::DefaultHint;
if (stringutils::consumePrefix(libname, "export:")) {
flag |= LibraryLoadHint::ExportExternalSymbolsHint;
}
const auto file =
stringutils::concat(libname, FCITX_LIBRARY_SUFFIX);
const auto libraryPaths = standardPaths_.locateAll(
StandardPathsType::Addon, file);
if (libraryPaths.empty()) {
FCITX_ERROR() << "Could not locate library " << file
<< " for addon " << info.uniqueName() << ".";
}
bool loaded = false;
for (const auto &libraryPath: libraryPaths) {
Library library(libraryPath);
if (library.load(flag)) {
libraries.push_back(std::move(library));
loaded = true;
break;
}
FCITX_ERROR()
<< "Failed to load library for addon " << info.uniqueName()
<< " on " << libraryPath << ". Error: " << library.error();
}
if (!loaded) {
break;
}
}
if (libraries.size() == libnames.size()) {
try {
registry_.emplace(info.uniqueName(),
std::make_unique<AndroidSharedLibraryFactory>(
info, std::move(libraries)));
} catch (const std::exception &e) {
FCITX_ERROR() << "Failed to initialize addon factory for addon "
<< info.uniqueName() << ". Error: " << e.what();
}
iter = registry_.find(info.uniqueName());
}
}
if (iter == registry_.end()) {
return nullptr;
}
try {
return iter->second->factory()->create(manager);
} catch (const std::exception &e) {
FCITX_ERROR() << "Failed to create addon: " << info.uniqueName() << " "
<< e.what();
} catch (...) {
FCITX_ERROR() << "Failed to create addon: " << info.uniqueName();
}
return nullptr;
}
} // namespace fcitx

View File

@ -0,0 +1,85 @@
/*
* SPDX-License-Identifier: LGPL-2.1-or-later
* SPDX-FileCopyrightText: Copyright 2016-2016 CSSlayer <wengxt@gmail.com>
* SPDX-FileCopyrightText: Copyright 2023-2025 Fcitx5 for Android Contributors
* SPDX-FileComment: Modified from https://github.com/fcitx/fcitx5/blob/5.1.14/src/lib/fcitx/addonloader_p.h
*/
#ifndef FCITX5_ANDROID_ANDROIDADDONLOADER_H
#define FCITX5_ANDROID_ANDROIDADDONLOADER_H
#include <memory>
#include <stdexcept>
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>
#include <fcitx-utils/library.h>
#include <fcitx-utils/standardpaths.h>
#include <fcitx-utils/stringutils.h>
#include <fcitx/addonfactory.h>
#include <fcitx/addoninfo.h>
#include <fcitx/addoninstance.h>
#include <fcitx/addonloader.h>
namespace fcitx {
namespace {
constexpr char FCITX_ADDON_FACTORY_ENTRY[] = "fcitx_addon_factory_instance";
}
class AndroidSharedLibraryFactory {
public:
explicit AndroidSharedLibraryFactory(const AddonInfo &info, std::vector<Library> libraries)
: libraries_(std::move(libraries)) {
std::string v2Name = stringutils::concat(FCITX_ADDON_FACTORY_ENTRY, "_",
info.uniqueName());
if (libraries_.empty()) {
throw std::runtime_error("Got empty libraries.");
}
// Only resolve with last library.
auto &library = libraries_.back();
auto *funcPtr = library.resolve(v2Name.data());
if (!funcPtr) {
funcPtr = library.resolve(FCITX_ADDON_FACTORY_ENTRY);
}
if (!funcPtr) {
throw std::runtime_error(library.error());
}
auto func = Library::toFunction<AddonFactory *()>(funcPtr);
factory_ = func();
if (!factory_) {
throw std::runtime_error("Failed to get a factory");
}
}
AddonFactory *factory() { return factory_; }
private:
std::vector<Library> libraries_;
AddonFactory *factory_;
};
class AndroidSharedLibraryLoader : public AddonLoader {
public:
[[nodiscard]] std::string type() const override { return "SharedLibrary"; }
AddonInstance *load(const AddonInfo &info, AddonManager *manager) override;
private:
// Android specific: create a new StandardPaths instance in case FCITX_ADDON_DIRS changes
StandardPaths standardPaths_ = StandardPaths(
"fcitx5",
std::unordered_map<std::string, std::vector<std::filesystem::path>>{},
Flags<StandardPathsOption>(StandardPathsOption::SkipBuiltInPath)
);
// Android specific end
std::unordered_map<std::string, std::unique_ptr<AndroidSharedLibraryFactory>>
registry_;
};
} // namespace fcitx
#endif //FCITX5_ANDROID_ANDROIDADDONLOADER_H

View File

@ -40,6 +40,7 @@
#include <boost/iostreams/stream_buffer.hpp>
#include "customphrase.h"
#include "androidaddonloader/androidaddonloader.h"
#include "androidfrontend/androidfrontend_public.h"
#include "jni-utils.h"
#include "nativestreambuf.h"
@ -82,7 +83,7 @@ public:
void startup(const std::function<void(fcitx::AddonInstance *)> &setupCallback) {
p_instance = std::make_unique<fcitx::Instance>(0, nullptr);
p_instance->addonManager().registerDefaultLoader(nullptr);
p_instance->addonManager().registerLoader(std::make_unique<fcitx::AndroidSharedLibraryLoader>());
p_dispatcher = std::make_unique<fcitx::EventDispatcher>();
p_dispatcher->attach(&p_instance->eventLoop());
p_instance->initialize();
@ -527,7 +528,10 @@ Java_org_fcitx_fcitx5_android_core_Fcitx_startupFcitx(
const std::string data_home = fcitx::stringutils::joinPath(*extData_, "data");
const std::string usr_share = fcitx::stringutils::joinPath(*appData_, "usr", "share");
const std::string locale_dir = fcitx::stringutils::joinPath(usr_share, "locale");
const std::string libime_data = fcitx::stringutils::joinPath(usr_share, "libime");
const std::string libime_data = fcitx::stringutils::concat(
fcitx::stringutils::joinPath(*extData_, "data", "libime"), ":",
fcitx::stringutils::joinPath(usr_share, "libime")
);
const std::string lua_path = fcitx::stringutils::concat(
fcitx::stringutils::joinPath(data_home, "lua", "?.lua"), ";",
fcitx::stringutils::joinPath(data_home, "lua", "?", "init.lua"), ";",
@ -542,7 +546,7 @@ Java_org_fcitx_fcitx5_android_core_Fcitx_startupFcitx(
);
// prevent StandardPath from resolving it's hardcoded installation path
setenv("SKIP_FCITX_PATH", "1", 1);
// setenv("SKIP_FCITX_PATH", "1", 1);
// for fcitx default profile [DefaultInputMethod]
setenv("LANG", lang_.c_str(), 1);
// for libintl-lite loading gettext .mo translations