# 微信小游戏JSSDK

为了更好地帮助游戏开发商(以下简称CP)发行微信小游戏,翘蛙网络提供小游戏客户端SDK来帮助CP快速接入微信小游戏登录、支付等能力。CP研发只需要参照本文档指引完成SDK接入即可快速使用SDK提供的相关能力。

# 接入准备

接入发行SDK前需完成如下前置工作:

# 添加服务器域名

参照服务器域名配置文档 (opens new window)添加https://api.mcfrogtech.com到request合法域名。

# 开启消息推送

如果要接入发行SDK提供的支付能力,小游戏必须开通消息推送能力。参考消息推送文档 (opens new window)在小游戏后台打开消息推送开关并设置通知服务器地址为https://api.mcfrogtech.com/minigame/customer并设置消息加密方式为明文模式,当前发行SDK没有实现消息加密,如有消息加密诉求,请联系发行对接技术。

# 提供小游戏ID和密钥

CP需要提供小游戏ID(AppID)和密钥(AppSecret)给发行对接技术人员,为了安全起见,SDK会将密钥存储在服务端,不会在客户端存储。AppID和AppSecret获取方式参考文档 (opens new window)

# 下载SDK

发行SDK下载方式:

// 以下是最新版本下载地址,其他版本可以查看发版记录,建议始终下载最新版本
curl https://static.mcfrogtech.com/minigame-sdk/wx/mcfrogtech-sdk.1.0.1.js -o mcfrogtech-sdk.js

版本记录:

  • 1.0.0-beta.6 支持自定义打开客服会话带入的小程序消息。
  • 1.0.0-beta.5 修复一些已知问题。
  • 1.0.0-beta.4 支付结果支持客户端状态回调。
  • 1.0.0-beta.3 广告数据改为手动上报,自动上报暂停使用。
  • 1.0.0-beta.2 提供转化分析能力。
  • 1.0.0-beta.1 修改library export方式,支持直接require,不需要加default。
  • 1.0.0-beta.0 第一个版本的用户测试版。这个版本用require语法引入时需要需要注意需要使用require().default,原因是开发SDK用的es6语法,编译成SDK使用的commonjs2,默认输出挂在default上了。之后的版本已修复。

# 初始化SDK

下载完SDK后,在小游戏入口文件(一般是game.js)引入SDK,并在小游戏业务逻辑初始化之前调用init方法完成初SDK始化:

// 下载完SDK后直接引入本地文件
const wxAppSdk = requrie('local/path/to/wxminigame-sdk.js');

wxAppSdk.init({
  appId: <your wx minigame appId>,
});

SDK提供的init方法说明如下:

# 方法定义

interface InitOptions {
  appId: string;
}

function init(options: InitOptions): void;

# 参数介绍

属性 类型 默认值 必填 说明
appId string 小游戏appId

# 返回值介绍

init方法返回值为void。

# 登录

SDK接入了微信官方登录能力,CP研发只需要调用SDK提供的登录方法即可实现用户无感登录并获取发行平台对应的user_id和access_token。登录方法调用方式说明如下:

# 方法定义

interface LoginData {
  access_token: string;
  user_id: string;
}

function login(): Promise<LoginData> 

# 参数介绍

void,无需传参。

# 返回值介绍

返回一个Promise对象,Promise对象返回值包含的属性说明如下:

属性 类型 默认值 必填 说明
access_token string 访问验证token。直接请求发行平台服务端API需要带上,具体携带方式下文会介绍。
user_id string 发行平台定义的用户id。CP研发可以用来映射业务用户id。

# 调用示例

wxAppSdk.login().then(({ access_token, user_id }) => {
  console.log(access_token, user_id);
}).catch((e) => {
  console.error(e);
});

# access_token使用

SDK提供了小游戏无感登录能力,登录成功之后会返回access_token和user_id。access_token是调用发行服务端API的凭证,必须通过HTTP请求头‘Authorization’来传递access_token给服务端API,具体格式如下:

// 注意Bearer后面有一个英文空格
Authorization: Bearer [access_token]

需要注意的是,access_token具有时效性,过期之后服务端API会返回状态码为401的响应,此时需要调用SDK登录方法重新登录获取新的access_token。user_id是SDK内部定义的一个用户唯一id,CP研发可以依据这个id来生成或者映射自己业务对应的用户id。

# 广告行为上报

目前由于一些技术问题,SDK无法自动收集用户广告行为,因此,为了更好地帮助小游戏进行推广,需要CP方上报用户广告关键行为给SDK。

# 方法定义

enum AdTraceName {
  // 创建广告
  CreateAd = 'create_ad',
  // 加载广告
  LoadAd = 'load_ad',
  // 曝光广告
  ShowAd = 'show_ad',
  // 关闭广告
  CloseAd = 'close_ad',
  // 隐藏广告
  HideAd = 'hide_ad'
}

enum WxAdTypes {
  // 激励视频广告
  RewardedVideo = 'rewarded_video',
  // 插屏广告
  Interstitial = 'interstitial',
  // banner广告
  Banner = 'banner',
  // grid广告
  Grid = 'grid',
  // 原生模板广告
  Custom = 'custom',
}

interface WxAdTraceData {
  // 广告单元 id
  unitId: string;
  // 广告类型
  type: WxAdType;
}

function reportAdTrace(adTraceName: AdTraceName, params: WxAdTraceData): void;

# 参数介绍

参数 类型 默认值 必填 说明
adTraceName AdTraceName枚举 广告行为事件名称,创建、加载、曝光、关闭、隐藏分别对应create_adload_adshow_adclose_adhide_ad
params WxAdTraceData 广告行为对应数据,unitId字段上报广告单元id,type字段上报广告类型,取值为rewarded_video(激励视频广告)、interstitial(插屏广告)、banner(banner广告)、grid(grid广告)、custom(原生模板广告)。

# 返回值介绍

void

# 调用示例

wxAppSdk.reportAdTrace('create_ad', {
  unitId: 'testunitId',
  type: 'rewarded_video',
});

# 调用须知

尽量上报全创建、加载、曝光、关闭、隐藏这五类事件,以便于精确的分析用户行为,更有利于投放

# 支付

发行SDK接入了支付能力,CP研发可以直接调用,无需重复开发。在android系统上SDK直接调用微信官方提供的虚拟支付 (opens new window)能力来完成支付。在ios系统上,SDK通过推送客服消息的形式来引导用户完成H5支付 (opens new window)。SDK提供了支付结果通知能力,通过API回调的形式通知CP后台订单支付结果。

# 方法定义

interface PaymentParams {
  // 虚拟物品名称
  name: string;
  // 小游戏运行系统
  // android采用微信官方虚拟支付进行支付
  // ios采用跳H5的方式进行支付
  platform: 'android' | 'ios';
  // 购买数量
  quantity: number;
  // 虚拟商品单价,单位为分
  unitPrice: number;
  // CP业务订单id
  cpOrderId: string;
  // 支付结果回调地址。填入CP小游戏服务端接受支付结果回调的API地址
  notifyUrl: string;
  // 在米大师侧申请的应用id
  offerId: string;
  // 虚拟支付环境,沙箱或者正式环境,0表示正式环境,1表示沙箱环境,默认为0
  env?: 0 | 1;
  // 虚拟支付分区ID
  zoneId?: string;
  // 虚拟支付分区名称
  zoneName?: string;
  // 本次支付描述,如果为ios支付,则会展示在客服消息支付卡片上
  description?: string;
  // 配置ios支付客服自动回复的卡片消息的标题,默认为"点击充值"
  title?: string;
  // 配置ios支付客服自动回复的卡片消息展示的缩略图的链接
  thumbUrl?: string;
  // H5支付时打开客服会话带入的消息卡片标题
  sendMessageTitle?: string;
  // H5支付时打开客服会话带入的消息卡片路径
  sendMessagePath?: string;
  // H5支付时打开客服会话带入的消息卡片图片路径
  sendMessageImg?: string;
}

interface PaymentResponse {
  // 发行平台内部订单id
  sdkOrderId: string;
}

function requestPayment(params: PaymentParams): Promise<PaymentResponse>;

# 参数介绍

参数 类型 默认值 必填 说明
name string 虚拟物品名称,比如“钻石”。
platform string 小游戏运行系统,"android"表示安卓系统,"ios"表示ios系统。
quantity number 虚拟商品购买数量。按照微信小游戏虚拟支付规则,quantity 不可任意填写。需满足 quantity * 单价 = 限定的价格等级。当前限定价格等级(单位:元):1、3、6、8、12、18、25、30、40、45、50、60、68、73、78、88、98、108、118、128、148、168、188、198、328、648、998、1998、2998。如果游戏币单价为 0.1 元,那么一次可购买的最少数量是 10。
unitPrice number 虚拟商品单价,单位为
cpOrderId string CP方业务订单id。
notifyUrl string 支付结果回调地址。填入CP小游戏服务端接受支付结果回调的API地址。
offerId string 在米大师侧申请的应用id。
env number 0 虚拟支付环境。沙箱或者正式环境,0表示正式环境, 1 表示沙箱环境,默认为 0 。测试时可以用沙箱环境,正式版本使用正式环境。
zoneId string "1" 虚拟支付分区ID。
zoneName string "默认分区" 虚拟支付分区名称。
description string "" 本次支付描述,如果为ios支付,则会展示在客服消息支付卡片上。
title string "" 配置ios支付客服自动回复的卡片消息的标题,默认为"点击充值"。
thumbUrl string "" 配置ios支付客服自动回复的卡片消息展示的缩略图的链接。
sendMessageTitle string "" H5支付时打开客服会话带入的消息卡片标题。
sendMessagePath string "" H5支付时打开客服会话带入的消息卡片路径。
sendMessageImg string "" H5支付时打开客服会话带入的消息卡片图片路径。

# 返回值介绍

返回一个Promise对象,Promise对象返回值包含的属性说明如下:

参数 类型 默认值 必填 说明
sdkOrderId string 发行平台内部的订单id。

# 调用示例

举个例子,某个CP研发的小游戏提供充值购买钻石的能力,并且1元钱可以购买10个钻石,小游戏使用默认分区。用户在小游戏内购买300个钻石,CP研发在获取业务订单id后,调用requestPayment方法完成安卓系统上虚拟支付:

const pay = async () => {
  const {sdkOrderId} = await wxAppSdk.requestPayment({
    platform: 'android',
    quantity: 300,
    cpOrderId: 'testcporderId',
    name: "钻石",
    offerId: "testofferid",
    unitPrice: 10,
  });
  return sdkOrderId;
};

pay();

调用requestPayment完成ios系统上跳转支付:

const pay = async () => {
  const {sdkOrderId} = await wxAppSdk.requestPayment({
    platform: 'ios',
    quantity: 300,
    cpOrderId: 'testcporderId',
    name: "钻石",
    offerId: "testofferid",
    unitPrice: 10,
  });
  return sdkOrderId;
};

pay();

# 支付流程

# 虚拟支付

使用SDK完成android虚拟支付的一个典型时序图如下,CP研发可以参考时序图理解SDK在android虚拟支付流程中扮演的角色和作用。

uml diagram

# H5支付

参考JSAPI支付 (opens new window)

# 支付结果回调

为了防止由于用户小游戏客户端问题可能造成的小游戏客户端支付成功回调无法执行或者失败的情况,发行平台提供了服务端API回调的能力。CP研发可以将CP接受支付结果通知的url通过requestPayment方法的notifyUrl参数传递给支付平台,notifyUrl格式以及回调方式和参数如下:

# notifyUrl格式
// 必须使用https协议
https://[your api]
# 回调方式

发行平台后端会以POST请求的方式将如下参数以JSON数据格式回调给CP指定的API:

参数 类型 说明
sdk_order_id string 发行平台内部的订单id。
cp_order_id string CP传递过来的业务订单id。
sdk_user_id string 发行平台内部用户id
platform string 小游戏平台。"android"表示安卓系统,"ios"表示ios系统
price number 支付金额。单位为"分"
status string 订单状态, 创建: "CREATED", 成功: "SUCCEEDED", 失败: "FAILED"
nonce_str string 随机字符串
sign string 签名。为了防止回调参数被篡改,发行平台会对回调参数进行签名。CP方接受到回调参数后需要验证签名的合法性。如果签名验证不通过,则回调数据不合法。签名算法参考下文介绍。

CP接收到回调后,一定要校验签名是否正确并且保证回调的金额和CP存储的对应订单金额是一致的,校验无问题,必须在10s内响应字符串"success"给发行服务标识CP正确收到回调。

# 签名算法

签名生成的通用步骤如下:
第一步,设所有发送或者接收到的数据为集合M,将集合M内非空参数值的参数按照参数名ASCII码从小到大排序(字典序),使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串stringA。
特别注意以下重要规则:

  • 参数名ASCII码从小到大排序(字典序);
  • 如果参数的值为空字符则不参与签名;
  • 参数名区分大小写;
  • CP验证回调信息或发行平台主动通知签名时,传送的sign参数不参与签名,将生成的签名与该sign值作校验。

第二步,对stringA进行MD5运算,再将得到结果以十六进制的的字符串格式输出,将所有字符转换为大写,得到sign值signValue。

举例:
假设传送的参数如下:

{
  sdk_order_id: '121212131313131313',
  cp_order_id: 'fewfhjjwhfewhfhewfhwehf',
  sdk_user_id: '13213-231241-423423-4234',
  platform: 'android',
  price: 10000,
  status: 'SUCCEEDED'
  nonce_str: '1213213123dadqdqw3'
}

第一步:对参数按照key=value的格式,注意如果参数值为空则不参与计算,并按照参数名ASCII字典序排序如下:

ascStr = "cp_order_id=fewfhjjwhfewhfhewfhwehf&nonce_str=1213213123dadqdqw3&platform=android&price=10000&sdk_order_id=121212131313131313&sdk_user_id=13213-231241-423423-4234&status=SUCCEEDED"

第二步:计算MD5值signValue。

signValue = MD5(ascStr).toUpperCase();

最终发送的数据:

{
  sdk_order_id: '121212131313131313',
  order_id: 'fewfhjjwhfewhfhewfhwehf',
  sdk_user_id: '13213-231241-423423-4234',
  platform: 'android',
  price: 10000,
  status: 'SUCCEEDED',
  nonce_str: '1213213123dadqdqw3',
  sign: 'signValue'
}

需要注意的是,发行服务器在将支付结果消息发给CP回调API之后,如果10s内收不到响应会断掉连接,并且重新发起请求,总共重试三次,重试间隔依次是10s/20s/40s。

# 服务端API

注意,直接调用API需要在请求头中携带access_token,具体方式详见上文关于access_token的介绍。

# 订单查询

为了防止由于网络或者服务问题导致的支付结果回调失败的问题,平台提供了订单状态查询API来让CP主动查询订单状态。

# API名

https://api.mcfrogtech.com/minigame/pay/orderquery

# 调用方式

POST

# 请求参数

参数 类型 默认值 必填 说明
sdk_order_id string 发行平台内部的订单id。

# 响应参数

参数 类型 默认值 必填 说明
code number 状态码,0表示成功,-1表示失败。
message string 消息。
data {status: string} 响应数据。status表示订单状态,取值参考参考上文相关介绍。