App 图标更换为制冷杯主题 + 名称改 SmartAssister + 自定义基座蓝牙模块配置

- static/appIcon.png: 重绘 1024x1024 图标(冰蓝渐变底 + 白色制冷杯 + 雪花标志 + 蓝牙角标),
  生成脚本 .icon_build/make_icon.py(Pillow,4x 超采样)
- manifest.json: name 改 SmartAssister;modules 增加 Bluetooth(自定义基座必需);
  删除手工声明的 4 个蓝牙权限(模块自动注入,避免 AndroidManifest 合并冲突)
- docs: 追加修改记录_2026-09-09_App图标更换为制冷杯主题.md
This commit is contained in:
evan.liu 2026-09-09 06:08:54 +08:00
parent 056790e8d1
commit 011feee05d
4 changed files with 227 additions and 79 deletions

View File

@ -0,0 +1,116 @@
# -*- coding: utf-8 -*-
# 生成 App 图标:制冷杯 + 蓝牙徽标
import math, sys
sys.path.insert(0, '.icon_build')
from PIL import Image, ImageDraw
S = 4 # 超采样倍数
N = 1024 # 目标尺寸
W = N * S
def sc(v):
return int(round(v * S))
# ---------- 背景:冰蓝纵向渐变 ----------
top = (110, 200, 235) # 浅冰蓝
bot = (24, 82, 152) # 深蓝
grad = Image.new('RGB', (1, 2))
grad.putpixel((0, 0), top)
grad.putpixel((0, 1), bot)
grad = grad.resize((W, W), Image.BICUBIC)
img = Image.new('RGBA', (W, W), (0, 0, 0, 0))
# 圆角矩形蒙版(角透明,与旧图标一致)
mask = Image.new('L', (W, W), 0)
md = ImageDraw.Draw(mask)
md.rounded_rectangle([0, 0, W - 1, W - 1], radius=sc(230), fill=255)
img.paste(grad, (0, 0), mask)
d = ImageDraw.Draw(img)
def thick_line(pts, color, width):
d.line(pts, fill=color, width=width, joint='curve')
r = width // 2
for (x, y) in (pts[0], pts[-1]):
d.ellipse([x - r, y - r, x + r, y + r], fill=color)
def rpoly(pts, r, color):
"""多边形 + 顶点圆角"""
d.polygon(pts, fill=color)
for (x, y) in pts:
d.ellipse([x - r, y - r, x + r, y + r], fill=color)
# ---------- 杯子 ----------
WHITE = (255, 255, 255, 255)
cx = 462
# 杯盖(圆角矩形,略宽于杯身)
lid = [sc(cx - 138), sc(240), sc(cx + 138), sc(330)]
d.rounded_rectangle(lid, radius=sc(32), fill=WHITE)
# 盖顶小凸起(冷感模块)
d.rounded_rectangle([sc(cx - 46), sc(196), sc(cx + 46), sc(250)],
radius=sc(22), fill=WHITE)
# 杯身(梯形,上宽下窄;仅顶部顶点补圆角,底部由圆角矩形收边)
body = [(sc(cx - 128), sc(316)),
(sc(cx + 128), sc(316)),
(sc(cx + 96), sc(712)),
(sc(cx - 96), sc(712))]
d.polygon(body, fill=WHITE)
tr = sc(14)
for (x, y) in (body[0], body[1]):
d.ellipse([x - tr, y - tr, x + tr, y + tr], fill=WHITE)
# 杯底圆角收边
d.rounded_rectangle([sc(cx - 100), sc(648), sc(cx + 100), sc(716)],
radius=sc(30), fill=WHITE)
# ---------- 雪花标志(杯身正面) ----------
SNOW = (39, 122, 190, 255)
fx, fy = sc(cx), sc(500)
arm = sc(78)
lw = sc(17)
br = sc(36) # 分叉长度
bpos = 0.62 # 分叉位置(沿臂比例)
# 中心圆点
cr = sc(14)
d.ellipse([fx - cr, fy - cr, fx + cr, fy + cr], fill=SNOW)
for k in range(6):
a = math.radians(k * 60 + 90)
dx, dy = math.cos(a), math.sin(a)
ex, ey = fx + dx * arm, fy + dy * arm
thick_line([(fx, fy), (ex, ey)], SNOW, lw)
# 每个臂上分叉
bx0, by0 = fx + dx * arm * bpos, fy + dy * arm * bpos
for sgn in (-1, 1):
ba = a + sgn * math.radians(55)
bex, bey = bx0 + math.cos(ba) * br, by0 + math.sin(ba) * br
thick_line([(bx0, by0), (bex, bey)], SNOW, lw)
# ---------- 蓝牙徽标(右下角白圆) ----------
bcx, bcy = sc(738), sc(742)
brad = sc(182)
d.ellipse([bcx - brad, bcy - brad, bcx + brad, bcy + brad], fill=WHITE)
RUNE = (24, 82, 152, 255)
a_ = sc(100) # 半高
d_ = sc(58) # 右伸距离
lw2 = sc(32)
p_top = (bcx, bcy - a_)
p_mid = (bcx, bcy)
p_bot = (bcx, bcy + a_)
p_ru = (bcx + d_, bcy - a_ // 2)
p_rl = (bcx + d_, bcy + a_ // 2)
p_lu = (bcx - d_, bcy - a_ // 2)
p_ll = (bcx - d_, bcy + a_ // 2)
for seg in ([p_top, p_bot], [p_top, p_ru, p_mid], [p_mid, p_rl, p_bot],
[p_lu, p_rl], [p_ll, p_ru]):
thick_line(seg, RUNE, lw2)
# ---------- 输出 ----------
out = img.resize((N, N), Image.LANCZOS)
out.save('static/appIcon.png')
print('saved static/appIcon.png')

View File

@ -0,0 +1,30 @@
# 修改记录 2026-09-09:App 图标更换为制冷杯主题
## 背景
原图标(奶瓶 + 蓝牙徽标)仍沿用母婴产品早期设计,现产品定位为**制冷杯**,图标需体现该概念。
## 改动内容
- `static/appIcon.png`:重新绘制 1024×1024 图标。
- 背景:冰蓝纵向渐变(浅冰蓝 → 深蓝),圆角矩形外形与旧图标一致;
- 主体:白色制冷杯剪影(杯盖 + 顶部模块凸起 + 上宽下窄杯身),杯身正面为蓝色雪花标志,表达"制冷";
- 右下角保留蓝牙徽标(白圆 + 蓝牙符文),延续 App 的 BLE 连接属性。
- `manifest.json` 无需改动:Android 各 dpi 与 iOS appstore 均指向 `/static/appIcon.png`,直接替换文件即可生效。
## 生成方式
图标由脚本 `.icon_build/make_icon.py` 程序化绘制(Pillow,4 倍超采样抗锯齿)。
本机无 Pillow 时重新生成需先执行:
```bash
python -m pip install --target .icon_build Pillow
python .icon_build/make_icon.py
```
(`.icon_build/` 仅为图标生成临时目录,不参与 App 构建;Pillow 依赖已清理,仅保留脚本。)
## 追加:自定义基座云打包配置修复
- `manifest.json`:`name` 改为 `SmartAssister`;`app-plus.modules` 增加 `Bluetooth`(云打包/自定义基座必须显式声明蓝牙模块,标准基座默认全模块故此前未暴露)。
- 勾选 Bluetooth 模块后,云端会自动注入 `BLUETOOTH`/`BLUETOOTH_ADMIN`/`BLUETOOTH_SCAN(neverForLocation)`/`BLUETOOTH_CONNECT` 权限,与 `distribute.android.permissions` 中手工声明的重复,导致 AndroidManifest 合并冲突(`BLUETOOTH_SCAN duplicated`)打包失败。**已删除手工声明的 4 个蓝牙权限**(模块注入版本自带 `neverForLocation`,行为不变),位置/WiFi 权限保留。

View File

@ -1,81 +1,83 @@
{ {
"name": "smartAssister", "name" : "smartAssister",
"appid": "__UNI__884AC41", "appid" : "__UNI__884AC41",
"description": "", "description" : "smartAssister",
"versionName": "1.0.1", "versionName" : "1.0.2",
"versionCode": "110", "versionCode" : 111,
/* 快应用特有相关 */ /* 快应用特有相关 */
"quickapp": {}, "quickapp" : {},
/* 小程序特有相关 */ /* 小程序特有相关 */
"mp-weixin": { "mp-weixin" : {
"appid": "wx50ffc3eab938ff4c", "appid" : "wx50ffc3eab938ff4c",
"setting": { "setting" : {
"urlCheck": true, "urlCheck" : true,
"minified": true "minified" : true
}, },
"usingComponents": true, "usingComponents" : true,
"permission": {} "permission" : {}
}, },
"mp-alipay": { "mp-alipay" : {
"usingComponents": true "usingComponents" : true
}, },
"mp-baidu": { "mp-baidu" : {
"usingComponents": true "usingComponents" : true
}, },
"mp-toutiao": { "mp-toutiao" : {
"usingComponents": true "usingComponents" : true
}, },
"uniStatistics": { "uniStatistics" : {
"enable": false "enable" : false
}, },
"vueVersion": "3", "vueVersion" : "3",
"app-plus": { "app-plus" : {
"usingComponents": true, "usingComponents" : true,
"modules": {}, "modules" : {
"distribute": { "Barcode" : {},
"android": { "Bluetooth" : {},
"permissions": [ "Camera" : {},
"Fingerprint" : {}
},
"distribute" : {
"android" : {
"permissions" : [
"<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>", "<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",
"<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>", "<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_FINE_LOCATION\"/>", "<uses-permission android:name=\"android.permission.ACCESS_FINE_LOCATION\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_COARSE_LOCATION\"/>", "<uses-permission android:name=\"android.permission.ACCESS_COARSE_LOCATION\"/>"
"<uses-permission android:name=\"android.permission.BLUETOOTH\"/>",
"<uses-permission android:name=\"android.permission.BLUETOOTH_ADMIN\"/>",
"<uses-permission android:name=\"android.permission.BLUETOOTH_SCAN\" android:usesPermissionFlags=\"neverForLocation\"/>",
"<uses-permission android:name=\"android.permission.BLUETOOTH_CONNECT\"/>"
] ]
}, },
"ios": { "ios" : {
"privacyDescription": { "privacyDescription" : {
"NSBluetoothPeripheralUsageDescription": "Please allow Bluetooth access. It is used to connect to the mother cup device: displaying runtime parameters such as temperature and fan speed, querying device system status, and upgrading the device firmware over Bluetooth.", "NSBluetoothPeripheralUsageDescription" : "Please allow Bluetooth access. It is used to connect to the mother cup device: displaying runtime parameters such as temperature and fan speed, querying device system status, and upgrading the device firmware over Bluetooth.",
"NSBluetoothAlwaysUsageDescription": "Please allow Bluetooth access. It is used to connect to the mother cup device: displaying runtime parameters such as temperature and fan speed, querying device system status, and upgrading the device firmware over Bluetooth.", "NSBluetoothAlwaysUsageDescription" : "Please allow Bluetooth access. It is used to connect to the mother cup device: displaying runtime parameters such as temperature and fan speed, querying device system status, and upgrading the device firmware over Bluetooth.",
"NSLocationWhenInUseUsageDescription": "Please allow the use of location services to identify the position of charging stations. This app promises that this function will not be used for any other purposes.", "NSLocationWhenInUseUsageDescription" : "Please allow the use of location services to identify the position of charging stations. This app promises that this function will not be used for any other purposes.",
"NSLocalNetworkUsageDescription": "Please allow the use of network connectivity for communication between the app and the cloud service backend to enable charging-related features. This app promises that it will only be used to complete charging-related services with the cloud backend and will not be utilized for any other purposes.", "NSLocalNetworkUsageDescription" : "Please allow the use of network connectivity for communication between the app and the cloud service backend to enable charging-related features. This app promises that it will only be used to complete charging-related services with the cloud backend and will not be utilized for any other purposes.",
"NSCameraUsageDescription": "Please allow the use of the camera function. This function is solely used for scanning the QR codes on charging piles to obtain information corresponding to the QR codes. This app promises that the function will not be used for any other purposes." "NSCameraUsageDescription" : "Please allow the use of the camera function. This function is solely used for scanning the QR codes on charging piles to obtain information corresponding to the QR codes. This app promises that the function will not be used for any other purposes."
},
"dSYMs" : false
},
"icons" : {
"android" : {
"hdpi" : "/static/appIcon.png",
"xhdpi" : "/static/appIcon.png",
"xxhdpi" : "/static/appIcon.png",
"xxxhdpi" : "/static/appIcon.png"
},
"ios" : {
"appstore" : "/static/appIcon.png"
} }
}, },
"icons": { "splashscreen" : {
"android": { "alwaysShowBeforeRender" : true,
"hdpi": "/static/appIcon.png", "waiting" : true,
"xhdpi": "/static/appIcon.png", "autoclose" : true,
"xxhdpi": "/static/appIcon.png", "delay" : 0
"xxxhdpi": "/static/appIcon.png"
},
"ios": {
"appstore": "/static/appIcon.png"
}
},
"splashscreen": {
"alwaysShowBeforeRender": true,
"waiting": true,
"autoclose": true,
"delay": 0
} }
} }
}, },
"web": { "web" : {
"router": { "router" : {
"mode": "" "mode" : ""
} }
} }
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 82 KiB