初始化
This commit is contained in:
+217
@@ -0,0 +1,217 @@
|
||||
---
|
||||
项目名称: 91porn #如果在dmp则使用dmp的名称 如果不在则使用自定义名称
|
||||
一级部门: 北斗 #请填写一级部门名称 北斗
|
||||
二级部门: 瑞升 #请填写二级部门名称,无则留空, 如无极
|
||||
|
||||
DMP编码: #无则留空
|
||||
|
||||
项目类型: APP
|
||||
# 可选值:
|
||||
# H5 / APP / PC / 服务 / 组件 / 工具 / AI / 中间件
|
||||
|
||||
开发语言: Dart
|
||||
# 可选值:
|
||||
# GO / Java / PHP / Node
|
||||
|
||||
项目负责人: DN5368 # 员工编号, 多个用逗号隔开,这里的负责是这套代码的负责人
|
||||
|
||||
运维负责人: DN9460,DN9651,DN4792 # 负责部署、监控、K8S、发布、证书等
|
||||
|
||||
产品负责人: YY1145,YY1208 # 项目产品经理
|
||||
|
||||
|
||||
项目成员: DN5368,DN1180
|
||||
|
||||
项目状态: 开发中
|
||||
# 可选值:
|
||||
# 开发中 / 维护中 / 已停止 / 已归档
|
||||
|
||||
项目级别: 高
|
||||
# 可选值:
|
||||
# 高 / 中 / 低 , 北斗体系 s和a为 高 b为中 c d为低
|
||||
|
||||
核心分支: main
|
||||
# 即部署时候使用的分支,可选值:
|
||||
# master / main / dev / release
|
||||
|
||||
代码仓库:
|
||||
- ssh://git@bd-git-sh.jsyyds.com:8082/ruisheng/jha-204-91pron/frontend/91porn-android-client.git
|
||||
|
||||
最后审计人: DN5368
|
||||
|
||||
最后审计时间: 2026-08-06
|
||||
|
||||
告警群: tg://blibli-alert-group
|
||||
|
||||
备注: Flutter 客户端(Android + iOS 双端),当前版本 1.12.1,Android 包名 com.noporn.newchatone_twelve_one(版本号变更需同步替换)
|
||||
|
||||
---
|
||||
|
||||
# 1. 项目说明
|
||||
|
||||
91porn 移动客户端(Android + iOS 同一套代码),基于 Flutter 3.38.3 + Dart 3.10.0,面向 C 端用户的视频/社区/AI/暗网综合内容 APP。
|
||||
|
||||
核心模块:
|
||||
|
||||
- **首页 (`hj_page/home/`)**:视频/短视频/漫画/动漫等多 Tab 内容流,含搜索、片库、排行
|
||||
- **发现 (`hj_page/find/`)**:榜单、分类、片单
|
||||
- **AI (`hj_page/mine/ai/`)**:AI 换脸、AI 脱衣、文生图、图生视频、文生小说等付费功能
|
||||
- **会员/支付 (`hj_page/mine/mine_vip/`、`hj_page/pre_sale/`)**:VIP 购买、金币充值、代理充值、预售
|
||||
- **个人中心 (`hj_page/user_center_page/`、`hj_page/mine/`)**:用户主页、客服、QA、设置
|
||||
- **社区 (`hj_page/community/`)**:帖子、评论、互动
|
||||
- **IM (`im_manager/`)**:自研私信/会话,无三方 IM SDK(会话列表、聊天详情、消息通知、聊天页广告位)
|
||||
- **暗网 (`hj_page/darkweb/`)**:分类专区,独立入口与 VIP 体系
|
||||
- **直播 (`hj_page/live/`)**:直播入口
|
||||
- **在线客服 (`hj_page/zaixiankefu/`)**:H5 客服对接
|
||||
- **播放器**:基于 video_player + ffmpeg_kit_flutter_new_https + 自研 m3u8_downloader
|
||||
- **视频下载**:Android 走 `m3u8_downloader` 原生 isolate;iOS 走 `IOSVideoDownloader`(用 ffmpeg 拉远程 m3u8 转 mp4 自动入相册,命令 `-c copy -bsf:a aac_adtstoasc -movflags +faststart`,不重编码)
|
||||
|
||||
技术栈:
|
||||
|
||||
- 状态管理:GetX (`GetxController` + `GetBuilder`) + Provider(全局状态)
|
||||
- 网络:Dio + 自研 `httpManager` + RSA 请求加密
|
||||
- 屏幕适配:flutter_screenutil(设计稿 428×927)
|
||||
- 路由:GetX 路由
|
||||
- 本地存储:MMKV + shared_preferences
|
||||
- 视频下载:`m3u8_downloader-master`(本仓库内)
|
||||
- 调试工具:ume_core + ume_kit_dio / ume_kit_perf / ume_kit_ui(均取自 pub,不再本地维护)
|
||||
|
||||
项目目录结构:
|
||||
|
||||
```
|
||||
hgdj/
|
||||
├── lib/
|
||||
│ ├── alert/ # 全局弹窗
|
||||
│ ├── assets_tool/ # 颜色、图片、资源路径
|
||||
│ ├── config/ # 配置常量(域名、版本、AB 等)
|
||||
│ ├── extension/ # Dart 扩展方法
|
||||
│ ├── hj_model/ # 数据模型(手写 fromJson)
|
||||
│ ├── hj_page/ # 业务页面(按模块分目录)
|
||||
│ ├── hj_utils/ # 工具方法 + API service
|
||||
│ ├── im_manager/ # 自研 IM(会话/聊天页/通知)
|
||||
│ ├── routers/ # 路由定义与跳转
|
||||
│ ├── tools_base/ # 基础工具(网络/事件/loading/toast/refresh/缓存)
|
||||
│ ├── track_event_manager/ # 设备信息 / 请求头 sid 会话
|
||||
│ └── main.dart # 入口
|
||||
├── android/ # Android 工程
|
||||
├── ios/ # iOS 工程
|
||||
├── assets/ # 静态资源(图片/flare/字体)
|
||||
├── m3u8_downloader-master/ # 自研 m3u8 下载库
|
||||
├── third_party/ # 三方原生库
|
||||
├── dist/ # 打包产物输出目录
|
||||
├── build_apk.sh # 双端打包脚本(apk / ipa)
|
||||
└── pubspec.yaml
|
||||
```
|
||||
|
||||
|
||||
# 2. 基础设施与中间件
|
||||
|
||||
- 后端服务:91porn-server(Go,独立仓库)— 提供 APP API、Web 管理、Skd 任务
|
||||
- CDN:视频/图片/动漫资源分发(Cloudfront + 自有域名多线路)
|
||||
- 推送:Telegram Bot 客服群对接
|
||||
- 客户端依赖:
|
||||
- Dio:HTTP 网络层
|
||||
- cached_network_image:图片缓存
|
||||
- mmkv / shared_preferences:本地 KV
|
||||
- ffmpeg_kit_flutter_new_https:视频处理(社区维护 fork,自托管二进制带 SSL,原 minimal 包二进制已下架)
|
||||
- flutter_inappwebview:H5 嵌入(充值/客服/活动页)
|
||||
- permission_handler:权限申请
|
||||
- device_info_plus / package_info_plus:设备信息
|
||||
- flutter_native_image / image_pickers:图片选择压缩
|
||||
|
||||
|
||||
# 3. 运维部署
|
||||
|
||||
客户端通过 `build_apk.sh` 本地打包后分发,**不走 K8S/CI 流水线**。
|
||||
|
||||
发布流程:
|
||||
|
||||
1. 切到 `main` 分支,更新 `pubspec.yaml` 版本号 + `Config.innerVersion` + `local.properties` + applicationId(按版本号转换规则)
|
||||
2. 确认 `Config.isDebug = false`(开发分支常年为 `true`,最容易漏)
|
||||
3. 打包(脚本自动检测 FVM PATH,产物统一复制至 `dist/`):
|
||||
|
||||
```
|
||||
sh build_apk.sh <target> [mode] [export_method] [export_options_plist] [sign_mode]
|
||||
target a(android) | i(ios) | all
|
||||
mode release(默认) | debug | profile
|
||||
export_method (iOS) app-store(默认) | ad-hoc | development | enterprise
|
||||
export_options_plist ExportOptions.plist 路径,留空用默认
|
||||
sign_mode (iOS) codesign(默认) | nocodesign
|
||||
```
|
||||
|
||||
常用:`sh build_apk.sh a`(Android release,arm64 单 ABI)、`sh build_apk.sh i release ad-hoc`(iOS 内测包)、`sh build_apk.sh all`
|
||||
4. 产物命名(`APP_NAME` 取自 `pubspec.yaml` 的 `name`,即 `hgdj`):
|
||||
- Android:`hgdj_<mode>_<version>_<MMdd-HHmm>.apk`
|
||||
- iOS:`hgdj_<mode>_<exportMethod>_<version>_<MMdd-HHmm>.ipa`,如 `hgdj_release_adhoc_1.12.1_0806-0925.ipa`
|
||||
5. Android 发版前跑 VirusTotal 包毒检测
|
||||
6. 上传到分发平台(落地页 / 蒲公英 / 自有 CDN),Telegram 告警群通知
|
||||
|
||||
真机调试(不出正式包):`flutter build ios --release && flutter install --release -d <deviceId>`,Xcode 自动签名,Team `NWP977LR25`。
|
||||
|
||||
回滚方案:
|
||||
|
||||
- 仅客户端无服务端回滚概念
|
||||
- 旧版本安装包保留在分发平台,用户可重新下载
|
||||
- 服务端通过 `Config.dns` 接口下发动态域名实现服务端切换
|
||||
|
||||
|
||||
# 4. 风险说明
|
||||
|
||||
- **包名风险**:`com.noporn.newchatone_twelve_one` 与版本号强绑定,每次升版需替换 applicationId(数字转英文单词规则),遗漏会导致 push/支付失败
|
||||
- **加密密钥风险**:`Config.encryptKey` / `ANTI_REPLAY_ATTACK_KEY` / `Config.appId = JHA-204` 泄漏会被刷接口
|
||||
- **包毒检测**:APK 容易被部分杀毒软件误报,需走 VirusTotal 检测后再分发
|
||||
- **包体积**:当前接入 ffmpeg_kit_flutter_new_https(带 SSL,比 minimal 大 +5~10MB)/ video_player / 多个三方 SDK,需定期 `analyze-size` 控制体积
|
||||
- **iOS 最低系统版本**:Podfile + Runner.xcodeproj 锁定 15.0(Xcode 16+ 要求 + ffmpeg 7.x 要求),低于此版本无法安装
|
||||
- **Android SDK 版本**:minSdk 24 / targetSdk 36,targetSdk 升级需重新验证权限与后台限制
|
||||
- **三方依赖**:image_pickers / m3u8_downloader 为内部维护,Flutter 升级时需同步适配
|
||||
- **原生插件升级**:`flutter pub get` + `flutter analyze` 全过也不代表能用,含原生代码的插件必须真机 build 验证(audioplayers 升 v6 即栽在这里)
|
||||
- **release-only 缺陷**:混淆 + strip + 独立 manifest 让 release 有一整类 debug 不复现的问题(详见第 5 节),每次发版必须真机跑 release 包,不能只测 debug
|
||||
- **域名兜底**:`Config.dns = 91porn.zmnchs.com` 走运维下发,运维接口挂掉会导致 APP 启动失败
|
||||
- **Flutter 版本锁定**:3.38.3 强制 fvm,避免系统 SDK 切换触发 flutter_ume / leak_tracker 冲突
|
||||
- **暗网模块**:`Config.darkWebEnable` 通过运维下发开关,下发异常会暴露入口
|
||||
- **DEBUG 标志**:`Config.isDebug` 切换会影响 `lineList` 兜底线路与日志输出,正式包必须 `false`(开发分支当前为 `true`)
|
||||
|
||||
|
||||
# 5. 历史事故(可选)
|
||||
|
||||
## 5.1 release 包专有(debug 一律不复现,最贵的一类)
|
||||
|
||||
debug 与 release 在**混淆、符号 strip、manifest 合并**三处行为不同,以下问题只能靠真机 release 包发现:
|
||||
|
||||
| 现象 | 根因 | 修复 |
|
||||
|---|---|---|
|
||||
| iOS 启动卡死 / 本地存储静默读不到 | FFI(MMKV)符号被 strip 掉,运行时找不到 | `STRIP_INSTALLED_PRODUCT = NO`(只设 `STRIP_STYLE = non-global` 不够) |
|
||||
| Android 安装后直接闪退(SIGSEGV) | 含 native 方法的插件(ffmpeg-kit)被 R8 混淆,`RegisterNatives` 失败 | proguard 补 `-keep`;**新增带 JNI 的插件都要补** |
|
||||
| 启动弹「线路检测失败」,host lookup errno=7 | `INTERNET` 权限只声明在 debug/profile 的 manifest,`src/main` 漏了 | 权限写进 `src/main/AndroidManifest.xml`,别指望三方插件替你声明 |
|
||||
| 页面灰屏 / 列表静默空白 | 用 `T.toString() == '类名'` 做分支,混淆后类名变了必然失配 | 一律改 `T == 类型`(比较 Type 对象,不碰名字字符串) |
|
||||
|
||||
## 5.2 其他
|
||||
|
||||
- **视频下载进度不刷新**(退出重进才更新):本仓库内 `m3u8_downloader` 的 `callbackDispatcher` 缺 `@pragma('vm:entry-point')`,后台 isolate 起不来。教训:本地插件不是黑盒,出问题要读它的源码
|
||||
- **刷新控制器双重释放崩溃**:`refreshCtr` 归 `CustomRefreshView` 释放,logic / 子 widget 又 dispose 一次 → `headerMode!` 空断言崩在 unmount 阶段 → 中断整棵树的卸载并连带泄漏。规则:只释放自己 new 的
|
||||
- **dio 5.9 偶发 `DioException[unknown] Null check operator`**:仅 CDN 接口偶发,根因不可复现(已证伪 adapter / FusedTransformer 两个方向),用幂等 GET 的 `RetryInterceptor` 自愈
|
||||
- **截图保存「提示成功但相册没有」**:`RepaintBoundary` 套在 `SingleChildScrollView` 内被裁剪,截出空图。改用 `Center + FittedBox` 完整渲染,且调用处必须 `await` 判断结果
|
||||
- **设置锁屏密码当次不生效、重启后才生效**:把内部可变 list 直接交给未 `await` 的异步回调,回调在 `await` 之后读到的已是被 clear 的空 list(内存态空、持久化态有值)。传副本 `List<int>.of(x)` 修复
|
||||
- **audioplayers 无法升 v6**:`pub get` / `analyze` 全过但 Android 侧 build 挂(5.2.1 与 platform_interface 7.1.1 错配 + Kotlin 2.1),已停在 v5.2.1
|
||||
- **`pull_to_refresh` 升级后回弹手感夸张**(Flutter 3.16.8 → 3.38.3):改 `pull_refresh.dart` 参数解决;**不迁移 EasyRefresh**——logic 层有 305 处依赖 SmartRefresher 专有 API
|
||||
- **华为多任务卡片隐私遮盖失败**:系统截快照早于 Flutter 生命周期回调,任何遮盖层(View / 独立 Window)都盖不住,也无法把黑屏换成自定义图。结论:只能用 `FLAG_SECURE`
|
||||
|
||||
|
||||
# 6. 交接说明(可选)
|
||||
|
||||
- **Flutter 版本**:必须使用 `fvm flutter`,版本锁定 3.38.3(见 `.fvmrc`),`build_apk.sh` 已内置 FVM PATH 检测
|
||||
- **打包**:`build_apk.sh a` 打 Android,`build_apk.sh i` 打 iOS,`build_apk.sh all` 双端;完整参数见第 3 节
|
||||
- **applicationId 规则**:`com.noporn.newchat` + `<major>_<minor>_<patch>`(数字转英文),如 1.12.1 → `com.noporn.newchatone_twelve_one`
|
||||
- **版本号同步点**:`pubspec.yaml` / `Config.innerVersion` / `android/local.properties` / `android/app/build.gradle` 四处必须一致
|
||||
- **加密密钥**:RSA 公私钥位于 Android 端 native 层 + Dart 层,调整时需双端同步
|
||||
- **AB 配置**:`Config` 类中集中维护(`aiSwitchConf` / `showAbTestAd` 等),新增 AB 需走运维下发
|
||||
- **客服地址**:`/customer/url` 接口动态下发完整 URL,前端不再拼 `baseHost`
|
||||
- **provider 注入**:`main.dart` 中 `MultiProvider` 注入若干 `ChangeNotifier`,新增全局状态走该处
|
||||
- **图片资源**:`assets_tool/` 统一管理路径扩展(`.commonImgPath` / `.homePath` / `.darkWebPath` 等)
|
||||
- **域名错误兜底**:DNS 接口失败时降级到 `Config.LINE_LIST` 本地兜底
|
||||
- **网络层异常约定**:dio 异常已被网络层吞成 `BaseRespBean`(业务层不要写 `DioException` catch),但**请求前的签名加密会抛**,需 try 兜底;拦截器只在「有响应但失败」时弹 toast,超时/断网(code 2001-2003)不弹,要各自兜底
|
||||
- **列表分页**:统一继承 `tools_base/base_list_controller.dart` 的 `ListBaseLogic`(配 `pullYsRefresh`),别自己重写分页
|
||||
- **支付下单**:走 `PayManager().buy / buyVip`(含 loading、余额不足跳充值、回调、source 透传),不要直接调 `BuyService`
|
||||
- **弹窗**:提示类统一用 `tools_base/widget/common_alert.dart`;「停留 N 分钟后满足条件才弹」走 `TimedPopupManager`(`onClose` 必须 `cancel`,否则泄漏)
|
||||
- **包毒检测**:发版前必须用 `/check-apk-virus` 跑 VirusTotal
|
||||
- **包体积分析**:使用 `apk-analyzer` skill 跑 `flutter build apk --analyze-size`
|
||||
Reference in New Issue
Block a user