# 调用指引
# 说明
本指引旨在详细阐述合作平台与游戏侧进行数据通信的流程,包括但不限于游戏数据拉取、平台数据上报、用户发货请求等操作。通过遵循本指引,合作平台能够确保与腾讯游戏来联侧的数据交互准确、高效且安全。
# 网关地址:
https://s1.livelink.qq.com/livelink
# 请求示例
以下是一个调用活动流程的示例,用于获取用户参与数据。其中,立项的活动ID为1201,游戏ID为cf。活动中由腾讯游戏来联运营人员配置的流程ID为69f33ur0。
请求类型:application/json
curl "https://s1.livelink.qq.com/livelink/?apiName=ApiRequest&actId=1201&livePlatId=xxx&gameId=cf&v=2.0&t=1710832329&nonce=urdszl&code=ikGRKGbjKrv86QU3UYlSPQ1rLUlTYFf1v3h2WJUpuNEZi%2B%2BXrkBwkfx0kLnCXXYYjcI%2B%2FumZHGvxlMIU1I51YtAtFO2KRg35KGA%2FG6ovKA3GLJ6tMcaUo8HHECD%2F1ULT&sig=187d8c99c79850b7c20d68799c3988fa" -d '{"flowId":"69f33ur0"}'
1
# 公共参数(GET)
以下是请求中必须携带的公共参数,主要用于确保请求的安全性。
apiName=ApiRequest&actId=1201&livePlatId=xxx&gameId=cf&v=2.0&t=1710832329&nonce=urdszl&code=ikGRKGbjKrv86QU3UYlSPQ1rLUlTYFf1v3h2WJUpuNEZi%2B%2BXrkBwkfx0kLnCXXYYjcI%2B%2FumZHGvxlMIU1I51YtAtFO2KRg35KGA%2FG6ovKA3GLJ6tMcaUo8HHECD%2F1ULT&sig=187d8c99c79850b7c20d68799c3988fa
1
参数 | 参与签名 | 必填 | 类型 | 说明 |
---|---|---|---|---|
apiName | 否 | 是 | string | 请求方式。当前支持的请求方式包括:ApiRequest, FlowTaskQuery等。 |
livePlatId | 是 | 是 | string | 平台ID,由腾讯游戏来联统一分配。 |
actId | 是 | 是 | int | 活动ID。具体如何生成和查看活动ID请参考相关文档。 如何生成活动ID 如何查看活动列表 (opens new window) |
gameId | 是 | 是 | string | 游戏ID(gameID)。见《业务代码》 |
v | 是 | 是 | float | 版本号,当前场景默认填写:2.0 |
t | 是 | 是 | int | Unix时间戳,精度:秒 |
nonce | 是 | 是 | string | 8位随机字符串,范围为[a-zA-Z0-9]。,范围[a-zA-Z0-9] |
code | 是 | 是 | string | 用户登录态。平台侧参考《平台侧接入》。见下文Demo:_get_code 函数 |
sig | 否 | 是 | string | 签名,见《加密与签名》。见下文Demo:get_sig_info |
# 私有参数(json)
私有参数用于流程相关调用参数的填充。以下是支持的参数及其说明。
参数 | 必填 | 类型 | 说明 |
---|---|---|---|
flowId | 是 | string | 流程id,必填项。由腾讯游戏来联在配置接口时生成。请确保填写正确,否则调用将无法成功。 |
serialCode | 否 | string | 选填项,用于请求防重。建议填写以提高数据一致性。如果为空,则每次都会发起新的请求处理。 |
anchorId | 否 | string | 选填项,主播id。如果填写,可以与特定主播的流程相关联。 |
serialCode
是一个重要的可选参数,用于防止外部网络请求中的重复处理。由于外网环境的不稳定性,合作平台与腾讯游戏之间的网络请求可能无法每次都正常到达。为了保证数据的一致性,我们添加了serialCode
字段。通过此字段,您可以多次重复尝试请求,以解决外网访问可能出现的超时问题。我们强烈建议您在使用接口时填写此字段。
# 请求示例
curl "https://s1.livelink.qq.com/livelink/?
apiName=ApiRequest&livePlatId=egame&actId=1201&gameId=cf&v=2.0&t=&nonce=&code=diVa28UpyL5G%2BVmKNVIcg%3D%3D&sig=e3909d0a2cb7f7d8f2ec03fb4ea96007" -d '{"flowId":"69f33ur0"}'
1
2
2
# 接口返回
{
"iRet": 0,
"apiName": "{接口ID}", // 当前处理输出的模块ID
"v":2,
"jData": {
// 每个模块ID输出结构固定
},
"sMsg": "ok",
"tid": "174591110042135028"
}
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
# 返回说明
参数 | 类型 | 说明 |
---|---|---|
iRet | int | 接口状态码,0-正常,非0-错误 |
v | int | 协议版本号,当前协议版本为2 |
apiName | string | 用于输出的模块名称 |
jData | int | 具体结构依赖apiName,详见《接口标准返回》 |
# 接口标准返回(持续迭代)
接口ID | 接口名称 | 使用说明 |
---|---|---|
ApiActList | 活动列表获取 | 获取平台在腾讯游戏来联上的立项活动列表 |
ApiDoc | 活动详情获取 | 获取单个活动id的配置信息,包含流程列表,流程描述,以及其他流程配置属性 |
ApiGameList | 获取游戏列表 | 获取腾讯游戏来联侧已支持的游戏列表信息 |
GetBindInfo | 用户绑定查询 | 读取平台用户绑定过的游戏角色信息 |
ActBind | 绑定用户与活动关系 | 固定用户参与该活动的绑定信息 |
GetActBind | 查询用户在活动中的绑定信息 | 读取平台用户在禁止换绑活动绑定的游戏角色信息 |
Output | 标准化返回 | 通用标准化输出 |
Error | 接口异常 | 通用异常判定 |
ApiActionActQuas | 查询活动流程资格 | 查询指定活动下某个流程的用户资格 |
JFCloud | 云积分查询 | 查询用户云积分信息,包含总积分与可用积分 |
Lottery | 道具发放(抽奖/领取) | 通用道具发放返回信息 |
FlowTaskQuery | 流程条件判定 | 快速判定用户是否满足流程信息,仅仅返回bool类型 |
FlowConditionQuery | 输出条件信息 | 输出用户在流程条件中的数字信息 |
LotteryRecord | 输出用户抽奖领取记录 | 输出用户角色在腾讯礼包单中的领取记录信息 |
# Demo:发起请求
#!/usr/bin/python
# -*- coding: UTF-8 -*-
from typing import Match
import requests
import time
import random
import string
import json
from Crypto.Cipher import AES
import urllib
import hashlib
from urllib.parse import urlencode, quote_plus
import binascii
import base64
def _show_output(msg,title=''):
print("*****{}*****".format(title),end="\n")
print(msg,end="\n\n")
def _encrypt(data, password):
if isinstance(password, str):
password = password.encode('utf8')
bs = AES.block_size
pad = lambda s: s + (bs - len(s) % bs) * chr(bs - len(s) % bs)
cipher = AES.new(password, AES.MODE_ECB)
data = cipher.encrypt(pad(data).encode('utf8'))
encrypt_data = binascii.b2a_hex(data) # 输出hex
encrypt_data = base64.b64encode(data) # 取消注释,输出Base64格式
return encrypt_data
## code 加密计算
def _get_code(user_id, seckey):
# test login_info = {'userid':'000311'}
login_info = {'userid': user_id, 'isAnchor': 0}
json_str = json.dumps(login_info)
ecb_data = _encrypt(json_str,seckey)
_show_output(ecb_data,'code加密完成')
return str( ecb_data,'utf-8')
# 根据key升序排序后生成query string
def _sorted_string(target_dict):
sorted_vk = []
for i in sorted(target_dict.keys()):
k = i
v = urllib.parse.quote( str(target_dict[k]), safe="")
sorted_vk.append(v)
sorted_string = '+'.join(sorted_vk)
return sorted_string
def _get_md5(stored_string, sigkey):
origin_str = (stored_string + '+'+sigkey).encode(encoding='utf-8')
_show_output(origin_str,'计算md5')
return hashlib.new('md5', origin_str).hexdigest()
# sig 计算
def get_sig_info(act_id,user_id, seckey, sigkey):
sign_info = {}
sign_info["livePlatId"] = liveplat_id
sign_info["gameId"] = game_id
sign_info["v"] = 2.0
sign_info["t"] = int( time.time() )
sign_info["nonce"] = ''.join(random.choice(
string.ascii_lowercase) for _ in range(6))
sign_info["code"] = _get_code(user_id, seckey)
sign_info['actId'] = act_id
# 按key升序排序
sorted_string = _sorted_string(sign_info)
_show_output(sorted_string,'计算签名')
sig = _get_md5(sorted_string, sigkey)
# 最终参数
params = urllib.parse.urlencode(sign_info,quote_via=urllib.parse.quote) + "&sig="+sig
return params
# 读取接口返回结构
def main_return_hanlder(ret_str):
json_obj = json.loads(ret_str)
# 读取apiname确定返回是来自那种模块,更多apiname参考文档《2.0协议版本说明》
apiname = json_obj['apiName']
# 如果是报错,则apiname为Error模块,可直接输出Msg错误信息,也可以捕获iRet之后结合《全局返回码》自定义错误信息
if apiname =="Error":
print(json_obj['sMsg'])
return
# 接口为报错,模块数据存在jData下
data = json_obj['jData']
# 根据不同模块处理不同的返回
if apiname == "Lottery":
print("恭喜您获得了:"+data['packageName'])
# 若是采用默认腾讯游戏来联返回,可直接弹出msg部分
print(data['message'])
return
if apiname == "JFCloud":
print("用户当前总积分为:"+ data['all']+",剩余积分为:"+data['left'])
return
# 请求流程测试
if __name__ == '__main__':
# 平台配置
liveplat_id = "tencent"
sigkey = "ertyuiopasdfghjl"
seckey = "JHyuxq123xhtgwdc"
# 游戏活动配置
game_id = "cf"
# 参与活动的平台用户ID,且该用户UID已完成与游戏角色的绑定,这里是cf活动
user_id = "1234567"
# 腾讯游戏来联平台活动立项ID
act_id = 790
# 活动流程ID
flow_id = 'v0wgv6yb'
request_params = get_sig_info(act_id,user_id, seckey, sigkey)
headers={'Content-Type': 'application/json'}
url = 'https://s1.livelink.qq.com/livelink/?apiName=ApiRequest&{}'.format(http_prefix,ip,request_params)
_show_output(url,'开始http请求')
rsp = requests.post(url, data=json.dumps({"flowId": flow_id}), headers={
'Content-Type': 'application/json'})
print(rsp.text)
# 返回值处理
main_return_hanlder(rsp.text)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127