Skip to content

Addon Compat

HoshinoYumeka edited this page Sep 7, 2026 · 1 revision

版本与两端安全

首页附属接口文档 | 下一页:浏览器后端


五条兼容承诺

契约写在 MCphoneApi 的类注释里。改 API 之前守住这五条:

# 承诺 含义
已发布的接口不加抽象方法 新增能力一律走 default 方法或新接口
已发布的记录不改构造函数 对外只给 builder(见 AppInfo
不改已发布的方法签名 要改就新增重载,旧的标 @Deprecated 至少留一个大版本
包名也是 API 挪一个类的包等于删了它再新建一个
这些规矩只管 api corefeaturecompatutil 均为内部实现,附属不该引用

第五条的唯一例外是浏览器后端,那一页说明它为何仍在 feature 下。

MCphoneApi.VERSION

public static final int VERSION = 1;

API 代号。每次向 API 新增内容即 +1,只增不减。

VERSION = 1 覆盖:IPhoneAppRequiredModIPhonePagePhoneCanvasPhoneStyleIAppSourceAppInfoICostItemCostEmcCostIAppPriceProviderIEmcWalletEmcWallets

它只能判断语义,不能替代类加载

// ✗ 错误:旧版上 JVM 校验这个方法时即抛 NoClassDefFoundError,轮不到那句 if
if (MCphoneApi.VERSION >= 2) {
    new SomeNewApiType().doThing();
}

// ✓ 正确:把新能力关进单独一个类,判断通过再碰它
if (MCphoneApi.VERSION >= 2) {
    NewFeatureBridge.doThing();     // 只有这个类里才引用新类型
}

⚠ 见坑 · VERSION 判断挡不住类加载


两端安全

api.client 及其子包(app / ui / store 仅客户端
api.cost 两端
MCphoneApi 两端

api.client 的接口签名中带有 GuiGraphics 一类的客户端类型,其实现类只能在客户端加载

不要从物品、方块、菜单、网络包或服务端事件处理中引用它们,也不要让实现类被服务端的类顺带加载到。

⚠ 后果是专用服务器启动即崩,且崩溃信息不会指向出问题的 App。见坑 · 客户端类型泄漏到服务端

做法

实现类放在 yourmod.client 包下,只由客户端代码接触。主类也可以直接声明为客户端专用:

@Mod(value = "yourmod", dist = Dist.CLIENT)

服务端需要触发客户端行为时,把客户端逻辑单独放一个类、用静态方法调过去,且方法签名中不得出现客户端类型——invokestatic 的属主类在第一次执行到时才解析,校验期不碰它。

可参照 core/client/PhoneScreenOpener

api.cost 的额外约束

该包的实现类(IAppPriceProviderIEmcWallet两端都会加载:客户端画价格与余额,服务端在扣减前核对。其中同样不得出现客户端类型。


首页附属接口文档 | 下一页:浏览器后端

Clone this wiki locally