为菜品管理、菜品学习、菜品识别等依赖银歌 AI SDK 的业务建立统一的前置检查,确保只有在“插件可用、SDK 初始化成功、设备真实已激活”后才进入具体业务。
本设计解决以下问题:
SETTING_AI_DISH_ACTIVATED 与 SDK 真实状态不一致时仍可能放行业务。DishManagementActivity 将 SDK 的具体失败统一显示为“学习数据校正失败”。DishManagementActivity 在门禁通过前不请求菜品及学习数据,不执行校正。MainActivity。采用在 AiSdkManager 中建设统一“AI 就绪门禁”的方案。
不采用以下方案:
DishManagementActivity 增加判断:会继续保留学习页和识别页的重复逻辑。AI 业务真正可用必须同时满足:
插件已安装
+ 插件版本不要求强制升级
+ SDK 服务初始化成功
+ queryAiActiveStatus() 返回已激活
= READY
统一状态定义:
enum AiReadyState {
IDLE,
INITIALIZING,
CHECKING_ACTIVE,
READY,
NOT_ACTIVE,
PLUGIN_NOT_INSTALLED,
UPGRADE_REQUIRED,
INIT_TIMEOUT,
SERVICE_ERROR
}
SETTING_AI_DISH_ACTIVATED 只作为设置页展示缓存,不能作为业务放行依据。业务放行以本次 SDK 会话中的 queryAiActiveStatus() 结果为准。
进入 AI 业务页面
-> 请求统一门禁 ensureAiReady()
-> 初始化 SDK 服务
-> SDK 回调插件未安装:提示安装,拒绝则返回主页
-> SDK 回调必须升级:提示升级,拒绝则返回主页
-> SDK 初始化成功:调用 queryAiActiveStatus()
-> 已激活:状态置为 READY,继续业务
-> 未激活:提示前往设置,拒绝则返回主页
-> 设置页激活成功返回:使旧状态失效并重新执行完整门禁
不能在插件未安装时先查询激活状态,因为激活状态由插件服务提供;插件服务不可用时,查询结果不可信。
AiSdkManager 设计public interface ReadyCallback {
void onReady(@NonNull YingeoAiSDK sdk);
void onBlocked(
@NonNull AiReadyState state,
@NonNull String message
);
}
public void ensureAiReady(
@NonNull Activity activity,
@NonNull ReadyCallback callback
);
public void invalidateReadyState();
public void markNotActive(@Nullable String message);
public AiReadyState getReadyState();
页面只消费统一结果,不再自行组合初始化、插件、升级和激活判断。
同一时间只允许一次初始化或激活状态查询:
initAiService()。onInitSuccess() 后再查询激活状态。SDK_PLUGIN_NOT_INSTALL,进入 PLUGIN_NOT_INSTALLED。PLUGIN_MUST_UPGRADE,进入 UPGRADE_REQUIRED。INIT_TIMEOUT。SDK 初始化成功后,在后台线程调用 queryAiActiveStatus():
SUCCESS:状态置为 READY。NOT_ACTIVE:状态置为 NOT_ACTIVE,同步写入本地 ACTIVATED=false。SERVICE_ERROR,保留 SDK 原始错误信息。所有页面回调切回主线程。
以下情况必须清除 READY:
NOT_ACTIVE。unInitAiService()。DishManagementActivity 流程当前的启动顺序需要由:
初始化 SDK -> 注册监听 -> 立即 syncDishList()
调整为:
初始化页面 -> 注册监听 -> ensureAiReady()
-> READY 后 syncDishList()
门禁检查期间:
onReady() 后:
learnDateRivise()。即使门禁曾通过,learnDateRivise() 仍需处理 NOT_ACTIVE:
markNotActive()。提示文案:
AI 菜品识别设备尚未激活,暂时无法进行菜品学习和数据校正。
请前往设置页填写激活码并完成激活。
按钮:
前往设置返回主页行为:
SettingActivity。CLEAR_TOP | SINGLE_TOP 打开 MainActivity,随后结束当前页面。SettingActivity 使用专用流程参数进入激活处理:
EXTRA_AI_DISH_ACTIVATION_FLOW = true;
该流程固定展示基础设置,并向 SettingsBasicFragment 传递定位参数。基础设置页收到参数后:
queryAiActiveStatus() 二次确认。RESULT_OK。如果用户取消、激活失败或直接退出设置页,返回 RESULT_CANCELED。
业务页面使用 Activity Result 接收结果:
RESULT_OK:调用 invalidateReadyState(),重新执行 ensureAiReady()。RESULT_CANCELED:返回主页。RESULT_OK,也不得直接执行菜品业务。不单独依赖普通 onResume(),避免弹框、权限页或屏幕切换造成重复检查。
提示用户安装银歌 AI 插件:
安装插件:打开项目统一的插件更新弹框。返回主页:返回 MainActivity。插件安装成功后重新执行“初始化 -> 版本检查 -> 激活状态查询”。
提示当前版本无法继续使用:
立即升级:打开项目统一的插件更新弹框。返回主页:返回 MainActivity。升级完成后旧的初始化和激活缓存全部失效,必须重新走完整门禁。
项目不再直接展示 SDK 内置下载弹框,由 AiPluginUpdateDialog 与
AiPluginUpdateManager 统一承接安装、强制升级和基础设置激活中的插件更新流程:
AppInfoBean。PluginManager.downloadFile(),将 onProgress(int) 映射为
0 至 100 的进度条和百分比。SmdtManagerNew.sys_doSilentInstallApp() 后台安装,项目弹框在安装阶段
切换为“AI算法SDK更新”,不再展示 Android 系统安装器。下载前必须校验地址为带有效主机名的 HTTPS URL;下载完成后必须校验文件存在、非空,
且 APK 包名为 com.yingeo.ai.sdk。后台安装前必须确认主板服务可用,安装后必须确认目标
插件版本已生效;任一校验失败均停止流程并在项目弹框显示明确错误。
AI 门禁与插件更新流程的弹框统一复用项目现有视觉基线:固定 common_pop_width、白色圆角
卡片、白色标题栏与黑色标题文字、标题分隔线、灰色正文、左侧次按钮和右侧橙色主按钮。
覆盖范围包括:
AI 服务检查和基础设置激活中的等待提示直接复用 NewSingleTipPop 与
single_tip_pop_layout.xml,仅隐藏底部操作区,不再维护独立加载弹框或显示系统样式的
圆形进度控件,确保其卡片尺寸、白色标题栏、分隔线和正文排版与项目提示框完全一致。
弹框外部区域均不可关闭;下载中和安装中禁用取消。未激活提示的返回键、返回主页及前往 设置行为不变,插件安装和升级提示在打开下载弹框后继续保留业务阻断。
当前校正流程会在 SDK 校正前清理现有学习图片。实施时应改为临时目录准备和成功后替换:
READY 时执行 SDK 校正。这部分与就绪门禁同时实施,避免解决激活问题后仍存在数据破坏风险。
页面提示必须区分:
| 状态 | 用户提示 |
|---|---|
PLUGIN_NOT_INSTALLED |
未安装 AI 插件 |
UPGRADE_REQUIRED |
AI 插件版本过低,必须升级 |
NOT_ACTIVE |
设备尚未激活,请前往设置处理 |
INIT_TIMEOUT |
AI 服务初始化超时,请重试 |
SERVICE_ERROR |
AI 服务异常,请重启插件或设备 |
| 网络失败 | 菜品数据请求失败,请检查网络 |
| 图片下载失败 | 学习图片下载失败 |
| 图片保存失败 | 学习图片保存失败,请检查存储空间 |
| SDK 校正失败 | 显示 SDK 返回的具体错误信息 |
日志至少包含:页面、操作、门禁状态、SDK code、SDK message、耗时和本地数据准备状态。禁止记录激活码。
NOT_ACTIVE 会使 READY 失效。1004 时保留原有学习数据。AiSdkManager.ensureAiReady() 放行业务。DishManagementActivity 不发起菜品学习业务请求。1004、1010 等错误统一显示为“学习数据校正失败”。ai/AiSdkManager.java:统一门禁、状态机、并发与状态失效。ai/AiDishActivationManager.java:复用统一初始化和插件状态,修正安装期间超时。ai/AiPluginUpdatePolicy.java:定义查询、下载、安装状态和按钮行为。ai/AiPluginUpdateManager.java:统一版本查询、下载进度、APK 校验与安装回调链。ai/AiPluginUpdateDialog.java:统一展示版本、内容、进度、安装状态和重试操作。activity/DishManagementActivity.java:门禁后启动业务、弹框和设置页返回处理。activity/NewDishLearningActivity.java:移除重复的激活与插件判断,接入统一门禁。activity/DishRecognitionActivity.java:接入统一门禁,保留运行中 NOT_ACTIVE 兜底。activity/SettingActivity.java、fragment/SettingsBasicFragment.java:目标项导航及激活结果回传。DishLearningStore.java:支持临时目录与成功替换。strings.xml:补充明确状态和弹框文案。dialog_ai_plugin_update.xml 及对应 drawable:统一插件更新弹框界面。queryAiActiveStatus() 是同步 AIDL 调用,必须避免阻塞主线程。2026-07-21 已按本设计完成项目落地:
AiReadyState、AiReadinessPolicy、AiSdkManager 两层门禁和统一 AiReadinessGuard。READY 后启动 AI 业务。设备侧插件安装、强制升级和激活交互尚未安装本次 APK 实测,仍需在目标设备上完成五类场景验收。