71 KiB
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 │
└─────────────┴─────────────┴─────────────┴─────────────┘
核心设计原则
- 统一接口: 所有平台实现相同的JS Bridge API接口
- 功能对等: 确保各平台功能基本一致
- 性能优化: 针对不同平台特性进行优化
- 用户体验: 遵循各平台的设计规范
项目功能特性
核心功能模块
-
多地方棋牌游戏支持
- 崇仁聚友棋牌
- 进贤聚友棋牌
- 广州聚友棋牌
- 慈溪聚友棋牌
- 东乡棋牌等多个地方特色游戏
-
WebView游戏引擎
- Android: 腾讯X5 WebView内核
- iOS: WKWebView
- HarmonyOS: Web组件
- 支持HTML5游戏运行
- 自定义JS桥接功能
-
社交分享功能
- 微信好友/朋友圈分享
- QQ分享(Android)
- 系统分享(iOS/HarmonyOS)
- 抖音分享(Intent/URL Scheme方式)
-
位置服务
- Android: 高德地图SDK
- iOS: 高德地图SDK + CoreLocation
- HarmonyOS: 华为地图服务
- GPS/网络定位支持
-
语音功能
- 声网Agora音频SDK(全平台支持)
- 实时语音通话
- 录音功能
-
版本管理
- 应用自动更新
- 游戏资源热更新
- 配置文件动态加载
跨平台项目目录结构
通用项目结构
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启动流程
-
应用启动入口
AndroidManifest.xml → SplashActivity → MainActivity → WebViewActivity -
初始化阶段 (
SplashActivity.onCreate)1. 权限检查和存储权限申请 2. 设置全屏显示和屏幕常亮 3. 初始化日志系统 4. 友盟统计初始化 5. 微信API初始化 6. 获取当前Activity信息
iOS启动流程
-
应用启动入口
Info.plist → AppDelegate → TSMainViewController → TSWebViewController -
初始化阶段 (
AppDelegate.didFinishLaunchingWithOptions)1. 权限检查和申请 2. 状态栏和导航栏配置 3. 日志系统初始化 4. 统计SDK初始化 5. 微信API初始化 6. 根视图控制器设置
HarmonyOS启动流程
-
应用启动入口
module.json5 → EntryAbility → Index.ets → WebView.ets -
初始化阶段 (
EntryAbility.onCreate)1. 权限检查和申请 2. 窗口属性配置 3. 日志系统初始化 4. 分析服务初始化 5. 第三方SDK初始化 6. 主页面加载
配置加载流程(通用)
// 第一阶段:本地配置加载
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 (版本配置)
{
"version": 1,
"gameid": "game001",
"name": "游戏名称",
"platform": "all"
}
app_data.js (运行时配置)
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 {
直接启动游戏
}
第六阶段:游戏启动
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桥接原理
// JS端调用原生方法
WebViewJavascriptBridge.callHandler('handlerName', data, function(response) {
console.log('Response from native:', response);
});
// JS端注册方法供原生调用
WebViewJavascriptBridge.registerHandler('jsHandlerName', function(data, responseCallback) {
responseCallback('Response from JS');
});
// 原生端注册方法供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调用示例:
// 触发微信登录
WebViewJavascriptBridge.callHandler('accreditlogin', '2', function(response) {
console.log('登录触发成功');
});
用户信息JSON格式:
{
"openid": "用户openid",
"headimgurl": "头像URL",
"nickname": "用户昵称",
"sex": "性别(1男2女)",
"city": "所在城市",
"province": "所在省份",
"unionid": "微信unionid"
}
2. 社交分享功能
| API名称 | 调用方向 | 参数 | 返回值 | 说明 |
|---|---|---|---|---|
friendsSharetypeUrlToptitleDescript |
JS→Native | 分享参数JSON | 无 | 微信分享(好友/朋友圈/抖音) |
sharesuccess |
Native→JS | 分享结果JSON | 无 | 分享结果回调 |
JS调用示例:
// 微信好友分享
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));
分享结果回调:
// 注册分享结果监听
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调用示例:
// 获取设备信息
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 | 无 | 图片路径 | 打开相机拍照 |
图片下载示例:
// 批量下载图片
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 | 循环播放参数 | 无 | 设置音频循环播放 |
音频播放示例:
// 播放音频
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 | 显示类型 | 无 | 控制视频悬浮窗显示/隐藏 |
房间管理示例:
// 创建音视频房间
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 | 无 | 定位结果回调 |
定位功能示例:
// 开始定位
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 | 通知内容 | 无 | 发送系统通知 |
系统交互示例:
// 震动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 | 摇一摇事件 | 无 | 摇一摇动作回调 |
摇一摇功能示例:
// 开始摇一摇监听
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 | 返回数据 | 无 | 返回上级页面并传递数据 |
页面跳转示例:
// 打开新页面
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 | 无 | 剪贴板内容 | 获取剪贴板中的文本 |
复制粘贴示例:
// 复制文本
WebViewJavascriptBridge.callHandler('gameCopytext', '要复制的文本内容');
// 获取剪贴板内容
WebViewJavascriptBridge.callHandler('gamepastetext', '', function(response) {
console.log('剪贴板内容:' + response);
});
12. 电话状态监听类
| API名称 | 调用方向 | 参数 | 返回值 | 说明 |
|---|---|---|---|---|
getphonestate |
JS→Native | 无 | 电话状态码 | 获取当前电话通话状态 |
phoneStateChanged |
Native→JS | 状态码 | 无 | 电话状态变化回调 |
电话状态监听示例:
// 获取电话状态
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 | 无 | 其他信息 | 获取其他配置信息 |
应用管理示例:
// 检查应用是否安装
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 | 前后台状态 | 无 | 应用前后台状态变化通知 |
前后台监听示例:
// 监听应用前后台状态
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端桥接脚本
消息传递流程:
- JS调用原生:
WebViewJavascriptBridge.callHandler(handlerName, data, callback) - 消息序列化并添加到消息队列
- 通过
loadUrl()触发原生方法flushMessageQueue() - 原生端解析消息并调用对应的
BridgeHandler - 处理完成后通过
CallBackFunction返回结果给JS
线程安全保证:
// 确保JS调用在主线程执行
if (Thread.currentThread() == Looper.getMainLooper().getThread()) {
this.loadUrl(javascriptCommand);
}
权限管理机制
应用采用动态权限申请机制,主要权限包括:
存储权限(必需):
// 动态申请存储权限
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即可更新游戏内容:
更新流程:
- 检查本地版本文件
version.xml - 请求服务器版本信息
- 比较版本号决定更新策略:
- APK版本更新:下载新APK并提示安装
- 资源版本更新:下载资源ZIP包并解压
- 更新本地版本文件
- 重新加载游戏
版本控制文件:
<!-- version.xml -->
<version>
<version>资源版本号</version>
<gameid>游戏标识</gameid>
<name>游戏名称</name>
</version>
微信SDK集成
项目集成微信开放平台SDK,支持登录、分享功能:
回调Activity配置:
<!-- 微信登录回调 -->
<activity
android:name=".wxapi.WXEntryActivity"
android:exported="true"
android:launchMode="singleTop" />
分享实现:
- 支持链接分享、图片分享、小程序分享
- 区分好友分享和朋友圈分享
- 抖音分享通过Intent方式实现
音视频功能
集成声网Agora SDK实现实时音视频通话:
基本功能:
- 语音房间创建/加入
- 实时语音通话
- 视频悬浮窗显示
- 音频录制播放
房间管理:
// 创建音视频房间
var roomConfig = {
"roomId": "房间ID",
"userId": "用户ID",
"token": "Agora Token",
"channelProfile": "COMMUNICATION"
};
定位服务
基于高德地图SDK实现精确定位:
定位模式:
- 连续定位:持续获取位置更新
- 单次定位:获取一次高精度位置
位置信息回调:
// 位置信息格式
{
"latitude": "31.12345", // 纬度
"longitude": "121.12345", // 经度
"accuracy": "15.0", // 精度(米)
"address": "详细地址",
"city": "城市名称",
"province": "省份"
}
API调用最佳实践
1. 错误处理
// 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. 生命周期管理
// 原生端生命周期处理
@Override
protected void onDestroy() {
super.onDestroy();
// 清理WebView
if(x5webview != null) {
x5webview.removeAllViews();
x5webview.destroy();
x5webview = null;
}
// 停止定位服务
if(locationClient != null) {
locationClient.stopLocation();
}
}
3. 内存优化
// WebView内存优化
public void optimizeWebView() {
// 清除缓存
x5webview.clearCache(true);
// 清除历史记录
x5webview.clearHistory();
// 暂停JavaScript执行
x5webview.onPause();
x5webview.pauseTimers();
}
4. 网络优化
// 网络状态监听
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调试
// 启用WebView调试模式
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
WebView.setWebContentsDebuggingEnabled(true);
}
在Chrome浏览器中访问 chrome://inspect 可以调试WebView内容。
JS Bridge测试
// 测试桥接连通性
function testBridge() {
if(typeof WebViewJavascriptBridge !== 'undefined') {
console.log('Bridge已就绪');
// 测试简单API调用
WebViewJavascriptBridge.callHandler('getTime', '', function(response) {
console.log('当前时间:', response);
});
} else {
console.error('Bridge未初始化');
}
}
性能监控
// 监控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页面集成示例
<!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>
原生端集成示例
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();
}
}
}
这个完整的集成示例展示了:
- 前端HTML页面如何初始化Bridge连接
- 如何注册监听原生回调
- 如何调用各种原生API
- 原生端如何注册Handler处理JS调用
- 如何实现完整的登录、分享、定位等功能流程
通过这个示例,开发者可以快速理解和集成TSGame的WebView与原生交互功能。
JS端调用原生方法示例
// 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方法示例
// 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);
注意事项
数据传递规范
- 数据格式: 所有传递的数据都是字符串格式,复杂数据需要JSON序列化
- 异步回调: 大部分API都支持异步回调机制
- 错误处理: 需要在JS和原生端都做好异常处理
- 线程安全: 原生端调用JS必须在主线程进行
- 生命周期: 注意WebView生命周期,避免内存泄漏
WebView与原生通信注意事项
- 消息队列: 使用消息队列机制确保数据不丢失
- 特殊字符转义: JSON字符串中的特殊字符需要转义处理
- 回调函数: 每个API调用可以包含一个回调函数
- 超时处理: 长时间无响应的API调用需要超时机制
性能优化建议
- 减少频繁调用: 避免在短时间内频繁调用原生API
- 数据压缩: 传递大量数据时考虑压缩或分批传输
- 内存管理: 及时释放不需要的WebView资源
- 缓存策略: 合理利用WebView缓存机制
安全性考虑
- 数据校验: 对JS传入的数据进行严格校验
- 权限控制: 敏感API需要权限检查
- 防注入: 防范恶意JS代码注入
- HTTPS通信: 敏感数据传输使用HTTPS
兼容性处理
- Android版本: 针对不同Android版本做适配
- 设备差异: 考虑不同设备的硬件差异
- WebView版本: 处理不同WebView内核版本的差异
- 网络环境: 适配不同网络环境下的功能表现
3. 主要Activity流转
weclomeactivity1 (启动页)
↓ (配置加载完成)
webviewActivity/NewwebviewActivity (主游戏页面)
↓ (外部链接)
openwebActivity1 (外部页面)
↓ (微信回调)
WXEntryActivity (微信相关)
4. 关键配置文件
version.xml (版本配置)
<version>
<version>1</version>
<gameid>game001</gameid>
<name>游戏名称</name>
</version>
app_data.js (运行时配置)
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权限配置
核心权限
<!-- 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" />
定位权限
<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" />
音频权限
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
其他权限
<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配置
<!-- 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
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
HarmonyOS权限配置
module.json5配置
{
"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权限申请
// 检查和申请权限
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权限申请
// 请求相机权限
- (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权限申请
// 申请权限
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
构建命令
# 调试版本
./gradlew assembleDebug
# 发布版本
./gradlew assembleRelease
# 清理项目
./gradlew clean
# 生成签名APK
./gradlew assembleRelease -Pandroid.injected.signing.store.file=keystore/gamehall.keystore
签名配置
// 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+
构建步骤
# 安装依赖
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
证书配置
<!-- 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+
构建步骤
# 清理项目
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
签名配置
// 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)
# .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接口:
// 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. 平台差异处理
// 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开发环境
# 安装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开发环境
# 安装Xcode (仅限macOS)
# 安装CocoaPods
sudo gem install cocoapods
# 创建项目
cd ios
pod init
pod install
open TSGame.xcworkspace
3. HarmonyOS开发环境
# 下载DevEco Studio
# 安装HarmonyOS SDK
# 创建项目
cd harmonyos
hvigorw assembleHap
代码复用策略
1. 共享Web资源
// 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. 平台抽象层
// 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特定的登录实现
}
}
// 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
// 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. 单元测试
// 跨平台测试用例
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. 集成测试
# test-plan.yml
test_scenarios:
- name: "登录流程测试"
platforms: ["android", "ios", "harmonyos"]
steps:
- "打开应用"
- "点击登录按钮"
- "验证登录结果"
- name: "分享功能测试"
platforms: ["android", "ios", "harmonyos"]
steps:
- "进入游戏页面"
- "点击分享按钮"
- "选择分享平台"
- "验证分享成功"
性能优化建议
1. WebView优化
// 通用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. 资源加载优化
// 预加载关键资源
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. 版本管理
// 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. 兼容性处理
// 版本兼容性检查
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;
}
}
项目总结与展望
技术特色
- 跨平台统一: 基于WebView + JS Bridge的跨平台解决方案
- 功能完备: 涵盖认证、分享、定位、音视频等完整功能
- 性能优化: 针对不同平台特性进行深度优化
- 易于维护: 统一的API接口和代码架构
适用场景
- 棋牌游戏: 完整的棋牌游戏解决方案
- 社交游戏: 支持实时音视频和社交分享
- 地方特色应用: 可快速适配不同地区需求
- 跨平台应用: 一套代码适配多个平台
开发优势
- 开发效率: H5游戏 + 原生能力,快速开发
- 维护成本: 统一的业务逻辑,降低维护成本
- 用户体验: 原生性能 + Web灵活性
- 迭代速度: 支持热更新,快速迭代
扩展方向
- 平台支持: 扩展到更多平台(Windows、Web)
- 技术升级: 升级到最新的SDK版本和技术栈
- 功能增强: 添加更多游戏类型和社交功能
- 性能优化: 进一步优化启动速度和运行性能
常见问题解答
Q: 如何在现有项目基础上开发iOS版本?
A:
- 复制
shared/目录下的所有Web资源 - 创建iOS项目,实现相同的JS Bridge接口
- 根据iOS平台特性调整权限配置和第三方SDK
- 参考本文档的iOS开发指南进行适配
Q: HarmonyOS版本开发有什么注意事项?
A:
- 使用ArkTS语言开发,语法类似TypeScript
- 权限管理更加严格,需要详细配置使用场景
- 部分第三方SDK可能需要寻找替代方案
- 遵循华为应用市场的审核规范
Q: 如何保证各平台功能一致性?
A:
- 使用统一的API接口定义
- 建立跨平台测试用例
- 定期进行功能对比测试
- 维护详细的功能兼容性文档
Q: 性能优化的重点是什么?
A:
- WebView初始化和资源加载优化
- JS Bridge通信效率优化
- 内存管理和垃圾回收优化
- 网络请求和数据缓存优化
技术支持
- 文档更新: 定期更新技术文档和API说明
- 问题反馈: 通过Issue跟踪和解决技术问题
- 技术交流: 建立开发者交流群组
- 版本发布: 提供稳定的版本发布和更新通知
文档版本: v2.0
更新时间: 2025年7月5日
适用版本: TSGame 3.6.3+
支持平台: Android、iOS、HarmonyOS
本文档为TSGame跨平台项目的完整技术说明,涵盖了项目架构、开发指南、API参考等所有必要信息。开发者可以基于本文档快速理解项目结构,并在任意支持的平台上实现相同功能的应用。