本文分享如何在H5/Web端实现在线抓娃娃机功能,Android和iOS端整体流程类似,具体可参考即构开发者相关文档。
娃娃机 web 端场景的主要结构及流程如下图所示:
请注意:
- 上图中的
用户选择上机
步骤,可使用 jZego.js SDK 拉流切换实现。 - **开发者注意区分
娃娃机 App 端
和娃娃机
**。前者指的是,提供给玩家抓娃娃的、安装在 iOS 或 Android 平台的 App。后者指的是,直接与娃娃机通过串口通信的、安装在 Android 平台上的 App,类似于娃娃机 Server。 - 为了便于开发者更快理解 WaWaJi Client 中的逻辑,下述每节会将功能核心源码片段挑出来并加以讲解。开发者亦可直接阅读 WaWaJi Client 源码,两者是一致的。
娃娃机系统实现流程
1、安装娃娃机控制端APK到安卓板子上
2、娃娃机启动,推流成功后,Zego后台会给业务后台POST 流创建的相关信息(业务后台提供回调地址),用于业务侧维护娃娃机列表
3、客户端的开发
娃娃机系统实现流程如下图所示。该方案中,娃娃机控制端无需与业务后台直接通信。
系统架构图
API 调用时序图
实现流程
通过config接口注入基本参数配置
//new 一个实例
var zg = new ZegoClient();
// 1.配置参数
zg.config({
appid: appid, // 必填,应用id,由即构分配
idName: idName, // 必填,用户自定义id
nickName: nickName, // 必填,用户自定义昵称
server: server // 必填,接入服务器地址, 由即构分配
logUrl: logUrl // 必填,logServer地址,由即构分配
});
登录房间
以下所有步骤均基于登录房间成功的前提
。WaWaJi Web 中相关源码片段如下,仅供参考:
// 2. 登录
zg.login(roomID, role, token, function(streamList){
// 登录成功回调
// code
}, function(err){
// 登录失败回调
// code
});
拉流
观众想看到娃娃机画面,需先拉流
WaWaJi Web 中拉流相关源码片段如下,仅供参考:
// 3. 初始化流 流信息可在登录成功回调函数中获得
// 得到流信息后,传入流ID和指定的原生canvas元素,播放与该ID对应的视频流
// 正面
zg.startPlayingStream(useStreamList[0].stream_id, frontView);
// 正面流音量设置为最大
zg.setPlayVolume(useStreamList[0].stream_id, 100);
// 侧面
zg.startPlayingStream(useStreamList[1].stream_id, sideview);
// 侧面流音量设置为静音
zg.setPlayVolume(useStreamList[1].stream_id, 0);
- 调用
stopPlayingStream
停止播放指定流 - 调用
startPlayingStream
重新播放指定流
请注意:
- 目前 WaWaJi Web 使用的方案是,进入房间后,创建两个 view 分别播放两条流数据,用户可通过手动切换 view,继而切换当前可见流。
- 这里需要注意的是,如果某一条流从可见切换为不可见,需要调用
setPlayVolume
改变流播放声音为无声,否则可能造成流画面和流声音混乱的情况。反之亦然。
发送指令
用户需要调用 sendCustomCommand
接口发送指令给娃娃机(此处的娃娃机,指的是控制娃娃机硬件的 Server 端,后面简称为娃娃机),娃娃机收到指令后,做出对应的响应。
请注意,此处指令是发送给娃娃机控制端,而不是房间里的其他玩家或自己。
WaWaJi Web 中发出指令相关源码片段如下,仅供参考:
zg.sendCustomCommand(
[anchor_id],
custom_msg,
function(seq, custom_content){
console.log('customCMD 成功', custom_content);
},
function(err, seq, custom_content) {
console.log('customCMD 失败', custom_content);
}
);
娃娃机客户端与控制端信令交互流程请参考:娃娃机-信令交互
接收指令
WaWaJi Web 端可以通过 onRecvCustomCommand
接受娃娃机返回的命令:
// 接收消息接口
zg.onRecvCustomCommand = function(from_userid, from_idName, custom_content) {
// code
})
退出
如果用户不再进行游戏,退出当前的娃娃机房间,注意调用退出房间,确保停止拉流,并清空状态。
WaWaJi Client 中退出房间相关源码片段如下,仅供参考:
// 登出
zg.stopPlayingStream(useStreamList[1].stream_id);
zg.stopPlayingStream(useStreamList[0].stream_id);
zg.logout()
安全方案
娃娃机房间登录安全
1 基本流程
- App与业务后台建立通讯,获取Token信息
- App调用ZegoClient.Login登陆Zego服务器,传入Token信息,验证通过后,完成登陆。
- 之后ZegoClient保持与Zego服务器的长连接,处理发送或接收的消息
- App调用ZegoClient.Logout登出Zego服务器
2 login_token信息
- login_token信息为标准json格式,具体为:
{
“ver": 1, //int类型
"hash": 710a5199398176a316ebcc88bc5b4470, //字符串类型
“nonce": 随机串,需要保证同一USER_ID在失效时间内不重复, 建议按guid生成, //字符串类型
"expired": 失效时间,unix_timestamp //int64类型,单位秒
}
- login_token信息由业务后台负责,其中hash的生成算法如下: hash=MD5(app_id+app_key_32+id_name+nonce+expired)。
app_key_32: 通过app_key运算获得。
算法:剔除app_key里的"0x", ","字符后,获取前面32字节即为app_key_32(具体算法可参考以下代码)
id_name:为客户登录时候传入的字符串用户id
nonce: 一次性随机字符串串
expired: 过期时间- login_token传输过程中,经过base64加密。
- 每次登陆都要重新获取login_token
- go语言login_token生成示例代码
func makeTokenSample(appid uint32, app_key string, idname string, expired_add int64) (ret string, err error){
nonce := UniqueId()
expired := time.Now().Unix() + expired_add //单位:秒
app_key = strings.Replace(app_key, "0x","",-1)
app_key = strings.Replace(app_key, ",", "", -1)
if len(app_key) < 32 {
return "", fmt.Errorf("app_key wrong")
}
app_key_32 := app_key[0:32]
source := fmt.Sprintf("%d%s%s%s%d",appid,app_key_32,idname,nonce,expired)
sum := GetMd5String(source)
token := tokenInfo{}
token.Ver = 1
token.Hash = sum
token.Nonce = nonce
token.Expired = expired
buf, err := json.Marshal(token)
if err != nil {
return "", err
}
encodeString := base64.StdEncoding.EncodeToString(buf)
return encodeString, nil
}
// 获取MD5加密
func GetMd5String(s string) string {
h := md5.New()
h.Write([]byte(s))
return hex.EncodeToString(h.Sum(nil))
}
- php语言login_token生成示例代码
public function getToken(int $app_id, string $app_key, string $idname, int $expired_add)
{
$nonce = uniqid();
$expired = time() + $expired_add; //单位:秒
$app_key = str_replace("0x", "", $app_key);
$app_key = str_replace(",", "", $app_key);
if(strlen($app_key) < 32) {
return false;
}
$app_key_32 = substr($app_key, 0, 32);
$source = $app_id.$app_key_32.$idname.$nonce.$expired;
$sum = md5($source);
$tokenInfo = [
'ver' => 1,
'hash' => $sum,
'nonce' => $nonce,
'expired' => $expired,
];
$token = base64_encode(json_encode($tokenInfo));
return $token;
}
- 如何保证获取Token信息的过程是安全的? 业务APP需要和业务后台建立一种安全通讯和鉴权机制,业务APP使用自有的账户体系/第三方认证体系的登陆完成后,业务APP和业务后台交互获取该login_token, AppSecret是存储在业务后台的。
娃娃机信令安全
1 问题
- 娃娃机信令是指App通过ZegoClient.sendCustomCommand的接口发送娃娃机的控制命令,包括上机前或者上机过程如何确保控制是被授权过的?比如支付环节过程,娃娃机接受控制请求,需要确保用户已经完成支付。
2 解决方案
- 对custom_msg进行鉴权,对ZEGO透明
- 对custom_msg进行鉴权的一种方案是在msg中携带token, Zego负责透传,业务方负责生成和验证
3 基本流程-App
- App成功登陆之后与娃娃机通讯可以建立msg_token进行消息验证。(如支付验证流程)
- App与业务后台建立通讯,实现自己msg_token获取策略, token生成机制和更新策略对ZEGO透明。
- App调用ZegoClient.sendCustomCommand,传入携带token的msg, Zego服务负责发送到娃娃机。
- 娃娃机收到msg对msg_token进行鉴权,通过后执行请求命令,具体哪些命令需要鉴权,App可以自行决定。
4 如何保证获取msg_token的过程是安全的
msg_token对Zego是透明的,由业务设计具体方案去实施,对于业务APP很自然的方案是在业务APP使用自有的账户体系/第三方认证体系的登陆完成后,业务APP和业务后台交互获取和更新该Token.
安全验证
本文为原创稿件,版权归作者所有,如需转载,请注明出处:https://www.nxrte.com/jishu/8794.html