授權碼License 開發調試上線全流程指南

v1.0.0

客戶端軟件開發 → 調試 → 上線全流程指南(v4)

適用於:在幂棧網發佈客戶端軟件並接入授權碼體系的開發者。 本文覆蓋從「創建產品」到「真實用戶購買」的完整生命週期,重點是 v4 新增的雙環境調試能力:上線前用真實支付鏈路(Waffo Test 環境)把自己的電腦當調試機走通全流程。

一、全流程總覽

┌──────────────┐   ┌──────────────┐   ┌──────────────┐   ┌──────────────┐
│ ① 開發階段   │ → │ ② 調試階段   │ → │ ③ 上線階段   │ → │ ④ 上線後運營 │
│              │   │              │   │              │   │              │
│ 創建產品草稿 │   │ 註冊調試機   │   │ 提交審核     │   │ 查看訂單     │
│ 集成授權 SDK │   │ 走通真實鏈路 │   │ 審核通過     │   │ 解綁/退款    │
│ 保存草稿     │   │ (Test 環境)│   │ 同步生產環境 │   │ 版本迭代     │
└──────────────┘   └──────────────┘   └──────────────┘   └──────────────┘
階段 產品狀態 授權/訂單落在哪 會產生真實收入嗎
① 開發 草稿(DRAFT)
② 調試 草稿 / 審核中 Test 表(授權碼帶 T- 前綴) 否(測試支付通道)
③ 上線 已發佈 生產表

核心規則:調試與生產完全隔離。 調試機上發生的一切(試用、下單、支付、發碼、激活、退款)只影響測試表,不進分潤、不進對賬、不影響任何真實用戶;非調試機的訪問永遠走生產鏈路。

二、開發階段

2.1 創建產品

  1. 登錄幂棧網開發者中心 → 發佈產品,產品形態選「客戶端軟件」
  2. 售賣方式選 先用後付,填寫試用天數(建議 7~14 天)
  3. 配置授權版本(edition):默認三檔 BASIC / PRO / ULTIMATE,可自定義 code、名稱、價格與功能清單
  4. 勾選「平台代收授權費」(先用後付強制勾選)
  5. 上傳軟件包與介紹素材

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 + activationTokenLicenseError 錯誤碼處理。

核心代碼(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。同時,成功響應還附帶 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,
    "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 已購買過該產品,無需再領取試用 提示已購並引導至購買頁
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 登記機器碼

  1. 個人中心 →「我的機器碼」→ 登記調試電腦的機器碼
    • 機器碼可用 SDK 的 machine_code() 生成(同一台機器三語言結果一致)
  2. 記下該機器碼

4.2 註冊調試設備

  1. 開發者中心 → 產品列表 → 目標產品的「調試設備」按鈕
  2. 在彈窗中從已登記機器碼中選擇,添加到本產品(可寫備註)
  3. 限制:每個產品最多 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 提交審核

  1. 調試清單全部通過後,在產品表單點「保存並提交審核」
  2. 產品進入審核佇列(PENDING_RELEASE

調試期保存過草稿的產品,提審時內容即為最新草稿內容;審核期間再編輯會自動回退為草稿狀態(防止審核中內容變更),需重新提審。

5.2 審核通過 → 自動同步生產

平台運營審核通過後:

  1. 產品狀態變為已發佈、上架
  2. 平台自動把商品同步到 Waffo 生產環境(回寫 waffo_product_id),創建/恢復生產收銀台商品
  3. 產品詳情頁、搜索結果對全部用戶可見

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 升級版,完整覆蓋其全部內容,並新增雙環境調試與草稿/提審能力。