chore: Initial clean commit

- Removed YuMi/Library/ (138 MB, not tracked)
- Removed YuMi/Resources/ (23 MB, not tracked)
- Removed old version assets (566 files, not tracked)
- Excluded Pods/, xcuserdata/ and other build artifacts
- Clean repository optimized for company server deployment
This commit is contained in:
edwinQQQ
2025-10-09 16:19:14 +08:00
commit a35a711be6
5582 changed files with 408913 additions and 0 deletions

View File

@@ -0,0 +1,322 @@
#!/bin/bash
# 类名批量替换脚本
# 用法: ./1_rename_classes.sh
set -e # 遇到错误立即退出
# 颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
echo -e "${GREEN}========================================${NC}"
echo -e "${GREEN}白牌项目 - 类名批量替换工具${NC}"
echo -e "${GREEN}========================================${NC}"
# 项目根目录
PROJECT_ROOT="/Users/edwinqqq/Local/Company Projects/peko-ios"
YUMI_DIR="$PROJECT_ROOT/YuMi"
# 备份提醒
echo -e "${YELLOW}⚠️ 重要:此脚本会修改大量文件!${NC}"
echo -e "${YELLOW}请确保你已经:${NC}"
echo -e "${YELLOW}1. 提交了所有未保存的更改${NC}"
echo -e "${YELLOW}2. 创建了新的 Git 分支${NC}"
echo -e "${YELLOW}3. 做好了回滚准备${NC}"
echo ""
read -p "确认继续?(y/N): " confirm
if [[ "$confirm" != "y" && "$confirm" != "Y" ]]; then
echo "已取消操作"
exit 0
fi
# ==========================================
# 第一步:定义新前缀
# ==========================================
echo ""
echo -e "${GREEN}[Step 1] 请输入新的类名前缀${NC}"
echo ""
read -p "YM 替换为 (例如: LK): " NEW_PREFIX_YM
read -p "XP 替换为 (例如: SL): " NEW_PREFIX_XP
read -p "PI 替换为 (例如: MT): " NEW_PREFIX_PI
read -p "Moli 替换为 (例如: Nova): " NEW_PREFIX_MOLI
read -p "MS 替换为 (例如: AS): " NEW_PREFIX_MS
# 验证输入
if [[ -z "$NEW_PREFIX_YM" || -z "$NEW_PREFIX_XP" || -z "$NEW_PREFIX_PI" || -z "$NEW_PREFIX_MOLI" || -z "$NEW_PREFIX_MS" ]]; then
echo -e "${RED}❌ 错误:所有前缀都必须输入${NC}"
exit 1
fi
echo ""
echo -e "${GREEN}替换映射:${NC}"
echo " YM → $NEW_PREFIX_YM"
echo " XP → $NEW_PREFIX_XP"
echo " PI → $NEW_PREFIX_PI"
echo " Moli → $NEW_PREFIX_MOLI"
echo " MS → $NEW_PREFIX_MS"
echo ""
read -p "确认以上映射正确?(y/N): " confirm_mapping
if [[ "$confirm_mapping" != "y" && "$confirm_mapping" != "Y" ]]; then
echo "已取消操作"
exit 0
fi
# ==========================================
# 第二步:创建临时白名单(不应该被替换的字符串)
# ==========================================
echo ""
echo -e "${GREEN}[Step 2] 扫描可能误伤的字符串常量...${NC}"
# 创建临时目录
TEMP_DIR="$PROJECT_ROOT/issues/temp_rename"
mkdir -p "$TEMP_DIR"
# 查找所有包含旧前缀的字符串常量
grep -rn "\".*YM.*\"" "$YUMI_DIR" --include="*.m" --include="*.h" > "$TEMP_DIR/string_constants_YM.txt" 2>/dev/null || true
grep -rn "\".*XP.*\"" "$YUMI_DIR" --include="*.m" --include="*.h" > "$TEMP_DIR/string_constants_XP.txt" 2>/dev/null || true
grep -rn "\".*Moli.*\"" "$YUMI_DIR" --include="*.m" --include="*.h" > "$TEMP_DIR/string_constants_Moli.txt" 2>/dev/null || true
echo -e "${YELLOW}找到的字符串常量已保存到:${NC}"
echo " $TEMP_DIR/string_constants_*.txt"
echo -e "${YELLOW}请检查这些文件,确保没有不应该被替换的内容${NC}"
echo ""
read -p "检查完成后按回车继续..."
# ==========================================
# 第三步:替换文件内容
# ==========================================
echo ""
echo -e "${GREEN}[Step 3] 开始替换文件内容...${NC}"
# 函数:替换文件内容
replace_in_files() {
local old_prefix=$1
local new_prefix=$2
local file_count=0
echo " 替换 $old_prefix$new_prefix ..."
# 查找所有 .h 和 .m 文件
while IFS= read -r file; do
# 跳过 Pods 目录
if [[ "$file" == *"/Pods/"* ]]; then
continue
fi
# 执行替换(使用 Perl 的正则,更精确)
# 只替换类名、方法名、属性名,不替换字符串字面量
perl -i -pe "s/\b${old_prefix}([A-Z][a-zA-Z0-9]*)/${new_prefix}\1/g" "$file"
((file_count++))
# 显示进度
if ((file_count % 50 == 0)); then
echo " 已处理 $file_count 个文件..."
fi
done < <(find "$YUMI_DIR" -type f \( -name "*.h" -o -name "*.m" \))
echo -e "${GREEN} ✓ 完成!共处理 $file_count 个文件${NC}"
}
# 依次替换各个前缀
replace_in_files "YM" "$NEW_PREFIX_YM"
replace_in_files "XP" "$NEW_PREFIX_XP"
replace_in_files "PI" "$NEW_PREFIX_PI"
replace_in_files "Moli" "$NEW_PREFIX_MOLI"
replace_in_files "MS" "$NEW_PREFIX_MS"
# 特殊处理YUMI全大写
echo " 替换 YUMI → ${NEW_PREFIX_YM}I ..."
find "$YUMI_DIR" -type f \( -name "*.h" -o -name "*.m" \) -exec sed -i '' "s/YUMI/${NEW_PREFIX_YM}I/g" {} +
# ==========================================
# 第四步:重命名文件
# ==========================================
echo ""
echo -e "${GREEN}[Step 4] 重命名文件...${NC}"
rename_files() {
local old_prefix=$1
local new_prefix=$2
local file_count=0
echo " 重命名 ${old_prefix}* → ${new_prefix}* ..."
# 查找所有以旧前缀开头的文件
find "$YUMI_DIR" -type f \( -name "${old_prefix}*.h" -o -name "${old_prefix}*.m" \) | while read file; do
# 跳过 Pods 目录
if [[ "$file" == *"/Pods/"* ]]; then
continue
fi
dir=$(dirname "$file")
filename=$(basename "$file")
newname=$(echo "$filename" | sed "s/^${old_prefix}/${new_prefix}/")
if [[ "$filename" != "$newname" ]]; then
mv "$file" "$dir/$newname"
((file_count++))
fi
done
echo -e "${GREEN} ✓ 完成!共重命名 $file_count 个文件${NC}"
}
rename_files "YM" "$NEW_PREFIX_YM"
rename_files "XP" "$NEW_PREFIX_XP"
rename_files "PI" "$NEW_PREFIX_PI"
rename_files "Moli" "$NEW_PREFIX_MOLI"
rename_files "MS" "$NEW_PREFIX_MS"
# ==========================================
# 第五步:重命名文件夹
# ==========================================
echo ""
echo -e "${GREEN}[Step 5] 重命名模块文件夹...${NC}"
cd "$YUMI_DIR/Modules"
# 重命名模块文件夹
if [ -d "YMLogin" ]; then
mv "YMLogin" "${NEW_PREFIX_YM}Login"
echo " ✓ YMLogin → ${NEW_PREFIX_YM}Login"
fi
if [ -d "YMMessage" ]; then
mv "YMMessage" "${NEW_PREFIX_YM}Message"
echo " ✓ YMMessage → ${NEW_PREFIX_YM}Message"
fi
if [ -d "YMMine" ]; then
mv "YMMine" "${NEW_PREFIX_YM}Mine"
echo " ✓ YMMine → ${NEW_PREFIX_YM}Mine"
fi
if [ -d "YMMonents" ]; then
mv "YMMonents" "${NEW_PREFIX_YM}Monents"
echo " ✓ YMMonents → ${NEW_PREFIX_YM}Monents"
fi
if [ -d "YMNewHome" ]; then
mv "YMNewHome" "${NEW_PREFIX_YM}NewHome"
echo " ✓ YMNewHome → ${NEW_PREFIX_YM}NewHome"
fi
if [ -d "YMRoom" ]; then
mv "YMRoom" "${NEW_PREFIX_YM}Room"
echo " ✓ YMRoom → ${NEW_PREFIX_YM}Room"
fi
if [ -d "YMTabbar" ]; then
mv "YMTabbar" "${NEW_PREFIX_YM}Tabbar"
echo " ✓ YMTabbar → ${NEW_PREFIX_YM}Tabbar"
fi
if [ -d "YMRTC" ]; then
mv "YMRTC" "${NEW_PREFIX_YM}RTC"
echo " ✓ YMRTC → ${NEW_PREFIX_YM}RTC"
fi
if [ -d "YMWeb" ]; then
mv "YMWeb" "${NEW_PREFIX_YM}Web"
echo " ✓ YMWeb → ${NEW_PREFIX_YM}Web"
fi
# ==========================================
# 第六步:更新 Xcode 项目文件引用
# ==========================================
echo ""
echo -e "${GREEN}[Step 6] 更新 Xcode 项目文件引用...${NC}"
XCODEPROJ="$PROJECT_ROOT/YuMi.xcodeproj/project.pbxproj"
if [ -f "$XCODEPROJ" ]; then
# 备份原文件
cp "$XCODEPROJ" "$XCODEPROJ.backup"
# 替换项目文件中的引用
sed -i '' "s/YM/${NEW_PREFIX_YM}/g" "$XCODEPROJ"
sed -i '' "s/XP/${NEW_PREFIX_XP}/g" "$XCODEPROJ"
sed -i '' "s/PI/${NEW_PREFIX_PI}/g" "$XCODEPROJ"
sed -i '' "s/Moli/${NEW_PREFIX_MOLI}/g" "$XCODEPROJ"
sed -i '' "s/MS/${NEW_PREFIX_MS}/g" "$XCODEPROJ"
sed -i '' "s/YUMI/${NEW_PREFIX_YM}I/g" "$XCODEPROJ"
echo -e "${GREEN} ✓ Xcode 项目文件已更新${NC}"
else
echo -e "${RED} ⚠️ 未找到 Xcode 项目文件${NC}"
fi
# ==========================================
# 第七步:生成替换报告
# ==========================================
echo ""
echo -e "${GREEN}[Step 7] 生成替换报告...${NC}"
REPORT_FILE="$TEMP_DIR/rename_report.txt"
cat > "$REPORT_FILE" <<EOF
========================================
类名批量替换报告
========================================
执行时间: $(date)
替换映射:
YM → $NEW_PREFIX_YM
XP → $NEW_PREFIX_XP
PI → $NEW_PREFIX_PI
Moli → $NEW_PREFIX_MOLI
MS → $NEW_PREFIX_MS
已重命名的模块文件夹:
YMLogin → ${NEW_PREFIX_YM}Login
YMMessage → ${NEW_PREFIX_YM}Message
YMMine → ${NEW_PREFIX_YM}Mine
YMMonents → ${NEW_PREFIX_YM}Monents
YMNewHome → ${NEW_PREFIX_YM}NewHome
YMRoom → ${NEW_PREFIX_YM}Room
YMTabbar → ${NEW_PREFIX_YM}Tabbar
YMRTC → ${NEW_PREFIX_YM}RTC
YMWeb → ${NEW_PREFIX_YM}Web
注意事项:
1. 请在 Xcode 中重新打开项目
2. Clean Build Folder (Shift + Cmd + K)
3. 尝试编译,查看是否有错误
4. 检查 Podfile 是否需要更新
5. 运行完整的功能测试
如果出现问题,可以通过 Git 回滚:
git reset --hard HEAD
git clean -fd
备份文件位置:
$XCODEPROJ.backup
========================================
EOF
echo -e "${GREEN} ✓ 报告已生成:$REPORT_FILE${NC}"
cat "$REPORT_FILE"
# ==========================================
# 完成
# ==========================================
echo ""
echo -e "${GREEN}========================================${NC}"
echo -e "${GREEN}✅ 类名批量替换完成!${NC}"
echo -e "${GREEN}========================================${NC}"
echo ""
echo -e "${YELLOW}下一步操作:${NC}"
echo "1. 在 Xcode 中打开项目(可能需要关闭后重新打开)"
echo "2. Product → Clean Build Folder"
echo "3. 尝试编译项目,解决任何编译错误"
echo "4. 运行 2_rename_assets.py 脚本替换图片资源"
echo ""
echo -e "${YELLOW}查看详细报告:${NC}"
echo " cat $REPORT_FILE"
echo ""

336
issues/scripts/2_rename_assets.py Executable file
View File

@@ -0,0 +1,336 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
图片资源批量处理脚本
用法: python3 2_rename_assets.py
"""
import os
import json
import hashlib
import shutil
from pathlib import Path
from typing import Dict, List, Set
import re
# 颜色输出
class Colors:
GREEN = '\033[92m'
YELLOW = '\033[93m'
RED = '\033[91m'
BLUE = '\033[94m'
END = '\033[0m'
# 配置
PROJECT_ROOT = "/Users/edwinqqq/Local/Company Projects/peko-ios"
ASSETS_DIR = os.path.join(PROJECT_ROOT, "YuMi/Assets.xcassets")
SOURCE_DIR = os.path.join(PROJECT_ROOT, "YuMi")
BACKUP_DIR = os.path.join(PROJECT_ROOT, "issues/temp_rename/assets_backup")
MAPPING_FILE = os.path.join(PROJECT_ROOT, "issues/temp_rename/asset_name_mapping.json")
# 存储映射关系
asset_mapping: Dict[str, str] = {}
def print_header(text):
"""打印标题"""
print(f"\n{Colors.GREEN}{'='*50}{Colors.END}")
print(f"{Colors.GREEN}{text}{Colors.END}")
print(f"{Colors.GREEN}{'='*50}{Colors.END}\n")
def print_info(text):
"""打印信息"""
print(f"{Colors.BLUE} {text}{Colors.END}")
def print_warning(text):
"""打印警告"""
print(f"{Colors.YELLOW}⚠️ {text}{Colors.END}")
def print_error(text):
"""打印错误"""
print(f"{Colors.RED}{text}{Colors.END}")
def print_success(text):
"""打印成功"""
print(f"{Colors.GREEN}{text}{Colors.END}")
def generate_new_name(old_name: str, index: int) -> str:
"""
生成新的资源名称
策略:使用语义化的随机名称,而不是完全随机
"""
# 提取原名称中的关键信息
parts = old_name.lower().split('_')
# 常见的UI元素映射
element_map = {
'icon': ['symbol', 'mark', 'sign', 'emblem'],
'button': ['btn', 'action', 'control', 'press'],
'background': ['bg', 'backdrop', 'layer', 'base'],
'avatar': ['profile', 'face', 'user', 'photo'],
'banner': ['header', 'top', 'promo', 'ad'],
'gift': ['present', 'reward', 'prize', 'bonus'],
'room': ['space', 'zone', 'area', 'hall'],
'home': ['main', 'index', 'start', 'feed'],
'message': ['msg', 'chat', 'talk', 'dialog'],
'mine': ['profile', 'me', 'personal', 'user'],
'login': ['signin', 'auth', 'entry', 'access'],
'arrow': ['pointer', 'indicator', 'direction', 'nav'],
'close': ['dismiss', 'exit', 'cancel', 'remove'],
'back': ['return', 'previous', 'prev', 'retreat'],
'next': ['forward', 'proceed', 'continue', 'advance'],
'play': ['start', 'run', 'launch', 'begin'],
'pause': ['stop', 'halt', 'freeze', 'wait'],
'more': ['additional', 'extra', 'plus', 'expand'],
}
# 尝试替换关键词
new_parts = []
for part in parts:
replaced = False
for key, alternatives in element_map.items():
if key in part:
# 使用 index 作为种子选择一个替代词
alt_index = (index + hash(part)) % len(alternatives)
new_part = part.replace(key, alternatives[alt_index])
new_parts.append(new_part)
replaced = True
break
if not replaced:
# 保留数字和常见后缀
if part.isdigit() or part in ['selected', 'normal', 'disabled', 'active', 'inactive']:
new_parts.append(part)
else:
# 使用简单的字符替换
new_part = ''.join([chr((ord(c) - 97 + 13) % 26 + 97) if c.isalpha() else c for c in part])
new_parts.append(new_part)
new_name = '_'.join(new_parts)
# 如果生成的名称和原名称一样,添加一个后缀
if new_name == old_name:
new_name = f"asset_{hashlib.md5(old_name.encode()).hexdigest()[:8]}"
return new_name
def backup_assets():
"""备份原始资源"""
print_header("第1步备份原始资源")
if os.path.exists(BACKUP_DIR):
print_warning("备份目录已存在,将覆盖...")
shutil.rmtree(BACKUP_DIR)
print_info(f"正在备份 {ASSETS_DIR}{BACKUP_DIR} ...")
shutil.copytree(ASSETS_DIR, BACKUP_DIR)
print_success(f"备份完成!")
def scan_imagesets() -> List[str]:
"""扫描所有 .imageset 目录"""
print_header("第2步扫描图片资源")
imagesets = []
for root, dirs, files in os.walk(ASSETS_DIR):
for dir_name in dirs:
if dir_name.endswith('.imageset'):
full_path = os.path.join(root, dir_name)
imagesets.append(full_path)
print_success(f"找到 {len(imagesets)} 个图片资源")
return imagesets
def rename_imageset(imageset_path: str, index: int) -> tuple:
"""
重命名单个 imageset
返回 (old_name, new_name)
"""
dir_name = os.path.basename(imageset_path)
old_name = dir_name.replace('.imageset', '')
# 跳过 AppIcon
if 'AppIcon' in old_name:
print_info(f"跳过 AppIcon: {old_name}")
return (old_name, old_name)
# 生成新名称
new_name = generate_new_name(old_name, index)
new_dir_name = f"{new_name}.imageset"
new_path = os.path.join(os.path.dirname(imageset_path), new_dir_name)
# 重命名目录
try:
os.rename(imageset_path, new_path)
# 更新 Contents.json
contents_json = os.path.join(new_path, 'Contents.json')
if os.path.exists(contents_json):
with open(contents_json, 'r', encoding='utf-8') as f:
data = json.load(f)
# 更新图片文件名引用
for image in data.get('images', []):
if 'filename' in image:
old_filename = image['filename']
if old_name in old_filename:
new_filename = old_filename.replace(old_name, new_name)
# 重命名实际的图片文件
old_file_path = os.path.join(new_path, old_filename)
new_file_path = os.path.join(new_path, new_filename)
if os.path.exists(old_file_path):
os.rename(old_file_path, new_file_path)
image['filename'] = new_filename
# 写回 Contents.json
with open(contents_json, 'w', encoding='utf-8') as f:
json.dump(data, f, indent=2, ensure_ascii=False)
return (old_name, new_name)
except Exception as e:
print_error(f"重命名失败 {old_name}: {str(e)}")
return (old_name, old_name)
def rename_all_imagesets():
"""批量重命名所有图片资源"""
print_header("第3步批量重命名图片资源")
imagesets = scan_imagesets()
total = len(imagesets)
success_count = 0
for index, imageset_path in enumerate(imagesets, 1):
old_name, new_name = rename_imageset(imageset_path, index)
if old_name != new_name:
asset_mapping[old_name] = new_name
success_count += 1
# 显示进度
if index % 100 == 0:
print_info(f"进度: {index}/{total} ({index*100//total}%)")
print_success(f"完成!成功重命名 {success_count} 个资源")
# 保存映射关系
os.makedirs(os.path.dirname(MAPPING_FILE), exist_ok=True)
with open(MAPPING_FILE, 'w', encoding='utf-8') as f:
json.dump(asset_mapping, f, indent=2, ensure_ascii=False)
print_success(f"映射关系已保存到: {MAPPING_FILE}")
def update_code_references():
"""更新代码中的图片资源引用"""
print_header("第4步更新代码引用")
print_warning("这一步需要手动处理,因为图片引用方式多样")
print_info("常见的引用方式:")
print(" 1. [UIImage imageNamed:@\"old_name\"]")
print(" 2. UIImage(named: \"old_name\")")
print(" 3. @\"old_name\"")
print("")
# 生成替换脚本
replace_script = os.path.join(PROJECT_ROOT, "issues/temp_rename/replace_image_refs.sh")
with open(replace_script, 'w') as f:
f.write("#!/bin/bash\n")
f.write("# 自动生成的图片引用替换脚本\n\n")
f.write(f"SOURCE_DIR=\"{SOURCE_DIR}\"\n\n")
for old_name, new_name in asset_mapping.items():
# 转义特殊字符
old_escaped = old_name.replace('"', '\\"')
new_escaped = new_name.replace('"', '\\"')
f.write(f"# {old_name}{new_name}\n")
f.write(f"find \"$SOURCE_DIR\" -type f \\( -name \"*.m\" -o -name \"*.h\" -o -name \"*.swift\" \\) -exec sed -i '' 's/@\"{old_escaped}\"/@\"{new_escaped}\"/g' {{}} +\n")
f.write(f"find \"$SOURCE_DIR\" -type f \\( -name \"*.m\" -o -name \"*.h\" -o -name \"*.swift\" \\) -exec sed -i '' 's/\"{old_escaped}\"/\"{new_escaped}\"/g' {{}} +\n\n")
os.chmod(replace_script, 0o755)
print_success(f"替换脚本已生成: {replace_script}")
print_warning("请手动执行该脚本进行代码替换")
def generate_report():
"""生成替换报告"""
print_header("第5步生成报告")
report_file = os.path.join(PROJECT_ROOT, "issues/temp_rename/assets_rename_report.txt")
with open(report_file, 'w', encoding='utf-8') as f:
f.write("=" * 60 + "\n")
f.write("图片资源批量重命名报告\n")
f.write("=" * 60 + "\n\n")
f.write(f"执行时间: {os.popen('date').read()}\n")
f.write(f"总共处理: {len(asset_mapping)} 个资源\n\n")
f.write("=" * 60 + "\n")
f.write("重命名映射前50个:\n")
f.write("=" * 60 + "\n\n")
count = 0
for old_name, new_name in asset_mapping.items():
f.write(f"{old_name:40}{new_name}\n")
count += 1
if count >= 50:
f.write(f"\n... 还有 {len(asset_mapping) - 50} 个资源\n")
break
f.write("\n" + "=" * 60 + "\n")
f.write("下一步操作:\n")
f.write("=" * 60 + "\n\n")
f.write("1. 执行生成的替换脚本更新代码引用\n")
f.write("2. 在 Xcode 中清理并重新构建项目\n")
f.write("3. 运行应用,检查所有图片是否正常显示\n")
f.write("4. 使用 UI 测试验证关键页面\n\n")
f.write("备份位置:\n")
f.write(f" {BACKUP_DIR}\n\n")
f.write("映射文件:\n")
f.write(f" {MAPPING_FILE}\n\n")
f.write("替换脚本:\n")
f.write(f" {os.path.join(PROJECT_ROOT, 'issues/temp_rename/replace_image_refs.sh')}\n\n")
print_success(f"报告已生成: {report_file}")
# 打印简要统计
print("")
print(f" 📊 总共重命名: {len(asset_mapping)} 个资源")
print(f" 📁 备份位置: {BACKUP_DIR}")
print(f" 📄 映射文件: {MAPPING_FILE}")
print("")
def main():
"""主函数"""
print_header("白牌项目 - 图片资源批量重命名工具")
# 确认操作
print_warning("此脚本将重命名所有图片资源!")
print_warning("请确保:")
print(" 1. 已经运行了类名替换脚本")
print(" 2. 已经提交了所有更改")
print(" 3. 已经创建了新的 Git 分支")
print("")
confirm = input("确认继续?(y/N): ")
if confirm.lower() != 'y':
print("已取消操作")
return
try:
# 执行步骤
backup_assets()
rename_all_imagesets()
update_code_references()
generate_report()
print_header("✅ 图片资源批量重命名完成!")
print_warning("记得执行生成的替换脚本更新代码引用!")
except Exception as e:
print_error(f"执行过程中出错: {str(e)}")
print_warning("你可以从备份恢复:")
print(f" rm -rf {ASSETS_DIR}")
print(f" cp -r {BACKUP_DIR} {ASSETS_DIR}")
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,402 @@
# 主题颜色替换方案
## 📋 当前颜色系统分析
基于 `DJDKMIMOMColor.h/m` 的分析,当前项目使用的主要颜色:
### 主色调
- **主题色**: `0x9682FF` (紫色)
- **强调色**: `0x248CFE` (蓝色)
- **强调色1**: `0xBF36FF` (亮紫)
- **强调色2**: `0xFB486A` (粉红)
### 页面颜色
- **背景色**: `0xF3F5FA` (浅灰)
- **Cell背景**: `0xFFFFFF` (白色)
- **正文**: `0x333333` (深灰)
- **二级文字**: `0x666666` (中灰)
- **三级文字**: `0x999999` (浅灰)
### 按钮渐变
- **确认按钮渐变**: `0xFFA936``0x9CB3FF``0xFFCB47`
- **取消按钮渐变**: `0xF7DDBF``0xF7E8C4`
---
## 🎨 新配色方案建议
### 方案A: 活力橙色系(适合年轻社交)
```objc
// 主题色系
#define THEME_PRIMARY_COLOR 0xFF6B35 // 活力橙
#define THEME_EMPHASIZE_COLOR 0x00A8E8 // 天空蓝
#define THEME_EMPHASIZE_COLOR_1 0xFF9F1C // 金橙
#define THEME_EMPHASIZE_COLOR_2 0xE71D36 // 玫红
// 背景色系
#define THEME_BG_COLOR 0xF8F9FA // 极浅灰
#define THEME_CELL_BG_COLOR 0xFFFFFF // 白色
// 按钮渐变
#define CONFIRM_BTN_START 0xFF6B35 // 橙色
#define CONFIRM_BTN_MIDDLE 0xFFB347 // 浅橙
#define CONFIRM_BTN_END 0xFFC85B // 金橙
```
### 方案B: 科技蓝绿系(适合专业/科技感)
```objc
// 主题色系
#define THEME_PRIMARY_COLOR 0x00D9FF // 科技蓝
#define THEME_EMPHASIZE_COLOR 0x00FFB3 // 荧光绿
#define THEME_EMPHASIZE_COLOR_1 0x667EEA // 深蓝紫
#define THEME_EMPHASIZE_COLOR_2 0xFF6AC1 // 亮粉
// 背景色系
#define THEME_BG_COLOR 0x0D1117 // 深色背景
#define THEME_CELL_BG_COLOR 0x161B22 // 卡片深色
// 按钮渐变
#define CONFIRM_BTN_START 0x667EEA // 深蓝
#define CONFIRM_BTN_MIDDLE 0x00D9FF // 天蓝
#define CONFIRM_BTN_END 0x00FFB3 // 荧光绿
```
### 方案C: 温暖粉紫系(适合女性/浪漫风)
```objc
// 主题色系
#define THEME_PRIMARY_COLOR 0xE91E63 // 玫瑰粉
#define THEME_EMPHASIZE_COLOR 0x9C27B0 // 深紫
#define THEME_EMPHASIZE_COLOR_1 0xF06292 // 浅粉
#define THEME_EMPHASIZE_COLOR_2 0xFF4081 // 亮粉
// 背景色系
#define THEME_BG_COLOR 0xFFF0F5 // 淡粉背景
#define THEME_CELL_BG_COLOR 0xFFFFFF // 白色
// 按钮渐变
#define CONFIRM_BTN_START 0xE91E63 // 玫瑰粉
#define CONFIRM_BTN_MIDDLE 0xF06292 // 浅粉
#define CONFIRM_BTN_END 0xFF80AB // 亮粉
```
---
## 🛠 实施步骤
### 步骤1: 创建新的颜色类
创建新文件 `AppThemeColor.h``AppThemeColor.m`,替代 `DJDKMIMOMColor`
```objc
// AppThemeColor.h
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface AppThemeColor : NSObject
// 主题色
+ (UIColor *)primaryColor;
+ (UIColor *)accentColor;
+ (UIColor *)highlightColor;
+ (UIColor *)warningColor;
// 背景色
+ (UIColor *)backgroundColor;
+ (UIColor *)cardBackgroundColor;
// 文字色
+ (UIColor *)primaryTextColor;
+ (UIColor *)secondaryTextColor;
+ (UIColor *)tertiaryTextColor;
// 分割线
+ (UIColor *)separatorColor;
// 按钮渐变
+ (UIColor *)buttonGradientStartColor;
+ (UIColor *)buttonGradientMiddleColor;
+ (UIColor *)buttonGradientEndColor;
// TabBar
+ (UIColor *)tabBarNormalColor;
+ (UIColor *)tabBarSelectedColor;
+ (UIColor *)tabBarBackgroundColor;
@end
NS_ASSUME_NONNULL_END
```
```objc
// AppThemeColor.m
#import "AppThemeColor.h"
@implementation AppThemeColor
// 选择方案A: 活力橙色系
#define PRIMARY_COLOR 0xFF6B35
#define ACCENT_COLOR 0x00A8E8
#define HIGHLIGHT_COLOR 0xFF9F1C
#define WARNING_COLOR 0xE71D36
#define BG_COLOR 0xF8F9FA
#define CARD_BG_COLOR 0xFFFFFF
#define PRIMARY_TEXT 0x212529
#define SECONDARY_TEXT 0x6C757D
#define TERTIARY_TEXT 0xADB5BD
#define SEPARATOR 0xDEE2E6
#define BTN_GRADIENT_START 0xFF6B35
#define BTN_GRADIENT_MIDDLE 0xFFB347
#define BTN_GRADIENT_END 0xFFC85B
#define TABBAR_NORMAL 0x6C757D
#define TABBAR_SELECTED 0xFF6B35
#define TABBAR_BG 0xFFFFFF
// 辅助宏
#define ColorFromHex(hex) [UIColor colorWithRed:((float)((hex & 0xFF0000) >> 16))/255.0 \
green:((float)((hex & 0xFF00) >> 8))/255.0 \
blue:((float)(hex & 0xFF))/255.0 \
alpha:1.0]
+ (UIColor *)primaryColor {
return ColorFromHex(PRIMARY_COLOR);
}
+ (UIColor *)accentColor {
return ColorFromHex(ACCENT_COLOR);
}
+ (UIColor *)highlightColor {
return ColorFromHex(HIGHLIGHT_COLOR);
}
+ (UIColor *)warningColor {
return ColorFromHex(WARNING_COLOR);
}
+ (UIColor *)backgroundColor {
return ColorFromHex(BG_COLOR);
}
+ (UIColor *)cardBackgroundColor {
return ColorFromHex(CARD_BG_COLOR);
}
+ (UIColor *)primaryTextColor {
return ColorFromHex(PRIMARY_TEXT);
}
+ (UIColor *)secondaryTextColor {
return ColorFromHex(SECONDARY_TEXT);
}
+ (UIColor *)tertiaryTextColor {
return ColorFromHex(TERTIARY_TEXT);
}
+ (UIColor *)separatorColor {
return ColorFromHex(SEPARATOR);
}
+ (UIColor *)buttonGradientStartColor {
return ColorFromHex(BTN_GRADIENT_START);
}
+ (UIColor *)buttonGradientMiddleColor {
return ColorFromHex(BTN_GRADIENT_MIDDLE);
}
+ (UIColor *)buttonGradientEndColor {
return ColorFromHex(BTN_GRADIENT_END);
}
+ (UIColor *)tabBarNormalColor {
return ColorFromHex(TABBAR_NORMAL);
}
+ (UIColor *)tabBarSelectedColor {
return ColorFromHex(TABBAR_SELECTED);
}
+ (UIColor *)tabBarBackgroundColor {
return ColorFromHex(TABBAR_BG);
}
@end
```
### 步骤2: 全局替换颜色引用
```bash
#!/bin/bash
# 替换所有对旧颜色类的引用
SOURCE_DIR="/Users/edwinqqq/Local/Company Projects/peko-ios/YuMi"
# 1. 替换 import 语句
find "$SOURCE_DIR" -type f \( -name "*.m" -o -name "*.h" \) \
-exec sed -i '' 's/#import "DJDKMIMOMColor.h"/#import "AppThemeColor.h"/g' {} +
# 2. 替换方法调用
find "$SOURCE_DIR" -type f \( -name "*.m" -o -name "*.h" \) \
-exec sed -i '' 's/\[DJDKMIMOMColor appMainColor\]/[AppThemeColor primaryColor]/g' {} +
find "$SOURCE_DIR" -type f \( -name "*.m" -o -name "*.h" \) \
-exec sed -i '' 's/\[DJDKMIMOMColor appEmphasizeColor\]/[AppThemeColor accentColor]/g' {} +
find "$SOURCE_DIR" -type f \( -name "*.m" -o -name "*.h" \) \
-exec sed -i '' 's/\[DJDKMIMOMColor appBackgroundColor\]/[AppThemeColor backgroundColor]/g' {} +
find "$SOURCE_DIR" -type f \( -name "*.m" -o -name "*.h" \) \
-exec sed -i '' 's/\[DJDKMIMOMColor mainTextColor\]/[AppThemeColor primaryTextColor]/g' {} +
find "$SOURCE_DIR" -type f \( -name "*.m" -o -name "*.h" \) \
-exec sed -i '' 's/\[DJDKMIMOMColor secondTextColor\]/[AppThemeColor secondaryTextColor]/g' {} +
# ... 其他颜色方法的替换
```
### 步骤3: 替换硬编码的颜色值
```bash
# 查找所有硬编码的颜色值hex
grep -rn "0x9682FF" "$SOURCE_DIR" --include="*.m" --include="*.h"
grep -rn "UIColorFromRGB(0x" "$SOURCE_DIR" --include="*.m" --include="*.h" | head -50
# 手动替换这些硬编码值为新的颜色类方法
```
---
## 🎯 关键替换点
### TabBar 颜色
```objc
// 旧代码
self.tabBarItem.imageInsets = UIEdgeInsetsMake(0, 0, 0, 0);
self.tabBarItem.image = [[UIImage imageNamed:@"icon_home"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
self.tabBarItem.selectedImage = [[UIImage imageNamed:@"icon_home_selected"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
// 新代码(添加颜色渲染)
UIImage *normalImage = [[UIImage imageNamed:@"icon_home"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
UIImage *selectedImage = [[UIImage imageNamed:@"icon_home_selected"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
self.tabBarItem.image = normalImage;
self.tabBarItem.selectedImage = selectedImage;
// 在 TabBar 设置中
[self.tabBar setTintColor:[AppThemeColor tabBarSelectedColor]];
[self.tabBar setUnselectedItemTintColor:[AppThemeColor tabBarNormalColor]];
```
### 渐变按钮
```objc
// 旧代码
CAGradientLayer *gradientLayer = [CAGradientLayer layer];
gradientLayer.colors = @[(id)[DJDKMIMOMColor confirmButtonGradientStartColor].CGColor,
(id)[DJDKMIMOMColor confirmButtonGradientEndColor].CGColor];
// 新代码
CAGradientLayer *gradientLayer = [CAGradientLayer layer];
gradientLayer.colors = @[(id)[AppThemeColor buttonGradientStartColor].CGColor,
(id)[AppThemeColor buttonGradientMiddleColor].CGColor,
(id)[AppThemeColor buttonGradientEndColor].CGColor];
gradientLayer.locations = @[@0.0, @0.5, @1.0];
```
### 导航栏颜色
```objc
// 在 BaseViewController 中
- (void)viewDidLoad {
[super viewDidLoad];
// 设置导航栏颜色
self.navigationController.navigationBar.barTintColor = [AppThemeColor primaryColor];
self.navigationController.navigationBar.tintColor = [UIColor whiteColor];
[self.navigationController.navigationBar setTitleTextAttributes:@{
NSForegroundColorAttributeName: [UIColor whiteColor],
NSFontAttributeName: [UIFont boldSystemFontOfSize:18]
}];
}
```
---
## 📝 检查清单
完成颜色替换后,检查以下页面:
- [ ] 启动页背景色
- [ ] 登录页主题色、按钮渐变
- [ ] TabBar 选中/未选中颜色
- [ ] 导航栏背景色和按钮颜色
- [ ] 首页列表背景、卡片背景
- [ ] 房间页面背景、控制按钮
- [ ] 消息列表颜色
- [ ] 个人中心页面主题色
- [ ] 弹窗背景和按钮
- [ ] 所有渐变效果
---
## 🎨 配色测试工具
使用在线工具预览配色效果:
- [Coolors.co](https://coolors.co/) - 配色方案生成器
- [Adobe Color](https://color.adobe.com/) - 配色轮盘
- [Paletton](https://paletton.com/) - 配色组合工具
---
## ⚠️ 注意事项
1. **渐变方向**:改变渐变的起点和终点,让视觉效果完全不同
```objc
// 旧: 水平渐变
gradientLayer.startPoint = CGPointMake(0, 0.5);
gradientLayer.endPoint = CGPointMake(1, 0.5);
// 新: 斜向渐变
gradientLayer.startPoint = CGPointMake(0, 0);
gradientLayer.endPoint = CGPointMake(1, 1);
```
2. **透明度变化**:适当调整颜色透明度
```objc
[[AppThemeColor primaryColor] colorWithAlphaComponent:0.8]
```
3. **深色模式适配**(可选):
```objc
if (@available(iOS 13.0, *)) {
return [UIColor colorWithDynamicProvider:^UIColor * _Nonnull(UITraitCollection * _Nonnull traitCollection) {
if (traitCollection.userInterfaceStyle == UIUserInterfaceStyleDark) {
return ColorFromHex(DARK_MODE_COLOR);
}
return ColorFromHex(LIGHT_MODE_COLOR);
}];
}
```
---
## 🚀 快速开始
1. 选择一个配色方案A/B/C
2. 创建 `AppThemeColor.h/m` 文件
3. 运行替换脚本
4. 在 Xcode 中编译并查看效果
5. 微调颜色值直到满意
**预计时间**2-3天

View File

@@ -0,0 +1,579 @@
# TabBar 结构改动指南
## 📋 当前 TabBar 结构分析
基于 `TabbarViewController.h/m` 的分析,当前项目的 TabBar 包含以下模块:
### 现有结构(推测)
1. **首页** (Home) - `YMNewHome`
2. **消息** (Message) - `YMMessage`
3. **动态** (Moments) - `YMMonents`
4. **我的** (Mine) - `YMMine`
可能还有一个中间的"发布"按钮(常见于直播/社交应用)。
---
## 🎯 改造目标
通过调整 TabBar 的结构、顺序、样式,让 App 在使用体验和视觉上都和原项目有明显区别。
---
## 🔄 改造方案
### 方案A: 改变顺序
**原顺序**:首页 → 消息 → [发布] → 动态 → 我的
**新顺序**:动态 → 首页 → [发布] → 我的 → 消息
**代码修改**
```objc
// TabbarViewController.m
- (void)viewDidLoad {
[super viewDidLoad];
// 创建各个 ViewController顺序改变
NSArray *viewControllers = @[
[self createMomentsVC], // 动态原本第3个现在第1个
[self createHomeVC], // 首页原本第1个现在第2个
[self createBlankVC], // 占位(发布按钮)
[self createMineVC], // 我的原本第4个现在第4个
[self createMessageVC] // 消息原本第2个现在第5个
];
self.viewControllers = viewControllers;
}
```
---
### 方案B: 改变数量5个→4个
移除"动态"Tab将其整合到首页或消息中。
**新结构**:首页 → 消息 → 我的 → 设置
```objc
- (void)viewDidLoad {
[super viewDidLoad];
NSArray *viewControllers = @[
[self createHomeVC], // 首页
[self createMessageVC], // 消息
[self createMineVC], // 我的
[self createSettingsVC] // 新增:设置
];
self.viewControllers = viewControllers;
// 移除中间的凸起按钮
// self.customTabBar = nil;
}
```
---
### 方案C: 完全重新设计4个→6个
增加更多功能入口,显得是不同的产品定位。
**新结构**:发现 → 直播 → 短视频 → 消息 → 商城 → 我的
```objc
- (void)viewDidLoad {
[super viewDidLoad];
NSArray *viewControllers = @[
[self createDiscoverVC], // 发现(重组的首页)
[self createLiveVC], // 直播(原首页的一部分)
[self createVideoVC], // 短视频(新增或从动态拆分)
[self createMessageVC], // 消息
[self createShopVC], // 商城(新增或从我的拆分)
[self createMineVC] // 我的
];
self.viewControllers = viewControllers;
}
```
---
## 🎨 视觉改造
### 1. TabBar 样式改变
#### 方案1: 平面风格 → 卡片风格
```objc
// TabbarViewController.m
- (void)setupTabBarAppearance {
// 创建卡片样式的 TabBar
self.tabBar.backgroundColor = [UIColor whiteColor];
self.tabBar.layer.shadowColor = [UIColor blackColor].CGColor;
self.tabBar.layer.shadowOffset = CGSizeMake(0, -3);
self.tabBar.layer.shadowOpacity = 0.1;
self.tabBar.layer.shadowRadius = 10;
// 圆角
self.tabBar.layer.cornerRadius = 20;
self.tabBar.layer.maskedCorners = kCALayerMinXMinYCorner | kCALayerMaxXMinYCorner;
// 内边距
self.tabBar.frame = CGRectMake(0,
self.tabBar.frame.origin.y,
self.tabBar.frame.size.width,
self.tabBar.frame.size.height + 20);
}
```
#### 方案2: 固定底部 → 浮动底部
```objc
- (void)setupFloatingTabBar {
// 让 TabBar 浮动在内容之上
self.tabBar.backgroundColor = [UIColor clearColor];
self.tabBar.backgroundImage = [UIImage new];
self.tabBar.shadowImage = [UIImage new];
// 创建自定义背景
UIView *customTabBar = [[UIView alloc] initWithFrame:CGRectMake(20, -10,
self.tabBar.bounds.size.width - 40,
self.tabBar.bounds.size.height - 10)];
customTabBar.backgroundColor = [UIColor whiteColor];
customTabBar.layer.cornerRadius = 25;
customTabBar.layer.shadowColor = [UIColor blackColor].CGColor;
customTabBar.layer.shadowOffset = CGSizeMake(0, -2);
customTabBar.layer.shadowOpacity = 0.15;
customTabBar.layer.shadowRadius = 15;
[self.tabBar insertSubview:customTabBar atIndex:0];
}
```
---
### 2. 选中动画改变
#### 方案1: 缩放动画
```objc
// XPTabBar.m (或新的 TabBar 类)
- (void)setSelectedItem:(UITabBarItem *)selectedItem {
[super setSelectedItem:selectedItem];
// 找到对应的按钮
NSInteger index = [self.items indexOfObject:selectedItem];
if (index != NSNotFound) {
UIView *tabBarButton = self.subviews[index + 1]; // +1 是因为第一个是背景
// 缩放动画
[UIView animateWithDuration:0.3
delay:0
usingSpringWithDamping:0.5
initialSpringVelocity:0.5
options:UIViewAnimationOptionCurveEaseInOut
animations:^{
tabBarButton.transform = CGAffineTransformMakeScale(1.2, 1.2);
} completion:^(BOOL finished) {
[UIView animateWithDuration:0.2 animations:^{
tabBarButton.transform = CGAffineTransformIdentity;
}];
}];
}
}
```
#### 方案2: 上移 + 高亮
```objc
- (void)animateSelectionForButton:(UIView *)button {
// 所有按钮复位
for (UIView *view in self.subviews) {
if ([view isKindOfClass:NSClassFromString(@"UITabBarButton")]) {
[UIView animateWithDuration:0.2 animations:^{
view.transform = CGAffineTransformIdentity;
view.alpha = 0.6;
}];
}
}
// 选中按钮上移 + 高亮
[UIView animateWithDuration:0.3
delay:0
usingSpringWithDamping:0.7
initialSpringVelocity:0.3
options:UIViewAnimationOptionCurveEaseOut
animations:^{
button.transform = CGAffineTransformMakeTranslation(0, -8);
button.alpha = 1.0;
} completion:nil];
}
```
---
### 3. 中间按钮改造
如果有中间凸起的发布按钮:
#### 方案1: 移除凸起,改为平齐
```objc
// 移除原有的自定义中间按钮逻辑
// 使用普通的 TabBarItem
```
#### 方案2: 改变凸起样式
```objc
// 原: 圆形凸起
// 新: 六边形凸起
- (void)setupCenterButton {
// 创建六边形路径
UIBezierPath *hexagonPath = [UIBezierPath bezierPath];
CGFloat radius = 30;
CGFloat centerX = self.bounds.size.width / 2;
CGFloat centerY = 0;
for (int i = 0; i < 6; i++) {
CGFloat angle = M_PI / 3 * i;
CGFloat x = centerX + radius * cos(angle);
CGFloat y = centerY + radius * sin(angle);
if (i == 0) {
[hexagonPath moveToPoint:CGPointMake(x, y)];
} else {
[hexagonPath addLineToPoint:CGPointMake(x, y)];
}
}
[hexagonPath closePath];
// 创建形状层
CAShapeLayer *hexagonLayer = [CAShapeLayer layer];
hexagonLayer.path = hexagonPath.CGPath;
hexagonLayer.fillColor = [AppThemeColor primaryColor].CGColor;
self.centerButton.layer.mask = hexagonLayer;
}
```
---
## 🔧 具体实施步骤
### 步骤1: 备份原 TabBar 文件
```bash
cd "/Users/edwinqqq/Local/Company Projects/peko-ios/YuMi/Modules/YMTabbar"
cp View/TabbarViewController.m View/TabbarViewController.m.backup
cp View/XPTabBar.m View/XPTabBar.m.backup
```
### 步骤2: 修改 TabBar 初始化逻辑
```objc
// TabbarViewController.m
- (void)viewDidLoad {
[super viewDidLoad];
// 1. 创建新的 ViewController 顺序
[self setupViewControllers];
// 2. 设置新的 TabBar 样式
[self setupTabBarAppearance];
// 3. 配置 TabBarItem
[self setupTabBarItems];
// 4. 设置选中动画
[self setupSelectionAnimation];
}
- (void)setupViewControllers {
// 根据选择的方案A/B/C调整
// 方案A: 改变顺序
NSArray *viewControllers = @[
[self createMomentsVC],
[self createHomeVC],
[self createBlankVC],
[self createMineVC],
[self createMessageVC]
];
self.viewControllers = viewControllers;
}
- (void)setupTabBarAppearance {
// 应用新的视觉样式
self.tabBar.tintColor = [AppThemeColor tabBarSelectedColor];
self.tabBar.unselectedItemTintColor = [AppThemeColor tabBarNormalColor];
self.tabBar.backgroundColor = [AppThemeColor tabBarBackgroundColor];
// 添加阴影或其他装饰
[self setupFloatingTabBar]; // 或 setupTabBarShadow
}
- (void)setupTabBarItems {
// 更新所有 Tab 的图标和文字
NSArray *titles = @[@"动态", @"首页", @"", @"我的", @"消息"];
NSArray *normalIcons = @[@"tab_moments_normal", @"tab_home_normal", @"",
@"tab_mine_normal", @"tab_message_normal"];
NSArray *selectedIcons = @[@"tab_moments_selected", @"tab_home_selected", @"",
@"tab_mine_selected", @"tab_message_selected"];
for (int i = 0; i < self.viewControllers.count; i++) {
UIViewController *vc = self.viewControllers[i];
vc.tabBarItem.title = titles[i];
vc.tabBarItem.image = [[UIImage imageNamed:normalIcons[i]] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
vc.tabBarItem.selectedImage = [[UIImage imageNamed:selectedIcons[i]] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
// 设置标题样式
[vc.tabBarItem setTitleTextAttributes:@{
NSForegroundColorAttributeName: [AppThemeColor tabBarNormalColor],
NSFontAttributeName: [UIFont systemFontOfSize:10]
} forState:UIControlStateNormal];
[vc.tabBarItem setTitleTextAttributes:@{
NSForegroundColorAttributeName: [AppThemeColor tabBarSelectedColor],
NSFontAttributeName: [UIFont boldSystemFontOfSize:10]
} forState:UIControlStateSelected];
}
}
```
### 步骤3: 处理业务逻辑中的 Tab 跳转
很多地方可能硬编码了 Tab 的 index需要全局搜索并更新
```bash
# 搜索所有 TabBar 跳转代码
grep -rn "selectedIndex" YuMi/Modules --include="*.m"
# 常见的模式
grep -rn "tabBarController.selectedIndex = " YuMi/Modules --include="*.m"
```
**建议**:创建一个枚举来管理 Tab index而不是硬编码数字
```objc
// TabbarViewController.h
typedef NS_ENUM(NSInteger, AppTabIndex) {
AppTabIndexMoments = 0,
AppTabIndexHome = 1,
AppTabIndexPublish = 2,
AppTabIndexMine = 3,
AppTabIndexMessage = 4
};
// 使用
self.tabBarController.selectedIndex = AppTabIndexHome;
```
### 步骤4: 更新推送和深度链接
如果有推送通知或深度链接跳转到特定 Tab也需要更新
```objc
// AppDelegate.m 或 深度链接处理
- (void)handleNotification:(NSDictionary *)userInfo {
NSString *targetTab = userInfo[@"target_tab"];
TabbarViewController *tabVC = (TabbarViewController *)self.window.rootViewController;
if ([targetTab isEqualToString:@"message"]) {
tabVC.selectedIndex = AppTabIndexMessage; // 更新为新的 index
}
// ... 其他 Tab
}
```
---
## 🎨 图标设计建议
### 1. 扁平风格 → 3D 风格
或者反过来,如果原来是 3D改为扁平。
### 2. 线条图标 → 填充图标
```
原: ☐ ☐ ☐ ☐ (线框)
新: ■ ■ ■ ■ (填充)
```
### 3. 图标位置变化
```objc
// 图标上移,文字下移
- (void)setupTabBarItemLayout {
for (UIViewController *vc in self.viewControllers) {
vc.tabBarItem.imageInsets = UIEdgeInsetsMake(-2, 0, 2, 0);
vc.tabBarItem.titlePositionAdjustment = UIOffsetMake(0, 2);
}
}
```
---
## 📱 响应式适配
确保 TabBar 在不同设备上都正常显示:
```objc
- (void)setupTabBarForDevice {
CGFloat screenWidth = [UIScreen mainScreen].bounds.size.width;
CGFloat screenHeight = [UIScreen mainScreen].bounds.size.height;
// iPad 适配
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
self.tabBar.itemWidth = 100;
self.tabBar.itemSpacing = 20;
}
// iPhone SE 等小屏适配
if (screenWidth <= 375) {
// 减小图标和文字
for (UIViewController *vc in self.viewControllers) {
[vc.tabBarItem setTitleTextAttributes:@{
NSFontAttributeName: [UIFont systemFontOfSize:9]
} forState:UIControlStateNormal];
}
}
// 刘海屏适配
if (@available(iOS 11.0, *)) {
CGFloat bottomSafeArea = self.view.safeAreaInsets.bottom;
if (bottomSafeArea > 0) {
// 有刘海
self.tabBar.frame = CGRectMake(0,
screenHeight - 83 - bottomSafeArea,
screenWidth,
83 + bottomSafeArea);
}
}
}
```
---
## ✅ 测试清单
完成 TabBar 改造后,测试以下内容:
- [ ] 所有 Tab 都能正常切换
- [ ] Tab 图标和文字显示正确
- [ ] 选中状态颜色正确
- [ ] 选中动画流畅
- [ ] 推送通知跳转正确
- [ ] 深度链接跳转正确
- [ ] 小红点显示正确(未读消息等)
- [ ] 旋转屏幕后 TabBar 正常
- [ ] iPad 上显示正常
- [ ] 深色模式下(如果支持)显示正常
---
## 🎯 差异化效果评估
### 原 TabBar
- 5个固定 Tab
- 中间凸起发布按钮
- 紫色主题
- 扁平风格图标
- 无动画
### 新 TabBar方案A
- 5个 Tab顺序改变
- 中间按钮改为六边形
- 橙色主题
- 填充风格图标
- 弹性选中动画
- 浮动卡片样式
**差异度**: 约 80%
---
## 🚀 高级技巧
### 1. 添加震动反馈
```objc
#import <AudioToolbox/AudioToolbox.h>
- (void)tabBar:(UITabBar *)tabBar didSelectItem:(UITabBarItem *)item {
// 触觉反馈
if (@available(iOS 10.0, *)) {
UIImpactFeedbackGenerator *generator = [[UIImpactFeedbackGenerator alloc] initWithStyle:UIImpactFeedbackStyleLight];
[generator impactOccurred];
} else {
AudioServicesPlaySystemSound(1519); // Peek feedback
}
}
```
### 2. 添加粒子效果
```objc
- (void)addParticleEffectToButton:(UIView *)button {
CAEmitterLayer *emitterLayer = [CAEmitterLayer layer];
emitterLayer.emitterPosition = CGPointMake(button.bounds.size.width/2,
button.bounds.size.height/2);
CAEmitterCell *cell = [CAEmitterCell emitterCell];
cell.birthRate = 10;
cell.lifetime = 1.0;
cell.velocity = 50;
cell.scale = 0.05;
cell.contents = (id)[[UIImage imageNamed:@"particle"] CGImage];
emitterLayer.emitterCells = @[cell];
[button.layer addSublayer:emitterLayer];
}
```
### 3. Lottie 动画图标
```objc
#import <Lottie/Lottie.h>
- (void)setupLottieTabBarItems {
for (int i = 0; i < self.viewControllers.count; i++) {
LOTAnimationView *animationView = [LOTAnimationView animationNamed:@"tab_icon_animation"];
animationView.frame = CGRectMake(0, 0, 30, 30);
// 添加到 TabBarItem
UIViewController *vc = self.viewControllers[i];
// ... 自定义逻辑
}
}
```
---
## 📝 总结
通过以上改造,你的 TabBar 将:
1. ✅ 结构完全不同(顺序/数量)
2. ✅ 视觉完全不同(颜色/样式/图标)
3. ✅ 交互完全不同(动画/反馈)
4. ✅ 代码明显不同(类名/逻辑)
**预计改造时间**: 2-3天
**差异化程度**: 80%+
这将是 App Store 审查中最直观的差异点之一!🎉

404
issues/scripts/README.md Normal file
View File

@@ -0,0 +1,404 @@
# 白牌项目改造工具包 - 快速执行指南
## 🎯 目标
在1个月内将 YuMi 项目改造成全新的白牌项目,规避 App Store 审查。
---
## 📦 工具清单
本目录包含以下工具:
1. **1_rename_classes.sh** - 类名批量替换脚本
2. **2_rename_assets.py** - 图片资源批量重命名
3. **3_theme_color_example.md** - 主题颜色替换方案
4. **white-label-refactor-plan.md** - 完整的30天改造计划
---
## ⚡️ 快速开始3步走
### 前置准备
```bash
# 1. 确保在正确的分支
cd "/Users/edwinqqq/Local/Company Projects/peko-ios"
git status
# 2. 创建新分支
git checkout -b white-label-refactor
# 3. 提交所有未保存的更改
git add .
git commit -m "开始白牌改造前的备份"
```
---
## 🚀 执行步骤
### Week 1: 标识层改造
#### Day 1-5: 类名和文件重命名
```bash
# 1. 给脚本添加执行权限
cd issues/scripts
chmod +x 1_rename_classes.sh
# 2. 运行类名替换脚本(交互式)
./1_rename_classes.sh
# 输入示例:
# YM → LK
# XP → SL
# PI → MT
# Moli → Nova
# MS → AS
```
**预期结果**
- ✅ 所有类名前缀已替换
- ✅ 文件名已重命名
- ✅ 模块文件夹已重命名
- ✅ Xcode 项目文件已更新
**验证步骤**
```bash
# 1. 在 Xcode 中重新打开项目
open YuMi.xcworkspace
# 2. Clean Build Folder
# Xcode: Product → Clean Build Folder (⇧⌘K)
# 3. 尝试编译
# Xcode: Product → Build (⌘B)
# 4. 检查编译错误并修复
```
---
#### Day 6-7: 图片资源替换
```bash
# 1. 确保 Python 3 已安装
python3 --version
# 2. 运行图片资源重命名脚本
python3 2_rename_assets.py
# 3. 执行生成的代码替换脚本
cd ../temp_rename
chmod +x replace_image_refs.sh
./replace_image_refs.sh
```
**预期结果**
- ✅ 2971个图片资源已重命名
- ✅ Contents.json 已更新
- ✅ 代码中的图片引用已替换
- ✅ 生成了映射文件备查
**验证步骤**
```bash
# 1. 编译项目
# Xcode: Product → Build
# 2. 运行应用
# Xcode: Product → Run (⌘R)
# 3. 检查关键页面的图片是否正常显示
# - 登录页
# - 首页
# - TabBar
# - 房间页
```
---
### Week 2: 视觉层改造
#### Day 8-10: 主题颜色替换
```bash
# 1. 阅读配色方案文档
cat 3_theme_color_example.md
# 2. 选择一个配色方案A/B/C
# 3. 手动创建新的颜色类
# 在 Xcode 中:
# YuMi/CustomUI/ → New File → Cocoa Touch Class
# 类名: AppThemeColor
# 父类: NSObject
```
**实施步骤**
1. 复制 `3_theme_color_example.md` 中的示例代码
2. 创建 `AppThemeColor.h``AppThemeColor.m`
3. 运行文档中的替换脚本
4. 手动调整硬编码的颜色值
**验证步骤**
```bash
# 运行应用,检查所有页面的颜色
# 重点检查:
# - TabBar 颜色
# - 导航栏颜色
# - 按钮渐变
# - 背景色
# - 文字颜色
```
---
#### Day 11-12: TabBar 结构调整
**手动操作**(在 Xcode 中):
1. 打开 `TabbarViewController.m`
2. 找到 TabBar 初始化代码
3. 调整 Tab 顺序,例如:
```objc
// 旧顺序: 首页 → 消息 → 动态 → 我的
// 新顺序: 动态 → 首页 → 消息 → 我的
// 或者改变 Tab 数量
// 5个 Tab → 4个 Tab移除某个功能
```
4. 更换所有 TabBar 图标
5. 修改 TabBar 选中/未选中动画
---
### Week 3: 代码结构层改造
#### Day 13-15: 核心页面 UI 重构
**优先级**
1. 登录页(必须改)
2. 首页(必须改)
3. 房间页(可选择性改)
4. 个人中心(必须改)
**策略**
- 不改业务逻辑,只改 UI 布局
- 使用 Interface Builder → 纯代码(或反之)
- 改变控件位置和排列方式
---
#### Day 16-19: 拆分超大类
重点处理 `XPRoomViewController.m`4605行
```objc
// 创建 Category 拆分
// XPRoomViewController+Gift.h/m - 礼物相关
// XPRoomViewController+PK.h/m - PK相关
// XPRoomViewController+Game.h/m - 游戏相关
// XPRoomViewController+Chat.h/m - 聊天相关
```
---
### Week 4: 测试和提审
#### Day 20-23: 功能测试
```bash
# 测试检查清单
- [ ] 登录/注册(所有方式)
- [ ] 首页浏览和筛选
- [ ] 进入房间
- [ ] 发送消息
- [ ] 发送礼物
- [ ] 充值流程(测试环境)
- [ ] 个人中心设置
- [ ] 第三方登录Facebook/Google/Apple
- [ ] 推送通知
- [ ] 分享功能
- [ ] 深度链接
```
#### Day 24-26: 最终调整
1. 修复所有测试中发现的 bug
2. 优化性能(内存泄漏、卡顿)
3. 更新应用截图5-10张
4. 撰写新的应用描述
#### Day 27-30: 提审准备
```bash
# 1. 更新 Bundle ID
# 在 Xcode: Targets → General → Bundle Identifier
# 2. 更新 App 名称
# 在 Info.plist: CFBundleDisplayName
# 3. 准备新的 App Store 截图
# 4. 撰写应用描述(完全不同的文案)
# 5. 提交审核
```
---
## 📊 进度追踪
使用以下命令查看当前进度:
```bash
# 检查已重命名的类
find YuMi -name "*.m" | grep -v Pods | wc -l
# 检查颜色替换进度
grep -r "DJDKMIMOMColor" YuMi --include="*.m" | wc -l
grep -r "AppThemeColor" YuMi --include="*.m" | wc -l
# 检查图片资源
ls -l YuMi/Assets.xcassets/**/*.imageset | wc -l
```
---
## 🔧 常见问题
### Q1: 编译错误 "Use of undeclared identifier"
**原因**:类名替换不完整
**解决**
```bash
# 搜索旧的类名
grep -r "YMSomeClass" YuMi --include="*.m" --include="*.h"
# 手动替换
```
### Q2: 图片不显示
**原因**:图片名称替换遗漏
**解决**
```bash
# 1. 检查映射文件
cat issues/temp_rename/asset_name_mapping.json
# 2. 搜索旧的图片名
grep -r "old_image_name" YuMi --include="*.m"
# 3. 手动替换
```
### Q3: 颜色显示异常
**原因**:硬编码的颜色值未替换
**解决**
```bash
# 搜索硬编码的 hex 颜色
grep -r "0x9682FF" YuMi --include="*.m"
grep -r "UIColorFromRGB" YuMi --include="*.m" | grep "0x"
# 手动替换为 [AppThemeColor xxx]
```
### Q4: TabBar 跳转失败
**原因**:代码中硬编码了 Tab index
**解决**
```bash
# 搜索 selectedIndex
grep -r "selectedIndex" YuMi --include="*.m"
# 更新所有硬编码的 index
```
---
## 🆘 回滚方案
如果出现严重问题,可以快速回滚:
```bash
# 方法1: Git 回滚
git reset --hard HEAD
git clean -fd
# 方法2: 恢复备份
# 类名替换备份: issues/temp_rename/
# 图片资源备份: issues/temp_rename/assets_backup/
# Xcode 项目备份: YuMi.xcodeproj/project.pbxproj.backup
```
---
## 📞 技术支持
如果遇到无法解决的问题:
1. 查看详细日志
```bash
cat issues/temp_rename/rename_report.txt
cat issues/temp_rename/assets_rename_report.txt
```
2. 检查 Git 提交记录
```bash
git log --oneline
git diff
```
3. 分步骤回滚测试
---
## ✅ 最终检查清单
提审前必须确认:
- [ ] 所有编译警告已解决
- [ ] 核心功能测试通过
- [ ] 没有明显的崩溃
- [ ] UI 和原项目有显著差异至少70%
- [ ] Bundle ID 已更改
- [ ] App 名称已更改
- [ ] 所有图片资源已替换
- [ ] 主题色已完全不同
- [ ] 准备好新的应用截图和描述
- [ ] 第三方 SDK 配置正确
- [ ] 测试环境和生产环境切换正确
---
## 📈 成功标准
**技术层面**
- 代码相似度 < 30%
- 资源文件完全不同
- UI 视觉差异 > 70%
**审查层面**
- App Store 截图无相似性
- 应用描述和关键词不重复
- 功能展示有差异化
---
## 🎉 完成后
恭喜!你已经完成了白牌项目的改造。
**建议**
1. 保留完整的映射文档,便于后续维护
2. 定期同步原项目的 bug 修复
3. 使用 Git submodule 或 monorepo 管理多个白牌版本
**祝你成功通过 App Store 审核!** 🚀