# 客户端app跳转微信小程序
# 接入示例
使用活动测试工具快速测试
# 安卓版调用代码示例
String appId = "平台的AppId"; // 填接入平台的移动应用(App)的 AppId,非小程序的 AppID
IWXAPI api = WXAPIFactory.createWXAPI(context, appId);
WXLaunchMiniProgram.Req req = new WXLaunchMiniProgram.Req();
req.userName = "gh_49af166706ae"; // 填腾讯游戏来联小程序原始id: gh_49af166706ae
req.path = "/pages/gameAccountBind/index?t=1591236939&gameIdList=lol,cjm&livePlatId=egame&sig=6e766f5017a737b82d99ae09b7b922da&faceUrl=http%3A%2F%2Fthirdqq.qlogo.cn%2Fg%3Fb%3Doidb%26k%3DgeNGjUqkHHLJdibhAaKycMQ%26s%3D100%26t%3D1483405761&nickName=%E6%96%97%E9%B1%BC%E6%98%B5%E7%A7%B0&redirectUrl=dydeeplink%3A%2F%2Fplatformapi%2FstartApp%3Ftype%3D37&code=25QY9rzaUK9vO0QYUHbNnNTkp0B4tRrmp%2BLog1LhBSYe6psYyShjUnUwzOa7t%2FwoP8RpzTYZICVTXwvNHgh7cg%3D%3D"; // 拉起小程序页面的带参路径,由basePath + queryString拼出
req.miniprogramType = WXLaunchMiniProgram.Req.MINIPTOGRAM_TYPE_RELEASE;// 可选打开 0-正式版,1-开发版,2-体验版
api.sendReq(req);
2
3
4
5
6
7
# 调用小程序相关参数
# 移动应用 appId
待接入的 app 在微信开放平台 (opens new window)注册时生成的 appid
以 腾讯游戏来联 APP 示例:
# 小程序原始 ID
gh_49af166706ae
(注:app 拉起时使用)
# 小程序 appId
wx707e2eb408780a5b
(注:小程序拉起时使用)
# 基础路径
basePath: /pages/gameAccountBind/index
# 调用的 queryString 参数
字段 | 字段说明 | 是否需要加入签名(sig) | 参数是否必填 |
---|---|---|---|
gameIdList | 游戏 id 列表,参考已接入业务 示例:cf,lol,yxzj | 是 | 是 |
livePlatId | 平台 id | 是 | 是 |
code | 包含 uid 的加密串,参考 平台侧构建code | 是 | 是 |
t | 时间戳 | 是 | 是 |
sig | 签名,参考《小程序绑定:生成拉起签名》 | 否 | 是 |
actId | 指活动 ID,在平台综合绑定中心入口不需要传该参数。但活动场景下为必传 | 否 | 是 |
faceUrl | 用户所在平台头像地址 | 否 | 是 |
nickName | 用户所在平台昵称 | 否 | 是 |
livePlatName | 对应小程序中返回 app 的按钮名称,不传的话显示默认名称(需要通知 腾讯游戏来联 侧添加相关映射) | 否 | 否 |
type | 跳转小程序的具体功能场景,如qqCoinDeliver,表示进入到Q币发放页面。详细类型参照《type类型》 | 否 | 否 |
nextFlow | 为发放真实Q币的流程id。若需引导用户到小程序内完成QB兑换,则此参数为必传参数, nextFlow参数中的值来自上一步发货接口的返回(注意:只有type为qqCoinDeliver时,此参数才有效。) | 否 | 否 |
gameAuthScene | 授权场景(对应不同的授权字段,活动场景为act_${actId} ,其他场景可咨询对接人员) | 是 | 否 |
hideQQLogin | 微信小程序内是否隐藏QQ登录模式; 不传默认为false, 传入true 表示后续隐藏QQ登录模式 | 否 | 否 |
fromId | 来源Id, 后续会在后台回调中带上该信息,长度限制为32,超过则丢弃 | 否 | 否 |
*注意1:不应传入多余的参数,最终生成的路径与参数的总长度不可超过1024,超过会被小程序底层逻辑截断 *注意2:所有参数均需 encode(编码)一次,编码规范参见encodeURIComponent (opens new window)。go语言中应使用url.PathEscape
方法**,其他语言类似。注意生成的参数其中不包含;,/?:@&=+$#
等参数
# type类型
qqCoinDeliver
: 跳转到Q币发放页面newGamePreorder
: 跳转到新游预约页面loginLauncherWithBind
: 跳转云游戏登录页面
# 小程序绑定:生成拉起签名
sig签名计算流程如下:
第一步:对基于特定参数:livePlatId、gameIdList、t、code和gameAuthScene(无授权场景时则该参数不参与计算签名)参数键名称部分使用ASCII排序。排序后,将键名对应的键值按顺序加入队列,假设队列名为array1。此时,队列中的值为排序后键值对应的实际值。
第二步:排序后对键值做URLENCODE,针对第一步队列中的值使用**+**链接。操作方式为: str1= implode("+", array1)。(js中implode替换为join)
编码补充: 为了了保持编码⼀一致性,腾讯后台侧使⽤用了了RFC 3986编码 规范,故在遇到空格字符时,该规范也会将单个空格变 成%20。而老一些的http encode使⽤用 RFC 1866规范,导致空格字符被编码为+号。
第三步:str1添加从腾讯游戏来联分配的key(每个平台有独立的key,如果遗忘可以联系腾讯游戏来联同学)。str1= str1+"+"+{key}。(注意是+号字符串)
第四步:计算签名。echo strtolower(md5(str1)),并转换成小写。
python实现签名示例代码如下:
#!/usr/bin/python
# -*- coding: UTF-8 -*-
import base64
import hashlib
import json
import time
import urllib
from urllib.parse import urlencode
import requests
from Crypto.Cipher import AES
from requests.utils import requote_uri
def _show_output(msg, title=''):
print("*****{}*****".format(title), end="\n")
print(msg, end="\n")
# AES ecb encrypt
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 = base64.b64encode(data) # 取消注释,输出Base64格式
return encrypt_data
# code计算,code用于加密用户UID信息
def _get_code(user_id, seckey):
_show_output("", "code计算")
login_info = {'userid': user_id, 'isAnchor': 0}
json_str = json.dumps(login_info)
_show_output(json_str, "code计算前先处理json部分")
ecb_data = _encrypt(json_str, seckey)
encrypt_str = str(ecb_data, 'utf-8')
_show_output(encrypt_str, 'code加密完成')
_show_output("https://oktools.net/aes", "ECB验证地址")
return encrypt_str
# 根据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, 'sig计算,需要在签名后携带中台分配的sigkey,如下')
return hashlib.new('md5', origin_str).hexdigest()
def get_sig_info(liveplat_id, gameIdList):
# 签名所需参数配置
_show_output("", "开始计算sig")
sign_info = {
"livePlatId": liveplat_id,
"gameIdList": gameIdList,
"t": int(time.time()),
"code": _get_code("1", seckey) # urlencode
}
# 按升序排序
sorted_string = _sorted_string(sign_info)
_show_output(sorted_string, '计算签名前先完成参数排序')
# 计算签名
sig = _get_md5(sorted_string, sigkey)
_show_output(sig, "md5结果")
# 最终参数
params = urllib.parse.urlencode(sign_info, quote_via=urllib.parse.quote) + "&sig=" + sig
_show_output(params, "最终结果")
return params
if __name__ == '__main__':
# sig签名计算
liveplat_id = "test"
sigkey = "YzJ6MqD1CT1z9aDr"
seckey = "udeval1ErioGc1F9"
gameIdList = "yxzj"
actID = '904'
get_sig_info(liveplat_id, gameIdList)
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
输出:
*****code计算前先处理json部分*****
{"userid": "1", "isAnchor": 0}
*****code加密完成*****
QwCF9dWRJG7EHkKEmnaCKn7eDhUgI1y/ByKrY+ctc6E=
*****ECB验证地址*****
https://oktools.net/aes
*****计算签名前先完成参数排序*****
QwCF9dWRJG7EHkKEmnaCKn7eDhUgI1y%2FByKrY%2Bctc6E%3D+yxzj+test+1702974479
*****sig计算,需要在签名后携带中台分配的sigkey,如下*****
b'QwCF9dWRJG7EHkKEmnaCKn7eDhUgI1y%2FByKrY%2Bctc6E%3D+yxzj+test+1702974479+YzJ6MqD1CT1z9aDr'
*****md5结果*****
18cc71c744c375d641f71671bbe42bdd
*****最终结果*****
livePlatId=test&gameIdList=yxzj&t=1702974479&code=QwCF9dWRJG7EHkKEmnaCKn7eDhUgI1y%2FByKrY%2Bctc6E%3D&sig=18cc71c744c375d641f71671bbe42bdd
2
3
4
5
6
7
8
9
10
11
12
13
14
其他语言sig计算可以参考接入SDK
# 返回 APP
用户完成角色绑定后,点击返回 APP 按钮,即可返回 APP,接入详情请参考返回说明 (opens new window)
返回时会将传递到小程序的 queryString 透传到 app
# 回调说明
WXEntryActivity 中
public void onResp(BaseResp resp) {
if (resp.getType() == ConstantsAPI.COMMAND_LAUNCH_WX_MINIPROGRAM) {
WXLaunchMiniProgram.Resp launchMiniProResp = (WXLaunchMiniProgram.Resp) resp;
String extraData =launchMiniProResp.extMsg; // 对应传递过来的queryString参数
}
}
2
3
4
5
6
# 绑定测试
绑定测试工具地址: https://livelink.qq.com/activities/#/testTool?activeName=bindCenter (opens new window)
隐私授权工具地址: https://livelink.qq.com/activities/#/testTool?activeName=gameDataAuth (opens new window)
# Q&A
# 安卓机器无法从小程序正常回跳到 app
解决方案:WXEntryActivity
中添加taskAffinity
属性,参见: https://www.jianshu.com/p/53cfb1b5995c (opens new window)
# 打开小程序报 bad_param 参数错误
解决方案: 检查 appID 为应用(app)的 appId, 检查 userName 为小程序(miniProgram)的原始 Id
# 提示应用安全检验不通过
自检流程: 1.不要同时调用SendReq和自检函数调用,自检函数会覆盖sendReq中的一些上下文数据,导致无法校验通过。 2. 上一次SendReq拉起微信完成操作前,不要再次调用sendReq。 后一次会覆盖前一次的上下文数据,导致检验不通过。 3. 确保拉起微信和微信跳回的App是同一个
# 应用第一次不能从小程序跳回app,第二次可以跳回
解决方案: 可以通过这个接口去注册一次来解决
public interface IWXAPI {
boolean registerApp(String var1); //应用App
}
2
3
← 接入指引 客户端app跳转QQ小程序 →