# 手動開發接入指南（9 種語言，無需 AI）

本指南適用于 Licentivo 提供方。已有其他授權系統的商戶，可在后臺“授權選擇與自定義”選擇自定義服務，按[自定義授權 API 與對接流程](/zh-hant/launch-documents/external-licensing/)接入，并繼續使用自有授權系統的 SDK。

> 當前未發布改動采用帳號身份交換，具體職責和遷移約束見 [購買期限與帳號 SDK 邊界](/zh-hant/launch-documents/account-purchase-boundary/)。Launch 計算購買期限；Licentivo SDK 執行授權。

只安裝對應語言的 Launch 接入包。Launch 包內部包含官方 SDK、預設適配器和鏈接配置；官方授權地址固定為 `https://www.licentivo.com`。程序使用購買者在當前 Launch 商店注冊的帳號登錄。

## 取得已填寫的初始化代碼

1. 在 Launch 后臺完成軟體、銷售套餐和 Licentivo 授權策略的關聯，并在對應環境發布。
2. 打開 **程序接入 → 接入檢查與代碼**，選擇軟體、語言和測試/正式環境。
3. 點擊“讀取產品資訊并生成接入代碼”。Launch 自動讀取站點當前公開地址、已有產品映射和簽名公鑰。
4. 復制頁面上的連接函數到自己的工程，按下文手動編寫界面和業務調用。也可以查看自動填好的參數后自行調用對應語言的 `Connect/connect`。

無需手填兩個內部產品 ID，無需生成 `launch-config.json` 或 `product.json`。頁面可保存的是源碼連接函數。伺服器私有 `config.yaml` 只供 Launch 服務啟動，不能隨客戶軟體發布。

站點地址來自當前實例的有效公開地址（啟動配置 `public_url`，或后臺網站設置中的有效公開地址）。它可以是域名或包含連接埠的 IP 地址，但須帶協議；正式接入使用有效 HTTPS。監聽地址 `http_addr` 不是客戶訪問地址。更換站點地址、產品映射或環境后，從當前站點重新取得連接函數；舊站點的會話和快取不得作為新站點授權。

兩個產品編號是系統已有的內部對應關系：Launch 軟體商品和 Licentivo 授權產品。接入頁根據所選軟體自動填入；購買者只輸入商店帳號。簽名公鑰由伺服器使用已配置的 Licentivo 連接讀取，管理密鑰和客戶授權憑據不會進入源碼。

## `Connect/connect` 的作用

`Connect/connect` 是不同語言對“創建 Launch 應用客戶端”這一操作的命名。Go、C# 和部分原生接口使用首字母大寫的 `Connect`，Python、JavaScript、Ruby 等語言按各自風格使用 `connect`。后臺生成的 `connectLaunch()`、`connect_launch()` 或 `LaunchConnection.Open()` 是把公開參數預先填好的項目函數，內部調用的就是對應語言入口。

連接只完成初始化：它驗證商店地址、產品映射、環境與簽名公鑰，創建 Launch 客戶端，并配置包內官方 Licentivo SDK。它不會驗證客戶身份，也不會直接開放付費功能。完整順序為：

```text
Connect/connect → Login or Restore → RunFeature → Logout / Close
                                       └──────────→ ReleaseDevice (explicit device unlink only)
```

應用運行期間應保留同一個客戶端對象，讓 SDK 正常處理心跳與浮動席位。普通關閉保留設備綁定；客戶明確退出與 ReleaseDevice 兼容入口調用同一官方 SDK 退出流程。

## 安裝與初始化入口

0.1.6 的九種語言公開安裝驗證已全部通過（9/9），下表安裝方式均已驗證。[GitHub Release](https://github.com/spf86/licentivo-launch-sdk/releases/tag/v0.1.6) 也提供原生包和離線文件，使用方式見[下載包安裝說明](/zh-hant/launch-documents/integration-packages/#install-a-downloaded-distribution)。

| 語言 | 只安裝 Launch | 頁面提供的連接函數 | 包內直接初始化 API |
| --- | --- | --- | --- |
| Go | `go get github.com/spf86/licentivo-launch-sdk/pkg/launchclient@v0.1.6` | `connectLaunch()` | `launchclient.Connect` |
| Python 3.10+ | `python -m pip install licentivo-launch==0.1.6` | `connect_launch()` | `Application.connect` |
| C# / .NET 8+ | `dotnet add package Licentivo.Launch --version 0.1.6` | `LaunchConnection.Open()` | `Application.Connect` |
| Java 17+ | Maven/Gradle：`com.licentivo.launch:launch-client:0.1.6` | `LaunchConnection.open()` | `Launch.connect` |
| Node.js 20.3+ | `npm install @licentivo/launch@0.1.6` | `connectLaunch()` | `Application.connect` |
| Rust 1.85+ | `cargo add licentivo-launch@=0.1.6` | `connect_launch()` | `Application::connect` |
| Ruby 3.1+ | `gem install licentivo-launch --version 0.1.6` | `connect_launch` | `Application.connect` |
| C11 | 從 [GitHub Release](https://github.com/spf86/licentivo-launch-sdk/releases/tag/v0.1.6) 下載原生包，CMake 導入 | `connect_launch()` | `launch_application_connect` |
| C++17 | 使用同一 Launch 原生包 | `connectLaunch()` | `Application::Connect` |

公開源碼和各語言 README 見 [Launch SDK 倉庫](https://github.com/spf86/licentivo-launch-sdk)，原生包與離線文件見 [v0.1.6 Release](https://github.com/spf86/licentivo-launch-sdk/releases/tag/v0.1.6)，公開安裝結果見 [九種語言注冊表驗證](https://github.com/spf86/licentivo-launch-sdk/blob/main/docs/registry-verification.json)。每個包自己的 README 提供安裝命令和 API。JavaScript 包包含 TypeScript 聲明。普通語言依賴由包管理器解析，例如 Python 的 cryptography、C# 的 BouncyCastle 和 Ruby 的 base64；無需安裝官方 SDK 包。

Go 公開模塊名為 `github.com/spf86/licentivo-launch-sdk`，導入路徑為 `github.com/spf86/licentivo-launch-sdk/pkg/launchclient`，應用無需本地 replace。Windows 原生包采用 amd64 GNU/MinGW，另有 Linux amd64 原生包。Ruby 平臺包和 Rust/native 的 Windows 分發包含 curl；其他平臺源碼構建需要常規 C11、curl/OpenSSL 開發依賴。平臺工具鏈說明見各包 README。

## 登錄與受保護操作

以下片段使用上一步復制的連接函數。`email`、`password` 來自自己的登錄界面；不得將密碼寫入源碼或配置。`export` 必須替換為套餐策略中實際存在的功能名。

### Go

```go
app, err := connectLaunch()
if err != nil { return err }
defer app.Close()
if _, err := app.Login(ctx, email, password); err != nil { return err }
return app.RunFeature("export", func() error {
    return exportReport()
})
```

`ctx` 使用應用生命周期上下文，不能在登錄請求結束時立即取消心跳。網路操作放在后臺工作線程。恢復調用 `Restore(ctx)`；退出帳號調用 `Logout(ctx)`；釋放設備調用 `ReleaseDevice(ctx)`。

### Python

```python
with connect_launch() as app:
    app.login(email, password)
    result = app.run_feature("export", export_report)
```

`restore()` 恢復已有安全會話；無會話時顯示登錄界面。`logout()` 清理帳號；`release_device()` 明確釋放設備。不要讓同步網路操作阻塞桌面事件循環。

### C# / .NET

```csharp
await using var app = LaunchConnection.Open();
await app.Login(email, password);
await app.RunFeature("export", async () => {
    await ExportReport();
});
```

使用 `await Restore()`、`await Logout()` 和 `await ReleaseDevice()`。保持應用存活期間的 SDK 生命周期，使用異步界面流程。

### Java

```java
try (var app = LaunchConnection.open()) {
    app.login(email, passwordChars);
    app.runFeature("export", () -> exportReport());
}
```

密碼使用 `char[]`。`restore()` 無會話時返回 `NO_SESSION` 失敗，應顯示登錄界面；其它失敗不能視為授權。`logout()` 和 `releaseDevice()` 是不同操作。try-with-resources 負責關閉。

### JavaScript / Node.js / TypeScript

```javascript
const app = connectLaunch();
try {
  await app.login(email, password);
  const result = await app.runFeature('export', () => exportReport());
} finally {
  await app.close();
}
```

`restore()` 沒有會話時返回 `null`；正常恢復后才允許執行業務。`logout()` 的布爾返回值表示遠端退出是否確認，設備釋放失敗應顯示錯誤。代碼運行在 Node.js、Electron 主進程或可信后端；瀏覽器和 Electron 渲染進程不保存授權憑據。

### Rust

```rust
let mut app = connect_launch()?;
app.login(&email, &password)?;
let result = app.run_feature("export", || {
    export_report()?;
    Ok(())
})?;
app.close();
```

回調返回 `Result<T, Failure>`。`restore()`、`logout()`、`release_device()` 返回結果，必須處理失敗。`Drop` 也負責關閉運行時。預設原生核心由 build.rs 編譯和鏈接，不需自己鏈接官方 SDK。

### Ruby

```ruby
app = connect_launch
begin
  app.login(email, password)
  result = app.run_feature('export') { export_report }
ensure
  app.close
end
```

`restore` 恢復會話，`logout` 退出帳號，`release_device` 釋放設備。保護操作使用代碼塊；異常不能轉換為成功。

### C

```c
static int export_action(void *context) {
    return export_report(context); /* Return 1 only on success. */
}

launch_application *app = connect_launch();
if (!app) return 0;
int ok = launch_application_login(app, email, password);
if (ok) ok = launch_application_run_feature(app, "export", export_action, context);
/* Check launch_application_error(app) on failure; never log credentials. */
launch_application_close(app);
return ok;
```

`launch_application_restore` 為三態：`1` 已恢復、`0` 沒有會話、`-1` 失敗。只有沒有會話時正常顯示登錄；拒絕或異常不能當作成功。`logout` 和 `release_device` 的返回值也必須檢查。

CMake 只導入 Launch：

```cmake
find_package(LicentivoLaunch CONFIG REQUIRED)
add_executable(myapp main.c)
licentivo_launch_link(myapp)
```

### C++

```cpp
auto app = connectLaunch();
app.Login(email.c_str(), password.c_str());
app.RunFeature("export", [&] { exportReport(); });
```

`Restore()`、`Logout()`、`ReleaseDevice()` 遵循 C++ 異常語義。RAII 析構負責關閉。CMake 使用 `licentivo_launch_link(myapp CXX)`，Launch 自動處理 SDK 鏈接和分發包內運行庫。

## 生命周期、安全存儲與錯誤

創建連接對象只完成初始化。程序必須登錄或恢復成功，并在每次業務操作中使用功能保護回調。訂單已付款、會話存在或按鈕可點擊都不能代替 SDK 驗證。

預設會話僅保存在內存。記住登錄需要安全存儲：Go、Python、C# 和原生 C/C++ 提供 Windows 當前用戶 DPAPI；Java、Node、Rust 和 Ruby 提供使用調用方密鑰的 AES-GCM 存儲。跨平臺應用應對接系統憑據庫。不能把密鑰和密文放在同一普通目錄。

普通關閉保留用戶主動記住的會話并停止運行時。退出帳號先調用官方 SDK 統一退出，再清理 Launch 自有帳號記錄。ReleaseDevice 是同一流程的兼容入口，遠端撤銷待完成時不能提示釋放成功。不要清理官方 SDK 的快取目錄或退出恢復日志。Launch 的會話保護不代表官方 SDK 的全部設備文件都已加密，應限制快取目錄權限。

| 狀態 | 程序處理 |
| --- | --- |
| 帳號或密碼失敗 | 顯示通用登錄失敗，不泄露帳號是否存在 |
| EMAIL_VERIFICATION_REQUIRED | 引導完成商店郵箱驗證 |
| ENTITLEMENT_PENDING | 顯示同步中，按包的有限重試和 Retry-After 等待 |
| ENTITLEMENT_NOT_PURCHASED | 引導購買或切換帳號 |
| ENTITLEMENT_EXPIRED | 引導續費，不使用舊憑據繞過拒絕 |
| ENTITLEMENT_SUSPENDED | 停止受保護功能，聯系商家 |
| 設備數量已滿 | 引導管理或明確釋放設備 |
| 網路/HTTP 5xx | 僅可使用 SDK 已驗證、仍在有效期內的離線授權 |

明確的 401/403/404、帳號不符、取消或限流不能變成離線授權成功。首次激活和禁止離線的策略仍需聯網。服務端域名/IP 無法訪問時應顯示連接問題，不能偷偷連接其它站點。

## 驗收與參考

驗證真實登錄、所屬帳號授權、受保護操作、重啟恢復、有效離線與離線到期、快取篡改、退出、帳號切換和設備釋放。本文不要求使用 AI。測試工具和外部驗收邊界見 [acceptance.md](/zh-hant/launch-documents/acceptance/)；本地包和構建說明見 [integration-packages.md](/zh-hant/launch-documents/integration-packages/)。

配置檢查、代碼生成和本地測試不會自動證明真實支付、授權簽發或官網激活成功。外部商店和支付沙箱需配置后單獨驗收。
