游戏家联盟

RankPaySdk 接入与接口文档

SDK 1.0.0 合并版 · 2026-11-05
RankPaySdk · Integration & API Reference

RankPaySdk 接入与接口文档

面向游戏宿主(Android原生)的接入指南,以及面向合作方服务端的 CP API 接口说明。

  • SDK 版本 1.0.0(versionCode 10000)
  • minSdk 21 / compileSdk 33
  • 正式域名 https://sdkapi.rankrank.com
  • CP 接口 4 个(3 GET + 1 POST)
  • Apifox 共享文档 https://uf5xm7yovl.apifox.cn/ · 密码 MtwIowMA
第一部分

客户端接入指南(Android 原生宿主)

RankPaySdk 1.0.0 的宿主接入主链路:环境依赖、初始化、登录、实名、支付、角色上报、分包与出包检查清单。

RankPaySdk 接入文档

面向游戏宿主(Android 原生)的接入指南。SDK 版本 1.0.0(versionCode 10000)。

1. 概览

RankPaySdk 是渠道支付 SDK,一个 AAR 提供:账号(验证码/密码登录、令牌维护、注销)、实名认证、下单与收银台拉起(微信 / 支付宝 / H5)、商品与订单查询、角色当前态上报(等级/VIP/战力/公会,见 6.9b)、游戏内悬浮球。本文只展开接入主链路:登录、支付、分包。

i
同一个 AAR 里还有广告变现上报(getAdSlots / reportAdWatched)与数据埋点(refreshEventDict / track / flushEvents),本文不展开:这两块要接入时向 SDK 维护人索取接口说明,别自己按方法名猜语义。
  • • minSdk 21 / compileSdk 33,Java 8 兼容,全部对外方法可在主线程调用;
  • • 所有回调(SdkCallback)保证在主线程派发,且成功/失败二选一、恰好一次,可直接刷 UI;
  • • 登录、实名等界面由 SDK 提供(半透明 Activity),不侵入宿主 UI;也可以完全免 UI 自绘(见 6.3、6.4)。

接入方需要提供的东西

项说明
gameId后管分配的游戏 ID,SdkConfig 必填
服务端地址无需宿主配置:baseUrl 由 SDK 内置正式域名 ;仅联调需要测试库时才显式传入
微信 AppId需要微信支付时配 wxAppId,并在宿主包内声明 WXEntryActivity(见 9.2)
渠道分包由后台打进 APK,宿主不用配

2. 环境与依赖

引入方式决定这张表要不要宿主自己抄:用第 3 节的方式 A(源码模块)时这张表一行都不用写(标 api 的进宿主编译期,标「内部」的随运行期自动带上);用方式 B(aar 直挂)时这张表每一行都不会自动带上、包括标「内部」的那些(标「内部」只说明它对宿主的编译期不可见,运行时照样需要),要逐条写进宿主 build.gradle。版本冲突时以宿主工程为准做对齐:

依赖版本传递性
retrofit / converter-gson2.9.0api(宿主可见)
okhttp4.11.0api(宿主可见)
okhttp logging-interceptor4.11.0内部(SDK 的日志脱敏那一层用到)
gson2.10.1内部
微信 opensdk6.8.24内部(宿主已有可 exclude,见 9.2)
支付宝 alipaysdk-android15.8.15内部(同上)
androidx.appcompat1.6.1内部(SDK 自带界面用到)
androidx.annotation1.6.0内部
kotlin-stdlib1.8.10内部(宿主是 Kotlin 工程时本来就带;纯 Java 工程走方式 B 要补这一行)
Walle payload_reader-1.1.7.jar—实体 jar 已在产物 AAR 的 libs/ 里,但不写进 POM——走方式 B 时同样建议自己补一条,见第 3 节末

3. 引入方式

产物 AAR 直挂(files() / flatDir)

groovy
implementation files('libs/sdk-release.aar')

4. AndroidManifest

AAR 已自动合并以下内容,宿主无需重复声明:

  • • 权限:INTERNET、ACCESS_NETWORK_STATE(不申请 IMEI、不申请悬浮窗权限);
  • • <queries>:com.tencent.mm、com.eg.android.AlipayGphone、https VIEW(Android 11+ 拉起收银台必需,宿主若自己声明过 package 可见性,注意不要覆盖掉这两条;https 那条现在也服务协议阅读页的「在浏览器中打开」兜底);
  • • SDK 内部界面:LoginActivity、RealnameActivity、AgreementActivity(协议阅读页,2026-10-29 加;三个都 exported=false、都只由 SDK 内部拉起,宿主不需要为它们写任何声明)。

宿主必须自己声明的只有微信回调页(见 9.2)。正式包请不要带 android:usesCleartextTraffic="true"(demo 里那行仅用于本地联调)。

5. 初始化

5.1 SdkConfig

kotlin
val config = SdkConfig.builder()                             // baseUrl 无需配置,SDK 内置域名
    .gameId("8766431358")                                    // 必填,空即 build() 抛异常
    .debug(BuildConfig.DEBUG)
    .collectDeviceId(false)                                  // 隐私政策同意后再开
    .floatingBall(true)                                      // 游戏内悬浮球,默认 false
    .realnameDialog(true)                                    // SDK 实名弹窗,默认 true
    .heartbeatEnabled(true)                                  // 防沉迷心跳,默认 false(2026-10-29 起),要采集得显式传 true
    .wxAppId("wx1234567890abcdef")                           // 用微信支付时必填
    .sendTokenProvider { riskService.getToken() }            // 见 6.2
    .build()

RankPaySdk.init(context, config)
RankPaySdk.setSessionListener(sessionListener)               // 必须处理 onSessionExpired

规则与默认值要点:

项规则
baseUrl宿主不用配置,builder() 无参重载即取 SDK 内置的正式地址 https://sdkapi.rankrank.com(域名全库仅此一处常量)。联调要连测试库 http://test-sdkapi.xyren.com/ 或本地 mock 时才用 builder(baseUrl) 显式传,且它们是 http 明文、必须同时 allowHttp(true)。出包前自查 config.redact():
http 明文内置正式域名为 HTTPS,正常无需关心;任何 http 地址(含测试库、局域网 mock)一律必须显式 allowHttp(true),且只允许出现在联调构建里
channelKey / gameKey都不在这里配。前者随 Walle 分包进 APK,后者登录成功时下发(RankPaySdk.hasSigningKey() 可查有无)
collectDeviceId默认 false。必须在用户同意隐私政策之后才开启;运行时切换用 setCollectDeviceId()(适合 Application 里先 init、隐私弹窗后置的老游戏时序,不必 release + 重 init)
超时/重试默认 connect 15s、read/write 20s、幂等请求重试 2 次;资金链路(下单/重取收银台)不自动重试
payPolling(interval, timeout)支付结果轮询,默认 1.5s / 300s;越界自动夹到 [1s,10s] / [10s,30min]
eventFlushInterval(ms, batch, maxQueue)埋点队列,batch 上限 50(服务端硬约束)
pinCertificates(...)可选 SPKI SHA-256 锁定;不配则只校验系统信任链
重复 init幂等忽略并打 warn;换配置需先 release()(一般只在切渠道包/退出时做)

5.2 初始化时序建议

http
Application/启动页 → (隐私弹窗同意后)init → refreshInitConfig 不用调(init 内自发一次 GET /partner/init)
进入游戏          → login(已登录时直接回缓存会话 = 自动登录)
进游戏/切角色    → reportRole(...)(角色当前态上报,见 6.9b;只有游戏自己知道等级与公会)
充值              → pay(...)
退出到后台        → onBackground()(落盘未发送埋点)

init 阶段 SDK 会自动拉一次服务端配置(功能开关、心跳间隔、支付方式限制),不等结果、不阻塞,拉不到就当服务端没说过。后管改了开关、或运行期换了 gameId,再调 refreshInitConfig() 重取。

6. 功能与 API

门面是 RankPaySdk 单例(全 @JvmStatic,Java 可直接调)。未 init 就调用任何方法,回调 SDK_NOT_INITIALIZED,不会崩。

回调 SdkCallback<T> 是抽象类,不是函数式接口——onSuccess / onFailure 两个方法都必须给,所以 RankPaySdk.login(activity) { … } 这种尾随 lambda 写法编译不过(Type mismatch)。能写的只有下面两种,本文其余示例里的 cb / callback 都指它们:

kotlin
SdkCallback.of(onOk = { r -> /* 成功 */ }, onErr = { e -> /* 失败,见第 7 节 */ })
// onErr 有默认空实现,只关心成功时可以只给 onOk:SdkCallback.of(onOk = { r -> … })

object : SdkCallback<LoginResult>() {                                  // 或自己实现(Java 侧 new SdkCallback<LoginResult>() { … })
    override fun onSuccess(result: LoginResult) { }
    override fun onFailure(error: SdkException) { }
}

6.1 会话与登录

text
RankPaySdk.login(activity, SdkCallback.of(
    onOk = { result -> /* LoginResult,已在主线程,直接刷 UI */ },
    onErr = { e -> /* 玩家关掉登录页回 SDK_CANCELLED,属正常分支 */ }
))                                                       // 已登录直接回缓存;否则弹 SDK 登录页
RankPaySdk.login(activity, forceUi = true, cb)            // 强制重弹登录页
RankPaySdk.isLoggedIn(); RankPaySdk.partnerOpenId(); RankPaySdk.token()
RankPaySdk.logout()                                               // 清本地会话,并向服务端吊销这一枚令牌(尽力而为)
RankPaySdk.logout(cb)                                             // 可选回调:回报的是**服务端吊销**的结果(本地退出在调用当时已完成)
RankPaySdk.checkToken(callback)                                   // 主动校验并续期;失效时 SDK 已自动清会话

logout() 顺序仍是先清本地、后发网络,发送失败也不回滚(不然弱网下点「退出」要转圈等一次 RTT,悬浮球还挂在屏幕上)。接入时因此要记住五点:

  • • 不要拿这一发的回调当「退出完成」:本地会话与 SessionListener.onLogout() 在调用当时已同步完成,UI 直接跟着 onLogout 切就好。
  • • 收到失败时不要提示玩家「退出失败」:他确实已经退出去了,代价只是旧令牌要在服务端活到自然过期(重登会换新令牌)。想埋这个点才需要传 cb。
  • • 这一发回的 PARTNER_TOKEN_INVALID 不会再触发 onSessionExpired:去吊销令牌却被告知「令牌已无效」等于目的达成,SDK 刻意不把它升级成全局被踢(否则宿主刚收到 onLogout 紧接着又收到一次会话过期,常见后果是莫名多弹一个重新登录框)。
  • • 只吊销「当前渠道 + 当前游戏」这一维度的令牌,同一个账号在另一个游戏的登录不受影响;与 6.5 的注销不是一回事(那一发连账号映射一起禁用)。
  • • 未登录时调用直接回成功(幂等,一个请求也不发),重复点「退出」不会报错。

LoginResult:partnerOpenId / passId / token / maskedTel(脱敏手机号,仅 UI 展示)/ realnameStatus(1 已实名 / 0 未 / -1 服务端未下发)。toString() 已对 token 与密钥遮码,可放心打日志。

登录成功后 realnameStatus=0 时 SDK 自动弹实名页(受 5.3 两道开关控制);玩家点「暂不认证」不算登录失败——会话有效,只是充值时还会被拦。

i
条款地址请用 https。Android 9+ 默认禁止明文流量,而正式接入不允许带 usesCleartextTraffic="true"(第 5 章开头、第 10 章检查清单都钉了这条):那时 http:// 的条款页会直接落到加载失败态。

SessionListener(务必注册并处理 onSessionExpired):

kotlin
RankPaySdk.setSessionListener(object : SessionListener {
    override fun onLoginSuccess(result: LoginResult) { /* 刷新 UI / 上报角色 */ }
    override fun onSessionExpired(error: SdkException) { /* 引导重新登录,否则玩家会在下单时才撞到失效码 */ }
    override fun onLogout() { /* 悬浮球「退出登录」、注销成功、本地清会话都走这里 */ }
})

6.2 免 UI 登录(宿主自绘登录界面)

text
RankPaySdk.sendSmsCode(tel, callback)                       // 防刷 token 走 SdkConfig.sendTokenProvider
RankPaySdk.sendSmsCode(tel, sendToken, callback)            // 或显式传入
RankPaySdk.loginBySms(tel, smsCode, smsToken, serverId, cb) // 验证码登录需回传发送码时拿到的 smsToken
RankPaySdk.loginByPassword(tel, password, serverId, cb)

老游戏已有登录态、不想让玩家再登一次:

text
RankPaySdk.adoptSession(partnerOpenId, token, expireTime = "", callback)
// 种入后立刻向服务端 token/check 复核;判定无效会清掉刚写入的会话并回 PARTNER_TOKEN_INVALID

6.3 实名认证

text
RankPaySdk.requestRealname(activity, cb)     // 主动拉认证页(已实名直接回成功)
RankPaySdk.submitRealname(name, idCard, cb)  // 免 UI 直提,校验与签名照常
RankPaySdk.queryRealnameStatus(cb)           // 服务端权威结论(回脱敏姓名/证件号);未实名是正常结果走 onSuccess
RankPaySdk.realnameStatus(); RankPaySdk.isRealnameVerified()

弹窗开关有两道,都只能关不能开:宿主 realnameDialog(false) 与服务端 init 回 realnameEnabled=0。关掉弹窗不等于绕过实名——服务端拦截码 PARTNER_REALNAME_REQUIRED 会原样回到 onFailure,只是换成宿主自己收集证件。姓名/证件号只在提交瞬间持有:不落盘、不进日志、不进埋点,且仅 HTTPS 发送。

6.4 支付

kotlin
val options = OrderOptions(
    serverId = "s101",                 // 必填
    roleId = "role_8848",              // 必填,SDK 无从获取,只能游戏传
    productName = "月卡",               // 必填(product 重载可自动补)
    productDescription = "",           // 选填
    ext = ""                           // 透传给支付回调,参与签名
)

// 方式一:指定支付方式
RankPaySdk.pay(activity, productId, amount /* 分 */, PayType.ALIPAY_APP, options, cb)
// 方式二:支付方式由 SDK 弹窗让玩家选
RankPaySdk.pay(activity, productId, amount, options, cb)
// 方式三/四:用商品对象(金额取服务端下发值,productName/serverId 自动补,宿主给的非空值优先)
RankPaySdk.pay(activity, product, PayType.WECHAT_APP, options, cb)
RankPaySdk.pay(activity, product, options, cb)

流程编排(SDK 内部完成,宿主只有一个回调):未登录先弹登录 → 未实名先弹实名 → 下单 → 拉起收银台 → 轮询服务端确认。

  • • serverId/roleId/productName 缺一即在本地拒绝(SDK_INVALID_ARGUMENT,不发请求);金额与服务端商品登记价不一致回 PARTNER_AMOUNT_MISMATCH——不要写死价格,优先用 getProducts() 的 ProductInfo 重载。
  • • 支付方式常量:PayType.WECHAT_APP(WechatPay_APP)、ALIPAY_APP、WECHAT_H5;渠道开通集合 = 激活/⑭ 下发的 payTypes(supportedPayTypes() 可查),与实际可拉起器取交集后:空 → SDK_INVALID_ARGUMENT(配置问题);一种 → 直接用它不弹;多种 → 弹选择框,玩家关掉回 SDK_PAY_CANCELLED。
  • • 已下单需换方式/重新拉起:relaunchPay(activity, gameOrderId, [payType,] cb)——不会重复建单,只是拿已有订单重取收银台参数。
  • • 超时必须以服务端为准对账:收到 SDK_PAY_RESULT_TIMEOUT 后钱可能已扣,用 queryOrder(gameOrderId) 做最终确认(服务端「查即补单」会把状态拉齐),切勿直接判失败漏发道具。
  • • 订单状态判定用 OrderStatus.paid(= 1/2/3),便捷方法 isPaidStatus(status)。不要写 status >= 1——4 是后管撤销,数值更大但一分没收到;轮询见到 4 应立刻停(SDK_ORDER_REVOKED),让玩家重新下单。
text
data class PayResult(gameOrderId, productId, amount /* 分 */, payType, status, payTime)
data class OrderInfo(gameOrderId, passOrderId, productId, amount, status, notifyCount, createTime, payTime)

6.5 注销账号(不可逆,务必谨慎)

text
RankPaySdk.cancelAccount(cb)

与 logout() 完全不是一回事:注销会让服务端吊销令牌并把这个账号置为停用(服务端改的是这条渠道上登记的账号映射),该账号再登录被直接拒绝(PARTNER_ACCOUNT_CANCELLED),只能客服/运营后台恢复,玩家自己重登无效。SDK 悬浮球里的入口已带二次确认;宿主直接调这个方法时必须自己拦这道确认。成功后 SDK 清会话并通知 onLogout;失败(网络等)会话原样保留,不会踢玩家下线。注销不到底层通行证账号:通行证账号、实名信息、已完成订单不受影响。悬浮球那张确认卡的文案按「账号」说、不出现「渠道」二字(2026-10-29 口径:玩家注销的就是当前登录的这个账号)。

6.7 悬浮球

floatingBall(true) 或运行时 setFloatingBall(enabled)。挂在宿主 Activity 内容视图上(不用悬浮窗权限、不跨 App),仅已登录时显示;静止 4 秒半隐到屏边,可拖动、位置记忆。面板入口:用户信息/实名、退出登录(带二次确认,确认后 = logout():先清本地会话、再向服务端吊销令牌,见 6.1)、注销账号(带二次确认 = 6.5)。

6.9b 角色上报(宿主在合适的时机自己调)

SDK 自己看不到玩家的等级/VIP/战力/公会——下单链路只带 serverId/roleId,成长数据必须由游戏方在自己的节点上报回来(POST /partner/role/report),后台的「玩家角色列表」才有得看。

text
// ① 登录成功、玩家进游戏那一次——这是唯一该把 loginReport 置 true 的一发
RankPaySdk.reportRole(
    RoleReport(
        serverId = game.serverId,      // 必填
        roleId = game.roleId,          // 必填,SDK 无从获取,只能游戏传
        serverName = "一区·龙渊",       // 选填
        roleName = "剑十一",            // 选填
        level = "87", vipLevel = "9", combatPower = "1250000",   // 选填,字符串
        guildId = "g_12", guildName = "龙渊阁",                   // 选填
        loginReport = true
    ),
    null                               // 回调可空(`SdkCallback<Unit>?`),传 null = 不关心结果(SDK 自己记日志)
)

// ② 切区服 / 切角色时;③ 等级、VIP、战力、公会发生变化时(loginReport 不要再置 true)
RankPaySdk.reportRole(
    RoleReport(serverId = game.serverId, roleId = game.roleId, level = "88"),
    SdkCallback.of(
        onOk = { /* 这一发已经落库 */ },
        onErr = { e -> /* 透传类错误一般不用管;PARTNER_ACCOUNT_CANCELLED 要停止上报 */ }
    )
)

口径要点(字段名就是上报用的那些,无额外包装):

  • • 必须已登录。gameId/partnerOpenId/token 都由 SDK 从会话里取(gameId 取登录下发的那个,宿主没有传它的入参);未登录时本地直接回 PARTNER_OPENID_INVALID,一个请求都不发。放在 SessionListener.onLoginSuccess 之后调最稳。
  • • 必填只有 serverId 与 roleId(它们与 openId 组成唯一键),其余全部可留空;缺了、或格式/长度不对都在本地先拒(SDK_INVALID_ARGUMENT,message 会点出字段名),省一次往返。
  • • 数值字段一律用字符串:level/vipLevel/combatPower 传 "87" 而不是 87,必须是非负整数(0 是合法值、照常覆盖),combatPower 可超 int、单位由接入方自定义。字符串上限:定位类(serverId/roleId/guildId)64,名称类(serverName/roleName/guildName)128。
  • • 留空 = 本次不上报这一项,不是清空。服务端只对非空值做覆盖,所以「玩家退出公会」这种想置空的场景本接口做不到,别拿空串或占位值绕(占位值会被当正常数据入库)。
  • • 重复上报安全、不需要定时轮询:服务端按唯一键 upsert,同一角色再报只覆盖数据、不会产生第二行;网络失败可以直接重试(SDK 内部也按幂等处理)。带不带 reqId 不影响落库(它只进链路日志)。
  • • loginReport = true 只刷服务端那个「最后登录时间」,所以只在进游戏那一次置 true,平时带上会污染这个口径。
  • • 定位提醒:它记的是当前态快照,不是角色事件流水,也不是账号交易/结算口径的权威角色档案(那份在通行证域),不参与任何金额计算与发货判定,别拿它当对账依据。带 serverName 时服务端会顺带登记区服名,与角色写入同事务,游戏后台没配好时会整单失败(PARTNER_GAME_KEY_MISSING)。
  • • Unity 桥本期没扩这个方法(与心跳/注销同口径):引擎侧要用得先在 adapters/unity/ 补一个桥接方法,不要在 C# 里拼 HTTP 绕开签名。

6.10 其它

方法用途
refreshInitConfig(cb) / initConfig()重取/读取服务端配置(init 已自发一次;注意升级四件套等字段服务端仍是占位值,别拿来做灰度强更决策)
supplyDeviceIds(imei, oaid, androidId)宿主已有合规设备标识(如厂商 OAID SDK)时注入,仅在 collectDeviceId(true) 时才发出
setLogger { level, tag, msg -> }接管 SDK 日志(level 同 android.util.Log);传 null 恢复默认。日志已对密钥/证件脱敏
packageId()只读:当前包的分码(空串 = 该包没打渠道)
applyPackageIdFromChannel(ctx)仅一种场景需要:覆盖安装了另一个渠道包且进程还活着时强制重读渠道。正常接入不用调(init 已读)。必须在 login 之前,登录后再换会吃 PARTNER_OPENID_INVALID
hasSigningKey()登录下发的签名密钥是否已落盘。排查 PARTNER_SIGN_ERROR 的第一站
serverTimeOffsetMillis()服务端时间补偿量,排查 PARTNER_REPLAY(设备时间漂移)用
deliverWxResult(errCode, errStr)宿主自有 WXEntryActivity 时转交微信结果(见 9.2)
registerPayLauncher(l)注入自定义收银台拉起器,优先级高于内置(宿主有自己的支付中台时用)

7. 错误处理

失败统一回 SdkException(code, message, category, httpStatus):message 已是可上屏中文;retryable(网络/超时/5xx)与 needRelogin(令牌类)两个判定属性可直接用。按 category 粗分处理即可:

SdkErrorCategory建议处理
NETWORK / TIMEOUT提示重试(retryable=true 的接口 SDK 内部已重试)
AUTH引导重新登录(onSessionExpired 也会通知)
VALIDATION宿主自身参数/配置问题,改调用方,不要重试
BUSINESS透传 message 给玩家
PAY区分「取消」(可再买)「超时」(必须 queryOrder 对账)「被撤销」(重新下单)
PROTOCOL / INTERNAL上报排查,玩家侧给通用文案

高频错误码速查:

code含义处理
SDK_NOT_INITIALIZED未 init检查初始化时序
SDK_INVALID_ARGUMENT本地校验拒绝(必填缺失 / 无可用支付方式 / 角色上报的字段超长或不是非负整数)补参;支付方式为空是渠道配置或没装微信/支付宝;角色上报看 message 里点出的字段名
SDK_PAY_CANCELLED玩家在收银台或选择弹窗取消正常分支,不报错
SDK_PAY_RESULT_TIMEOUT轮询超时,结果未知必须 queryOrder 对账后再决定发不发货
SDK_ORDER_REVOKED订单被后管撤销(status=4)让玩家重新下单
PARTNER_TOKEN_INVALID / PARTNER_OPENID_INVALID / PARTNER_GAME_KEY_MISSING登录态问题重新登录(needRelogin=true)
PARTNER_SIGN_ERROR验签失败先查 hasSigningKey();再确认 Walle 分包是否正确写入 channelKey、设备时间是否漂移
PARTNER_REPLAY / PARTNER_TS_ERROR时间戳异常/重放让用户校准系统时间
PARTNER_REALNAME_REQUIRED未实名拦截SDK 默认会自动补弹实名页并重试一次;关弹窗时宿主自行引导
PARTNER_ANTI_ADDICTION_PAY_LIMIT未成年消费限额透传文案,重试无意义
PARTNER_ACCOUNT_CANCELLED账号已注销/禁用(通行证账号本身还在)透传文案(需客服处理),不要引重登死循环
PARTNER_PACKAGE_INVALID分包码未登记/停用出包配置问题,联系运营,玩家侧无法解决
PARTNER_AMOUNT_MISMATCH下单金额与商品登记价不符改用 ProductInfo 重载,别写死价格
PARTNER_PARAM_INVALID服务端判定参数不合法(数值不是非负整数、字符串超列宽);角色上报 SDK 已把同一判据前置到本地按 message 改调用方的值,重试无意义
PARTNER_GAME_MISMATCH请求里的 gameId 与登录令牌绑定的游戏不是同一个(角色上报会撞)。gameId 由 SDK 取登录下发值,正常情况下不该出现出现了就是登录态串了(多开/换账号),清会话重新登录
PARTNER_CHANNEL_NOT_FOUND / PARTNER_CHANNEL_DISABLED渠道定位失败检查分包 channelKey 与渠道启用状态

8. 混淆与安全

  • • SDK 自带 consumer-rules.pro(随 AAR 生效),宿主无需为 SDK 添加任何规则;建议宿主开 minifyEnabled true(R8),能提高签名密钥提取成本。
  • • 宿主需要自己 keep 的只有反射入口(如微信回调 Activity 按类名查找):-keep class ${你的包名}.wxapi.WXEntryActivity { *; }。
  • • 敏感数据口径:姓名/证件号仅提交瞬间持有、只在 HTTPS 发送;maskedTel、实名查询返回的姓名证件号均为脱敏文本。

9. 微信 / 支付宝

9.1 支付宝

内置拉起,无宿主工作:配好 gameId 即可,payType=AliPay_APP。

9.2 微信

  • 1. SdkConfig.builder(...).wxAppId("wx…")——不配则微信拉起直接回错误码;
  • 2. 在宿主 applicationId 对应包下建空壳类并在 Manifest 声明(微信 SDK 只认 ${applicationId}.wxapi.WXEntryActivity 这个固定路径,AAR 无法代提供):
bash
package com.your.game.wxapi
class WXEntryActivity : com.leju.paysdk.wx.RankPayWXEntryActivity()
<activity android:name=".wxapi.WXEntryActivity"
    android:exported="true"
    android:launchMode="singleTop"
    android:taskAffinity="com.your.game"
    android:theme="@android:style/Theme.Translucent.NoTitleBar" />
  • 3. 宿主已有自己的 WXEntryActivity(在做微信登录/分享、不能改继承基类)时,保持原实现,在 onResp 里转交一次支付结果即可:
kotlin
override fun onResp(resp: BaseResp?) {
    if (resp?.type == ConstantsAPI.COMMAND_PAY_BY_WX) {
        RankPaySdk.deliverWxResult(resp.errCode, resp.errStr)   // 0 成功 / -1 错误 / -2 取消
    }
    super.onResp(resp)   // 宿主自己的登录/分享分支照旧
}

宿主已自行接入微信开放 SDK 的,可 exclude SDK 的 wechat-sdk-android 传递依赖(支付宝同理),注意版本需覆盖 6.8.24 的接口面。

10. 出包检查清单

  • □ 未做 baseUrl 宿主配置(走 SDK 内置正式域名),并核对 redact() 日志中的地址为 https://sdkapi.rankrank.com、无 (TEST) 标记;
  • □ 正式包无 allowHttp(true)、无 usesCleartextTraffic="true";
  • □ gameId 与后管登记一致;
  • □ APK 已由后台用 Walle 写入渠道(RankPaySdk.packageId() 非空、登录后签名可用);
  • □ 用方式 B(aar 直挂)时:第 2 节那张表已在宿主 build.gradle 里逐条写全,payload_reader 也照 3 节末补了一道(漏了不会崩,只是 packageId() 恒空、分包校验过不了);
  • □ 需要微信支付时:wxAppId 已配、${applicationId}.wxapi.WXEntryActivity 已声明并可被微信拉回;
  • □ SessionListener.onSessionExpired 有真实处理(引导重登);
  • □ 隐私政策同意后调 setCollectDeviceId(true)(或直接开配置),之前保持 false;
  • □ 真机跑通一条完整资金链路:登录 → (实名)→ 下单 → 拉起 → 支付成功回调 status=PAID/NOTIFIED;
  • □ 断网/取消/超时三个失败分支各试一次:取消不报错、超时走 queryOrder 对账。

11. 常见问题

现象原因与处置
登录后所有需签名接口 PARTNER_SIGN_ERROR先 hasSigningKey():false = 登录响应没带密钥(服务端问题);true = 多为设备时间漂移或分包 channelKey 与服务端登记不符
点支付直接回调 SDK_INVALID_ARGUMENTOrderOptions 三个必填没齐,或渠道开通的支付方式在本机都没有拉起器(没装微信/支付宝且未 registerPayLauncher)
支付成功但宿主没收到回调检查是否在 SDK_PAY_RESULT_TIMEOUT 分支自己吞了失败——超时是「未确认」,必须 queryOrder 补判
换了渠道包后 openId 对不上覆盖安装渠道包后进程未死,缓存里还是旧渠道值:login 之前调 applyPackageIdFromChannel(ctx) 强读一次
悬浮球不出现三个条件缺一不挂:配置开启、已登录、宿主 Activity 处于前台;SDK 自己的弹窗(登录/实名)弹出期间球会暂时收起属正常
未成年玩家充值被拒PARTNER_ANTI_ADDICTION_PAY_LIMIT,服务端实名,客户端无法绕过也不该重试
后台看不到玩家的等级/战力/公会这些只有游戏自己能报(6.9b),SDK 不会自己采集:确认宿主真的调过 reportRole,且已登录、serverId/roleId 与下单用的是同一套值
reportRole 回调 SDK_INVALID_ARGUMENT必填只有 serverId/roleId 两个;level 之类传了不是非负整数的值(-1/1.5/V9)或字符串超 64/128 也会被本地拦下,message 里点了字段名

本文与 SDK 1.0.0 同步维护;二者冲突时以代码为准并请反馈文档维护人。

第二部分

合作方服务端接口(CP API)

面向合作方服务端的 HTTP 接口:订单查询、用户信息查询、有效性验证、订单发货回执,以及全局鉴权约定与错误码。接口以最新版《RankRank SDK 接口文档》与《SDK 接口文档 —— 订单发货回执》为准。

合作方(CP)服务端接口

整理日期:2026-11-04

1. 文档信息

项目内容
文档名称SDK接口(Apifox 共享文档站点标题)
访问地址https://uf5xm7yovl.apifox.cn/
访问方式需要密码访问(MtwIowMA)
Apifox 项目 ID9011689(由各接口页 "Run in Apifox" 链接解析得到)
接口数量4 个(3 个 GET + 1 个 POST)
说明性页面2 个(全局说明、错误码)

2. 全局说明

以下为原文「全局说明」页面的全部内容:

text
请求的header里需要加下面参数:SDK-Authorization:授权码,SDK分配,测试环境:b3883a603bb5438aba6978d3e3555416,正式环境:a81e3fe5c92a4261b78320a9811d256c
测试url:http://test-sdkapi.xyren.com正式url:https://sdkapi.rankrank.com
项目约定
服务地址(Base URL)https://sdkapi.rankrank.com
鉴权方式HTTP 请求头 SDK-Authorization,值为 SDK 分配的授权码
测试环境授权码b3883a603bb5438aba6978d3e3555416
正式环境授权码a81e3fe5c92a4261b78320a9811d256c
鉴权失败行为fail-closed:缺失或不匹配时返回错误码 CP_UNAUTHORIZED(见第 5 节)
接口风格统一为 GET + query 参数;响应为 JSON
响应外壳查询订单信息、有效性验证接口的 schema 为 {code, message, data};查询用户信息的 schema 未定义该外壳,但官方示例带外壳(差异见第 6 节第 2 条)
成功码code = succ

3. 接口总览

序号接口名称方法路径状态
1查询订单信息GET/cp/api/order/query已发布
2查询用户信息GET/cp/api/user/info已发布
3有效性验证接口GET/cp/api/user/verify已发布
4订单发货回执POST/cp/api/order/deliver_notify见 4.4

四个接口都要求请求头携带 SDK-Authorization;

4. 接口详情

GET4.1 查询订单信息

GET /cp/api/order/query

请求参数

参数名位置类型必填说明示例值
orderIdquerystring是订单id
openIdquerystring是用户Id 既SDK里面的gamerId
gameIdquerystring是游戏 Id
SDK-Authorizationheaderstring是授权码,SDK 分配a81e3fe5c92a4261b78320a9811d256c

响应字段(HTTP 200,响应名「成功」)

字段类型必填说明
codestring是结果码;示例取值 succ
messagenull是消息;schema 类型标注为 null,示例值为 null
dataobject是订单数据,字段见下
data.gameOrderIdstring是我方订单号
data.passOrderIdstring是(原文未给字段释义;示例中与 gameOrderId 相同)
data.productIdstring是商品 ID;示例 P_648
data.amountinteger是支付金额,单位分;示例 64800(即 648 元)
data.statusinteger是支付维度:0 待支付 / 1 已支付 / 4 已退款 / 5 已关闭
data.notifyStatusinteger是发货回调维度:0 未通知 / 1 已通知 / 2 通知失败
data.notifyCountinteger是发货回调重试次数
data.createTimestring是下单时间
data.payTimestring是支付时间,未支付为空

响应说明(原文 200 描述)

支付成功以 status=1 为准;status=1 且 notifyStatus=1 表示支付完成且发货已确认;status=1 且 notifyStatus=2 表示支付完成但发货失败,SDK 会自动重推。

响应示例

json
{  "code": "succ",  "message": null,  "data": {    "gameOrderId": "2039000000000000001",    "passOrderId": "2039000000000000001",    "productId": "P_648",    "amount": 64800,    "status": 1,    "notifyStatus": 1,    "notifyCount": 1,    "createTime": "2026-11-05 10:00:00",    "payTime": "2026-11-05 10:01:12"  }}

请求示例(渲染页给出的 cURL)

bash
curl --location '/cp/api/order/query?orderId=&openId=undefined' \  --header 'SDK-Authorization: a81e3fe5c92a4261b78320a9811d256c'
i
据《SDK 接口文档 —— 订单发货回执》(见 4.4),订单查询返回体还含三个入站字段 deliverStatus / deliverTime / deliverCpNo,与出站 notifyStatus 并列。上表按原文保留,未增补这三行。

GET4.2 查询用户信息

GET /cp/api/user/info

请求参数

参数名位置类型必填说明示例值
openIdquerystring是用户Id
gameIdquerystring是游戏 Id
SDK-Authorizationheaderstring是授权码,SDK 分配

响应字段(HTTP 200,响应名「成功」)

字段类型必填说明
partnerOpenIdstring是SDK 域对外的唯一用户标识
gamerCodestring是游戏家唯一 code
nickNamestring是用户名称
avatarstring是头像完整路径
realnameStatusinteger是是否实名:0 未实名 / 1 已实名
realNamestring是真实姓名
idCardNostring是身份证Id

响应示例

json
{  "code": "succ",  "message": null,  "data": {    "partnerOpenId": "PO_10001",    "gamerCode": "RR88888",    "nickName": "玩家小明",    "avatar": "https://cdn.example.com/avatar/10001.png",    "realnameStatus": 1,    "realName": "张*三",    "idCardNo": "110***********1234"  }}

请求示例(渲染页给出的 cURL)

bash
curl --location '/cp/api/user/info?openId=undefined&gameId=undefined' \  --header 'SDK-Authorization;'

GET4.3 有效性验证接口

GET /cp/api/user/verify

请求参数

参数名位置类型必填说明示例值
openIdquerystring是用户Id
gameIdquerystring是游戏Id
SDK-Authorizationheaderstring是授权码,SDK 分配

响应字段(HTTP 200,响应名「成功」)

字段类型必填说明
codestring是结果码;示例取值 succ
messagenull是消息;
databoolean是验证结果;原文未说明 true / false 的语义与失败时的 code

响应说明(原文 200 描述)

响应示例

json
{  "code": "succ",  "message": null,  "data": true}

请求示例(渲染页给出的 cURL)

bash
curl --location 'cp/api/user/verify?openId=undefined&gameId=undefined' \  --header 'SDK-Authorization;'

POST4.4 订单发货回执

SDK 接口文档 —— 订单发货回执(CP 发货后通知我方)

环境域名

环境对外域名(拼在 URL 前)SDK-Authorization(请求头取值)
正式https://sdkapi.rankrank.coma81e3fe5c92a4261b78320a9811d256c
i

两枚 SDK-Authorization 为对应环境服务端配置 partner.cp.authorization 的当前值,正式/测试互相独立、不可混用;变更以服务端实际配置为准。

一、接口用途与定位

支付成功、我方(SDK)按 yxj_partner_game.cp_notify_url 通知 CP 去发货(出站)之后,CP 完成发货再回执我方(入站)本次发货结果,写入订单的 deliver_status。

i

两个方向、两列状态,互不覆盖(务必区分):

  • notify_status(出站,我方→CP)= 我方通知 CP 去发货的回调结果,0 未通知 / 1 已通知 / 2 通知失败;
  • deliver_status(入站,CP→我方,本接口写入)= CP 发货完成后回执我方的结果,0 未回执 / 1 已发货 / 2 发货失败。

notify_status=1 只代表"发货请求已送达 CP",是否真正发货以 deliver_status=1 为准。

二、面向与鉴权

本接口只开放 CP 免验签面 /cp/api/**(服务端到服务端),没有客户端 /partner 面版本:实际调用方是 CP 后台,它不持有玩家登录 token、也不持有 gameKey/channelKey,出站发货通知只回传了 gameOrderId+partnerOpenId,故回执入口按全局唯一 orderId 定位订单即可。鉴权沿用本面统一口径:

  • 仅以全局共享密钥请求头 SDK-Authorization 鉴权:值取自服务端配置 partner.cp.authorization,每次请求在 HTTP 头携带,无需按参数签名;缺失或不符返回 CP_UNAUTHORIZED(服务端未配置时 fail-closed 全拒)。头名统一用连字符 SDK-Authorization,早期下划线写法 SDK_Authorization 会被 Nginx 等网关默认丢弃(underscores_in_headers off)导致鉴权失败,服务端仍兼容旧名,但 CP 侧请用连字符名。
  • 不校验 sign、不校验 token、不做 ts/nonce 防重放:安全边界靠该全局密钥仅限 CP 服务端持有、严禁下发客户端或写入前端来保证。
  • 非资金的状态写入:只改 deliver_status/deliver_time/deliver_cp_no,不触碰 status、notify_status 等支付与资金字段。

三、URL

  • 正式:https://sdkapi.rankrank.com/cp/api/order/deliver_notify

四、HTTP 请求方式

POST,业务参数走 application/x-www-form-urlencoded 表单或 URL query(鉴权走请求头 SDK-Authorization)。

五、请求参数

参数必填类型说明
orderId是String我方订单号(gameOrderId,全局唯一,出站发货通知已下发给 CP),服务端据此反查订单自身渠道
gameId是String游戏ID(对外业务标识);与本面订单查询同口径必填,服务端先据此判断游戏是否已接入(未接入报 PARTNER_GAME_NOT_FOUND),并要求与订单归属游戏一致(跨游戏回执拒绝)
deliverStatus是String发货回执状态,仅 1 已发货 / 2 发货失败,其它值报 PARTNER_DELIVER_STATUS_INVALID
openId否String下单用户 openId(partnerOpenId);传则校验订单归属,不符按"订单不存在"处理
cpOrderNo否StringCP 侧发货流水号,透传落 deliver_cp_no 仅作留痕/对账,不参与状态判定
SDK-Authorization是String(请求头)CP 全局共享密钥,须与服务端配置一致
i

免传 channelKey、gameKey、token、ts、nonce、sign:channelKey 由服务端按 orderId 读订单自身渠道得出;gameId 仅用于前置游戏接入校验与跨游戏一致性判定,不用于验签。

六、校验与落库规则

  1. SDK-Authorization 鉴权(全局密钥,fail-closed);
  2. gameId 必填且须已在 SDK 登记(yxj_partner_game),未接入直接拒绝,便于 CP 区分"游戏标识配错"与"订单问题";
  3. deliverStatus 合法性校验:仅接受 1/2,其它值(含 0/空/非数字)拒绝;
  4. 归属校验:按 orderId 读取订单,订单不存在、或传了 openId 但与下单 openId 不符,统一报 PARTNER_ORDER_NOT_FOUND(不透露差异,防用订单号试探他人交易);
  5. 游戏一致性:请求 gameId 须与订单已绑 gameId 一致(跨游戏回执拒绝;迁移期老订单 gameId 为空放过);
  6. 状态守卫:仅 status=1(已支付)订单可被回执,否则报 PARTNER_ORDER_NOT_PAID;SQL 侧带 status=1 guard 兜底并发(支付/退款与回执交错时以最终态为准);
  7. deliver_time 由服务端取当前时间落库(不接收 CP 上报时间,防篡改与时区不一致),cpOrderNo 空串归一为 null;
  8. 幂等:重复回执后到覆盖(last-write-wins),不报错,只保留 CP 最后一次上报的状态。

七、返回结果

统一返回信封,成功与否以 code 判定(业务失败同样返回 HTTP 200):

json
{
  "code": "succ",
  "message": null,
  "data": true
}
字段类型说明
codeStringsucc 表示成功;失败为错误码(见第九节)
messageString失败原因文案,成功时通常为 null
dataBoolean回执处理成功恒为 true

回执结果可通过本面订单查询读取:GET /cp/api/order/query,返回体含 deliverStatus / deliverTime / deliverCpNo 三个入站字段(与出站 notifyStatus 并列)。

八、请求示例

http
POST /cp/api/order/deliver_notify HTTP/1.1
Host: test-sdkapi.xyren.com
Content-Type: application/x-www-form-urlencoded
SDK-Authorization: a81e3fe5c92a4261b78320a9811d256c

orderId=2039000000000000001&gameId=5781921412&deliverStatus=1&openId=PO_10001&cpOrderNo=CP-DLV-20261105-0001
i

若本次无 CP 流水号,cpOrderNo 可省略或传空串,服务端按空值(null)落库;openId 亦为选填,传则追加归属校验。

九、错误码

错误码触发条件
CP_UNAUTHORIZED请求头 SDK-Authorization 缺失/与服务端密钥不符,或服务端未配置 partner.cp.authorization(fail-closed)
PARTNER_GAME_MISSINGgameId 为空
PARTNER_GAME_NOT_FOUNDgameId 未在 SDK 登记(游戏未接入或已删除),说明 CP 侧游戏标识配错,与订单本身无关
PARTNER_DELIVER_STATUS_INVALIDdeliverStatus 非数字,或不为 1(已发货)/2(发货失败)
PARTNER_ORDER_NOT_FOUNDorderId 为空 / 订单不存在 / 传了 openId 但归属不符 / 订单 gameId 与请求不符(统一按订单不存在处理,不透露差异)
PARTNER_ORDER_NOT_PAID订单非已支付状态(status != 1)无法回执,或并发下状态已变回执未生效
valid.fail缺少必填参数 orderId、gameId 或 deliverStatus
error.unknown服务端未预期异常

十、联调注意事项

  1. 密钥保密:SDK-Authorization 是本面唯一的鉴权凭据,替代了逐请求签名,一旦泄露即全量可写/可查且无防重放,严禁下发到客户端或写入前端代码;正式/测试取值不同,不可混用。
  2. gameId 必须与订单归属游戏一致:同一订单只能在下单游戏下回执,跨游戏回执会被拒绝。
  3. openId 为选填的加固项:建议 CP 回传出站通知里带的 partnerOpenId,可防止用订单号试探他人交易。
  4. 幂等重试安全:CP 因超时重发回执不会报错,以最后一次 deliverStatus 为准;如需避免"先失败后成功"被覆盖,请在 CP 侧保证上报顺序。
  5. 本接口不返回资金字段,deliver_time 为我方服务端落库时刻,非 CP 上报时间。

5. 错误码

原文「错误码」页面的表格存在一行串行:valid.fail(缺少 userId)那一行与 PARTNER_ORDER_NOT_FOUND 行被合并渲染,渲染页里 PARTNER_ORDER_NOT_FOUND 整行丢失、并残留了半截 `user 与 Id`。下表按上下文还原,需与后端核对后回改 Apifox(见第 6 节第 11 条)。

错误码触发条件
CP_UNAUTHORIZED请求头 SDK-Authorization 缺失/与服务端密钥不符,或服务端未配置
PARTNER_OPENID_INVALIDopenId为空,或按 openId 未查到用户映射
PARTNER_USERINFO_MISSING主平台正常响应但未返回资料
PARTNER_ORDER_NOT_FOUNDorderId 为空 / 订单不存在 / 传了 openId 但与订单归属不符(统一按订单不存在处理,不透露差异) 
valid.fail缺少必填 query 参数 openId 
valid.fail缺少必填 query 参数 orderId
error.unknown服务端未预期异常
PARTNER_GAME_MISSINGgameId 为空(订单发货回执)
PARTNER_GAME_NOT_FOUNDgameId 未在 SDK 登记(游戏未接入或已删除),属 CP 侧游戏标识配错,与订单本身无关(订单发货回执)
PARTNER_DELIVER_STATUS_INVALIDdeliverStatus 非数字,或不为 1(已发货)/ 2(发货失败)(订单发货回执)
PARTNER_ORDER_NOT_PAID订单非已支付状态(status != 1)无法回执,或并发下状态已变回执未生效(订单发货回执)

按错误码可反推出的行为约定:

  • 鉴权是 fail-closed,缺授权码或服务端漏配 partner.cp.authorization 都会直接拒绝,不会降级放行。
  • 订单查询在「orderId 为空」「订单不存在」「openId与订单归属不符」三种情况下统一返回 PARTNER_ORDER_NOT_FOUND,刻意不区分,避免透露订单归属差异。
  • valid.fail 用于必填 query 参数缺失(openId / orderId),属于参数校验层错误。
  • error.unknown 兜底,且会把主平台不可达的情况透传出来。
发布日期:2026-11-05