M2(领域层): ConfigManager/VersionResolver/ResourceManager/AppDataInjector/StartupOrchestrator

T-M2-05 ConfigManager:本地 rawfile/app_config.json(§4.2 实测值)、远程 URL 拼装('-'→'/'+.txt+?a=ts 禁缓存)、
        长度<30 走 showmessage 阻断、二级 url 二次请求(语义待真机校验)、产出版本决策
T-M2-06 VersionResolver:纯函数,agentlist/gamelist 两棵树 + agent→channel→market→game 后层覆盖 +
        两树取更高 version(§4.4)。单测 8 用例全通过,覆盖率 81.8%(≥80%)
T-M2-07 ResourceManager:沙箱路径规范、内置包拷贝解压、version.xml 解析(@ohos.xml)、远程 zip 下载/删旧/解压、版本比较
T-M2-09 AppDataInjector:加载前写 <gameDir>/app_data.js(§6 全局变量同名同义,JSON.stringify 安全字面量)
T-M2-11 StartupOrchestrator:INIT→…→ENTER_HALL 状态机,远程失败降级本地、showmessage 阻断、weburl 空/非空入口规则
配套:module.json5 声明 ohos.permission.INTERNET + reason_internet 字符串

devecocli build 通过;scripts/test.sh 单测全通过(修复 PermissionRequestResult 顶层导入)。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
lanterngamescn
2026-06-25 18:29:45 +08:00
parent ecb0e4642a
commit d2da223c8d
15 changed files with 953 additions and 5 deletions
+10
View File
@@ -46,6 +46,16 @@
}
],
}
],
"requestPermissions": [
{
"name": "ohos.permission.INTERNET",
"reason": "$string:reason_internet",
"usedScene": {
"abilities": ["EntryAbility"],
"when": "inuse"
}
}
]
}
}
@@ -11,6 +11,10 @@
{
"name": "EntryAbility_label",
"value": "label"
},
{
"name": "reason_internet",
"value": "用于下载游戏资源与获取远程配置"
}
]
}
@@ -0,0 +1,13 @@
{
"agent": "veRa0qrBf0df2K1G4de2tgfmVxB2jxpv",
"channel": "FtJf073aa0d6rI1xD8J1Y42fINTm0ziK",
"gamedir": "FtJf073aa0d6rI1xD8J1Y42fINTm0ziK",
"gamestart": "gamehall",
"appversion": "49",
"market": "3",
"gameid": "",
"weburl": "",
"gameconfig": "tsgames.daoqi88.cn-config_test-update_jsonv2_test",
"other": "",
"tuiguang": ""
}
+2
View File
@@ -1,7 +1,9 @@
import localUnitTest from './LocalUnit.test';
import bridgeTest from './Bridge.test';
import versionResolverTest from './VersionResolver.test';
export default function testsuite() {
localUnitTest();
bridgeTest();
versionResolverTest();
}
+115
View File
@@ -0,0 +1,115 @@
import { describe, it, expect } from '@ohos/hypium';
import { VersionResolver, RemoteConfig, MatchKeys, VersionDecision } from 'domain_resource';
/**
* 分层版本决策单测(T-M2-06,契约 §4.4)。纯函数,构造典型多层样例验证后层覆盖、
* 两棵树取更高 version、showmessage 阻断。
*/
export default function versionResolverTest() {
const keys: MatchKeys = { agentid: 'A1', channelid: 'C1', marketid: 'M1', gameid: 'G1' };
describe('VersionResolver', () => {
it('empty_config_zero_decision', 0, () => {
const d: VersionDecision = VersionResolver.resolve({}, keys);
expect(d.gameVersion).assertEqual(0);
expect(d.appVersion).assertEqual(0);
expect(d.showmessage).assertEqual('');
expect(d.gameDownload).assertEqual('');
});
it('agent_tree_deeper_overrides', 0, () => {
// 代理树:agent 设 game_version=10market 覆盖为 20(深层覆盖浅层)
const remote: RemoteConfig = {
agentlist: [{
agentid: 'A1', game_version: '10', game_download: 'a_url', game_size: '100',
channellist: [{
channelid: 'C1',
marketlist: [{ marketid: 'M1', game_version: '20', game_download: 'm_url' }],
}],
}],
};
const d: VersionDecision = VersionResolver.resolve(remote, keys);
expect(d.gameVersion).assertEqual(20);
expect(d.gameDownload).assertEqual('m_url');
});
it('market_game_level_overrides', 0, () => {
// market.gamelist 中 gameid 命中,覆盖到最深
const remote: RemoteConfig = {
agentlist: [{
agentid: 'A1',
channellist: [{
channelid: 'C1',
marketlist: [{
marketid: 'M1', game_version: '20',
gamelist: [{ gameid: 'G1', game_version: '30', game_download: 'g_url' }],
}],
}],
}],
};
const d: VersionDecision = VersionResolver.resolve(remote, keys);
expect(d.gameVersion).assertEqual(30);
expect(d.gameDownload).assertEqual('g_url');
});
it('two_trees_take_higher_version', 0, () => {
// 代理树 game_version=20,游戏树 game_version=25 → 取 25 及其下载地址
const remote: RemoteConfig = {
agentlist: [{ agentid: 'A1', game_version: '20', game_download: 'agent_url' }],
gamelist: [{
gameid: 'G1',
agentlist: [{ agentid: 'A1', game_version: '25', game_download: 'game_url' }],
}],
};
const d: VersionDecision = VersionResolver.resolve(remote, keys);
expect(d.gameVersion).assertEqual(25);
expect(d.gameDownload).assertEqual('game_url');
});
it('app_and_game_independent_winners', 0, () => {
// app 升级取代理树(app_version=49)game 升级取游戏树(game_version=30)
const remote: RemoteConfig = {
agentlist: [{ agentid: 'A1', app_version: '49', app_download: 'apk_url', game_version: '10' }],
gamelist: [{
gameid: 'G1',
agentlist: [{ agentid: 'A1', app_version: '40', game_version: '30', game_download: 'g_url' }],
}],
};
const d: VersionDecision = VersionResolver.resolve(remote, keys);
expect(d.appVersion).assertEqual(49);
expect(d.appDownload).assertEqual('apk_url');
expect(d.gameVersion).assertEqual(30);
expect(d.gameDownload).assertEqual('g_url');
});
it('no_match_returns_empty', 0, () => {
const remote: RemoteConfig = {
agentlist: [{ agentid: 'OTHER', game_version: '99', game_download: 'x' }],
};
const d: VersionDecision = VersionResolver.resolve(remote, keys);
expect(d.gameVersion).assertEqual(0);
expect(d.gameDownload).assertEqual('');
});
it('showmessage_from_layer_or_top', 0, () => {
const top: RemoteConfig = { showmessage: '停服维护公告' };
expect(VersionResolver.resolve(top, keys).showmessage).assertEqual('停服维护公告');
const layer: RemoteConfig = {
agentlist: [{ agentid: 'A1', showmessage: '代理层公告' }],
};
expect(VersionResolver.resolve(layer, keys).showmessage).assertEqual('代理层公告');
});
it('empty_string_does_not_override', 0, () => {
// 深层空串不应覆盖浅层非空值
const remote: RemoteConfig = {
agentlist: [{
agentid: 'A1', game_download: 'keep', game_version: '10',
channellist: [{ channelid: 'C1', game_download: '' }],
}],
};
const d: VersionDecision = VersionResolver.resolve(remote, keys);
expect(d.gameDownload).assertEqual('keep');
});
});
}