
【免費下載鏈接】simpleui.kopluginA highly customizable UI plugin for KOReader that features a home screen, bottom navigation bar, top bar and desktop modules/widgets.項目地址https://gitcode.com/gh_mirrors/si/simpleui.koplugin點擊查看免費下載SimpleUI 是一款面向KOReader的高度可定制 UI 插件它為電子書閱讀器帶來主頁屏、底部導航欄、頂部狀態(tài)欄和豐富的桌面模塊。它的強大體驗靠的正是infra/sui_patches.lua5673 行中一套精心的monkey-patch機制——在不改動 KOReader 源碼的前提下劫持 并增強核心類的方法再在卸載時逐一可靠還原。本文帶你精讀這套鉤子體系看懂一個插件如何做到改得進去、收得回來。為什么插件需要 Monkey-PatchKOReader 是開源閱讀器插件無法直接修改它的源代碼。SimpleUI 想要在文件管理器下方加一條導航欄、調(diào)整布局尺寸讓返回鍵 / Home 鍵直達主頁屏給全屏菜單注入壁紙背景、縮小高度以避開導航欄刪除書籍前先把已讀完的書記入統(tǒng)計。這些需求都落在 KOReader 的核心類上比如FileManager、UIManager、Menu。Monkey-Patch 的思路很直白把原方法保存起來再替換成先做自己的事再調(diào)用原方法的新函數(shù)。關鍵在于——替換必須可逆否則關掉插件后殘留的鉤子會持續(xù)干擾原行為。核心設計一套可復用的可逆鉤子SimpleUI 沒有散落地orig Foo.bar; Foo.bar ...而是抽象出四個小函數(shù)統(tǒng)一管理全部集中在 infra/sui_patches.lua函數(shù)作用_acquireHooks(target, key, owner)登記使用者。若鉤子已存在返回nil保證同一方法永不被包兩次_addHook(state, target, key, wrapped)用rawget取出原函數(shù)存入state.hooks再替換target[key]_trackHooks(state, entries)為已被賦值過的函數(shù)補登記方便后續(xù)移除_releaseHooks(target, key, owner)注銷使用者當最后一個使用者離開時才真正還原且按逆序恢復還原時的逆序循環(huán)是整個設計的精髓infra/sui_patches.luafor i #state.hooks, 1, -1 do local h state.hooks[i] if rawget(h.target, h.key) h.wrapped then h.target[h.key] h.orig end end這里有個關鍵細節(jié)rawget(h.target, h.key) h.wrapped先確認現(xiàn)在掛在方法上的確實是我自己包的這一層才去還原。這樣即使別處又在它之上包了一層SimpleUI 也只會拆掉自己的那一層不會誤傷他人——這是它能和別的 user-patch 共存的基礎。為什么狀態(tài)要掛在類上而不是插件實例上因為 KOReader 每次打開/關閉書籍都會重建插件實例而類表在整個會話中是穩(wěn)定的。掛在類上鉤子才能跨越實例重建繼續(xù)生效。七大鐵律讓鉤子不怕重復安裝KOReader 會為每個宿主界面文件管理器、閱讀器各創(chuàng)建一個插件實例并在每次開書/關書時反復創(chuàng)建。SimpleUI 的installAll/teardownAll因此會被反復觸發(fā)且順序不受插件控制。為此作者在文件頭部寫明了 7 條規(guī)則一律通過_acquireHooks安裝——已存在則返回nil函數(shù)絕不會被包兩次每個包裝都要登記_addHook或_trackHooks以便移除在teardownAll中通過_releaseHooks釋放——只有最后一個使用者離開時才拆鉤子鉤子狀態(tài)放在被 patch 的類上絕不放在插件實例或模塊局部變量包裝內(nèi)部通過_live_plugin解析當前插件而非捕獲安裝時的那個實例逆序釋放只在包裝仍是最外層時才還原每次調(diào)用必須冪等并保證臨時改動的字段即便出錯也要還原。文件里有一句很重的警告A patch that skips these rules stacks one wrapper per instance, and its effect grows with every book opened.—— 違反規(guī)則的 patch 會每開一本書多疊一層效果隨閱讀越滾越大。關鍵技巧_live_plugin告別陳舊實例_acquireHooks保證只裝一次但會帶來一個新問題那唯一一次包裝捕獲的plugin變量可能早已指向一個被銷毀的舊實例。SimpleUI 用一個模塊級指針_live_plugin解決infra/sui_patches.lua每次patchFileManagerClass被調(diào)用時刷新_live_plugin plugin包裝函數(shù)內(nèi)部一律用_live_plugin而非閉包里那個過期的plugin。這就像給每個鉤子留了一個最新聯(lián)系人永遠指向當前存活的那個插件對象從根上避免了操作了一個已斷連的舊實例這類隱蔽 bug比如導航欄高亮停在舊標簽頁。實戰(zhàn)①包裝FileManager.setupLayout最典型的例子是給文件管理器加上導航欄。M.patchFileManagerClassinfra/sui_patches.lua先取狀態(tài)、判斷本會話是否已 patch 過local layout_state _acquireHooks(FileManager, FM_LAYOUT_STATE, plugin) local setup_already_patched (layout_state nil) local orig_setupLayout layout_state and FileManager.setupLayout若已 patch 過setup_already_patched為真就直接跳過重新包裝僅刷新_live_plugin。這樣即使文件管理器在一次會話中被重建 N 次setupLayout上也始終只有一層SimpleUI 包裝不會疊出導航欄套導航欄。?? 注釋里專門記錄了一個真實事故缺少這個守衛(wèi)時每次 FM 重建都會在外層再包一層導致壁紙背景被新的白色容器蓋住而消失。守衛(wèi)把這種隨生命周期膨脹的隱患徹底掐滅。實戰(zhàn)②UIManager.close的會話級守衛(wèi)UIManager是全局單例它的close被調(diào)用頻率極高。M.patchUIManagerCloseinfra/sui_patches.lua采用會話級標志位防止疊加if UIManager._simpleui_close_patched then UIManager._simpleui_close_plugin plugin -- 僅刷新指針 plugin._orig_uimanager_close UIManager._simpleui_close_orig return end UIManager._simpleui_close_patched true local orig_close UIManager.close UIManager._simpleui_close_orig orig_close plugin._orig_uimanager_close orig_close UIManager.close function(um_self, widget, ...) ... end再次進入時不再新建包裝只把共享插槽里的插件指針更新為最新實例。單個活著的包裝永遠通過.ui拿到當前文件管理器來做判斷從而在關閉全屏組件 → 自動彈回主頁屏這條高頻路徑上保持輕量且正確。 類似手法還用在patchUIManagerShowinfra/sui_patches.lua、壁紙注入patchWallpaperFMinfra/sui_patches.lua等處都是標志位守衛(wèi) 原函數(shù)存到類上的組合拳。可靠還原teardownAll的逆序大卸載安裝入口M.installAll一口氣裝上二十多個 patchinfra/sui_patches.lua與之對稱的M.teardownAllinfra/sui_patches.lua則負責逐一拆干凈。它的順序很有講究壁紙鉤子最后安裝所以最先釋放因為它疊在最上層接著恢復UIManager.show/UIManager.close調(diào)用頻率最高、層級最深然后依次還原BookList.new、Menu、FileManager、readcollection等類方法最后清理模塊級狀態(tài)_hs_boot_done、D-pad 焦點等讓禁用→再啟用能從干凈狀態(tài)重啟。每個還原點都先查標志位再動手例如if FM and FM._simpleui_deleteFile_patched and plugin._orig_fm_deleteFile then FM.deleteFile plugin._orig_fm_deleteFile FM._simpleui_deleteFile_patched nil plugin._orig_fm_deleteFile nil end這套標志位 原函數(shù) 逆序三件套確保插件無論被啟用/禁用多少輪最終 KOReader 都能回到與從未安裝 SimpleUI 完全一致的初始狀態(tài)。小結SimpleUI 的 monkey-patch 之所以安全且可靠靠的不是運氣而是把三件事制度化統(tǒng)一登記——_acquireHooks/_addHook/_releaseHooks讓每個包裝都有據(jù)可查、可逆可拆冪等守衛(wèi)——標志位與_acquireHooks的nil返回杜絕每開一本書疊一層的膨脹陷阱逆序還原 _live_plugin——teardownAll按安裝的反序干凈卸載指針始終指向存活實例。對任何想給 KOReader 寫插件、或研究 Lua 動態(tài)修改類方法的同學infra/sui_patches.lua 都堪稱一份生產(chǎn)級 monkey-patch 范本。配合 main.lua 里的Patches.installAll/Patches.teardownAll調(diào)用時機以及 modules/module_tbr.lua、screens/sui_bottombar.lua 等被鉤子調(diào)用的具體模塊可以完整讀懂改進去與收回來的全過程。贊分享【免費下載鏈接】simpleui.kopluginA highly customizable UI plugin for KOReader that features a home screen, bottom navigation bar, top bar and desktop modules/widgets.項目地址https://gitcode.com/gh_mirrors/si/simpleui.koplugin點擊查看免費下載相關推薦ContextMenuManager與系統(tǒng)還原點安全修改的保障ContextMenuManager與系統(tǒng)還原點安全修改的保障 你是否曾因誤刪注冊表項導致右鍵菜單功能異常是否擔心優(yōu)化右鍵菜單后系統(tǒng)出現(xiàn)不可預知的錯誤本文桌面應用系統(tǒng)工具revanced-patches安全性分析確保修改應用的安全可靠revanced patches安全性分析確保修改應用的安全可靠 你是否擔心使用修改版應用會帶來安全風險ReVanced Patches作為一個開源項目通移動開發(fā)快速上手Guake下拉終端一條命令裝好5個技巧讓你告別窗口來回切換快速上手Guake下拉終端一條命令裝好5個技巧讓你告別窗口來回切換 在 GNOME 桌面上寫代碼的你是不是也經(jīng)歷過這種崩潰瞬間改一行日志手忙腳亂地在編桌面應用創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考