# TSGame 跨平台项目说明文档

## 项目概述

TSGame 是一个跨平台的棋牌游戏应用，支持Android、iOS、HarmonyOS等主流移动平台。主要实现了聚友棋牌、进贤聚友棋牌等多个地方特色棋牌游戏。项目采用WebView混合开发模式，通过统一的JS Bridge接口实现跨平台功能。

### 支持平台
- **Android**: API 21+ (Android 5.0+)
- **iOS**: iOS 11.0+
- **HarmonyOS**: API 8+ (HarmonyOS 3.0+)

### 基本信息
- **应用标识**: `com.jx.jyhd` (可根据平台调整)
- **应用名称**: 进贤聚友棋牌（支持多种地方棋牌名称配置）
- **当前版本**: 3.6.3
- **架构模式**: WebView + JS Bridge 混合开发

## 跨平台技术架构

### 整体架构设计
```
┌─────────────────────────────────────────────────────┐
│                   H5游戏前端                          │
│              (HTML5 + CSS3 + JavaScript)           │
└─────────────────────────────────────────────────────┘
                            │
┌─────────────────────────────────────────────────────┐
│                 JS Bridge 通信层                      │
│            (统一的跨平台API接口定义)                    │
└─────────────────────────────────────────────────────┘
                            │
┌─────────────┬─────────────┬─────────────┬─────────────┐
│   Android   │     iOS     │ HarmonyOS   │   其他平台    │
│   Native    │   Native    │   Native    │   Native    │
└─────────────┴─────────────┴─────────────┴─────────────┘
```

### 核心设计原则
1. **统一接口**: 所有平台实现相同的JS Bridge API接口
2. **功能对等**: 确保各平台功能基本一致
3. **性能优化**: 针对不同平台特性进行优化
4. **用户体验**: 遵循各平台的设计规范

## 项目功能特性

### 核心功能模块
1. **多地方棋牌游戏支持**
   - 崇仁聚友棋牌
   - 进贤聚友棋牌
   - 广州聚友棋牌
   - 慈溪聚友棋牌
   - 东乡棋牌等多个地方特色游戏

2. **WebView游戏引擎**
   - Android: 腾讯X5 WebView内核
   - iOS: WKWebView
   - HarmonyOS: Web组件
   - 支持HTML5游戏运行
   - 自定义JS桥接功能

3. **社交分享功能**
   - 微信好友/朋友圈分享
   - QQ分享（Android）
   - 系统分享（iOS/HarmonyOS）
   - 抖音分享（Intent/URL Scheme方式）

4. **位置服务**
   - Android: 高德地图SDK
   - iOS: 高德地图SDK + CoreLocation
   - HarmonyOS: 华为地图服务
   - GPS/网络定位支持

5. **语音功能**
   - 声网Agora音频SDK（全平台支持）
   - 实时语音通话
   - 录音功能

6. **版本管理**
   - 应用自动更新
   - 游戏资源热更新
   - 配置文件动态加载

## 跨平台项目目录结构

### 通用项目结构
```
tsgame_multiplatform/
├── shared/                        # 共享资源
│   ├── webview/                   # H5游戏资源
│   │   ├── assets/               # 静态资源
│   │   ├── js/                   # JavaScript文件
│   │   ├── css/                  # 样式文件
│   │   └── index.html           # 游戏入口页面
│   ├── bridge/                   # JS Bridge接口定义
│   │   ├── bridge-api.js        # 统一API接口
│   │   └── bridge-types.ts      # TypeScript类型定义
│   └── config/                   # 配置文件
│       ├── game-config.json     # 游戏配置
│       └── platform-config.json # 平台配置
├── android/                      # Android平台实现
│   ├── app/
│   │   ├── src/main/java/       # Java/Kotlin源码
│   │   ├── src/main/assets/     # 资源文件
│   │   └── build.gradle         # 构建配置
│   └── libs/                    # 第三方库
├── ios/                          # iOS平台实现
│   ├── TSGame/
│   │   ├── Classes/             # OC/Swift源码
│   │   ├── Resources/           # 资源文件
│   │   └── Info.plist          # 应用配置
│   └── Podfile                  # 依赖管理
├── harmonyos/                    # HarmonyOS平台实现
│   ├── entry/
│   │   ├── src/main/ets/       # ArkTS源码
│   │   ├── src/main/resources/ # 资源文件
│   │   └── build-profile.json5 # 构建配置
│   └── oh-package.json5        # 依赖管理
├── docs/                         # 项目文档
│   ├── platform-guides/        # 平台开发指南
│   ├── api-reference/          # API参考文档
│   └── deployment/             # 部署指南
└── tools/                       # 开发工具
    ├── build-scripts/          # 构建脚本
    └── test-tools/             # 测试工具
```

### 平台特定代码包结构

#### Android (Java/Kotlin)
```
com.jx.jyhd/
├── activity/                    # 活动页面
│   ├── MainActivity            # 主入口
│   ├── WebViewActivity         # WebView容器
│   └── SplashActivity          # 启动页
├── bridge/                     # JS Bridge实现
│   ├── BridgeWebView          # WebView扩展
│   ├── BridgeHandler          # 方法处理器
│   └── BridgeManager          # 桥接管理器
├── service/                    # 业务服务
│   ├── AuthService            # 认证服务
│   ├── ShareService           # 分享服务
│   └── LocationService        # 定位服务
└── utils/                      # 工具类
    ├── NetworkUtils           # 网络工具
    └── StorageUtils           # 存储工具
```

#### iOS (Objective-C/Swift)
```
TSGame/
├── Controllers/                # 控制器
│   ├── TSMainViewController   # 主控制器
│   ├── TSWebViewController    # WebView控制器
│   └── TSSplashViewController # 启动页控制器
├── Bridge/                     # JS Bridge实现
│   ├── TSBridgeWebView        # WebView扩展
│   ├── TSBridgeHandler        # 方法处理器
│   └── TSBridgeManager        # 桥接管理器
├── Services/                   # 业务服务
│   ├── TSAuthService          # 认证服务
│   ├── TSShareService         # 分享服务
│   └── TSLocationService      # 定位服务
└── Utils/                      # 工具类
    ├── TSNetworkUtils         # 网络工具
    └── TSStorageUtils         # 存储工具
```

#### HarmonyOS (ArkTS)
```
src/main/ets/
├── entryability/              # 应用入口
│   └── EntryAbility.ts       # 主Ability
├── pages/                     # 页面
│   ├── Index.ets             # 主页面
│   ├── WebView.ets           # WebView页面
│   └── Splash.ets            # 启动页
├── bridge/                    # JS Bridge实现
│   ├── BridgeWebView.ets     # WebView扩展
│   ├── BridgeHandler.ets     # 方法处理器
│   └── BridgeManager.ets     # 桥接管理器
├── services/                  # 业务服务
│   ├── AuthService.ets       # 认证服务
│   ├── ShareService.ets      # 分享服务
│   └── LocationService.ets   # 定位服务
└── utils/                     # 工具类
    ├── NetworkUtils.ets      # 网络工具
    └── StorageUtils.ets      # 存储工具
```

## 跨平台应用启动流程

### 统一启动流程设计
```
应用启动
    ↓
平台初始化 (原生代码)
    ↓
权限检查与申请
    ↓
配置文件加载
    ↓
JS Bridge初始化
    ↓
WebView组件加载
    ↓
H5游戏资源加载
    ↓
游戏启动完成
```

### 平台特定启动流程

#### Android启动流程
1. **应用启动入口**
   ```
   AndroidManifest.xml → SplashActivity → MainActivity → WebViewActivity
   ```

2. **初始化阶段** (`SplashActivity.onCreate`)
   ```java
   1. 权限检查和存储权限申请
   2. 设置全屏显示和屏幕常亮
   3. 初始化日志系统
   4. 友盟统计初始化
   5. 微信API初始化
   6. 获取当前Activity信息
   ```

#### iOS启动流程
1. **应用启动入口**
   ```
   Info.plist → AppDelegate → TSMainViewController → TSWebViewController
   ```

2. **初始化阶段** (`AppDelegate.didFinishLaunchingWithOptions`)
   ```objc
   1. 权限检查和申请
   2. 状态栏和导航栏配置
   3. 日志系统初始化
   4. 统计SDK初始化
   5. 微信API初始化
   6. 根视图控制器设置
   ```

#### HarmonyOS启动流程
1. **应用启动入口**
   ```
   module.json5 → EntryAbility → Index.ets → WebView.ets
   ```

2. **初始化阶段** (`EntryAbility.onCreate`)
   ```typescript
   1. 权限检查和申请
   2. 窗口属性配置
   3. 日志系统初始化
   4. 分析服务初始化
   5. 第三方SDK初始化
   6. 主页面加载
   ```

### 配置加载流程（通用）
```javascript
// 第一阶段：本地配置加载
1. 从本地存储读取游戏配置参数:
   - gamestart: 游戏启动目录
   - gamedir: 游戏父目录  
   - gameconfig: 游戏配置URL
   - agent: 代理ID
   - channel: 渠道号
   - market: 市场来源

// 第二阶段：版本检查
1. 检查是否首次安装
2. 从assets/bundle复制初始游戏资源
3. 检查本地版本与服务器版本
4. 决定是否需要更新游戏资源

// 第三阶段：资源更新
if (需要应用更新) {
    // 跳转到应用商店或下载APK/IPA
} else if (需要游戏资源更新) {
    下载游戏ZIP包 -> 解压到本地 -> 更新配置
} else {
    直接启动游戏
}

// 第四阶段：游戏启动
1. 初始化H5数据 (app_data.js)
2. 写入游戏配置参数到JS文件
3. 启动主游戏WebView页面
4. 完成启动流程
```

### 关键配置文件

#### version.json (版本配置)
```json
{
    "version": 1,
    "gameid": "game001",
    "name": "游戏名称",
    "platform": "all"
}
```

#### app_data.js (运行时配置)
```javascript
var app_version = 1;
var app_gameconfig = 'config_url';
var app_gamedir = 'game_directory';
var app_gamestart = 'start_file';
var app_agent = 'agent_id';
var app_channel = 'channel_id';
var app_market = 'market_id';
var app_platform = 'android|ios|harmonyos';
    下载游戏ZIP包 -> 解压到本地 -> 更新配置
} else {
    直接启动游戏
}
```

#### 第六阶段：游戏启动
```java
1. 初始化H5数据 (app_data.js)
2. 写入游戏配置参数到JS文件
3. 启动主游戏WebView页面
4. 完成启动流程
```

## WebView与原生交互API

项目使用自定义的JS桥接框架实现WebView与原生Android之间的双向通信。主要基于 `BridgeWebView` 实现。

### API快速参考表

| 功能分类 | API名称 | 调用方向 | 主要用途 |
|---------|---------|----------|----------|
| **认证登录** | `accreditlogin` | JS→Native | 触发微信/QQ登录 |
| | `sharelogin` | Native→JS | 登录结果回调 |
| **社交分享** | `friendsSharetypeUrlToptitleDescript` | JS→Native | 微信/抖音分享 |
| | `sharesuccess` | Native→JS | 分享结果回调 |
| **设备信息** | `getphoneInfo` | JS→Native | 获取设备基本信息 |
| | `getbattery` | JS→Native | 获取电池电量 |
| | `getwifiLevel` | JS→Native | 获取WiFi信号强度 |
| | `getnetwork` | JS→Native | 获取网络连接状态 |
| | `getTime` | JS→Native | 获取系统时间 |
| **多媒体** | `getphoto` | JS↔Native | 图片下载处理 |
| | `opensaoma` | JS→Native | 二维码扫描 |
| | `opencamera` | JS→Native | 拍照功能 |
| **音频** | `prepareaudio` | JS→Native | 录音准备 |
| | `mediaTypeAudio` | JS→Native | 音频播放 |
| | `voicePlaying` | JS→Native | 语音动画 |
| **音视频通话** | `createRoom` | JS→Native | 创建音视频房间 |
| | `exitRoom` | JS→Native | 退出音视频房间 |
| **定位服务** | `startlocation` | JS→Native | 开始定位 |
| | `getlocationinfo` | JS→Native | 获取位置信息 |
| | `locationinfo` | Native→JS | 定位结果回调 |
| **系统交互** | `vibrator` | JS→Native | 手机震动 |
| | `orientation` | JS→Native | 屏幕方向控制 |
| | `finsh` | JS→Native | 退出应用 |
| | `notification` | JS→Native | 系统通知 |
| **摇一摇** | `startshake` | JS→Native | 开始摇一摇监听 |
| | `stopshake` | JS→Native | 停止摇一摇 |
| | `shake` | Native→JS | 摇一摇事件回调 |
| **页面操作** | `OpenurlTitleData` | JS→Native | 打开新WebView页面 |
| | `browser` | JS→Native | 系统浏览器打开链接 |
| | `backgameData` | JS→Native | 返回并传递数据 |
| **复制粘贴** | `gameCopytext` | JS→Native | 复制文本到剪贴板 |
| | `gamepastetext` | JS→Native | 获取剪贴板内容 |
| **电话状态** | `getphonestate` | JS→Native | 获取电话状态 |
| | `phoneStateChanged` | Native→JS | 电话状态变化 |
| **应用管理** | `getGameinstall` | JS→Native | 检查应用安装状态 |
| | `getmarketname` | JS→Native | 获取市场来源 |
| **前后台** | `appservice` | Native→JS | 前后台状态通知 |

### 核心组件

#### 1. 桥接框架核心类
- **`BridgeWebView`**: 继承自腾讯X5 WebView，实现JS桥接功能
- **`BridgeHandler`**: 处理JS调用原生的接口
- **`CallBackFunction`**: 原生向JS回调的接口
- **`Message`**: 消息传递的数据模型

#### 2. JS桥接原理
```javascript
// JS端调用原生方法
WebViewJavascriptBridge.callHandler('handlerName', data, function(response) {
    console.log('Response from native:', response);
});

// JS端注册方法供原生调用
WebViewJavascriptBridge.registerHandler('jsHandlerName', function(data, responseCallback) {
    responseCallback('Response from JS');
});
```

```java
// 原生端注册方法供JS调用
x5webview.registerHandler("handlerName", new BridgeHandler() {
    @Override
    public void handler(String data, CallBackFunction function) {
        // 处理JS传来的数据
        function.onCallBack("Response from native");
    }
});

// 原生端调用JS方法
x5webview.callHandler("jsHandlerName", data, new CallBackFunction() {
    @Override
    public void onCallBack(String data) {
        // 处理JS的回调数据
    }
});
```

### 完整API接口详细说明

#### 1. 用户认证与登录类
| API名称 | 调用方向 | 参数 | 返回值 | 说明 |
|---------|----------|------|-------|------|
| `accreditlogin` | JS→Native | 登录类型 | 无 | 触发授权登录（支持微信/QQ） |
| `sharelogin` | Native→JS | 用户信息JSON | 无 | 登录成功后回传用户信息 |

**JS调用示例：**
```javascript
// 触发微信登录
WebViewJavascriptBridge.callHandler('accreditlogin', '2', function(response) {
    console.log('登录触发成功');
});
```

**用户信息JSON格式：**
```json
{
    "openid": "用户openid",
    "headimgurl": "头像URL",
    "nickname": "用户昵称",
    "sex": "性别(1男2女)",
    "city": "所在城市",
    "province": "所在省份",
    "unionid": "微信unionid"
}
```

#### 2. 社交分享功能
| API名称 | 调用方向 | 参数 | 返回值 | 说明 |
|---------|----------|------|-------|------|
| `friendsSharetypeUrlToptitleDescript` | JS→Native | 分享参数JSON | 无 | 微信分享（好友/朋友圈/抖音） |
| `sharesuccess` | Native→JS | 分享结果JSON | 无 | 分享结果回调 |

**JS调用示例：**
```javascript
// 微信好友分享
var shareData = {
    "type": "1",           // 1-普通分享, 2-截图分享, 3-图片分享  
    "sharefriend": "1",    // 1-好友, 2-朋友圈, 3-抖音
    "webpageUrl": "https://example.com",
    "title": "分享标题",
    "description": "分享描述",
    "sharetype": "link"
};
WebViewJavascriptBridge.callHandler('friendsSharetypeUrlToptitleDescript', JSON.stringify(shareData));
```

**分享结果回调：**
```javascript
// 注册分享结果监听
WebViewJavascriptBridge.registerHandler('sharesuccess', function(data) {
    var result = JSON.parse(data);
    if(result.success === 1) {
        console.log('分享成功');
    } else {
        console.log('分享失败');
    }
});
```

#### 3. 设备信息获取类
| API名称 | 调用方向 | 参数 | 返回值 | 说明 |
|---------|----------|------|-------|------|
| `getphoneInfo` | JS→Native | 无 | 设备信息JSON | 获取手机基本配置信息 |
| `getbattery` | JS→Native | 无 | 电量百分比 | 获取当前电池电量 |
| `getwifiLevel` | JS→Native | 无 | WiFi信息JSON | 获取WiFi信号强度和名称 |
| `getnetwork` | JS→Native | 无 | 网络状态 | 获取网络连接类型 |
| `getTime` | JS→Native | 无 | 时间戳 | 获取系统当前时间戳 |
| `getcompareCode` | JS→Native | 无 | 版本对比结果 | 获取APK版本对比结果 |

**JS调用示例：**
```javascript
// 获取设备信息
WebViewJavascriptBridge.callHandler('getphoneInfo', '', function(response) {
    var deviceInfo = JSON.parse(response);
    console.log('设备型号：' + deviceInfo.model);
    console.log('系统版本：' + deviceInfo.version);
});

// 获取网络状态
WebViewJavascriptBridge.callHandler('getnetwork', '', function(response) {
    // 返回值：1-无网络, 2-WiFi, 3-移动网络
    console.log('网络状态：' + response);
});
```

#### 4. 多媒体功能类
| API名称 | 调用方向 | 参数 | 返回值 | 说明 |
|---------|----------|------|-------|------|
| `getphoto` | JS→Native | 图片URL数组JSON | 无 | 批量下载网络图片到本地 |
| `opensaoma` | JS→Native | 无 | 扫码结果 | 打开相机扫描二维码 |
| `opencamera` | JS→Native | 无 | 图片路径 | 打开相机拍照 |

**图片下载示例：**
```javascript
// 批量下载图片
var imageUrls = ["http://example.com/1.jpg", "http://example.com/2.jpg"];
WebViewJavascriptBridge.callHandler('getphoto', JSON.stringify(imageUrls));

// 监听下载完成回调
WebViewJavascriptBridge.registerHandler('getphoto', function(data) {
    var result = JSON.parse(data);
    console.log('图片下载完成：' + result.localPath);
});
```

#### 5. 音频功能类
| API名称 | 调用方向 | 参数 | 返回值 | 说明 |
|---------|----------|------|-------|------|
| `prepareaudio` | JS→Native | 无 | 无 | 开始录音准备 |
| `mediaTypeAudio` | JS→Native | 音频参数JSON | 无 | 播放音频文件 |
| `voicePlaying` | JS→Native | 语音动画参数 | 无 | 显示语音播放动画 |
| `srcIsloop` | JS→Native | 循环播放参数 | 无 | 设置音频循环播放 |

**音频播放示例：**
```javascript
// 播放音频
var audioData = {
    "audiourl": "http://example.com/audio.mp3",
    "type": "1",           // 1-普通播放, 2-历史记录播放
    "user": "0"            // 用户位置索引
};
WebViewJavascriptBridge.callHandler('mediaTypeAudio', JSON.stringify(audioData));
```

#### 6. 实时音视频功能（声网Agora）
| API名称 | 调用方向 | 参数 | 返回值 | 说明 |
|---------|----------|------|-------|------|
| `createRoom` | JS→Native | 房间信息JSON | 无 | 创建或加入语音/视频房间 |
| `exitRoom` | JS→Native | 无 | 无 | 退出当前音视频房间 |
| `getVideoinfo` | JS→Native | 无 | 视频窗口信息JSON | 获取视频悬浮窗位置信息 |
| `DragViewvideoIsshow` | JS→Native | 显示类型 | 无 | 控制视频悬浮窗显示/隐藏 |

**房间管理示例：**
```javascript
// 创建音视频房间
var roomData = {
    "roomId": "12345",
    "userId": "user001",
    "token": "agora_token",
    "type": "video"        // audio 或 video
};
WebViewJavascriptBridge.callHandler('createRoom', JSON.stringify(roomData));

// 退出房间
WebViewJavascriptBridge.callHandler('exitRoom', '');
```

#### 7. 地理位置服务类
| API名称 | 调用方向 | 参数 | 返回值 | 说明 |
|---------|----------|------|-------|------|
| `startlocation` | JS→Native | 定位类型 | 无 | 开始GPS定位 |
| `getlocationinfo` | JS→Native | 无 | 位置信息JSON | 获取当前位置信息 |
| `locationinfo` | Native→JS | 位置信息JSON | 无 | 定位结果回调 |

**定位功能示例：**
```javascript
// 开始定位
WebViewJavascriptBridge.callHandler('startlocation', '1'); // 1-连续定位, 2-单次定位

// 监听定位结果
WebViewJavascriptBridge.registerHandler('locationinfo', function(data) {
    var location = JSON.parse(data);
    console.log('纬度：' + location.latitude);
    console.log('经度：' + location.longitude);
    console.log('地址：' + location.address);
});
```

#### 8. 系统交互功能类
| API名称 | 调用方向 | 参数 | 返回值 | 说明 |
|---------|----------|------|-------|------|
| `vibrator` | JS→Native | 震动时长(毫秒) | 无 | 手机震动指定时长 |
| `repeatvibrator` | JS→Native | 震动参数 | 无 | 重复震动 |
| `canclevibrator` | JS→Native | 无 | 无 | 取消所有震动 |
| `orientation` | JS→Native | 方向值 | 无 | 设置屏幕方向锁定 |
| `finsh` | JS→Native | 无 | 无 | 退出应用程序 |
| `notification` | JS→Native | 通知内容 | 无 | 发送系统通知 |

**系统交互示例：**
```javascript
// 震动500毫秒
WebViewJavascriptBridge.callHandler('vibrator', '500');

// 设置横屏
WebViewJavascriptBridge.callHandler('orientation', '0'); // 0-横屏, 1-竖屏

// 发送通知
WebViewJavascriptBridge.callHandler('notification', '您有新消息');
```

#### 9. 摇一摇功能类
| API名称 | 调用方向 | 参数 | 返回值 | 说明 |
|---------|----------|------|-------|------|
| `startshake` | JS→Native | 无 | 无 | 开始监听摇一摇动作 |
| `stopshake` | JS→Native | 无 | 无 | 停止监听摇一摇 |
| `SwitchShake` | JS→Native | 开关状态 | 无 | 摇一摇震动声音开关 |
| `shake` | Native→JS | 摇一摇事件 | 无 | 摇一摇动作回调 |

**摇一摇功能示例：**
```javascript
// 开始摇一摇监听
WebViewJavascriptBridge.callHandler('startshake', '');

// 监听摇一摇事件
WebViewJavascriptBridge.registerHandler('shake', function(data) {
    console.log('检测到摇一摇动作');
    // 处理摇一摇逻辑
});

// 停止摇一摇
WebViewJavascriptBridge.callHandler('stopshake', '');
```

#### 10. 网页操作类
| API名称 | 调用方向 | 参数 | 返回值 | 说明 |
|---------|----------|------|-------|------|
| `OpenurlTitleData` | JS→Native | 网页参数JSON | 无 | 打开新的WebView页面 |
| `browser` | JS→Native | URL | 无 | 使用系统浏览器打开链接 |
| `backgameData` | JS→Native | 返回数据 | 无 | 返回上级页面并传递数据 |

**页面跳转示例：**
```javascript
// 打开新页面
var pageData = {
    "url": "http://example.com/page.html",
    "title": "页面标题",
    "data": "传递数据",
    "orientation": "1"    // 0-横屏, 1-竖屏
};
WebViewJavascriptBridge.callHandler('OpenurlTitleData', JSON.stringify(pageData));

// 返回上级页面
WebViewJavascriptBridge.callHandler('backgameData', '返回的数据');
```

#### 11. 复制粘贴功能类
| API名称 | 调用方向 | 参数 | 返回值 | 说明 |
|---------|----------|------|-------|------|
| `gameCopytext` | JS→Native | 要复制的文本 | 无 | 复制文本到系统剪贴板 |
| `gamepastetext` | JS→Native | 无 | 剪贴板内容 | 获取剪贴板中的文本 |

**复制粘贴示例：**
```javascript
// 复制文本
WebViewJavascriptBridge.callHandler('gameCopytext', '要复制的文本内容');

// 获取剪贴板内容
WebViewJavascriptBridge.callHandler('gamepastetext', '', function(response) {
    console.log('剪贴板内容：' + response);
});
```

#### 12. 电话状态监听类
| API名称 | 调用方向 | 参数 | 返回值 | 说明 |
|---------|----------|------|-------|------|
| `getphonestate` | JS→Native | 无 | 电话状态码 | 获取当前电话通话状态 |
| `phoneStateChanged` | Native→JS | 状态码 | 无 | 电话状态变化回调 |

**电话状态监听示例：**
```javascript
// 获取电话状态
WebViewJavascriptBridge.callHandler('getphonestate', '', function(response) {
    // 0-空闲, 1-通话中, 2-来电振铃
    console.log('电话状态：' + response);
});

// 监听电话状态变化
WebViewJavascriptBridge.registerHandler('phoneStateChanged', function(data) {
    console.log('电话状态改变：' + data);
});
```

#### 13. 应用管理类
| API名称 | 调用方向 | 参数 | 返回值 | 说明 |
|---------|----------|------|-------|------|
| `getGameinstall` | JS→Native | 包名 | 安装状态 | 检查指定应用是否已安装 |
| `openApplyDownloadpath` | JS→Native | 无 | 无 | 打开应用下载安装包 |
| `getmarketname` | JS→Native | 无 | 市场标识 | 获取应用市场来源标识 |
| `getothername` | JS→Native | 文件夹名 | 自定义名称 | 获取自定义文件夹名称 |
| `getOther` | JS→Native | 无 | 其他信息 | 获取其他配置信息 |

**应用管理示例：**
```javascript
// 检查应用是否安装
WebViewJavascriptBridge.callHandler('getGameinstall', 'com.tencent.mm', function(response) {
    if(response === '1') {
        console.log('微信已安装');
    } else {
        console.log('微信未安装');
    }
});

// 获取市场来源
WebViewJavascriptBridge.callHandler('getmarketname', '', function(response) {
    console.log('市场来源：' + response);
});
```

#### 14. 前后台状态管理类
| API名称 | 调用方向 | 参数 | 返回值 | 说明 |
|---------|----------|------|-------|------|
| `SwitchOverGameData` | JS→Native | 流量提醒参数 | 无 | 设置移动网络流量提醒 |
| `appservice` | Native→JS | 前后台状态 | 无 | 应用前后台状态变化通知 |

**前后台监听示例：**
```javascript
// 监听应用前后台状态
WebViewJavascriptBridge.registerHandler('appservice', function(data) {
    if(data === '1') {
        console.log('应用进入前台');
        // 恢复游戏逻辑
    } else if(data === '2') {
        console.log('应用进入后台');
        // 暂停游戏逻辑
    }
});
```

#### 15. 通讯录功能类（已禁用）
| API名称 | 调用方向 | 参数 | 返回值 | 说明 |
|---------|----------|------|-------|------|
| `getAddressBook` | JS→Native | 无 | 通讯录数据 | 获取手机通讯录（已注释禁用） |

> **注意**: 通讯录功能因隐私政策要求已被注释禁用。

### 技术实现细节

#### JS桥接机制
项目采用自定义的JS Bridge实现WebView与原生的双向通信：

**核心组件：**
- `BridgeWebView.java` - 继承腾讯X5 WebView，实现桥接功能
- `BridgeHandler.java` - 原生端消息处理接口
- `CallBackFunction.java` - JS回调函数接口
- `Message.java` - 消息实体类
- `WebViewJavascriptBridge.js` - JS端桥接脚本

**消息传递流程：**
1. JS调用原生：`WebViewJavascriptBridge.callHandler(handlerName, data, callback)`
2. 消息序列化并添加到消息队列
3. 通过`loadUrl()`触发原生方法`flushMessageQueue()`
4. 原生端解析消息并调用对应的`BridgeHandler`
5. 处理完成后通过`CallBackFunction`返回结果给JS

**线程安全保证：**
```java
// 确保JS调用在主线程执行
if (Thread.currentThread() == Looper.getMainLooper().getThread()) {
    this.loadUrl(javascriptCommand);
}
```

#### 权限管理机制
应用采用动态权限申请机制，主要权限包括：

**存储权限（必需）：**
```java
// 动态申请存储权限
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
    if (ContextCompat.checkSelfPermission(this, 
        Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
        ActivityCompat.requestPermissions(this, 
            new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
    }
}
```

**位置权限（可选）：**
- GPS定位：`ACCESS_FINE_LOCATION`
- 网络定位：`ACCESS_COARSE_LOCATION`

**音频权限（可选）：**
- 录音权限：`RECORD_AUDIO`
- 音频设置：`MODIFY_AUDIO_SETTINGS`

#### 资源更新机制
项目支持热更新，无需重新安装APK即可更新游戏内容：

**更新流程：**
1. 检查本地版本文件`version.xml`
2. 请求服务器版本信息
3. 比较版本号决定更新策略：
   - APK版本更新：下载新APK并提示安装
   - 资源版本更新：下载资源ZIP包并解压
4. 更新本地版本文件
5. 重新加载游戏

**版本控制文件：**
```xml
<!-- version.xml -->
<version>
    <version>资源版本号</version>
    <gameid>游戏标识</gameid>
    <name>游戏名称</name>
</version>
```

#### 微信SDK集成
项目集成微信开放平台SDK，支持登录、分享功能：

**回调Activity配置：**
```xml
<!-- 微信登录回调 -->
<activity
    android:name=".wxapi.WXEntryActivity"
    android:exported="true"
    android:launchMode="singleTop" />
```

**分享实现：**
- 支持链接分享、图片分享、小程序分享
- 区分好友分享和朋友圈分享
- 抖音分享通过Intent方式实现

#### 音视频功能
集成声网Agora SDK实现实时音视频通话：

**基本功能：**
- 语音房间创建/加入
- 实时语音通话
- 视频悬浮窗显示
- 音频录制播放

**房间管理：**
```javascript
// 创建音视频房间
var roomConfig = {
    "roomId": "房间ID",
    "userId": "用户ID", 
    "token": "Agora Token",
    "channelProfile": "COMMUNICATION"
};
```

#### 定位服务
基于高德地图SDK实现精确定位：

**定位模式：**
- 连续定位：持续获取位置更新
- 单次定位：获取一次高精度位置

**位置信息回调：**
```javascript
// 位置信息格式
{
    "latitude": "31.12345",    // 纬度
    "longitude": "121.12345",  // 经度  
    "accuracy": "15.0",        // 精度(米)
    "address": "详细地址",
    "city": "城市名称",
    "province": "省份"
}
```

### API调用最佳实践

#### 1. 错误处理
```javascript
// JS端错误处理
WebViewJavascriptBridge.callHandler('apiName', data, function(response) {
    try {
        var result = JSON.parse(response);
        if(result.success) {
            // 处理成功逻辑
        } else {
            console.error('API调用失败:', result.error);
        }
    } catch(e) {
        console.error('响应解析失败:', e);
    }
});
```

#### 2. 生命周期管理
```java
// 原生端生命周期处理
@Override
protected void onDestroy() {
    super.onDestroy();
    // 清理WebView
    if(x5webview != null) {
        x5webview.removeAllViews();
        x5webview.destroy();
        x5webview = null;
    }
    // 停止定位服务
    if(locationClient != null) {
        locationClient.stopLocation();
    }
}
```

#### 3. 内存优化
```java
// WebView内存优化
public void optimizeWebView() {
    // 清除缓存
    x5webview.clearCache(true);
    // 清除历史记录
    x5webview.clearHistory();
    // 暂停JavaScript执行
    x5webview.onPause();
    x5webview.pauseTimers();
}
```

#### 4. 网络优化
```java
// 网络状态监听
private void checkNetworkState() {
    ConnectivityManager cm = (ConnectivityManager) 
        getSystemService(Context.CONNECTIVITY_SERVICE);
    NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
    
    if(activeNetwork != null && activeNetwork.isConnected()) {
        if(activeNetwork.getType() == ConnectivityManager.TYPE_WIFI) {
            // WiFi连接
            notifyJSNetworkState("2");
        } else {
            // 移动网络连接
            notifyJSNetworkState("3");
        }
    } else {
        // 无网络连接
        notifyJSNetworkState("1");
    }
}
```

### 调试和测试

#### WebView调试
```java
// 启用WebView调试模式
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
    WebView.setWebContentsDebuggingEnabled(true);
}
```

在Chrome浏览器中访问 `chrome://inspect` 可以调试WebView内容。

#### JS Bridge测试
```javascript
// 测试桥接连通性
function testBridge() {
    if(typeof WebViewJavascriptBridge !== 'undefined') {
        console.log('Bridge已就绪');
        // 测试简单API调用
        WebViewJavascriptBridge.callHandler('getTime', '', function(response) {
            console.log('当前时间:', response);
        });
    } else {
        console.error('Bridge未初始化');
    }
}
```

#### 性能监控
```java
// 监控WebView性能
public class WebViewPerformanceMonitor {
    private long pageStartTime;
    
    @Override
    public void onPageStarted(WebView view, String url, Bitmap favicon) {
        pageStartTime = System.currentTimeMillis();
    }
    
    @Override
    public void onPageFinished(WebView view, String url) {
        long loadTime = System.currentTimeMillis() - pageStartTime;
        Log.d("Performance", "页面加载耗时: " + loadTime + "ms");
    }
}
```

### 常见问题和解决方案

#### 1. JS Bridge不响应
**问题**: JS调用原生方法无响应
**解决方案**: 
- 检查WebView是否已完全加载
- 确认Handler名称拼写正确
- 验证是否在主线程调用

#### 2. 分享功能失效
**问题**: 微信分享无法拉起
**解决方案**:
- 检查微信SDK版本兼容性
- 验证应用签名是否与微信开放平台一致
- 确认回调Activity配置正确

#### 3. 定位权限问题
**问题**: 无法获取位置信息
**解决方案**:
- 动态申请定位权限
- 检查GPS是否开启
- 验证高德SDK配置

#### 4. 音视频通话异常
**问题**: 声网通话质量差或连接失败
**解决方案**:
- 检查网络连接质量
- 验证Agora Token有效性
- 优化音频编码参数

### 完整集成示例

#### 前端HTML页面集成示例
```html
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>TSGame Web</title>
</head>
<body>
    <div id="app">
        <button onclick="loginWithWeChat()">微信登录</button>
        <button onclick="shareToWeChat()">微信分享</button>
        <button onclick="getDeviceInfo()">获取设备信息</button>
        <button onclick="startLocation()">开始定位</button>
        <button onclick="takePhoto()">拍照</button>
        <button onclick="playAudio()">播放音频</button>
        <button onclick="startShake()">开始摇一摇</button>
    </div>

    <script>
        // 初始化Bridge连接
        function connectWebViewJavascriptBridge(callback) {
            if (window.WebViewJavascriptBridge) {
                callback(WebViewJavascriptBridge);
            } else {
                document.addEventListener('WebViewJavascriptBridgeReady', function() {
                    callback(WebViewJavascriptBridge);
                }, false);
            }
        }

        // 等待Bridge就绪
        connectWebViewJavascriptBridge(function(bridge) {
            console.log('Bridge连接成功');
            
            // 注册接收原生回调的方法
            bridge.registerHandler('sharelogin', function(data) {
                var userInfo = JSON.parse(data);
                console.log('登录成功:', userInfo);
                alert('欢迎 ' + userInfo.nickname);
            });

            bridge.registerHandler('sharesuccess', function(data) {
                var result = JSON.parse(data);
                if(result.success === 1) {
                    alert('分享成功');
                } else {
                    alert('分享失败');
                }
            });

            bridge.registerHandler('locationinfo', function(data) {
                var location = JSON.parse(data);
                console.log('定位结果:', location);
                alert('当前位置: ' + location.address);
            });

            bridge.registerHandler('shake', function(data) {
                console.log('检测到摇一摇');
                alert('摇一摇触发!');
            });

            bridge.registerHandler('appservice', function(data) {
                if(data === '1') {
                    console.log('应用进入前台');
                } else if(data === '2') {
                    console.log('应用进入后台');
                }
            });
        });

        // 微信登录
        function loginWithWeChat() {
            WebViewJavascriptBridge.callHandler('accreditlogin', '2', function(response) {
                console.log('登录请求已发送');
            });
        }

        // 微信分享
        function shareToWeChat() {
            var shareData = {
                "type": "1",
                "sharefriend": "1",
                "webpageUrl": "https://example.com",
                "title": "精彩棋牌游戏",
                "description": "快来和朋友一起玩棋牌游戏吧！"
            };
            WebViewJavascriptBridge.callHandler('friendsSharetypeUrlToptitleDescript', 
                JSON.stringify(shareData));
        }

        // 获取设备信息
        function getDeviceInfo() {
            WebViewJavascriptBridge.callHandler('getphoneInfo', '', function(response) {
                var deviceInfo = JSON.parse(response);
                console.log('设备信息:', deviceInfo);
                alert('设备型号: ' + deviceInfo.model);
            });
        }

        // 开始定位
        function startLocation() {
            WebViewJavascriptBridge.callHandler('startlocation', '2'); // 单次定位
        }

        // 拍照
        function takePhoto() {
            WebViewJavascriptBridge.callHandler('opencamera', '', function(imagePath) {
                console.log('照片路径:', imagePath);
                if(imagePath) {
                    // 显示拍摄的照片
                    var img = document.createElement('img');
                    img.src = 'file://' + imagePath;
                    img.style.maxWidth = '300px';
                    document.body.appendChild(img);
                }
            });
        }

        // 播放音频
        function playAudio() {
            var audioData = {
                "audiourl": "https://example.com/audio.mp3",
                "type": "1",
                "user": "0"
            };
            WebViewJavascriptBridge.callHandler('mediaTypeAudio', JSON.stringify(audioData));
        }

        // 开始摇一摇
        function startShake() {
            WebViewJavascriptBridge.callHandler('startshake', '');
            alert('开始摇一摇监听，请摇动手机');
        }

        // 获取网络状态
        function checkNetwork() {
            WebViewJavascriptBridge.callHandler('getnetwork', '', function(response) {
                var status = ['无网络', 'WiFi', '移动网络'][parseInt(response) - 1];
                alert('网络状态: ' + status);
            });
        }

        // 复制文本
        function copyText() {
            var text = '这是要复制的文本内容';
            WebViewJavascriptBridge.callHandler('gameCopytext', text);
            alert('已复制到剪贴板');
        }

        // 获取剪贴板内容
        function pasteText() {
            WebViewJavascriptBridge.callHandler('gamepastetext', '', function(response) {
                alert('剪贴板内容: ' + response);
            });
        }

        // 震动
        function vibrate() {
            WebViewJavascriptBridge.callHandler('vibrator', '500'); // 震动500毫秒
        }

        // 退出应用
        function exitApp() {
            if(confirm('确定要退出应用吗？')) {
                WebViewJavascriptBridge.callHandler('finsh', '');
            }
        }
    </script>
</body>
</html>
```

#### 原生端集成示例
```java
public class GameWebViewActivity extends Activity {
    private BridgeWebView webView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_webview);

        // 初始化WebView
        webView = findViewById(R.id.webview);
        setupWebView();
        registerHandlers();

        // 加载游戏页面
        webView.loadUrl("file:///android_asset/game.html");
    }

    private void setupWebView() {
        WebSettings settings = webView.getSettings();
        settings.setJavaScriptEnabled(true);
        settings.setDomStorageEnabled(true);
        settings.setAllowFileAccess(true);
        settings.setAllowContentAccess(true);

        // 设置UserAgent
        String userAgent = settings.getUserAgentString();
        settings.setUserAgentString(userAgent + " TSGame/1.0");
    }

    private void registerHandlers() {
        // 注册登录处理
        webView.registerHandler("accreditlogin", new BridgeHandler() {
            @Override
            public void handler(String data, CallBackFunction function) {
                if("2".equals(data)) {
                    // 触发微信登录
                    wechatLogin();
                }
                function.onCallBack("success");
            }
        });

        // 注册分享处理
        webView.registerHandler("friendsSharetypeUrlToptitleDescript", new BridgeHandler() {
            @Override
            public void handler(String data, CallBackFunction function) {
                try {
                    JSONObject shareData = new JSONObject(data);
                    String type = shareData.getString("type");
                    String shareType = shareData.getString("sharefriend");
                    
                    if("1".equals(shareType)) {
                        // 微信好友分享
                        shareToWechatFriend(shareData);
                    } else if("2".equals(shareType)) {
                        // 微信朋友圈分享
                        shareToWechatTimeline(shareData);
                    }
                } catch (JSONException e) {
                    e.printStackTrace();
                }
            }
        });

        // 注册设备信息处理
        webView.registerHandler("getphoneInfo", new BridgeHandler() {
            @Override
            public void handler(String data, CallBackFunction function) {
                JSONObject deviceInfo = getDeviceInfo();
                function.onCallBack(deviceInfo.toString());
            }
        });

        // 注册定位处理
        webView.registerHandler("startlocation", new BridgeHandler() {
            @Override
            public void handler(String data, CallBackFunction function) {
                if("1".equals(data)) {
                    startContinuousLocation();
                } else {
                    startSingleLocation();
                }
            }
        });

        // 注册拍照处理
        webView.registerHandler("opencamera", new BridgeHandler() {
            @Override
            public void handler(String data, CallBackFunction function) {
                cameraCallback = function;
                openCamera();
            }
        });
    }

    private void wechatLogin() {
        // 微信登录实现
        SendAuth.Req req = new SendAuth.Req();
        req.scope = "snsapi_userinfo";
        req.state = "tsgame_login";
        api.sendReq(req);
    }

    private JSONObject getDeviceInfo() {
        JSONObject info = new JSONObject();
        try {
            info.put("model", Build.MODEL);
            info.put("brand", Build.BRAND);
            info.put("version", Build.VERSION.RELEASE);
            info.put("sdk", Build.VERSION.SDK_INT);
            
            DisplayMetrics dm = getResources().getDisplayMetrics();
            info.put("screenWidth", dm.widthPixels);
            info.put("screenHeight", dm.heightPixels);
            info.put("density", dm.density);
        } catch (JSONException e) {
            e.printStackTrace();
        }
        return info;
    }

    // 微信登录成功回调
    public void onWechatLoginSuccess(String openId, String nickname, String headUrl) {
        JSONObject userInfo = new JSONObject();
        try {
            userInfo.put("openid", openId);
            userInfo.put("nickname", nickname);
            userInfo.put("headimgurl", headUrl);
            
            // 回调给JS
            webView.callHandler("sharelogin", userInfo.toString(), null);
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }

    // 定位成功回调
    public void onLocationSuccess(double lat, double lng, String address) {
        JSONObject location = new JSONObject();
        try {
            location.put("latitude", String.valueOf(lat));
            location.put("longitude", String.valueOf(lng));
            location.put("address", address);
            
            // 回调给JS
            webView.callHandler("locationinfo", location.toString(), null);
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if(webView != null) {
            webView.removeAllViews();
            webView.destroy();
        }
    }
}
```

这个完整的集成示例展示了：
1. 前端HTML页面如何初始化Bridge连接
2. 如何注册监听原生回调
3. 如何调用各种原生API
4. 原生端如何注册Handler处理JS调用
5. 如何实现完整的登录、分享、定位等功能流程

通过这个示例，开发者可以快速理解和集成TSGame的WebView与原生交互功能。

#### JS端调用原生方法示例
```javascript
// 1. 获取设备信息
WebViewJavascriptBridge.callHandler('getphoneInfo', '', function(response) {
    console.log('设备信息:', response);
});

// 2. 微信分享
var shareData = {
    type: "1",
    sharefriend: "1", 
    webpageUrl: "https://example.com",
    title: "分享标题",
    description: "分享描述"
};
WebViewJavascriptBridge.callHandler('friendsSharetypeUrlToptitleDescript', 
    JSON.stringify(shareData));

// 3. 震动效果
WebViewJavascriptBridge.callHandler('vibrator', '500');
```

#### 原生端调用JS方法示例
```java
// 1. 发送用户登录信息给JS
JSONObject userInfo = new JSONObject();
userInfo.put("openid", openid);
userInfo.put("nickname", nickname);
x5webview.callHandler("sharelogin", userInfo.toString(), 
    new CallBackFunction() {
        @Override
        public void onCallBack(String data) {
            // JS的回调处理
        }
    });

// 2. 通知JS分享结果
JSONObject result = new JSONObject();
result.put("success", 1);
result.put("type", "1");
x5webview.callHandler("sharesuccess", result.toString(), null);
```

### 注意事项

#### 数据传递规范
1. **数据格式**: 所有传递的数据都是字符串格式，复杂数据需要JSON序列化
2. **异步回调**: 大部分API都支持异步回调机制
3. **错误处理**: 需要在JS和原生端都做好异常处理
4. **线程安全**: 原生端调用JS必须在主线程进行
5. **生命周期**: 注意WebView生命周期，避免内存泄漏

#### WebView与原生通信注意事项
1. **消息队列**: 使用消息队列机制确保数据不丢失
2. **特殊字符转义**: JSON字符串中的特殊字符需要转义处理
3. **回调函数**: 每个API调用可以包含一个回调函数
4. **超时处理**: 长时间无响应的API调用需要超时机制

#### 性能优化建议
1. **减少频繁调用**: 避免在短时间内频繁调用原生API
2. **数据压缩**: 传递大量数据时考虑压缩或分批传输
3. **内存管理**: 及时释放不需要的WebView资源
4. **缓存策略**: 合理利用WebView缓存机制

#### 安全性考虑
1. **数据校验**: 对JS传入的数据进行严格校验
2. **权限控制**: 敏感API需要权限检查
3. **防注入**: 防范恶意JS代码注入
4. **HTTPS通信**: 敏感数据传输使用HTTPS

#### 兼容性处理
1. **Android版本**: 针对不同Android版本做适配
2. **设备差异**: 考虑不同设备的硬件差异
3. **WebView版本**: 处理不同WebView内核版本的差异
4. **网络环境**: 适配不同网络环境下的功能表现

### 3. 主要Activity流转

```
weclomeactivity1 (启动页)
    ↓ (配置加载完成)
webviewActivity/NewwebviewActivity (主游戏页面)
    ↓ (外部链接)
openwebActivity1 (外部页面)
    ↓ (微信回调)
WXEntryActivity (微信相关)
```

### 4. 关键配置文件

#### version.xml (版本配置)
```xml
<version>
    <version>1</version>
    <gameid>game001</gameid>
    <name>游戏名称</name>
</version>
```

#### app_data.js (运行时配置)
```javascript
var app_version = 1;
var app_gameconfig = 'config_url';
var app_gamedir = 'game_directory';
var app_gamestart = 'start_file';
var app_agent = 'agent_id';
var app_channel = 'channel_id';
var app_market = 'market_id';
```

## 平台技术栈与第三方服务

### Android平台
#### 开发工具和框架
- **Gradle**: 7.0+ (构建工具)
- **Android SDK**: API 33
- **最低支持**: API 21 (Android 5.0)
- **开发语言**: Java 1.8 / Kotlin 1.8
- **IDE**: Android Studio

#### 第三方SDK集成
| 功能模块 | Android SDK | 版本 |
|---------|-------------|------|
| **WebView** | 腾讯X5 WebView | 44286 |
| **网络请求** | OkHttp | 4.12.0 |
| **JSON解析** | Gson | 2.8.9 |
| **微信SDK** | 微信开放平台SDK | 6.8.11 |
| **地图定位** | 高德地图SDK | 5.2.0 |
| **音视频** | 声网Agora SDK | 最新版 |
| **统计分析** | 友盟统计 | 7.5.0 |
| **崩溃收集** | 腾讯Bugly | 3.4.4 |
| **二维码扫描** | ZXing | 3.5.0 |

### iOS平台
#### 开发工具和框架
- **Xcode**: 14.0+
- **iOS SDK**: iOS 16.0
- **最低支持**: iOS 11.0
- **开发语言**: Objective-C / Swift 5.0
- **依赖管理**: CocoaPods / Swift Package Manager

#### 第三方SDK集成
| 功能模块 | iOS SDK | 版本 |
|---------|---------|------|
| **WebView** | WKWebView (系统) | - |
| **网络请求** | AFNetworking / Alamofire | 5.0+ |
| **JSON解析** | 系统JSONSerialization | - |
| **微信SDK** | 微信开放平台SDK | 1.9.2 |
| **地图定位** | 高德地图SDK / CoreLocation | 9.0+ |
| **音视频** | 声网Agora SDK | 最新版 |
| **统计分析** | 友盟统计 / Firebase | 最新版 |
| **崩溃收集** | Bugly / Crashlytics | 最新版 |
| **二维码扫描** | AVFoundation (系统) | - |

### HarmonyOS平台
#### 开发工具和框架
- **DevEco Studio**: 4.0+
- **HarmonyOS SDK**: API 9
- **最低支持**: API 8 (HarmonyOS 3.0)
- **开发语言**: ArkTS / TypeScript
- **应用模型**: Stage模型

#### 第三方SDK集成
| 功能模块 | HarmonyOS SDK | 版本 |
|---------|---------------|------|
| **WebView** | Web组件 (系统) | - |
| **网络请求** | @ohos.net.http | 系统API |
| **JSON解析** | JSON (系统) | - |
| **微信SDK** | 微信开放平台SDK | 待适配 |
| **地图定位** | 华为地图服务 | 最新版 |
| **音视频** | 声网Agora SDK | 最新版 |
| **统计分析** | 华为分析服务 | 最新版 |
| **崩溃收集** | 华为崩溃服务 | 最新版 |
| **二维码扫描** | @ohos.multimedia.camera | 系统API |

### 跨平台共享组件
- **H5游戏引擎**: HTML5 + CSS3 + JavaScript
- **JS Bridge**: 统一接口定义
- **音视频通话**: 声网Agora SDK（全平台支持）
- **数据存储**: 本地存储 + 云端同步
- **配置管理**: JSON配置文件

## 跨平台权限管理

### Android权限配置
#### 核心权限
```xml
<!-- AndroidManifest.xml -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
```

#### 定位权限
```xml
<uses-permission android:name="android.permission.ACCESS_NETWORK_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.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
```

#### 音频权限
```xml
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
```

#### 其他权限
```xml
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
```

### iOS权限配置
#### Info.plist配置
```xml
<!-- Info.plist -->
<key>NSCameraUsageDescription</key>
<string>应用需要使用相机进行拍照功能</string>

<key>NSMicrophoneUsageDescription</key>
<string>应用需要使用麦克风进行语音通话</string>

<key>NSLocationWhenInUseUsageDescription</key>
<string>应用需要获取位置信息提供定位服务</string>

<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>应用需要获取位置信息提供定位服务</string>

<key>NSPhotoLibraryUsageDescription</key>
<string>应用需要访问相册选择图片</string>

<key>NSContactsUsageDescription</key>
<string>应用需要访问通讯录获取联系人信息</string>
```

#### App Transport Security
```xml
<key>NSAppTransportSecurity</key>
<dict>
    <key>NSAllowsArbitraryLoads</key>
    <true/>
</dict>
```

### HarmonyOS权限配置
#### module.json5配置
```json
{
  "requestPermissions": [
    {
      "name": "ohos.permission.INTERNET",
      "reason": "网络访问",
      "usedScene": {
        "abilities": ["EntryAbility"],
        "when": "inuse"
      }
    },
    {
      "name": "ohos.permission.LOCATION",
      "reason": "获取位置信息",
      "usedScene": {
        "abilities": ["EntryAbility"],
        "when": "inuse"
      }
    },
    {
      "name": "ohos.permission.CAMERA",
      "reason": "拍照功能",
      "usedScene": {
        "abilities": ["EntryAbility"],
        "when": "inuse"
      }
    },
    {
      "name": "ohos.permission.MICROPHONE",
      "reason": "录音功能",
      "usedScene": {
        "abilities": ["EntryAbility"],
        "when": "inuse"
      }
    },
    {
      "name": "ohos.permission.READ_MEDIA",
      "reason": "读取媒体文件",
      "usedScene": {
        "abilities": ["EntryAbility"],
        "when": "inuse"
      }
    },
    {
      "name": "ohos.permission.WRITE_MEDIA",
      "reason": "写入媒体文件",
      "usedScene": {
        "abilities": ["EntryAbility"],
        "when": "inuse"
      }
    }
  ]
}
```

### 权限动态申请代码示例

#### Android权限申请
```java
// 检查和申请权限
private void checkPermissions() {
    String[] permissions = {
        Manifest.permission.WRITE_EXTERNAL_STORAGE,
        Manifest.permission.CAMERA,
        Manifest.permission.RECORD_AUDIO,
        Manifest.permission.ACCESS_FINE_LOCATION
    };
    
    List<String> permissionsToRequest = new ArrayList<>();
    for (String permission : permissions) {
        if (ContextCompat.checkSelfPermission(this, permission) 
            != PackageManager.PERMISSION_GRANTED) {
            permissionsToRequest.add(permission);
        }
    }
    
    if (!permissionsToRequest.isEmpty()) {
        ActivityCompat.requestPermissions(this, 
            permissionsToRequest.toArray(new String[0]), 
            REQUEST_PERMISSIONS);
    }
}
```

#### iOS权限申请
```objc
// 请求相机权限
- (void)requestCameraPermission {
    AVAuthorizationStatus status = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
    if (status == AVAuthorizationStatusNotDetermined) {
        [AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) {
            dispatch_async(dispatch_get_main_queue(), ^{
                if (granted) {
                    // 权限获取成功
                } else {
                    // 权限被拒绝
                }
            });
        }];
    }
}

// 请求定位权限
- (void)requestLocationPermission {
    CLLocationManager *locationManager = [[CLLocationManager alloc] init];
    [locationManager requestWhenInUseAuthorization];
}
```

#### HarmonyOS权限申请
```typescript
// 申请权限
import abilityAccessCtrl, { Permissions } from '@ohos.abilityAccessCtrl';

async requestPermissions() {
  const atManager = abilityAccessCtrl.createAtManager();
  const permissions: Permissions[] = [
    'ohos.permission.CAMERA',
    'ohos.permission.MICROPHONE',
    'ohos.permission.LOCATION'
  ];
  
  try {
    await atManager.requestPermissionsFromUser(this.context, permissions);
    console.log('权限申请成功');
  } catch (error) {
    console.log('权限申请失败:', error);
  }
}
```

## 安全配置

### 签名配置
- **Keystore**: gamehall.keystore
- **密码**: tswl2015
- **别名**: gamehall
- **签名版本**: v1 + v2

### 网络安全
- `usesCleartextTraffic="true"` - 允许HTTP流量
- 支持HTTPS和HTTP混合请求

### 文件权限
- 使用FileProvider共享文件
- 适配Android 7.0+文件访问限制

## 跨平台构建和发布

### Android平台构建
#### 环境要求
- **JDK**: OpenJDK 11+
- **Android Studio**: 2022.1.1+
- **Gradle**: 7.0+
- **Android SDK**: API 33

#### 构建命令
```bash
# 调试版本
./gradlew assembleDebug

# 发布版本  
./gradlew assembleRelease

# 清理项目
./gradlew clean

# 生成签名APK
./gradlew assembleRelease -Pandroid.injected.signing.store.file=keystore/gamehall.keystore
```

#### 签名配置
```gradle
// app/build.gradle
android {
    signingConfigs {
        release {
            storeFile file('../keystore/gamehall.keystore')
            storePassword 'tswl2015'
            keyAlias 'gamehall'
            keyPassword 'tswl2015'
        }
    }
    
    buildTypes {
        release {
            signingConfig signingConfigs.release
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}
```

### iOS平台构建
#### 环境要求
- **macOS**: 12.0+
- **Xcode**: 14.0+
- **iOS SDK**: 16.0+
- **CocoaPods**: 1.11+

#### 构建步骤
```bash
# 安装依赖
cd ios
pod install

# 清理项目
xcodebuild clean -workspace TSGame.xcworkspace -scheme TSGame

# 构建Debug版本
xcodebuild build -workspace TSGame.xcworkspace -scheme TSGame -configuration Debug

# 构建Release版本
xcodebuild archive -workspace TSGame.xcworkspace -scheme TSGame -configuration Release -archivePath build/TSGame.xcarchive

# 导出IPA
xcodebuild -exportArchive -archivePath build/TSGame.xcarchive -exportPath build/ipa -exportOptionsPlist ExportOptions.plist
```

#### 证书配置
```xml
<!-- ExportOptions.plist -->
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>method</key>
    <string>app-store</string>
    <key>teamID</key>
    <string>YOUR_TEAM_ID</string>
    <key>provisioningProfiles</key>
    <dict>
        <key>com.jx.jyhd</key>
        <string>YOUR_PROVISIONING_PROFILE</string>
    </dict>
</dict>
</plist>
```

### HarmonyOS平台构建
#### 环境要求
- **DevEco Studio**: 4.0+
- **HarmonyOS SDK**: API 9
- **Node.js**: 16.0+
- **npm**: 8.0+

#### 构建步骤
```bash
# 清理项目
hvigorw clean

# 构建Debug版本
hvigorw assembleHap --mode module -p module=entry@default -p debuggable=true

# 构建Release版本
hvigorw assembleHap --mode module -p module=entry@default -p debuggable=false

# 构建APP包
hvigorw assembleApp --mode module -p module=entry@default
```

#### 签名配置
```json5
// build-profile.json5
{
  "app": {
    "signingConfigs": [
      {
        "name": "default",
        "type": "HarmonyOS",
        "material": {
          "certpath": "path/to/certificate.p12",
          "storePassword": "your_password",
          "keyAlias": "your_key_alias",
          "keyPassword": "your_key_password",
          "profile": "path/to/profile.p7b",
          "signAlg": "SHA256withECDSA",
          "verify": true,
          "compatibleVersion": 9
        }
      }
    ]
  }
}
```

### 自动化构建配置

#### CI/CD流水线 (GitHub Actions)
```yaml
# .github/workflows/build.yml
name: Multi-Platform Build

on:
  push:
    branches: [ main, develop ]
  pull_request:
    branches: [ main ]

jobs:
  build-android:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3
    - name: Set up JDK 11
      uses: actions/setup-java@v3
      with:
        java-version: '11'
        distribution: 'adopt'
    - name: Build Android APK
      run: |
        cd android
        ./gradlew assembleRelease
    - name: Upload APK
      uses: actions/upload-artifact@v3
      with:
        name: android-apk
        path: android/app/build/outputs/apk/release/

  build-ios:
    runs-on: macos-latest
    steps:
    - uses: actions/checkout@v3
    - name: Set up Xcode
      uses: maxim-lobanov/setup-xcode@v1
      with:
        xcode-version: '14.0'
    - name: Install CocoaPods
      run: |
        cd ios
        pod install
    - name: Build iOS
      run: |
        cd ios
        xcodebuild build -workspace TSGame.xcworkspace -scheme TSGame -configuration Release

  build-harmonyos:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3
    - name: Set up Node.js
      uses: actions/setup-node@v3
      with:
        node-version: '16'
    - name: Build HarmonyOS
      run: |
        cd harmonyos
        npm install
        hvigorw assembleHap --mode module -p module=entry@default
```

### 发布配置

#### Android发布
- **Google Play Store**: 上传AAB包，配置应用签名
- **国内应用市场**: 上传APK包到各大应用商店
- **企业分发**: 配置内部分发渠道

#### iOS发布
- **App Store**: 通过App Store Connect上传IPA
- **TestFlight**: 内测版本分发
- **企业证书**: 企业内部分发

#### HarmonyOS发布
- **华为应用市场**: 上传HAP/APP包
- **企业分发**: 通过华为开发者平台配置

## 跨平台开发指南

### 平台适配策略
#### 1. 功能对等原则
确保各平台实现相同的核心功能，但可根据平台特性进行优化：
- **必须功能**: 游戏核心玩法、登录认证、基础分享
- **平台特色**: 分享渠道、推送通知
- **性能优化**: 根据平台特性调整渲染和网络策略

#### 2. 统一接口设计
所有平台实现相同的JS Bridge API接口：
```typescript
// bridge-api.d.ts - 统一接口定义
interface TSGameBridge {
  // 用户认证
  accreditLogin(type: string): Promise<void>;
  
  // 设备信息
  getPhoneInfo(): Promise<DeviceInfo>;
  getNetworkStatus(): Promise<NetworkStatus>;
  
  // 多媒体
  openCamera(): Promise<string>;
  playAudio(config: AudioConfig): Promise<void>;
  
  // 系统交互
  vibrate(duration: number): Promise<void>;
  showNotification(message: string): Promise<void>;
  
  // 平台特定功能（可选）
  platformSpecific?: {
    [key: string]: any;
  };
}
```

#### 3. 平台差异处理
```javascript
// platform-detector.js
const Platform = {
  isAndroid: () => /Android/i.test(navigator.userAgent),
  isIOS: () => /iPhone|iPad|iPod/i.test(navigator.userAgent),
  isHarmonyOS: () => /HarmonyOS/i.test(navigator.userAgent),
  
  // 根据平台调用不同的API
  shareToSocial: (data) => {
    if (Platform.isAndroid()) {
      return TSGameBridge.shareToWechat(data);
    } else if (Platform.isIOS()) {
      return TSGameBridge.shareToSystem(data);
    } else if (Platform.isHarmonyOS()) {
      return TSGameBridge.shareToHuawei(data);
    }
  }
};
```

### 开发环境搭建

#### 1. Android开发环境
```bash
# 安装Android Studio
# 配置环境变量
export ANDROID_HOME=/path/to/android-sdk
export PATH=$PATH:$ANDROID_HOME/tools:$ANDROID_HOME/platform-tools

# 创建项目
cd android
./gradlew build
```

#### 2. iOS开发环境
```bash
# 安装Xcode (仅限macOS)
# 安装CocoaPods
sudo gem install cocoapods

# 创建项目
cd ios
pod init
pod install
open TSGame.xcworkspace
```

#### 3. HarmonyOS开发环境
```bash
# 下载DevEco Studio
# 安装HarmonyOS SDK
# 创建项目
cd harmonyos
hvigorw assembleHap
```

### 代码复用策略

#### 1. 共享Web资源
```javascript
// shared/webview/js/game-core.js
class GameCore {
  constructor() {
    this.platform = this.detectPlatform();
    this.bridge = this.initBridge();
  }
  
  detectPlatform() {
    if (/Android/i.test(navigator.userAgent)) return 'android';
    if (/iPhone|iPad/i.test(navigator.userAgent)) return 'ios';
    if (/HarmonyOS/i.test(navigator.userAgent)) return 'harmonyos';
    return 'unknown';
  }
  
  initBridge() {
    // 统一的桥接初始化逻辑
    return new PlatformBridge(this.platform);
  }
}
```

#### 2. 平台抽象层
```java
// Android抽象层
public abstract class PlatformService {
    public abstract void login(String type, Callback callback);
    public abstract void share(ShareData data, Callback callback);
    public abstract DeviceInfo getDeviceInfo();
}

public class AndroidPlatformService extends PlatformService {
    @Override
    public void login(String type, Callback callback) {
        // Android特定的登录实现
    }
}
```

```objc
// iOS抽象层
@protocol TSPlatformService <NSObject>
- (void)loginWithType:(NSString *)type callback:(void(^)(NSDictionary *result))callback;
- (void)shareData:(NSDictionary *)data callback:(void(^)(BOOL success))callback;
- (NSDictionary *)getDeviceInfo;
@end

@interface TSIOSPlatformService : NSObject <TSPlatformService>
@end
```

```typescript
// HarmonyOS抽象层
abstract class PlatformService {
  abstract login(type: string): Promise<LoginResult>;
  abstract share(data: ShareData): Promise<boolean>;
  abstract getDeviceInfo(): DeviceInfo;
}

class HarmonyOSPlatformService extends PlatformService {
  async login(type: string): Promise<LoginResult> {
    // HarmonyOS特定的登录实现
  }
}
```

### 测试策略

#### 1. 单元测试
```javascript
// 跨平台测试用例
describe('Bridge API Tests', () => {
  test('should get device info on all platforms', async () => {
    const deviceInfo = await TSGameBridge.getPhoneInfo();
    expect(deviceInfo).toHaveProperty('model');
    expect(deviceInfo).toHaveProperty('version');
    expect(deviceInfo).toHaveProperty('platform');
  });
  
  test('should handle network status correctly', async () => {
    const network = await TSGameBridge.getNetworkStatus();
    expect(['1', '2', '3']).toContain(network);
  });
});
```

#### 2. 集成测试
```yaml
# test-plan.yml
test_scenarios:
  - name: "登录流程测试"
    platforms: ["android", "ios", "harmonyos"]
    steps:
      - "打开应用"
      - "点击登录按钮"
      - "验证登录结果"
  
  - name: "分享功能测试"
    platforms: ["android", "ios", "harmonyos"]
    steps:
      - "进入游戏页面"
      - "点击分享按钮"
      - "选择分享平台"
      - "验证分享成功"
```

### 性能优化建议

#### 1. WebView优化
```javascript
// 通用WebView优化配置
const webViewConfig = {
  android: {
    hardwareAccelerated: true,
    cacheMode: 'LOAD_CACHE_ELSE_NETWORK',
    domStorageEnabled: true
  },
  ios: {
    allowsInlineMediaPlayback: true,
    mediaTypesRequiringUserActionForPlayback: 'none',
    scrollView: { bounces: false }
  },
  harmonyos: {
    javaScriptAccess: true,
    domStorageAccess: true,
    imageAccess: true
  }
};
```

#### 2. 资源加载优化
```javascript
// 预加载关键资源
class ResourceManager {
  preloadAssets() {
    const criticalAssets = [
      'images/logo.png',
      'audio/bgm.mp3',
      'fonts/game-font.woff2'
    ];
    
    return Promise.all(
      criticalAssets.map(asset => this.loadAsset(asset))
    );
  }
  
  loadAsset(url) {
    return new Promise((resolve, reject) => {
      const ext = url.split('.').pop();
      if (['png', 'jpg', 'gif'].includes(ext)) {
        const img = new Image();
        img.onload = resolve;
        img.onerror = reject;
        img.src = url;
      } else if (['mp3', 'wav'].includes(ext)) {
        const audio = new Audio();
        audio.oncanplaythrough = resolve;
        audio.onerror = reject;
        audio.src = url;
      }
    });
  }
}
```

### 维护建议

#### 1. 版本管理
```json
// version-config.json
{
  "version": "3.6.3",
  "platforms": {
    "android": {
      "versionCode": 36300,
      "minSdkVersion": 21,
      "targetSdkVersion": 33
    },
    "ios": {
      "buildNumber": "36300",
      "minimumOSVersion": "11.0"
    },
    "harmonyos": {
      "versionCode": 36300,
      "minAPIVersion": 8,
      "targetAPIVersion": 9
    }
  }
}
```

#### 2. 更新策略
- **强制更新**: 影响安全性和关键功能的更新
- **建议更新**: 新功能和体验优化
- **静默更新**: 资源文件和配置更新
- **灰度发布**: 分阶段推送给不同用户群体

#### 3. 兼容性处理
```javascript
// 版本兼容性检查
class CompatibilityChecker {
  checkPlatformSupport() {
    const requirements = {
      android: { minVersion: 21 },
      ios: { minVersion: '11.0' },
      harmonyos: { minAPIVersion: 8 }
    };
    
    const current = this.getCurrentPlatformVersion();
    const required = requirements[this.platform];
    
    return this.compareVersions(current, required.minVersion) >= 0;
  }
}
```

## 项目总结与展望

### 技术特色
1. **跨平台统一**: 基于WebView + JS Bridge的跨平台解决方案
2. **功能完备**: 涵盖认证、分享、定位、音视频等完整功能
3. **性能优化**: 针对不同平台特性进行深度优化
4. **易于维护**: 统一的API接口和代码架构

### 适用场景
- **棋牌游戏**: 完整的棋牌游戏解决方案
- **社交游戏**: 支持实时音视频和社交分享
- **地方特色应用**: 可快速适配不同地区需求
- **跨平台应用**: 一套代码适配多个平台

### 开发优势
- **开发效率**: H5游戏 + 原生能力，快速开发
- **维护成本**: 统一的业务逻辑，降低维护成本
- **用户体验**: 原生性能 + Web灵活性
- **迭代速度**: 支持热更新，快速迭代

### 扩展方向
1. **平台支持**: 扩展到更多平台（Windows、Web）
2. **技术升级**: 升级到最新的SDK版本和技术栈
3. **功能增强**: 添加更多游戏类型和社交功能
4. **性能优化**: 进一步优化启动速度和运行性能

### 常见问题解答

#### Q: 如何在现有项目基础上开发iOS版本？
A: 
1. 复制`shared/`目录下的所有Web资源
2. 创建iOS项目，实现相同的JS Bridge接口
3. 根据iOS平台特性调整权限配置和第三方SDK
4. 参考本文档的iOS开发指南进行适配

#### Q: HarmonyOS版本开发有什么注意事项？
A: 
1. 使用ArkTS语言开发，语法类似TypeScript
2. 权限管理更加严格，需要详细配置使用场景
3. 部分第三方SDK可能需要寻找替代方案
4. 遵循华为应用市场的审核规范

#### Q: 如何保证各平台功能一致性？
A:
1. 使用统一的API接口定义
2. 建立跨平台测试用例
3. 定期进行功能对比测试
4. 维护详细的功能兼容性文档

#### Q: 性能优化的重点是什么？
A:
1. WebView初始化和资源加载优化
2. JS Bridge通信效率优化
3. 内存管理和垃圾回收优化
4. 网络请求和数据缓存优化

### 技术支持
- **文档更新**: 定期更新技术文档和API说明
- **问题反馈**: 通过Issue跟踪和解决技术问题
- **技术交流**: 建立开发者交流群组
- **版本发布**: 提供稳定的版本发布和更新通知

---

**文档版本**: v2.0  
**更新时间**: 2025年7月5日  
**适用版本**: TSGame 3.6.3+  
**支持平台**: Android、iOS、HarmonyOS  

> 本文档为TSGame跨平台项目的完整技术说明，涵盖了项目架构、开发指南、API参考等所有必要信息。开发者可以基于本文档快速理解项目结构，并在任意支持的平台上实现相同功能的应用。
