Files
youle_app_zhuoyitong/项目说明文档.md
2026-02-16 18:24:19 +08:00

71 KiB
Raw Permalink Blame History

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)

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

iOS启动流程

  1. 应用启动入口

    Info.plist → AppDelegate → TSMainViewController → TSWebViewController
    
  2. 初始化阶段 (AppDelegate.didFinishLaunchingWithOptions)

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

HarmonyOS启动流程

  1. 应用启动入口

    module.json5 → EntryAbility → Index.ets → WebView.ets
    
  2. 初始化阶段 (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端桥接脚本

消息传递流程:

  1. JS调用原生WebViewJavascriptBridge.callHandler(handlerName, data, callback)
  2. 消息序列化并添加到消息队列
  3. 通过loadUrl()触发原生方法flushMessageQueue()
  4. 原生端解析消息并调用对应的BridgeHandler
  5. 处理完成后通过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即可更新游戏内容

更新流程:

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

版本控制文件:

<!-- 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();
        }
    }
}

这个完整的集成示例展示了:

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

通过这个示例开发者可以快速理解和集成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);

注意事项

数据传递规范

  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 (版本配置)

<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;
  }
}

项目总结与展望

技术特色

  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参考等所有必要信息。开发者可以基于本文档快速理解项目结构并在任意支持的平台上实现相同功能的应用。