結繩外掛開發
面向「結繩 IDE / QiStudio」(宿主包名
com.tiecode.develop)的外掛開發文件。 「結繩 Studio」的官方正式名是 QiStudio(新一代開放工程平台,行動端首款實現 OSGi 標準的應用, 以「微組件 / 外掛」形式擴展工程開發環境)。 內容來源:反編譯studio-api-1.0-preview5.jar(com.rapid.api.*)+ go / scala / kotlin / linux / aar / libgdx / 免安裝執行 等十多個真實外掛的源碼還原。
官方資料與倉庫(重要)
官方 Gitee 倉庫
| 倉庫 | 說明 |
|---|---|
| MobileIPE-Plugin-DevManual | 官方外掛開發教程(QiStudio 微組件)。含 QiStudio核心體系介紹.md、Rapid框架介紹.md、plugin/擴展點介紹.md、plugin/外掛清單配置.md、plugin/註冊你的微組件——外掛.md |
| TiecodeCompiler-Public | 結繩編譯器(跨平台版)產物發布倉庫。含 docs/(編譯器使用/語法/封裝/平台集成文件)、headers/tiec/(C API + C++ 封裝頭文件)、prebuilt/(cli + android/windows/linux/ohos/wasm 動態庫)、stdlibs/(安卓/CXX/網頁基本庫) |
| QiStudio-PluginSamples | 官方外掛示例工程集(19+ 個示例:依賴注入、編輯器動效/彩虹括號、懸浮窗日誌、Html 項目管理器、網路請求、圖標擴展、Javac9 工具鏈、語言高亮、自定義主題、Application 生命週期、項目組件、各類選單、工具頁、設置頁等) |
官方 API jar 名是
qistudio-api-<版本>.jar(本 skill 裡反編譯的studio-api-1.0-preview5.jar是其宿主側 SDK)。 QQ 交流群:1016399857。
社區參考實現(GitHub)
本 skill 配套的真實外掛源碼集合(單倉庫多目錄,含 8 個完整可編譯外掛):
https://github.com/boboyr/tiecode-plugin
| 目錄 | 外掛 | 演示能力 |
|---|---|---|
go語言工程插件/ | go 語言工程(控制台+SDL3) | 雙模板 + LSP(gopls)補全 + TextMate 高亮 + 工具鏈 + 運行配置 + 文件樹虛擬節點 |
結繩安卓工程aar構建插件/ | aar/jar 構建 | 復用宿主编譯鏈 + NameGenerator 中文輸出 |
結繩免安裝運行插件/ | 免安裝運行器 | 復用宿主任務 + 外掛化加載未安裝 APK |
libgdx遊戲編輯器插件/ | libgdx 可視化編輯器 | 設計器 + 編輯器代碼區選單 + 新建場景類 |
scala安卓工程插件/ | Scala 安卓工程 | 完整 sbt 構建鏈 + 「結繩外掛工程」模板 + 構建/調試外掛 |
結繩Linux工程插件/ | 結繩 Linux-SDL3 | GCC 工具鏈 + SDL3 + 任務鏈 |
外部kotlin文件註解插件/ | 外部 Kotlin 文件註解 | 結繩編譯器 API:CompilerPlugin + AnnotationProcessor + Kotlin 補全 |
BasicLanguages-lang參考/ | 官方基礎語言 | csml/json/markdown/xml/properties 語言高亮參考 |
0. 核心概念與整體架構
結繩 是一個模塊化 IDE 宿主,外掛以 .rmx 文件分發。一個 .rmx
本質是一個 APK:AndroidManifest.xml + classes.dex + META-INF/program.json。
宿主通過 program.json 裡的**擴展點(extension point)**聲明來發現外掛能力,
而不是靠 manifest 的 <application> 或四大組件。
0.1 三個關鍵包
| 包 | 作用 |
|---|---|
com.rapid.api.* | 外掛 SDK(本次文件主體)。工程、語言、任務、結構、頁面、UI、網路等 |
com.rapid.framework.* | 框架層:VFS(虛擬文件系統)、Service/Data/Event Keys、program/plugin 容器 |
com.tiecode.compiler.* | 結繩編譯器(語法樹 / 符號表 / 工具鏈 completer/processor)——宿主側,外掛一般只用其 toolchain 子包 |
0.2 擴展點(program.json 的 extension 陣列)
META-INF/program.json 的完整結構:
{
"id": "com.goproject.plugin",
"name": "go語言工程插件",
"engine": "plugin",
"description": "...",
"versionCode": 4,
"versionName": "1.3",
"minSupport": 1,
"vendor": { "name": "boboyr", "email": "", "url": "#" },
"extension": [
{ "point": "application", "class": "com.goproject.plugin.MyApplication" },
{ "point": "project.manager", "class": "com.goproject.plugin.project.GoProjectManager" },
{ "point": "project.language", "class": "com.goproject.plugin.lang.GoLanguageFactory",
"scope": { "unit": "project", "identifiers": "sample.go" } },
{ "point": "domain.menu", "class": "com.goproject.plugin.Gomodmenu" }
]
}
minSupport 欄位說明(宿主最低支援版本)
minSupport 是整數,表示外掛要求宿主的結繩最低版本,不同版本取值不同:
| 結繩版本 | minSupport | 說明 |
|---|---|---|
| 結繩 4.6 | 1 | 4.6 外掛寫 "minSupport": 1 |
| 結繩 4.7 | 2 | 4.7 外掛寫 "minSupport": 2 |
即:給 4.6 開發外掛時
minSupport填1;升級到 4.7(或面向 4.7 的外掛)填2。 取值與宿主版本號綁定的具體規則以官方為準,開發時按目標宿主版本填寫即可。
已確認的擴展點全集(point 欄位):
| 擴展點 | 類要實作/繼承 | 作用 | 來源外掛 |
|---|---|---|---|
application | AndroidPlugin | 外掛入口,onInit/activate/onUninstall | go/scala/aar/免安裝 |
project.manager | ProjectManager(常用 CodeProjectManager) | 註冊一種工程類型 | go/scala/linux |
project.language | LanguageFactory | 註冊語言(高亮 + 關聯文件副檔名),可帶 scope | go/scala |
project.language.engine | LanguageEngine | 註冊語言引擎(補全/診斷等 provider 的容器) | 結繩控制台外掛 |
project.toolchain | Tool 子類(如 SunJdk8Compiler) | 註冊編譯工具鏈 | JavaCompiler8 |
project.component | ComponentIntegrator/ComponentFactory | 打開工程時掛組件(運行配置/首次彈窗/hook) | linux/kotlin/aar/免安裝 |
project.file.creationOption | PSObjectCreationOption | 文件樹「新建文件」選單項 | kotlin/libgdx |
project.file.openWithEditor | PSObjectOpeningOption | 文件「打開方式」 | kotlin |
project.event.fileUi | ProjectFileUiEvent | 文件樹 UI 事件(綁圖標等) | kotlin |
domain.menu | BaseDomainMenuAction/選單 action | 頂級選單項 | go |
domain.menu.editor.code | 編輯器代碼區選單 | libgdx | |
platform.settingsBuilder | SettingsBuilder | 設置頁新增子頁 | scala安卓 |
project.file.creationOption | — | — | — |
注意:
scope.identifiers用來把語言/組件限定到某個工程 typeId(如sample.go)。 某些擴展點 class 可以是None(佔位)。
1. 外掛入口:application 擴展點
import com.rapid.framework.program.android.app.AndroidPlugin;
import com.rapid.framework.program.android.DvmPluginDescriptor;
import com.rapid.api.Platform;
import com.rapid.api.framework.project.toolchain.ToolchainService;
import com.rapid.api.framework.project.ProjectServiceKeys;
public class MyApplication extends AndroidPlugin {
@Override
public void onInit(DvmPluginDescriptor descriptor) {
// 註冊自定義編譯工具鏈(示例:go 編譯器)
ToolchainService service = Platform.getService(ProjectServiceKeys.TOOLCHAIN);
service.setTool(GoCompileApiKeys.Gocompile, new BaseGoCompiler());
}
@Override
public void activate() {
// 外掛被激活時執行一次(常放 hook、監聽、裝配編譯外掛)
}
@Override
public void onUninstall() {
// 卸載清理:結束自己拉起的子進程(如 gopls)、斷開 LSP
}
}
關鍵 API(com.rapid.api.Platform):
Platform.getService(Key<T>)—— 取宿主服務(如ProjectServiceKeys.TOOLCHAIN)Platform.getProject()—— 當前打開的工程對象Platform.getApplicationContext()—— 宿主 Context
2. 工程類型:project.manager 擴展點
一個外掛通過 ProjectManager 註冊一種「工程類型」(如 go語言工程、結繩安卓工程)。
2.1 管理器骨架
public class GoProjectManager extends CodeProjectManager<GoProject> {
public final static String TYPE = "go語言工程"; // 顯示名
public final static String IDENTIFIER = "sample.go"; // typeId,project.json 裡存這個
public GoProjectManager() {
super();
this.fileManager = new GoFileManager(); // 可選:自定義文件管理器(綁圖標等)
// ① 文件打開方式(按副檔名)
fileManager.addPSObjectOpeningOption(DefaultOpeningOption.INSTANCE, ".go", ".mod");
// ② 文件樹節點展開方式(虛擬「外部庫」節點)
fileManager.addPSObjectExpansionCase(new ExternalLibrariesExpansionCase(), MARKER);
// ③ 新建文件選單項
fileManager.addPSObjectCreationOption(new GoFileCreationOption());
// ④ 語言引擎與語言工廠
languageManager.registerEngine("go", GoLanguageEngine.getInstance());
languageManager.registerLanguageFactory(new GoLanguageFactory());
languageManager.registerOperatorProvider(GoLanguage.ID, new GoOperatorProvider());
// ⑤ 工程創建模板
addTemplate(new GoConsoleTemplate());
addTemplate(new GoSdl3Template());
}
@Override public String getIdentifier() { return IDENTIFIER; }
@Override public TypeDescription getTypeDescription() {
Drawable d = ContextUtils.getDrawable(AndroidPlugins.getContext(this), R.drawable.golang);
return new TypeDescription(TYPE, TypeDescription.APPLICATION, d);
}
@Override public GoProject newProject() { return new GoProject(); }
@Override public boolean isProjectDir(File file) { return false; }
}
ProjectManager 接口方法(來自 javap):
String getIdentifier();
TypeDescription getTypeDescription(); // 名稱 + 類型 + 圖標
List<Template<T>> getTemplates();
void addTemplate(Template<T>);
ProjectFileManager<T> getFileManager();
T newProject();
void load(T, LoadingPresentation);
boolean isProjectDir(File); // 判斷某目錄是否該類型工程
String backup(T); void delete(T);
TypeDescription 的類型常量:APPLICATION / CONSOLE / LIBRARY。
3. 工程對象與流水線裝配:CodeProject.prepare()
工程類型對應一個 Project 子類。prepare() 在打開工程時被宿主調用,此時模板文件已寫出,可據目錄內容裝配任務鏈、運行配置、組件。
public class GoProject extends CodeProject {
@Override
public void prepare() {
if (GoProjectKind.isSdl3(getProjectDir())) {
Task buildLibmain = new BuildLibmainTask();
Task publishLib = new PublishLibTask();
addTask(buildLibmain);
addTask(publishLib);
publishLib.dependsOn(buildLibmain); // 任務依賴
addRunConfiguration(new GoSdl3RunConfiguration());
} else {
addTask(new CompilerGoTask());
addTask(new RunGoTask());
addRunConfiguration(new GoStartRunConfig());
addRunConfiguration(new ElfRunConfig());
}
}
@Override public ProjectVariant getVariant() { return ProjectVariant.DEBUG; }
}
CodeProject(extends BaseProject)關鍵方法:
void prepare();
TaskContainer getTasks(); TaskExecutor getTaskExecutor();
void addTask(Task); void setTasks(Iterable<Task>);
void addRunConfiguration(RunConfiguration); // CodeProject 獨有
ProjectVariant getVariant(); void setVariant(ProjectVariant);
Logger getLogger(); void setLogger(Logger);
String getName();
File getProjectDir(); File getChildFile(String); // 工程相對路徑解析成 File
void recycle();
ProjectVariant 取值:DEBUG / RELEASE / UNDEFINED。
技巧(來自 go 外掛):在
prepare()裡給工程補寫標記文件(如External Libraries), 能給已存在的舊工程一次性補上能力,不必重建工程。
4. 工程模板:BaseTemplate
模板決定「新建工程」對話框裡有哪些可選項、創建時寫出哪些文件。
public class GoConsoleTemplate extends BaseTemplate<GoProject> {
@Override public String getName() { return "控制台工程"; }
@Override public Drawable getPicture() { return null; } // 模板預覽圖,可 null
@Override public String getDefaultProjectName() { return "我的go控制台工程"; }
@Override public Form getForm() { return new Form(); } // 可加輸入項
@Override public void create(GoProject project, Form form,
Project.OnProjectCreateListener listener) {
try {
File file = project.getChildFile("src/main.go");
String html = AssetUtils.readAsset(AndroidPlugins.getContext(this), "sample/main.go");
html = html.replace("${project_name}", project.getName());
FileUtils.writeFile(html, file); // 寫到工程目錄
FileUtils.writeFile("module main\ngo 1.26.0", project.getChildFile("src/go.mod"));
listener.onSuccess(); // 成功回調
} catch (IOException e) {
listener.onFail("寫出默認文件失敗"); // 失敗回調
}
}
}
Template<T> 接口方法:
String getName();
Drawable getPicture();
String getDefaultProjectName();
Form getForm(); // com.rapid.framework.data.form.Form,可 addInput(new FormInput(...))
void create(T, Form, OnProjectCreateListener); // OnProjectCreateListener.onSuccess()/onFail(msg)
模板攜帶資源:把模板文件打進 app/src/main/assets/<name>,用
AssetUtils.readAsset / AssetUtils.unZipAssetsFolder(context, zipName, destDir) 讀取和解壓。
(SDL3 工程模板就是用 asset 裡的 gosdl3_template.zip 整個解壓到工程目錄。)
5. 編譯任務與工具鏈:BaseTask + ToolchainService
5.1 任務 BaseTask
public class CompilerGoTask extends BaseTask {
@Override public void execute() throws TaskInterruptError {
File output = new File(Platform.getProject().getProjectDir() + "/output");
if (!output.exists()) output.mkdirs();
GoCompile a = Platform.getService(ProjectServiceKeys.TOOLCHAIN)
.getTool(GoCompileApiKeys.Gocompile);
if (!a.isInstalled(ctx)) { logger.info("安裝工具鏈..."); a.install(ctx); }
GoCompileParams p = new GoCompileParams();
p.inputFiles = FileUtils.getGofile(srcDir);
p.outputPath = output.getPath();
p.options = new String[]{"build", "-o"};
a.compile(p, new CompileOnExecutionCallback());
}
// 必須覆寫:默認 BaseTask.prepare 拋 UnsupportedOperationException;
// 且 logger/variant 字段要在這裡賦值,否則 execute() 裡 logger.info 會 NPE。
@Override public void prepare(Project project, ProjectVariant variant, Logger logger) {
this.logger = logger;
this.variant = variant;
Os.setenv("GOROOT", goRoot, false); // 設置環境變量(android.system.Os)
}
@Override public String getId() { return "compileWithGo"; } // 供運行配置 getTaskId() 引用
@Override public String getName() { return "編譯到目標平台"; }
}
Task 接口(來自 javap):
String getId(); String getName();
void prepare(Project, ProjectVariant, Logger); // 注意默認拋異常,務必覆寫
void execute() throws TaskInterruptError;
TaskState getState();
void interrupt();
void dependsOn(Task...); void dependsOn(List<Task>);
Task getDependencyTask(String); Task getDependencyTaskByName(String);
String getIntermediatePath(); String getIntermediatePath(String);
String getOutputPath(); String getOutputPath(String);
File getGeneratedDir();
踩坑(go 外掛註釋原話):任務裡
logger不賦值,execute()裡用logger.info會 NPE 直接失敗,工具鏈安裝永不執行。
5.2 工具鏈 Tool + Installable
public interface Tool { /* 內置了 ANDROID_SDK/AAPT/AAPT2/D8/R8/DX/PROGUARD/
MANIFEST_MERGER/APK_SIGNER/JAVA_SDK/JAVA_COMPILER 等 Key */ }
public interface Installable {
boolean isInstalled(Context);
void install(Context) throws IOException;
}
- 自定義工具鏈在
application.onInit()裡用ToolchainService.setTool(customKey, impl)註冊。 - 內置 Android 工具鏈 Key 都在
Tool接口裡(可直接Platform.getService(TOOLCHAIN).getTool(Tool.AAPT2))。 - 復用宿主编譯鏈(aar 外掛 / 免安裝外掛做法):不自己打包編譯器,而是
getDependencyTaskByName("compileWithTiecodec")之類拿到宿主任務掛依賴,或直接復用getTaskId()。
6. 運行配置:RunConfiguration / TaskRunConfiguration
給工程的「運行」選單添加可執行項。最常用 TaskRunConfiguration:指定一個任務 id,
任務執行成功後回調 onResult。
public class GoStartRunConfig extends TaskRunConfiguration {
public Project getProject() { return Platform.getProject(); }
public String getTaskId() { return "RunWithGo"; } // 關聯的任務 id
public ProjectVariant getVariant() { return ProjectVariant.DEBUG; }
@Override public void onTaskSuccess(TaskResult result) {
// 任務成功後:執行 APK / ELF...
}
}
RunConfiguration 接口:
String getName(); Drawable getIcon();
String getDescription();
ProjectVariant getVariant();
boolean canRun();
void run();
boolean canStop(); void stop();
常見場景:
TaskRunConfiguration:直接關聯一個任務,任務執行後自動回調onTaskSuccess。- 自定義
RunConfiguration:實現run()中自己調用Platform.getProject().getTaskExecutor().execute(taskChain)。
7. 文件樹高級擴展
7.1 虛擬文件節點:ExpansionCase / PSObjectExpansionCase
文件樹的「外部庫」節點:
public class ExternalLibrariesExpansionCase extends PSObjectExpansionCase {
@Override
public List<PSObject> getChildren(PSObject parent, ExpansionCaseExpander expander) {
List<PSObject> nodes = new ArrayList<>();
// 遍歷 GOROOT/src 裡 go 目錄...
nodes.add(goPsObj);
return nodes;
}
@Override public boolean hideArrow() { return false; }
@Override public String getText() { return "外部庫"; }
@Override public Drawable getIcon() { return icon; }
}
7.2 新建文件嚮導:PSObjectCreationOption
public class GoFileCreationOption implements PSObjectCreationOption {
@Override public String getText() { return "Go 文件"; }
@Override public Drawable getIcon() { return icon; }
@Override public String getExtensionName() { return ".go"; }
@Override
public void onClick(PSObjectCreationDialog dialog, PSObject parent,
Runnable onRefresh) {
// 顯示對話框或直接創建
}
}
7.3 文件打開方式:PSObjectOpeningOption
public class GoModOpeningOption implements PSObjectOpeningOption {
@Override public String getText() { return "以 go.mod 編輯器打開"; }
@Override public void onClick(PSObject object, Project project) {
// 打開自定義 UI
}
}
8. 語言支持:高亮 + 補全 + 引擎
8.1 語言工廠 LanguageFactory
public class GoLanguageFactory implements LanguageFactory {
@Override public Language create() { return GoLanguage.INSTANCE; }
}
8.2 語言對象 Language
public class GoLanguage extends Language {
public final static String ID = "go";
public final static GoLanguage INSTANCE = new GoLanguage();
@Override public String getId() { return ID; }
@Override public List<String> getFileExtensions() {
return Arrays.asList(".go", ".mod");
}
@Override public TextMateProvider getTextMateProvider() {
return new GoTmbundleProvider(); // TextMate 高亮
}
@Override public OperatorProvider getOperatorProvider() { return operatorProvider; }
@Override public LanguageConfiguration getLanguageConfiguration() { return null; }
}
8.3 語言引擎 LanguageEngine(代碼補全 / 診斷)
public class GoLanguageEngine extends LanguageEngine {
// 生命週期:start (onProjectOpened) -> suspend -> (activates when file opened)
// -> complete/diagnose -> stop (user closes project)
@Override public void start(Project project, Language language) {
// 啟動 gopls 進程
}
@Override public Completion getCompletion(Document document, int offset) {
// 請求 gopls 補全
}
@Override public List<Diagnostic> getDiagnostics(Document document) {
// 診斷
}
@Override public void stop() {
// 殺死 gopls 進程
}
}
LanguageEngine 完整接口(javap):
void start(Project, Language);
void suspend();
Completion getCompletion(Document, int, CompletionConfiguration);
List<Diagnostic> getDiagnostics(Document);
List<NavItem> getNavigationItems(Document);
HoverResult getHoverHelp(Document, int);
List<UsageResult> getUsageResult(Document, int);
void stop();
TextMate 高亮:外掛把
.tmBundle或.tmLanguage文件放在assets/tmbundles/<語言名>/下,TextMateProvider讀取並返回。
9. 編譯器 API:CompilerPlugin + AnnotationProcessor
外部 Kotlin 文件註解外掛 演示了此 API: 宿主編譯過程中調用外掛的
CompilerPlugin處理語法樹節點(AST)。
@CompilerPlugin(id = "kotlin.annotation")
public class KotlinAnnotationPlugin extends CompilerPlugin {
@Override
public void process(@NotNull KtFile ktFile, @NotNull CompilerPluginContext context) {
// 遍歷 AST 節點...
// context.reportError(KtDiagnostic(...));
}
}
表現:
- 外掛 jar 的
META-INF/services/com.tiecode.compiler.CompilerPlugin裡註冊類名。 - 宿主在編譯工程時自動加載並調用
process()。 - 可報告診斷、修改 AST(實驗性)。
10. 選單與工具索引
10.1 頂級選單 domain.menu
public class Gomodmenu extends BaseDomainMenuAction {
@Override public String getText() { return "Go 模塊"; }
@Override public void onClick() {
// 顯示對話框或執行操作
}
}
10.2 編輯器代碼區選單 domain.menu.editor.code
// 在 libgdx 外掛裡:
// 選單項目目前支持 editor.code,文檔略
10.3 腳本索引 IndexActivity + ScriptIndexProvider
public class MyIndexProvider extends ScriptIndexProvider {
// 工具頁面(索引)入口
}
11. 設置頁:platform.settingsBuilder 擴展點
public class ScalaSettingsBuilder implements SettingsBuilder {
@Override public void addFunction(Context context, SettingsFunction function) {
function.addSetting(new SettingItem("sbt 路徑", "key_sbt_path", ""));
}
}
12. .rmx 打包與發布
.rmx = 普通 APK,但宿主只識別符合以下條件的 APK:
AndroidManifest.xml存在(可空)META-INF/program.json存在且格式正確- 有
classes.dex
打包方式(以 Android Studio / Gradle 為例):
- 用
com.android.application插件構建 APK。 program.json放src/main/assets/META-INF/或手動複製到 APK 的META-INF/。- 安裝:宿主(QiStudio)的「外掛管理」頁面選擇
.rmx文件安裝。
常見問題(FAQ)
Q: 執行配置點擊無反應?
A: 確認 TaskRunConfiguration.getTaskId() 與 BaseTask.getId() 匹配,且任務已在 prepare() 中添加。
Q: 外掛安裝後未生效?
A: 檢查宿主版本是否與 minSupport 匹配;檢查 program.json 的 extension 陣列中類名是否完整(含包名)。
Q: TextMate 高亮不工作?
A: 確認 .tmLanguage 文件格式為 Plist XML;確認 TextMateProvider 返回正確的 Grammar。
Q: 任務裡 logger 報 NPE?
A: 見 5.1 節,務必在 prepare() 中賦值 this.logger = logger。
附錄:相關 API 速查
Platform 靜態方法
| 方法 | 返回 | 說明 |
|---|---|---|
getService(Key) | T | 獲取宿主服務 |
getProject() | Project | 當前工程(可能 null) |
getApplicationContext() | Context | 宿主 Context |
getLogger() | Logger | 宿主 Logger |
getPlatformVersion() | int | 宿主版本號 |
ProjectServiceKeys
| 常量 | 服務類型 | 說明 |
|---|---|---|
TOOLCHAIN | ToolchainService | 工具鏈管理 |
LANGUAGE_MANAGER | LanguageManager | 語言管理 |
PROJECT_MANAGER | ProjectManagerService | 工程管理器 |
FILE_MANAGER | ProjectFileManager | 文件管理器 |
Tool 內置 Key 一覽
| Key | 對應工具 |
|---|---|
Tool.ANDROID_SDK | Android SDK 路徑 |
Tool.AAPT2 | aapt2 |
Tool.D8 | D8 dexer |
Tool.JAVA_COMPILER | javac |
Tool.APK_SIGNER | apksigner |
全部 Key 見
com.rapid.api.framework.project.toolchain.Tool接口常量。
本文件基於 com.rapid.api.* 的反編譯結果 + 真實外掛源碼整理,如有疏漏歡迎 PR。