# iOS

A native wrapper for the [JS library](/docs/in-person-payments/pay-in-person/integration-guide/js-library), for POS applications targeting iOS 13+. The
library is a thin wrapper around the iClient JavaScript library, using a `WKWebView` (or, for
older integrations, a `UIWebView`) in place of a browser page. There are no changes to how a
transaction is initiated or to the underlying JavaScript API — only to how the WebView is set up.

The original Tyro iOS SDK was based on `UIWebView`, which iOS no longer supports: new app
submissions using it stopped being accepted, and updates to existing apps were blocked, in
December 2020. The current implementation uses `WKWebView` instead, via a new `TyroClientUniversal`
framework added to the POS application.

Before you begin development, check the certification criteria:
[Certification Criteria Document](/assets/certification_criteria_iclient_retail_hospitality.7bf0b2b5462961db882fcba1f1e9ddbec0d942cc7ee96278907994599bebf62a.d564e73d.pdf).

Downloads:

- [POS simulator](/assets/possimulator.90a10096ef0950254515b26ab3f7801af25c7cd21d5c9f34aaa89d65793625a1.fbf1555a.zip) — an example project demonstrating the framework
- [TyroClientUniversal framework](/assets/tyroclientuniversal.framework.b6aeb23f9f8c0aba621d36df4f5105507d4d6e882d7858ac5d23db1953fad241.fbf1555a.zip) — just the framework
- [iClient API docs](/assets/iclient-api.57e262928075df78cfa8a01bd63db2f4b79b8d58736bbb024a56daa62cd686fe.fbf1555a.zip) — unzip, then open `doc/index.html`; the iOS
integration reference is under `TYRO.IClientEmbedded` in the left-hand navigation


## Objective-C purchase example

The main change from a standard web integration is how the WebView is initiated.

**WKWebView SDK:**


```objectivec
#import <TyroClientUniversal/TyroClient.h>
#import "PaymentsViewController.h"
#import "PosConfiguration.h"

@interface PaymentsViewController ()

@property(weak, nonatomic) IBOutlet UITextField *amountField;
@property(weak, nonatomic) IBOutlet UITextField *cashoutAmountField;
@property(weak, nonatomic) IBOutlet UITextField *refundAmountField;
@property(weak, nonatomic) IBOutlet UITextField *openTabAmountField;
@property(weak, nonatomic) IBOutlet UITextField *closeTabAmountField;
@property(weak, nonatomic) IBOutlet UITextField *closeTabCompletionReferenceField;
@property(weak, nonatomic) IBOutlet UITextField *voidTabCompletionReferenceField;

@property(strong, nonatomic) IBOutlet WKWebView *mainWebView;
@property(weak, nonatomic) IBOutlet UITextView *merchantReceiptTextView;
@property(weak, nonatomic) IBOutlet UITextView *customerReceiptTextView;

@property(nonatomic, strong) PosConfiguration *posConfiguration;
@property(nonatomic, strong) TyroClient *client;
@property (weak, nonatomic) IBOutlet UISwitch *enableSurcharge;

@end

@implementation PaymentsViewController

- (void) viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    self.posConfiguration = [PosConfiguration sharedInstance];
    
    WKPreferences * preferences = [[WKPreferences alloc] init];
    preferences.javaScriptEnabled = true;
    WKWebViewConfiguration* configuration = [[WKWebViewConfiguration alloc] init];
    configuration.preferences = preferences;
    self.mainWebView = [[WKWebView alloc] initWithFrame:self.mainWebView.frame configuration:configuration];
    
    [self.view addSubview:self.mainWebView];

    self.client = [[TyroClient alloc] initWithWebView:self.mainWebView
                                      webViewDelegate:self
                                               apiKey:self.posConfiguration.apiKey
                                     posProductVendor:self.posConfiguration.posProductVendor
                                       posProductName:self.posConfiguration.posProductName
                                    posProductVersion:self.posConfiguration.posProductVersion];
    
    self.client.baseUrl = self.posConfiguration.iclientBaseUrl;
}
```

**UIWebView SDK:**


```objectivec
#import <TyroClientUniversal/TyroClient.h>
#import "PaymentsViewController.h"
#import "PosConfiguration.h"

@interface PaymentsViewController ()

@property(weak, nonatomic) IBOutlet UITextField *amountField;
@property(weak, nonatomic) IBOutlet UITextField *cashoutAmountField;
@property(weak, nonatomic) IBOutlet UITextField *refundAmountField;
@property(weak, nonatomic) IBOutlet UITextField *openTabAmountField;
@property(weak, nonatomic) IBOutlet UITextField *closeTabAmountField;
@property(weak, nonatomic) IBOutlet UITextField *closeTabCompletionReferenceField;
@property(weak, nonatomic) IBOutlet UITextField *voidTabCompletionReferenceField;

@property(strong, nonatomic) IBOutlet UIWebView *mainWebView;
@property(weak, nonatomic) IBOutlet UITextView *merchantReceiptTextView;
@property(weak, nonatomic) IBOutlet UITextView *customerReceiptTextView;

@property(nonatomic, strong) PosConfiguration *posConfiguration;
@property(nonatomic, strong) TyroClient *client;

@end

@implementation PaymentsViewController

- (void) viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    self.posConfiguration = [PosConfiguration sharedInstance];
    self.mainWebView = [[UIWebView alloc] initWithFrame:self.mainWebView.frame];
    [self.view addSubview:self.mainWebView];

    self.client = [[TyroClient alloc] initWithWebView:self.mainWebView
                                      webViewDelegate:self
                                               apiKey:self.posConfiguration.apiKey
                                     posProductVendor:self.posConfiguration.posProductVendor
                                       posProductName:self.posConfiguration.posProductName
                                    posProductVersion:self.posConfiguration.posProductVersion];
    
    self.client.baseUrl = self.posConfiguration.iclientBaseUrl;
}
```

### Initiating a transaction

Initiating a transaction remains the same regardless of which WebView the POS uses:


```objectivec
- (IBAction)initiatePurchase {
    [self.amountField resignFirstResponder];
    [self clearReceipts];

    NSDictionary *parameters = @{
            @"amount" : self.amountField.text,
            @"cashout" : self.cashoutAmountField.text,
            @"integratedReceipt" : self.posConfiguration.integratedReceipt ? @"true" : @"false"};

    if ([self.amountField.text isEqualToString:@"error"]) {
        [self.client performOperation:@"invalid-operation"
                           parameters:parameters
              receiptReceivedCallback:[self receiptReceivedCallback]
          transactionCompleteCallback:[self transactionCompleteCallback]];
    } else {
        [self.client performOperation:@"purchase"
                           parameters:parameters
              receiptReceivedCallback:[self receiptReceivedCallback]
          transactionCompleteCallback:[self transactionCompleteCallback]];
    }
}
```

### Headless pairing

Using `pairTerminal(mid, tid)` is compulsory when implementing the iOS SDK with your POS. This
function establishes the connection with the terminal, and returns the integration key for you to
store in memory.

**Parameters:**

- `mid` (String) — Tyro Merchant ID (MID)
- `tid` (String) — Tyro Terminal ID (TID)


**Example:**


```objectivec
[self.client performOperation: @"pairTerminal" parameters: @{@"mid" : @"22323", @"tid": @"3" } receiptReceivedCallback: nil transactionCompleteCallback: ^(NSDictionary *result) {NSLog(@"Paired terminal: %@", result);}];
```

The POS must display the `status` and `message` fields on the POS UI gracefully. The POS must
store the MID, TID and integration key in the POS app's own database, and pass them when
processing a transaction.

For further information on `WKWebView` functionality, see
[Apple's documentation](https://developer.apple.com/documentation/webkit/wkwebview?language=objc).