授权码License 开发调试上线全流程指南
v1.0.0
客户端软件开发 → 调试 → 上线全流程指南(v4)
适用于:在幂栈网发布客户端软件并接入授权码体系的开发者。 本文覆盖从「创建产品」到「真实用户购买」的完整生命周期,重点是 v4 新增的双环境调试能力:上线前用真实支付链路(Waffo Test 环境)把自己的电脑当调试机走通全流程。
一、全流程总览
┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ ① 开发阶段 │ → │ ② 调试阶段 │ → │ ③ 上线阶段 │ → │ ④ 上线后运营 │
│ │ │ │ │ │ │ │
│ 创建产品草稿 │ │ 注册调试机 │ │ 提交审核 │ │ 查看订单 │
│ 集成授权 SDK │ │ 走通真实链路 │ │ 审核通过 │ │ 解绑/退款 │
│ 保存草稿 │ │ (Test 环境)│ │ 同步生产环境 │ │ 版本迭代 │
└──────────────┘ └──────────────┘ └──────────────┘ └──────────────┘
| 阶段 | 产品状态 | 授权/订单落在哪 | 会产生真实收入吗 |
|---|---|---|---|
| ① 开发 | 草稿(DRAFT) | — | 否 |
| ② 调试 | 草稿 / 审核中 | Test 表(授权码带 T- 前缀) |
否(测试支付通道) |
| ③ 上线 | 已发布 | 生产表 | 是 |
核心规则:调试与生产完全隔离。 调试机上发生的一切(试用、下单、支付、发码、激活、退款)只影响测试表,不进分润、不进对账、不影响任何真实用户;非调试机的访问永远走生产链路。
二、开发阶段
2.1 创建产品
- 登录幂栈网开发者中心 → 发布产品,产品形态选「客户端软件」
- 售卖方式选 先用后付,填写试用天数(建议 7~14 天)
- 配置授权版本(edition):默认三档
BASIC/PRO/ULTIMATE,可自定义 code、名称、价格与功能清单 - 勾选「平台代收授权费」(先用后付强制勾选)
- 上传软件包与介绍素材
2.2 保存草稿(新增能力)
产品表单底部有两个按钮:
| 按钮 | 行为 |
|---|---|
| 保存草稿 | 产品存为 DRAFT 状态,不进审核队列,可随时继续编辑 |
| 保存并提交审核 | 产品进入审核队列(PENDING_RELEASE) |
草稿/提审保存后,平台会异步把商品同步到 Waffo Test 环境(失败仅告警不阻塞保存),这是调试阶段能下单的前提。因此建议:开发期先保存草稿即可开始调试,无需提审。
保存后记下 productUniqueCode(发布页可见,非密钥)。
2.3 集成授权 SDK(两种接入场景)
幂栈网为客户端软件提供两种授权接入方式,开发者根据自身情况选择:
| 场景 A:平台完整链路(先用后付) | 场景 B:订单不在平台 | |
|---|---|---|
| 适用产品 | 客户端软件 + 先用后付售卖方式 | 仅推广软件(自行收款);或服务端软件 / 客户端软件,先付后用(PAY_FIRST)售卖方式或 VIP 功能的自行收款 |
| 谁管收款 | 幂栈网平台(Waffo、支付宝、PayPal);调试环节使用 Waffo 测试环境作为支付通道 | 开发者自己(软件内支付或其他渠道) |
| 谁管发码 | 平台支付成功后自动发码 | 软件调平台 API 发码(HMAC 签名) |
需要授权密钥 licenseApiSecret? |
❌ 不需要 | ✅ 需要(仅存服务端,不可存客户端) |
| 需要服务端? | ❌ 不需要,纯客户端即可 | ✅ 需要(保管 licenseApiSecret,转发发码请求) |
| 试用授权 | ✅ 支持(claimTrial) |
❌ 无试用(试用仅支持先用后付产品) |
| 购买页 | 平台提供,SDK 一行跳转 | 无平台购买页,开发者自行处理 |
关于版本配置:所有产品形态(客户端/服务端/仅推广)均可启用授权码并自定义版本(BASIC/PRO/ULTIMATE 等)。版本价格和功能清单仅在开发者勾选「平台代收授权费」(
licensePlatformPayment)时展示在购买页;不勾选则开发者自行处理收款,平台仅提供授权码发放与校验能力。
如何选择:
- 你是独立开发者 / 小团队,没有自己的服务端 → 选 场景 A(本文第四、五章的流程即以场景 A 为主线)
- 你已有支付渠道(如微信/支付宝商户),只想用平台发码校验 → 选 场景 B
2.3.1 SDK 安装
三语言(Node.js / Python / Java)均为零依赖,直接拷贝源码到你的项目中,无需任何包管理器。机器码算法跨语言一致(同一台机器生成相同 machineCode)。SDK 仓库:github.com/mizhanchengxi/powersoftware-license-sdk
2.3.2 场景 A:平台完整链路(先用后付)
前置条件:产品售卖方式为先用后付、已配置试用天数与授权版本、勾选「平台代收授权费」。不需要授权密钥 licenseApiSecret:
# Python
from ps_license_sdk import LicenseClient, machine_code
client = LicenseClient(product_unique_code="PRO-2026-001", api_secret="") # api_secret 留空
mc = machine_code()
// Node.js
import { LicenseClient, machineCode } from './index.js';
const client = new LicenseClient({ productUniqueCode: 'PRO-2026-001', apiSecret: "" }); // 场景 A 密钥留空
const mc = machineCode();
// Java
import com.powersoftware.sdk.LicenseClient;
LicenseClient client = new LicenseClient("PRO-2026-001", ""); // 场景 A 密钥留空
String mc = LicenseClient.machineCode();
完整接入流程:
首次启动
│
├─ claimTrial(machineCode) ────────────→ 获取试用授权
│ ↓ 返回 { licenseCode, activationToken, licenseUpgradeMode }
│ ↓ 本地持久化存储
│
├─ 试用期内:所有功能可用
│ │
│ └─ 点击付费功能 → verifyCached() 60s 缓存校验 → 放行
│
└─ 试用到期 / 未激活
│
├─ verifyCached() 返回 invalid/expired
├─ 弹窗提示"需要购买激活授权"
└─ purchaseUrl(machineCode) → 跳转平台购买页
│
↓ 用户在平台支付 → 平台发码 + 邮件送达
│
用户回到软件,输入授权码
│
├─ activate(licenseCode, machineCode)
│ ↓ 返回 { activationToken, licenseUpgradeMode },本地持久化存储
│
└─ 后续使用 → verifyCached() 校验 → 放行
需实现:claimTrial(首次启动领取试用)→ verifyCached(付费功能校验)→ purchaseUrl(未授权跳购买页)→ activate(用户输入授权码激活)→ 本地持久化 licenseCode + activationToken → LicenseError 错误码处理。
核心代码(Python):
import json
from pathlib import Path
from ps_license_sdk import LicenseClient, machine_code
# ---------- 初始化 ----------
client = LicenseClient(product_unique_code="PRO-2026-001", api_secret="")
CRED_FILE = Path.home() / ".myapp" / "license.json"
def load_cred():
if CRED_FILE.exists():
return json.loads(CRED_FILE.read_text())
return {}
def save_cred(d):
CRED_FILE.parent.mkdir(parents=True, exist_ok=True)
CRED_FILE.write_text(json.dumps(d, ensure_ascii=False))
# ---------- 首次启动:领取试用 ----------
def claim_trial():
mc = machine_code()
try:
result = client.claim_trial(mc)
save_cred({
"licenseCode": result["licenseCode"],
"activationToken": result["activationToken"],
})
print(f"试用已激活,授权码:{result['licenseCode']}")
except Exception as e:
print(f"领取试用失败:{e}")
# ---------- 校验授权(点击付费功能时调用) ----------
def check_license(required_edition="PRO"):
cred = load_cred()
if not cred.get("licenseCode"):
return {"valid": False, "reason": "未激活"}
mc = machine_code()
try:
result = client.verify_cached(
cred["licenseCode"], mc, cred["activationToken"]
)
if not result.get("valid"):
return {"valid": False, "reason": "授权无效或已过期"}
user_edition = result.get("edition", "")
levels = {"BASIC": 0, "PRO": 1, "ULTIMATE": 2}
if levels.get(user_edition, 0) < levels.get(required_edition, 0):
return {"valid": False, "reason": f"需要 {required_edition} 及以上版本"}
return {"valid": True, "edition": user_edition,
"expiryTime": result.get("expiryTime"),
"trialExpiryTime": result.get("trialExpiryTime")}
except Exception as e:
return {"valid": False, "reason": str(e)}
# ---------- 激活授权码(用户购买后输入) ----------
def activate(license_code):
mc = machine_code()
try:
result = client.activate(license_code, mc)
save_cred({
"licenseCode": license_code,
"activationToken": result["activationToken"],
})
return True
except Exception as e:
print(f"激活失败:{e}")
return False
# ---------- 跳转购买页 ----------
def open_purchase_page():
mc = machine_code()
url = client.purchase_url(mc)
import webbrowser
webbrowser.open(url)
功能拦截示例:
# 定义功能版本要求
FEATURE_EDITION = {
"basic_feature": "BASIC",
"plus_feature": "PRO",
"ultimate_feature": "ULTIMATE",
}
def run_feature(feature_name):
required = FEATURE_EDITION.get(feature_name, "BASIC")
if required == "BASIC":
do_basic_feature()
return
result = check_license(required)
if result["valid"]:
do_paid_feature(feature_name)
else:
print(f"无法使用此功能:{result['reason']}")
open_purchase_page()
2.3.3 场景 B:订单不在平台(自行收款)
适用产品:仅推广软件(自行收款),或服务端软件 / 客户端软件中先付后用(PAY_FIRST)售卖方式、VIP 功能的自行收款。
前置条件:产品开启 licenseEnabled;在开发者后台获取 licenseApiSecret(仅存服务端,不可泄露到客户端)。架构:
客户端 你的服务端 幂栈网平台
│ │ │
│ 用户付费(你的支付) │ │
├──────────────────────→│ │
│ │ generateForSoftware( │
│ │ machineCode, edition, │
│ │ clientOrderId) │
│ │ (HMAC 签名 + timestamp) │
│ ├────────────────────────────────→│
│ │ ← 返回 licenseCode │
│ ← 返回 licenseCode │ │
│ │ │
│ activate(licenseCode, machineCode) │
├───────────────────────────────────────────────────────→│
│ ← 返回 activationToken │
│ │ │
│ verifyCached(...) │ │
├───────────────────────────────────────────────────────→│
│ ← { valid, edition, expiryTime } │
服务端(保管授权密钥 licenseApiSecret,发码):
from ps_license_sdk import LicenseClient, machine_code
server_client = LicenseClient(
product_unique_code="PRO-2026-001",
api_secret="你的发码密钥_FROM_DEVELOPER_CONSOLE",
)
def issue_license(user_machine_code, edition="PRO", order_id=""):
"""用户付款后,服务端调平台发码"""
result = server_client.generate_for_software(
machine_code_value=user_machine_code,
edition=edition,
expiry_days=365,
client_order_id=order_id,
)
return result["licenseCode"]
客户端(不需要 licenseApiSecret,激活与校验):
client = LicenseClient(product_unique_code="PRO-2026-001", api_secret="")
def activate(license_code):
mc = machine_code()
result = client.activate(license_code, mc)
save_cred({"licenseCode": license_code,
"activationToken": result["activationToken"]})
需实现:服务端 generateForSoftware(发码)+ upgradeForSoftware(升级/续费);客户端 activate / verifyCached + 本地凭证持久化 + LicenseError 错误码处理。
2.3.4 SDK 方法速查
| 方法 | 场景 A | 场景 B | 签名 | 说明 |
|---|---|---|---|---|
machine_code() |
✅ | ✅ | — | 生成机器码(跨语言一致) |
claim_trial(mc) |
✅ | — | — | 领取试用授权(仅先用后付产品) |
activate(code, mc) |
✅ | ✅ | — | 激活授权码,绑定机器 |
verify(code, mc, token) |
✅ | ✅ | — | 校验授权状态 |
verify_cached(code, mc, token) |
✅ | ✅ | — | 带本地缓存(60s)的校验 |
deactivate(code, mc) |
✅ | ✅ | — | 解绑机器(需登录,浏览器场景) |
purchase_url(mc) |
✅ | — | — | 生成平台购买页 URL |
generate_for_software(mc, edition, ...) |
— | ✅ | HMAC | 软件内发码(仅服务端) |
upgrade_for_software(code, edition, ...) |
— | ✅ | HMAC | 软件内升级/续费(仅服务端) |
返回字段说明:
activate/verify/claimTrial三个接口的成功响应均附带licenseUpgradeMode(产品升级策略:SAME_CODE原码不变 /NEW_CODE原码换绑)。客户端据此决定是否展示「绑定授权码」输入框:SAME_CODE下授权码始终不变,无需引导用户重新输入;NEW_CODE下升级/续费会签发新码,须以接口返回的新licenseCode覆盖本地保存的授权码。产品未配置时按SAME_CODE处理;verify结果缓存约 60 秒,配置变更最长 60 秒生效。同时,成功响应还附带trialExpiryTime(试用到期时间快照,ISO 8601 字符串;授权非试用转购买时为null)。客户端可据此实现宽限:用户先试用全功能、再购买较低版本时,高阶功能可继续放行至trialExpiryTime。同时,成功响应还附带trialExpiryTime(试用到期时间快照,ISO 8601 字符串;授权非试用转购买时为null)。客户端可据此实现宽限:用户先试用全功能、再购买较低版本时,高阶功能可继续放行至trialExpiryTime。同时,成功响应还附带trialExpiryTime(试用到期时间快照,ISO 8601 字符串;授权非试用转购买时为null)。客户端可据此实现宽限:用户先试用全功能、再购买较低版本时,高阶功能可继续放行至trialExpiryTime。
双环境调试对两种场景完全透明:
- 场景 A:调试机
claimTrial/ 平台购买页支付全链路自动走 Test 环境(见第四章) - 场景 B:调试机调用
generateForSoftware时平台同样按机器码路由到 Test 环境,返回T-前缀授权码;服务端代码无需任何改动 - SDK 调用方式在调试期和上线后完全一致,无需任何环境参数或代码分支,环境路由由平台服务端自动完成
三、授权集成细节(两种场景通用)
3.1 本地凭证存储规范
SDK 本身不负责持久化,由开发者自行实现。存储内容:
{
"licenseCode": "XXXXXXXXXXXX",
"activationToken": "YYYYYYYYYYYY",
"lastVerify": {
"valid": true,
"edition": "ULTIMATE",
"expiryTime": 1735689600000,
"trialExpiryTime": 1735000000000,
"trialExpiryTime": 1735000000000,
"trialExpiryTime": 1735000000000,
"cachedAt": 1735689600000
}
}
原则:
- 只存
licenseCode+activationToken+ 最近一次 verify 结果 - 不存可解密的完整授权信息(防逆向无意义,只作缓存)
verifyCached的 60s 缓存在 SDK 进程内,重启后失效,需重新调verify
3.2 版本层级对比(edition)
开发者自定义 edition code(如 BASIC / PRO / ULTIMATE),在平台发布页配置。所有产品形态(客户端/服务端/仅推广)启用授权码后均可自定义版本。客户端校验时按层级比较:
EDITION_LEVEL = {"BASIC": 0, "PRO": 1, "ULTIMATE": 2, "TRIAL": 99}
def edition_sufficient(user_edition, required_edition):
return EDITION_LEVEL.get(user_edition, 0) >= EDITION_LEVEL.get(required_edition, 0)
常见映射(参考):
| 功能档位 | edition code | 层级 | 典型功能 |
|---|---|---|---|
| 基础版 | BASIC |
0 | 基础修图、格式转换 |
| 高阶版 | PRO |
1 | 批量处理、高清放大 |
| 旗舰版 | ULTIMATE |
2 | AI 修复、封面助手 |
版本名称和 code 由开发者在平台自定义,不强制叫 BASIC/PRO/ULTIMATE。版本价格和功能清单仅在勾选「平台代收授权费」时展示在购买页。
3.3 错误码处理(LicenseError)
SDK 抛出 LicenseError,携带 error_code 属性:
from ps_license_sdk import LicenseError
try:
result = client.verify_cached(...)
except LicenseError as e:
if e.error_code == "expired":
open_purchase_page()
elif e.error_code == "revoked":
show_message("授权已被吊销,请联系客服")
elif e.error_code == "machineLimit":
show_message("已达机器绑定上限,请在个人中心解绑旧设备")
elif e.error_code == "NETWORK_ERROR":
show_message("网络异常,请检查网络后重试")
else:
show_message(f"校验失败:{e}")
| 错误码 | 含义 | 客户端建议处理 |
|---|---|---|
codeNotFound |
授权码不存在 | 检查输入 |
revoked |
已吊销 | 提示联系客服 |
expired |
已过期 | 引导购买/续费 |
machineLimit |
机器绑定数已满 | 引导去个人中心解绑 |
tooManyAttempts |
触发限流 | 提示稍后重试 |
trialNotEnabled |
产品未开启试用 | 检查平台配置 |
trialAlreadyPurchased |
已购买过该产品,无需再领取试用 | 提示已购并引导至购买页 |
trialAlreadyPurchased |
已购买过该产品,无需再领取试用 | 提示已购并引导至购买页 |
trialAlreadyPurchased |
已购买过该产品,无需再领取试用 | 提示已购并引导至购买页 |
NETWORK_ERROR |
网络/超时 | 离线宽限或提示重试 |
3.4 购买页跳转(仅场景 A)
3.4.1 购买页 URL
https://www.powersoftware.app/product/license/purchase?productUniqueCode={productUniqueCode}&machineCode={machineCode}
SDK 方法:
url = client.purchase_url(mc)
调试机访问该页面时,顶部会出现「调试模式(测试环境)」徽标,支付走测试通道(见第四章)。 语言由购买页按用户浏览器自动检测(URL 前缀 /
Accept-Language),SDK 无需关心。
3.4.2 站点:统一用国际站 .app,开发者无需选择购买站
powersoftware.app(国际站) |
powersoftware.cn(国内站) |
|
|---|---|---|
| 支付方式 | Waffo(卡 / Apple Pay / Google Pay 等)+ PayPal + 支付宝 | 仅支付宝 |
| 国家/币种 | Cloudflare 按 IP 自动识别(CN→CNY,其余→USD) | 固定 country=CN,人民币 |
| 语言 | 按 URL 前缀 / Accept-Language 自动检测 |
固定 zh-CN |
| 定位 | 开发者唯一需要使用的购买入口 | 国际站支付宝支付的承接站 |
开发者无需做购买站选择:purchaseUrl 统一指向国际站 .app。海外用户在 .app 直接完成 Waffo / PayPal 支付;国内用户在 .app 选择支付宝时,平台会自动跳转到国内站 .cn 完成支付宝付款(登录状态自动同步,无需重新登录),支付成功后回到授权流程。整条链路对用户和开发者都是透明的。
# 正确:固定使用国际站,不要按地区/语言切换 base
url = client.purchase_url(mc)
# 不建议:自行判断地区传 .cn base——支付宝跳转已由平台处理,
# 且硬编码 .cn 会丢失 Waffo / PayPal 支付方式
四、调试阶段(双环境,v4 新增)
上线前最稳妥的验收方式:把自己日常开发用的电脑登记为「调试设备」,用真实支付链路走一遍完整流程。
4.1 登记机器码
- 个人中心 →「我的机器码」→ 登记调试电脑的机器码
- 机器码可用 SDK 的
machine_code()生成(同一台机器三语言结果一致)
- 机器码可用 SDK 的
- 记下该机器码
4.2 注册调试设备
- 开发者中心 → 产品列表 → 目标产品的「调试设备」按钮
- 在弹窗中从已登记机器码中选择,添加到本产品(可写备注)
- 限制:每个产品最多 3 台调试设备;支持开关(临时停用路由)与移除
4.3 调试机上会发生什么
在已注册且启用中的调试机上,该产品的全链路自动切换到 Waffo Test 环境:
调试机(你的电脑) 幂栈网平台(服务端自动判定环境)
│ │
│ claimTrial(machineCode)
├─────────────────→│ 该机器是本产品调试机 → 走 Test 路径
│ │
│ ← 试用授权(T- 前缀授权码,写测试授权表)
│ │
│ purchaseUrl(machineCode)
├─────────────────→│ 购买页显示「调试模式(测试环境)」徽标
│ │ → 用 Waffo Test 测试卡支付(不扣真钱)
│ │ → 订单落测试订单表,平台发测试码(T- 码)
│ ← 平台发码(T- 码)
│ │
│ activate(T-码, machineCode)
├─────────────────→│ 按 T- 前缀直接定位测试表
│ ← activationToken│
│ │
│ verifyCached(...)
├─────────────────→│ 校验通过
│ ← { valid, edition, expiryTime }
要点:
- 识别方式:授权码带
T-前缀即测试授权;购买页顶部会出现「调试模式(测试环境)」徽标 - 支付:走 Waffo Test 收银台,使用测试卡(如
4576 ... 0110)完成支付,不发生真实扣款 - 零代码改动:客户端不需要任何改动,同一份代码在调试机和真实用户机器上行为一致(只是后端落表不同)
4.4 建议的调试清单
- 调试机首次启动 →
claimTrial成功,拿到T-前缀试用码 - 试用期内
verifyCached返回valid,付费功能放行 -
purchaseUrl打开购买页,确认出现「调试模式」徽标 - 测试卡完成支付 → 收到测试授权码(邮件/页面)
-
activate激活成功 →verifyCached通过 - 版本拦截正确(低版本码访问高版本功能被拦截)
- 机器绑定上限(
machineLimit)与解绑路径正常 - (仅场景 B) 调试机调
generateForSoftware返回T-前缀授权码,激活校验正常;同一接口换未登记机器调用返回正式码 - 换一台未登记的机器重复
claimTrial,确认走生产链路(对照验证)
4.5 调试注意事项
| 事项 | 说明 |
|---|---|
| 测试数据清理 | 测试授权/订单不影响生产,无需清理;如需重置可在调试设备面板移除后重新添加 |
| 调试开关 | 临时不想走测试链路时,在调试设备面板关闭开关即可,无需删设备 |
| 仅推广产品 | 产品形态为「仅推广」时不同步 Waffo 商品目录,无调试购买链路 |
| 无有效价格 | 主/副价格与所有授权版本均无正价时,测试商品同步会失败(钉钉告警),请至少配置一个版本价格 |
五、上线阶段
5.1 提交审核
- 调试清单全部通过后,在产品表单点「保存并提交审核」
- 产品进入审核队列(
PENDING_RELEASE)
调试期保存过草稿的产品,提审时内容即为最新草稿内容;审核期间再编辑会自动回退为草稿状态(防止审核中内容变更),需重新提审。
5.2 审核通过 → 自动同步生产
平台运营审核通过后:
- 产品状态变为已发布、上架
- 平台自动把商品同步到 Waffo 生产环境(回写
waffo_product_id),创建/恢复生产收银台商品 - 产品详情页、搜索结果对全部用户可见
5.3 真实用户链路(生产)
真实用户(非调试机)的链路与调试完全一致,只是全部落在生产表:
首次启动 → claimTrial 领试用(正式授权码,无 T- 前缀)
→ 试用到期 → purchaseUrl 跳购买页(支付宝 / PayPal 真实支付)
→ 平台支付成功自动发码 + 邮件送达
→ activate 激活 → verifyCached 校验放行
场景 B(自行收款)的用户不走平台购买页:用户在你的渠道付费后,由你的服务端调
generateForSoftware发正式授权码,后续激活/校验链路与场景 A 相同。
5.4 上线验证清单
- 用一台未登记为调试机的电脑访问产品详情页,确认正常展示
- 购买页无「调试模式」徽标
- 真实小额支付 → 发码 → 激活成功
- 开发者中心订单列表能看到该笔订单(测试订单不会出现在此)
六、上线后运营
| 操作 | 入口 | 说明 |
|---|---|---|
| 查看订单 | 开发者中心 → 我的订单 | 仅生产订单;测试订单不参与分润与对账 |
| 用户解绑 | 用户个人中心 / 开发者人工授权 | 换绑配额:解绑后 30 天内不可再次解绑 |
| 版本迭代 | 产品编辑 → 保存草稿 / 提审 | 编辑会再次异步同步 Waffo Test,可持续用调试机验证新版本 |
| 退款 | Waffo Dashboard | 买家发起工单、商家在 Dashboard 审核;测试订单退款仅吊销测试授权 |
| 下线调试 | 调试设备面板移除设备 | 建议版本稳定后移除调试机,避免误用测试链路 |
七、常见问题(FAQ)
Q1:调试期需要修改客户端代码或配置吗? 不需要。环境路由由平台服务端根据「机器码是否在调试设备列表」自动判定,SDK 调用完全一致。
Q2:调试机上拿到的授权码能给真实用户用吗?
不能也不建议。T- 码只在测试表有效,且调试数据不参与任何生产逻辑;给真实用户发测试码会导致其无法通过正常校验路径获得售后保障。
Q3:调试需要花钱吗? 不需要。测试支付通道使用测试卡,不发生真实扣款;测试订单不参与分润/结算。
Q4:调试会影响我的产品审核吗? 不会。调试数据与审核完全解耦;草稿状态即可调试,提审与否由你决定。
Q5:多台电脑都想调试怎么办? 每个产品最多登记 3 台调试设备;在调试设备面板添加/移除即可。
Q6:产品形态是「仅推广」或没配置价格,能调试购买吗? 不能。仅推广产品不同步 Waffo 商品目录;无有效价格时测试商品同步会失败。此类产品只能调试试用与校验链路。
Q7:忘记关调试开关就上线了会怎样? 影响范围仅限你登记的那台机器——它仍走测试链路;所有真实用户不受影响。确认稳定后在调试设备面板移除即可。
八、集成清单(上线前逐项核对)
场景 A(平台完整链路)
- 在幂栈网发布产品,售卖方式选「先用后付」
- 配置试用天数(建议 7~14 天)
- 配置授权版本(edition code + 名称 + 价格 + 功能清单)
- 确认「平台代收授权费」已勾选(先用后付强制勾选)
- 记下
productUniqueCode - 拷贝 SDK 源码到项目(见 2.3.1)
- 实现
claimTrial→ 首次启动领取试用 - 实现
activate→ 用户输入授权码激活 - 实现
verifyCached→ 点击付费功能时校验 - 实现
purchaseUrl→ 未授权跳转购买页(统一用国际站.app,无需选择站点) - 实现本地凭证持久化(
licenseCode+activationToken) - 实现 edition 层级比较逻辑(见 3.2)
- 实现
LicenseError错误码处理(见 3.3) - 登记调试机并走通双环境调试清单(见 4.4)
- 提审 → 审核通过 → 上线验证(见 5.4)
场景 B(订单不在平台)
- 在幂栈网发布产品,开启
licenseEnabled - 配置授权版本(edition code + 名称);如需平台代收,勾选「平台代收授权费」并填写价格
- 在开发者后台获取
licenseApiSecret - 记下
productUniqueCode - 搭建服务端保管授权密钥
licenseApiSecret,实现发码接口(密钥不可下发到客户端) - 客户端拷贝 SDK 源码到项目
- 服务端实现
generateForSoftware(发码) - 服务端实现
upgradeForSoftware(升级/续费) - 客户端实现
activate/verifyCached - 实现本地凭证持久化
- 实现 edition 层级比较逻辑(见 3.2)
- 实现
LicenseError错误码处理(见 3.3) - 登记调试机验证
T-码链路(见 4.4) - 提审 → 审核通过 → 上线验证(见 5.4)
附录:SDK 仓库(GitHub)
github.com/mizhanchengxi/powersoftware-license-sdk
├── node/ SDK 源码(ESM, 零依赖, 单文件)
├── python/ SDK 源码(py3, 零依赖, 3 个文件)
├── java/ SDK 源码(Java 8+, 零依赖, 3 个文件)
└── docs/ SDK 规范文档
三个包均提供:machineCode() / sign() / LicenseClient(含 activate / verify / deactivate / claimTrial / generateForSoftware / upgradeForSoftware / verifyCached / purchaseUrl)。
本文档为 客户端软件授权接入指南(CLIENT_SOFTWARE_GUIDE) 的 v4 升级版,完整覆盖其全部内容,并新增双环境调试与草稿/提审能力。