# 快速接入

> 阅读此文档前，确保您已完成 [集成指南](/zh-hans/payments/docs/introduction/integrated-guide)，并了解了 [创建收银台的相关 API](/zh-hans/payments/apis/introduction/started)。


PayKKa 提供的 iOS SDK 可以方便您直接以 WebView 的方式嵌入 [Web 收银台](/zh-hans/payments/docs/transaction/web/hosted-web)，只需传给 SDK 一个 `sessionId` 即可在 App 内打开收银台页面，接收用户的付款，并且可以自定义和处理相关的支付回调。SDK 最新的下载地址可以在 [iOS SDK 历史版本和更新日志](/zh-hans/payments/docs/developer-resources/native-sdks/ios-sdk/release-history) 中找到。

## 步骤一：在项目中引入 SDK

SDK 下载后会得到一个 .zip 文件，大致目录结构如下：

```txt
.
├── PayKKaCheckoutApp-iOS
│   ├── OcCheckoutDemo
│   │   ├── OcCheckoutDemo
│   │   └── OcCheckoutDemo.xcodeproj
│   ├── PayKKaCheckoutApp-iOS.xcworkspace
│   │   ├── contents.xcworkspacedata
│   │   ├── xcshareddata
│   │   └── xcuserdata
│   └── SwiftCheckoutDemo
│       ├── SwiftCheckoutDemo
│       ├── SwiftCheckoutDemo.xcodeproj
│       ├── SwiftCheckoutDemoTests
│       └── SwiftCheckoutDemoUITests
└── sdk
    └── PayKKaCheckoutPayments.xcframework
        ├── Info.plist
        ├── ios-arm64
        └── ios-arm64_x86_64-simulator
```

其中，`PayKKaCheckoutApp-iOS` 包含两个使用 Objective-C 和 Swift 语言编写的示例 App 的 Xcode 项目工程，开发者可以通过示例代码了解 PayKKa SDK 的 API 使用方式。

解压后位于根目录下的 `sdk` 文件夹中的 `PayKKaCheckoutPayments.xcframework` 就是 PayKKa 的基础 SDK。

引入 PayKKa SDK 的方法很简单，在 Xcode 中，依次点击：`左侧目录树 <您的项目名称>` → `TARGETS <您的 TARGET>` → `上方 <Build Phases>` → `展开 <Link Binary With Libraries>` → `点击 <条目左下角 + 号>` → `弹窗点击左下角选项 <Add Files…>` → `文件浏览器选择 <sdk/PayKKaCheckoutPayments.xcframework>`，即可将 PayKKa SDK 引入项目。

需要注意的是，在：`TARGETS <您的 TARGET>` → `上方 <General>` → `<Frameworks, Libraries, and Embedded Content>` 中，请确保 `PayKKaCheckoutPayments.xcframework` 设置为 `Embed & Sign`。如下图所示：

Xcode configuration 1
## 步骤二：获取AppCode

SDK 在初始化时会校验宿主App的`Bundle Id`（包名）及签名的TeamID等信息是否和PayKKa数据库登记的信息一致，以确认SDK调用是来自商户官方渠道打包的App。因此需要告知您的App的以下信息：

- App `Bundle Identifier`
- App签名的开发者账号的 `Team ID`


其中，App的包名可以在项目代码中或者在Xcode：`TARGETS <您的 TARGET>` → `上方 <Signing & Capabilities>` → `<Signing>` → `Bundle Idntifier` 中找到。

App签名的Apple开发者账号的TeamID可在[Account - Apple Developer](https://developer.apple.com/account)找到。

将您的 App包名 及 Apple开发者账号的TeamID 告诉给我们的对接人员，我们会为您生成 `PayKKaAppCode`。

之后，在你的App工程项目的`Info.plist`，新增如下元数据：

- 名为`paykka_appcode`的元数据，对应值填写我们为您生成的`PayKKaAppCode`
- 名为`paykka_mch_teamid`的元数据，对应值填写您的Apple开发者账号的`Team ID`


## 步骤三：在项目中使用 SDK

SDK 引入之后，就可以开始在您的 App 内集成和使用 PayKKa 的收银台了。以下是使用 SDK 的关键代码，完整代码和示例可以参考随 SDK 下载的 `PayKKaCheckoutApp-iOS` Xcode 工程项目的源码。

Swift
```swift AppConf.swift
import Foundation
import PayKKaCheckoutPayments

struct AppConf {
    /// 定义你的配置
    static let CONFIGURATION: PayKKaConf = {
        PayKKaConf(dict: [
            /// 你的PayKKa商户号
            KEY_GATEWAY_MERCHANT_ID: "{YOUR_GATEWAY_MERCHANT_ID}",
            /// 你的客户端密钥
            KEY_CLIENT_KEY: "{YOUR_CLIENT_KEY}",
        ])
    }()
}
```

```swift ConfirmOrder.swift
import SwiftUI
/// 引入SDK
import PayKKaCheckoutPayments

struct ConfirmOrder: View {
    @EnvironmentObject var router: NavigationRouter

    /// PayKKa收银台`sessionId`，一般由后端接口返回，用于构建展示收银台
    private let sessionId: String

    let price: Double = 1118.83;
    var body: some View {
        ScrollView {
            ...
        }
        .navigationTitle("确认订单")
        .navigationBarTitleDisplayMode(.inline)
        HStack {
            Button {
                /// 在此处打开支付表单弹窗，可自定义支付回调
                PayKKa.goPay(sessionId) { paymentResult in
                    print("---->", paymentResult.toString())
                    switch paymentResult.status {
                    case .success:
                        // 收银台支付成功
                        router.redirect(to: .payment_complete(extraData: ["paymentResult": paymentResult]))
                    case .expired:
                        // 收银台会话过期
                        router.redirect(to: .payment_complete(extraData: ["paymentResult": paymentResult]))
                        print("onExpired: \(paymentResult.toString())")
                    default:
                        print("Unhandled payment status: \(paymentResult.status)")
                    }
                } onCloseTappedCallback: { jsEvent in
                    print("On close tapped.")
                }
            } label: {
                ...
            }
        }
        ...
    }
    
    init(sessionId: String) {
        /// 初始化 PayKKa SDK
        PayKKa.Init(AppConf.CONFIGURATION, AppConf.ENVIRONMENT)
        self.sessionId = sessionId
    }
}

...
```

Objective-C
```objective-c AppConf.m
#import "AppConf.h"

NS_ASSUME_NONNULL_BEGIN

@implementation AppConf

/// 定义你的配置
+ (PayKKaConf *)CONFIGURATION {
    static PayKKaConf *conf;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        conf = [[PayKKaConf alloc] initWithDict:@{
            /// 你的PayKKa商户号
            KEY_GATEWAY_MERCHANT_ID: @"{YOUR_GATEWAY_MERCHANT_ID}",
            /// 你的客户端密钥
            KEY_CLIENT_KEY: @"{YOUR_CLIENT_KEY}",
        }];
    });
    return conf;
}

@end

NS_ASSUME_NONNULL_END
```

```objective-c ConfirmOrderViewController.m
#import "ConfirmOrderViewController.h"
#import "../PaymentComplete/PaymentCompleteViewController.h"
/// 引入SDK头文件
#import <PayKKaCheckoutPayments/PayKKaCheckoutPayments.h>

NS_ASSUME_NONNULL_BEGIN

...

@implementation ConfirmOrderViewController

- (instancetype)initWithExtraData:(NSDictionary *)extra {
    self = [super init];
    if (self) {
        _sessionId = extra[@"sessionId"] ?: @"";
        _price = 1118.83;
        
        /// 初始化 PayKKaSDK
        [PayKKa init:AppConf.CONFIGURATION environment:AppConf.ENVIRONMENT];
        // [PayKKa init:AppConf.CONFIGURATION];
    }
    return self;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    self.title = @"确认订单";
    self.view.backgroundColor = [UIColor systemGray6Color];

    [self buildScrollView];
    [self buildOrderCard];
    [self buildBottomPayButton];
}

- (void)buildScrollView {
    ...
}

- (void)buildOrderCard {
    ...
}

- (void)buildBottomPayButton {
    ...
}

- (void)openCheckout {
    /// 显示WebViewSheet
    UINavigationController *nav = self.navigationController;
    UIViewController *presentingVC = nav.topViewController;
    /// 在此处直接调用方法，拉起WKWebViewSheet组件，可自定义支付回调
    [PayKKa goPay: AppConf.EXAMPLE_CHECKOUT_SESSION_ID onPaymentCallback:^(PaymentResult * _Nonnull paymentResult) {
        PaymentCompleteViewController *vc = [[PaymentCompleteViewController alloc] initWithPaymentResult:paymentResult];
        switch (paymentResult.status) {
            // 收银台支付成功
            case PaymentStatusSuccess: {
                NSArray *newStack = @[nav.viewControllers.firstObject, vc];
                [nav setViewControllers:newStack animated:YES];
                break;
            }
            // 收银台会话过期
            case PaymentStatusExpired: {
                NSArray *newStack = @[nav.viewControllers.firstObject, vc];
                [nav setViewControllers:newStack animated:YES];
                NSLog(@"onExpired: %@", [paymentResult toString]);
                break;
            }
            default:
                NSLog(@"Unhandled payment status: %@", @(paymentResult.status));
                break;
        }
    }];
}

@end

NS_ASSUME_NONNULL_END
```

## 步骤四：测试支付

您可以在 PayKKa 沙盒环境（`SANDBOX`）中使用测试卡进行支付测试，在打包 App release 版本时再切换到 `PROD` 环境。

Swift
```swift
// 可以在 init 方法中指定使用的支付环境
PayKKa.Init(AppConf.CONFIGURATION, AppConf.ENVIRONMENT)

/// SANDBOX（默认）
PayKKa.useEnv(.SANDBOX)
/// 切换到EU生产环境
PayKKa.useEnv(.PROD_EU)
/// 切换到HK生产环境
PayKKa.useEnv(.PROD_HK)
```

Objective-C
```objective-c
// 可以在 init 方法中指定使用的支付环境
[PayKKa init:AppConf.CONFIGURATION environment:AppConf.ENVIRONMENT];

/// SANDBOX（默认）
[PayKKa useEnv:PayKKaEnv.SANDBOX];
/// 切换到EU生产环境
[PayKKa useEnv:PayKKaEnv.PROD_EU];
/// 切换到HK生产环境
[PayKKa useEnv:PayKKaEnv.PROD_HK];
```

## 注意事项

### Apple Pay

#### 1. 如何使用测试卡进行支付测试？

您需要登录 App Store Connect，使用邮箱注册一个沙盒环境的账号，然后在 iOS 设备上登录这个沙盒账号，绑定 Apple Pay 的沙盒环境测试卡后进行支付测试。完整的配置教程可以在 Apple Pay 的官方文档中找到：[Apple Pay Sandbox Testing](https://developer.apple.com/apple-pay/sandbox-testing/)。

更多收银台相关文档，请参阅：[Payment Method - Apple Pay](/zh-hans/payments/docs/payment-method/apple-pay/apple-pay#%E6%B5%8B%E8%AF%95)