补齐移动壳启动视觉配置
复用真实品牌图标配置 Expo 启动页 复用透明品牌图标配置 Android adaptive icon 校验启动页、adaptive icon 与品牌底色不漂移 更新原生壳方案和团队决策记录
This commit is contained in:
@@ -7,6 +7,11 @@
|
||||
"orientation": "portrait",
|
||||
"icon": "./assets/icon.png",
|
||||
"userInterfaceStyle": "automatic",
|
||||
"splash": {
|
||||
"image": "./assets/icon.png",
|
||||
"resizeMode": "contain",
|
||||
"backgroundColor": "#fffdf9"
|
||||
},
|
||||
"assetBundlePatterns": [
|
||||
"**/*"
|
||||
],
|
||||
@@ -37,6 +42,10 @@
|
||||
"android": {
|
||||
"package": "world.genarrative.mobile",
|
||||
"versionCode": 1,
|
||||
"adaptiveIcon": {
|
||||
"foregroundImage": "./assets/icon.png",
|
||||
"backgroundColor": "#fffdf9"
|
||||
},
|
||||
"intentFilters": [
|
||||
{
|
||||
"action": "VIEW",
|
||||
|
||||
@@ -19,6 +19,7 @@ const packagePath = new URL('../package.json', import.meta.url);
|
||||
const packageConfig = JSON.parse(fs.readFileSync(packagePath, 'utf8'));
|
||||
const iconPath = new URL('../assets/icon.png', import.meta.url);
|
||||
const icon = PNG.sync.read(fs.readFileSync(iconPath));
|
||||
const brandBackgroundColor = '#fffdf9';
|
||||
const productionSourceRoots = [
|
||||
new URL('../App.tsx', import.meta.url),
|
||||
new URL('../app.json', import.meta.url),
|
||||
@@ -107,6 +108,24 @@ function assertNoDevScaffoldTerms(files) {
|
||||
}
|
||||
}
|
||||
|
||||
function countAlphaPixels(png) {
|
||||
let transparent = 0;
|
||||
let translucent = 0;
|
||||
let opaque = 0;
|
||||
for (let index = 3; index < png.data.length; index += 4) {
|
||||
const alpha = png.data[index];
|
||||
if (alpha === 0) {
|
||||
transparent += 1;
|
||||
} else if (alpha === 255) {
|
||||
opaque += 1;
|
||||
} else {
|
||||
translucent += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return { transparent, translucent, opaque };
|
||||
}
|
||||
|
||||
assertNoDevScaffoldTerms(
|
||||
productionSourceRoots.flatMap((root) => collectProductionSourceFiles(root)),
|
||||
);
|
||||
@@ -177,6 +196,19 @@ if (icon.width < 512 || icon.height < 512) {
|
||||
throw new Error('mobile shell icon must be a production-size brand asset');
|
||||
}
|
||||
|
||||
const iconAlpha = countAlphaPixels(icon);
|
||||
if (iconAlpha.transparent === 0 || iconAlpha.opaque === 0) {
|
||||
throw new Error('mobile shell adaptive icon foreground must use the real transparent brand asset');
|
||||
}
|
||||
|
||||
if (
|
||||
appConfig.splash?.image !== './assets/icon.png' ||
|
||||
appConfig.splash?.resizeMode !== 'contain' ||
|
||||
appConfig.splash?.backgroundColor !== brandBackgroundColor
|
||||
) {
|
||||
throw new Error('mobile shell splash must use the real brand icon and brand background');
|
||||
}
|
||||
|
||||
if (!appConfig.ios?.associatedDomains?.includes('applinks:app.genarrative.world')) {
|
||||
throw new Error('mobile shell iOS associated domain is missing');
|
||||
}
|
||||
@@ -197,6 +229,13 @@ if (appConfig.android?.versionCode !== 1) {
|
||||
throw new Error('mobile shell Android versionCode must start at 1');
|
||||
}
|
||||
|
||||
if (
|
||||
appConfig.android?.adaptiveIcon?.foregroundImage !== './assets/icon.png' ||
|
||||
appConfig.android?.adaptiveIcon?.backgroundColor !== brandBackgroundColor
|
||||
) {
|
||||
throw new Error('mobile shell Android adaptive icon must use the real brand icon and brand background');
|
||||
}
|
||||
|
||||
const androidFilter = appConfig.android?.intentFilters?.find((filter) =>
|
||||
filter?.data?.some(
|
||||
(entry) =>
|
||||
|
||||
@@ -53,6 +53,7 @@
|
||||
- 2026-06-18 Tauri 单实例:桌面壳启用 `tauri-plugin-single-instance` 并要求该插件最先注册;重复启动 App 时第二实例退出,只唤醒、取消最小化并聚焦已有主窗口,不把第二实例 argv / cwd / 深链内容作为事件透传给 H5。桌面深链后续如需接入,必须先定义受控 URL 归一和宿主边界,不能借单实例回调直接开放任意启动参数。
|
||||
- 2026-06-18 桌面壳安装包身份:Tauri 桌面壳的产品名固定为 `Genarrative`,应用 identifier 固定为 `world.genarrative.desktop`,Tauri 配置、`apps/desktop-shell/package.json` 与 Cargo package 版本统一为 `0.1.0`;Release 主窗口只加载打包的 `index.html` 和根 `dist` H5 资产,dev URL 只指向本机 Vite 调试入口。桌面壳 CSP 保持 `script-src 'self'`,不得加入 `unsafe-eval`、`tauri:` 或 `file:`,也不得在没有真实端点、签名密钥和发布流程前配置 updater;检查脚本会拒绝包身份、版本、CSP 或 updater 约束漂移。
|
||||
- 2026-06-18 壳生产代码禁用临时替身:Expo 与 Tauri 壳的生产源码和配置不得出现 mock / fake / placeholder / stub / TODO / FIXME 以及对应中文脚手架词;测试文件仍可使用 mock。两端壳配置检查会扫描生产入口、配置和壳实现,防止把临时替身、占位文案或伪实现带进可分发壳。
|
||||
- 2026-06-18 移动壳启动页与 adaptive icon:Expo 移动壳启动页和 Android adaptive icon 复用现有真实品牌图标 `apps/mobile-shell/assets/icon.png`,背景色固定为 H5 壳根背景 `#fffdf9`。该 PNG 是 1024x1024 RGBA 透明前景品牌资产,不新增占位图;配置检查会校验图标尺寸、透明像素、splash 和 adaptive icon 指向,避免后续换成非品牌或占位素材。
|
||||
- 影响范围:`src/services/host-bridge/`、未来 `apps/mobile-shell/`、未来 `apps/desktop-shell/`、移动端支付 / 分享 / 深链 / 推送、桌面端系统能力、AI H5 sandbox 的 GameBridge 边界。
|
||||
- 验证方式:普通浏览器、小程序、Expo 壳、Tauri 壳都能返回正确 `getHostRuntime()`;未支持能力能回退 H5;固定玩法在各宿主中读取同一作品数据和运行态 snapshot;AI sandbox 无法直接调用 HostBridge;Tauri release 不允许任意远端页面调用桌面命令。
|
||||
- 关联文档:`docs/【前端架构】ExpoReactNative与Tauri宿主壳方案-2026-06-17.md`、`docs/【前端架构】宿主壳能力统一协议-2026-06-17.md`。
|
||||
|
||||
@@ -309,6 +309,8 @@ GameBridge 禁止:
|
||||
|
||||
2026-06-18 追加:两端壳的生产源码和配置禁止出现 mock / fake / placeholder / stub / TODO / FIXME 以及对应中文脚手架词;测试文件仍可使用 `vi.mock` 或等价测试替身。`apps/mobile-shell/scripts/check-config.mjs` 与 `apps/desktop-shell/scripts/check-config.mjs` 会扫描各自生产入口、配置和壳实现,防止把临时替身或占位文案带进可分发壳。
|
||||
|
||||
2026-06-18 追加:移动壳启动页与 Android adaptive icon 复用现有真实品牌图标 `apps/mobile-shell/assets/icon.png`,背景色固定为 H5 壳根背景 `#fffdf9`。该 PNG 是 1024x1024 RGBA 透明前景品牌资产,不新增占位图;Expo `splash` 使用同一图标 `contain` 展示,Android `adaptiveIcon.foregroundImage` 使用同一透明前景图,`check-config.mjs` 会校验图标尺寸、透明像素、启动页和 adaptive icon 配置。
|
||||
|
||||
### Phase 4:宿主能力扩展
|
||||
|
||||
- 移动端接入系统分享、推送、原生登录和渠道支付。
|
||||
|
||||
Reference in New Issue
Block a user