客户端OpenSDK相关信息请点击以下链接获取：

* [OpenSDK基本信息](https://pay.douyinpay.com/wiki/639fd757f4a57b0226bb2066/668fcf3699cc6202f1bfb0ef)
* [OpenSDK集成指南](https://pay.douyinpay.com/wiki/639fd757f4a57b0226bb2066/639fd78317c2f3021d238378)

# iOS调用支付
### 依据[预下单](https://douyinpay.com/wiki/427lmayi/48mqiimc)接口返回的 prepay_id 组装拉起抖音支付 SDK 的参数
| <span style="background-color: rgb(250, 250, 250)">参数名</span> | <span style="background-color: rgb(250, 250, 250)">变量</span> <br> [大小写敏感] | <span style="background-color: rgb(250, 250, 250)">类型[长度限制]</span> | <span style="background-color: rgb(250, 250, 250)">必填</span> | <span style="background-color: rgb(250, 250, 250)">描述</span> |
| --- | --- | --- | --- | --- |
| 应用ID | appid | string[1,32] | 是 | 开放平台审核通过的移动应用appid 。 <br> 示例值：dy88888888 |
| 商户号 | partnerid | string[1,32] | 是 | 请填写商户号mchid对应的值。 <br> 示例值：1900000109 |
| 预支付交易会话ID | prepayid | string[1,64] | 是 | 抖音返回的支付交易会话ID，该值有效期为2小时。 <br> 示例值： dy1217758 |
| 支付产品类型 | package | string[1,128] | 是 | 签约或支付，根据不同业务流程填写不同的值。 <br> App支付：Sign=DYPay <br> 免密支付/商户代扣   签约并支付：Sign=DYPay <br> 示例值：**"package"："Sign=DYPay"** |
| 随机字符串 | noncestr | string[1,32] | 是 | 随机字符串，不长于32位。推荐随机数生成算法。 <br> 示例值： 5a409aa667ee4ee6 |
| 时间戳 | timestamp | string[1,10] | 是 | 时间戳，单位秒。 <br> 示例值：1412000000 |
| 签名 | sign | string[1,256] | 是 | 签名，使用字段appId、timeStamp、nonceStr、prepayid计算得出的签名值 <br> 注意：取值RSA、国密格式 <br> 示例值：oR9d8PuhnIc+YZ8cBHFCwfgpaK9gd7vaRvkYD7rthRAZ\/X+QBhcCYL21N7cHCTUxbQ+EAt6Uy+lwSN22f5YZvI45MLko8Pfso0jm46v5hqcVwrk6uddkGuT+Cdvu4WBqDzaDjnNa5UK3GfE1Wfl2gHxIIY5lLdUgWFts17D4WuolLLkiFZV+JSHMvH7eaLdT9N5GBovBwu5yYKUR7skR8Fu+LozcSqQixnlEZUfyE55feLOQTUYzLmR9pNtPbPsu6WVhbNHMS3Ss2+AehHvz+n64GDmXxbX++IOBvm2olHu3PsOUGRwhudhVf7UcGcunXt8cqNjKNqZLhLw4jq\/xDg== |
将上述参数组装为一个 NSDictionary<NSString *, NSString *> ，作为参数拉起抖音支付。
### **拉起抖音支付**

1. 在Xcode中，选择你的工程设置项，选中 "TARGETS" 一栏，在 "info" 标签栏下的 "Custom iOS Target Properties"里，设置 "Bundle name" 或 "Bundle display name"（如果没有则添加）。
2. 调用 openDypayWithInfo 拉起抖音支付，params参数就是上面组装的NSDictionary<NSString *, NSString *>，以下是示例代码：

```Objective-C
// 拉起抖音支付
 [DypayAPI openDypayWithInfo:params
                 fromViewController:self
                     resultCallback:^(NSDictionary * _Nonnull resultDict) {
           // resultDict的描述详见下面的SDK回调错误码定义
 }];
```

### SDK结果回调
支付结果将由抖音支付通过URL返回。
```Objective-C
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {
    // 处理SDK回调结果
    [DypayAPI processDypayResultWithURL:url callback:^(NSDictionary *resultDict) {
    
    }];
}


resultDict 包含SDK回调错误码信息，示例如下：
{
    "resultCode": @"0"
}
key: "resultCode"，字符串类型。
value：错误码，字符串类型，需要自己转换为整数。详见下面的SDK回调错误码定义。
```

# Android调用支付
### 依据[预下单](https://douyinpay.com/wiki/427lmayi/48mqiimc)接口返回的 prepay_id 组装拉起抖音支付 SDK 的参数
| <span style="background-color: rgb(250, 250, 250)">参数名</span> | 变量 <br> [大小写敏感] | <span style="background-color: rgb(250, 250, 250)">类型[长度限制]</span> | <span style="background-color: rgb(250, 250, 250)">必填</span> | <span style="background-color: rgb(250, 250, 250)">描述</span> |
| --- | --- | --- | --- | --- |
| 应用ID | appid | string[1,32] | 是 | 开放平台审核通过的移动应用appid 。 <br> 示例值：dy8888888888888888 |
| 商户号 | partnerid | string[1,32] | 是 | 请填写商户号mchid对应的值。 <br> 示例值：1900000109 |
| 预支付交易会话ID | prepayid | string[1,64] | 是 | 抖音返回的支付交易会话ID，该值有效期为2小时。 <br> 示例值： dy1217752501201407033233368018 |
| 支付产品类型 | package | string[1,128] | 是 | 签约或支付，根据不同业务流程填写不同的值。 <br> App支付：Sign=DYPay <br> 免密支付/商户代扣   签约并支付：Sign=DYPay <br> 示例值：**"package"："Sign=DYPay"** |
| 随机字符串 | noncestr | string[1,32] | 是 | 随机字符串，不长于32位。推荐随机数生成算法。 <br> 示例值： 5K8264ILTKCH16CQ2502SI8ZNMTM67VS |
| 时间戳 | timestamp | string[1,10] | 是 | 时间戳，单位秒。 |
| 签名 | sign | string[1,256] | 是 | 签名，使用字段appId、timeStamp、nonceStr、prepayid计算得出的签名值 <br> 注意：取值RSA、国密格式 <br> 示例值：oR9d8PuhnIc+YZ8cBHFCwfgpaK9gd7vaRvkYD7rthRAZ\/X+QBhcCYL21N7cHCTUxbQ+EAt6Uy+lwSN22f5YZvI45MLko8Pfso0jm46v5hqcVwrk6uddkGuT+Cdvu4WBqDzaDjnNa5UK3GfE1Wfl2gHxIIY5lLdUgWFts17D4WuolLLkiFZV+JSHMvH7eaLdT9N5GBovBwu5yYKUR7skR8Fu+LozcSqQixnlEZUfyE55feLOQTUYzLmR9pNtPbPsu6WVhbNHMS3Ss2+AehHvz+n64GDmXxbX++IOBvm2olHu3PsOUGRwhudhVf7UcGcunXt8cqNjKNqZLhLw4jq\/xDg== |
将上述参数组装为一个`Map<String, String>`作为参数拉起抖音支付。
### 拉起抖音支付
调用`DyPay(activity).pay(payInfoMap, callback)`拉起抖音支付，`payInfoMap`参数就是上面第二步中组装的map，callback为回调。
Kotlin示例：
```Kotlin
//唤端拉起抖音
DyPay(activity).pay(payInfoMap, object : IDyPayResultCallback {
    override fun onResult(map: Map<String, String>) {
        //处理回调结果
    }
})
```

Java示例：
```Java
DyPay dyPay = new DyPay(activity);
//唤端拉起抖音
dyPay.pay(payInfoMap, new IDyPayResultCallback(){
 @Override
 public void onResult(@NonNull Map<String, String> map) {
 //处理回调结果
 }
}, true);
```

### SDK结果回调
回调的数据为一个 Map<String, String> 集合
```Kotlin
{
  resultCode: 详见下面的SDK结果回调错误码定义
  errorMsg: 失败原因，可能为空串""
  extraParams:  扩展参数，JSON格式字符串，可能为空串""
}
```

# HarmonyOS调用支付
### 依据[预下单](https://douyinpay.com/wiki/427lmayi/48mqiimc)接口返回的 prepay_id 组装拉起抖音支付 SDK 的参数 
| 参数名 | 变量  <br> [大小写敏感]  | 类型[长度限制] | 必填 | 描述 |
| --- | --- | --- | --- | --- |
| 应用ID  | appid  | string[1,32]  | 是  | 开放平台审核通过的移动应用appid 。  <br> 示例值：dy8888888888888888  |
| 商户号  | partnerid  | string[1,32]  | 是  | 请填写商户号mchid对应的值。  <br> 示例值：1900000109  |
| 预支付交易会话ID  | prepayid  | string[1,64]  | 是  | 抖音返回的支付交易会话ID，该值有效期为2小时。  <br> 示例值： dy1217752501201407033233368018  |
| 支付产品类型  | package  | string[1,128]  | 是  | 签约或支付，根据不同业务流程填写不同的填。  <br> App支付：Sign=DYPay <br> 免密支付/商户代扣   签约并支付：Sign=DYPay <br> 示例值：**"package"："Sign=DYPay"** |
| 随机字符串  | noncestr  | string[1,32]  | 是  | 随机字符串，不长于32位。推荐随机数生成算法。  <br> 示例值： 5K8264ILTKCH16CQ2502SI8ZNMTM67VS  |
| 时间戳  | timestamp  | string[1,10]  | 是  | 时间戳，单位秒。 |
| 签名  | sign  | string[1,256]  | 是  | 签名，使用字段appId、timeStamp、nonceStr、prepayid计算得出的签名值  <br> 注意：取值RSA、国密格式  <br> 示例值：oR9d8PuhnIc+YZ8cBHFCwfgpaK9gd7vaRvkYD7rthRAZ\/X+QBhcCYL21N7cHCTUxbQ+EAt6Uy+lwSN22f5YZvI45MLko8Pfso0jm46v5hqcVwrk6uddkGuT+Cdvu4WBqDzaDjnNa5UK3GfE1Wfl2gHxIIY5lLdUgWFts17D4WuolLLkiFZV+JSHMvH7eaLdT9N5GBovBwu5yYKUR7skR8Fu+LozcSqQixnlEZUfyE55feLOQTUYzLmR9pNtPbPsu6WVhbNHMS3Ss2+AehHvz+n64GDmXxbX++IOBvm2olHu3PsOUGRwhudhVf7UcGcunXt8cqNjKNqZLhLw4jq\/xDg==  |
将上述参数组装为一个Map<String, String>对象作为参数拉起抖音支付。
### **拉起抖音支付**
```TypeScript

/** 
 * 拉起抖音支付
 *
 * @params prepayInfoMap：支付参数Map
 * @return resultMap：支付结果Map
 */

DypayAPI.openDypay(prepayInfoMap)
  .then(resultMap => {
    // 处理支付结果
    console.info(`openDypay callback.`);
}).catch((error: BusinessError) => {
  // API调用失败，可以当支付失败处理
  console.error(`openDypay failed.`);
})
```

# SDK结果回调错误码定义
```Objective-C
SDK结果回调resultCode定义：
    0: 成功，建议商户使用服务端接口查询，调用方法见支付结果通知接口文档
    1: 用户取消，商户自行处理。
    2：其他错误，可能原因：签名错误，未注册 appid，网络错误等异常原因。
    3：抖音未返回明确支付结果，建议商户使用服务端接口查询最终支付结果，调用方法见支付结果通知接口文档
    100：未安装抖音App或者抖音版本过低，需要引导用户升级抖音
    103：重复支付被拦截
```

**++注意：SDK结果回调仅供商户参考，准确的订单支付状态请使用服务端接口查询，调用方法请见：++**[支付结果通知接口文档](https://pay.douyinpay.com/wiki/639fd48f17c2f3021d237f61/639fd60cf4a57b0226bb1ef8)

# **APP调起支付的参数需要按照签名规则进行签名计算**
### **构造签名串**
```Plain Text
签名串一共有四行，每一行为一个参数。行尾以\n（换行符，ASCII编码值为0x0A）结束，包括最后一行。
如果参数本身以\n结束，也需要附加一个\n
```

**参与签名字段及格式：**
```JSON
应用id
时间戳
随机字符串
预支付交易会话ID
```


**数据举例：**
```Plain Text
dy8888888888888888
1670748766
1A2B3C4D5E6F7G8H9I8J7K6L5M4N3O2P1Q
dy12345678987654321
```


### **计算签名值**
绝大多数编程语言提供的签名函数支持对***签名数据*** 进行签名。强烈建议商户调用该类函数，使用商户私钥对***待签名串***进行SHA256 with RSA签名，并对签名结果进行***Base64编码***得到签名值。
下面我们使用命令行演示如何生成签名。
```Plain Text
$ echo -n -e \
"dy8888888888888888\n1670748766\n1A2B3C4D5E6F7G8H9I8J7K6L5M4N3O2P1Q\ndy12345678987654321\n" \
  | openssl dgst -sha256 -sign apiclient_key.pem \
  | openssl base64 -A

OMcVrwuE65YPHgBW8nSz08scTnUtLbG7mEOEwoywNyfZRBrK2K2A3UtTP/92H4SvgpuLMAfv/94JzHezr5Xh2zqN+VWPMVbh3eU64bPkjMM+75LKOf34MPmQ8bFsLwa2F7cJ328gDZaddvqv+I+586zqOdMlV65Y/IVfIk7XDYrVgouWZYtZWw6+D/wiYp3laqzVeSdnjdkMbhbIqyho6BjqdLbzoYC+eqnHP4Vvm5lnFCEoM7gtQD9KTid1jnbiGccTKHlWHJyHqipACxDqKL+lVuMNAMAppKYYetoLqTvxh4PmSsww7LY42NzXT0+dBuPmOCMDTAtcukssV5Wtsw==
```

绝大多数编程语言提供的签名函数支持对***签名数据*** 进行签名，下面是kotlin加载私钥进行签名的逻辑
Kotlin示例：
```Kotlin
val message = "$appId\n$timeStamp\n$noncestr\n$prepayId\n"
private fun sign(message: ByteArray?, outUsePPE: Boolean): String {
    val sign: Signature = Signature.getInstance("SHA256withRSA")
    sign.initSign(loadPrivateKey())
    sign.update(message)
    return Base64.encodeToString(sign.sign(), Base64.NO_WRAP)
}
```

Java示例：
```Java
public static String sign(boolean outUsePPE) throws Exception {
 String message = appId + "\n" + timeStamp + "\n" + noncestr + "\n" + prepayId + "\n";
 byte[] messageBytes = message.getBytes();

 Signature sign = Signature.getInstance("SHA256withRSA");
 sign.initSign(loadPrivateKey());
 sign.update(messageBytes);

 byte[] signedBytes = sign.sign();
 return Base64.encodeToString(signedBytes, Base64.NO_WRAP);
}
```

# 

