iOS SDK

SDK Guide for iOS

Demo project

SDK iOS Installation / Usage

Cocoapod

You can download MFSDK by adding this line to your Podfile

pod 'MyFatoorah'
pod repo update
pod install
pod 'MyFatoorah'
pod repo update
pod install

Swift Package Manager

You can download MFSDK by adding the https://dev.azure.com/myfatoorahsc/_git/MF-SDK-iOS-Demo repository as a Swift Package

Import framework in AppDelegate:

import MFSDK
import MFSDK

Add below code in the didFinishLaunchingWithOptions method:

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
// set up your My Fatoorah Merchant details
MFSettings.shared.configure(token: <#Put your token here#>, country: <# Country of your account #>, environment: <# Test or Live #>)


// you can change color and title of nvgigation bar
let them = MFTheme(navigationTintColor: .white, navigationBarTintColor: .lightGray, navigationTitle: "Payment", cancelButtonTitle: "Cancel")
MFSettings.shared.setTheme(theme: them)
return true
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// set up your My Fatoorah Merchant details
    [[MFSettings shared] configureWithToken:@<#Put your token here#> country: <#Country of your account#>  environment:<#Live or Test#>];


// you can change color and title of nvgigation bar
MFTheme* theme = [[MFTheme alloc] initWithNavigationTintColor:[UIColor whiteColor] navigationBarTintColor:[UIColor lightGrayColor] navigationTitle:@"Payment" cancelButtonTitle:@"Cancel"];
[[MFSettings shared] setThemeWithTheme:theme];

return YES;
}

Initiate/Execute Payment

As described earlier for the Gateway Integration, we are going to have the SDK integrated with the same steps to make a successful integration with the SDK.

🚧

Initiate Payment

As a good practice, you don't have to call the Initiate Payment function every time you need to execute payment, but you have to call it at least once to save the PaymentMethodId that you will need to call Execute Payment

// initiatePayment 
        let invoiceValue = 5.0
        var selectedPaymentMethod = 1
        let initiatePayment = MFInitiatePaymentRequest(invoiceAmount: invoiceValue, currencyIso: .kuwait_KWD)
        MFPaymentRequest.shared.initiatePayment(request: initiatePayment, apiLanguage: .english) { [weak self] (response) in
            switch response {
            case .success(let initiatePaymentResponse):
                var paymentMethods = initiatePaymentResponse.paymentMethods
                if let paymentMethods = initiatePaymentResponse.paymentMethods, !paymentMethods.isEmpty {
                    selectedPaymentMethod = paymentMethods[0].paymentMethodId
                }
            case .failure(let failError):
                print(failError)
            }
        }
        
    
    // executePayment 
        let request = MFExecutePaymentRequest(invoiceValue: invoiceValue, paymentMethod: paymentMethod.paymentMethodId)
        
        // Uncomment this to add ptoducts for your invoice
        // var productList = [MFProduct]()
        // let product = MFProduct(name: "ABC", unitPrice: 1, quantity: 2)
        // productList.append(product)
        // request.invoiceItems = productList
        
        MFPaymentRequest.shared.executePayment(request: request, apiLanguage: .english) { [weak self] (response,invoiceId) in
            switch response {
            case .success(let executePaymentResponse):
                print("\(executePaymentResponse.invoiceStatus ?? "")")
            case .failure(let failError):
                print(failError)
            }
        }


// ```MFPaymentDelegate```
// You can conform this protocol to listen for invoice status, now this protocol has `didInvoiceCreated`
// method to get the invoice id immediately after creating the invoice. 

class ViewController: UIViewController {

    override func viewDidLoad() {
    
        // Set delegate for your view controller
        MFSettings.shared.delegate = self
    }
}

// conforms ```MFPaymentDelegate```
extension ViewController: MFPaymentDelegate {
    func didInvoiceCreated(invoiceId: String) {
        print("#\(invoiceId)")
    }
}
double invoiceValue = 5.0;
        MFInitiatePaymentRequest* initiatePayment = [[MFInitiatePaymentRequest alloc] initWithInvoiceAmount:invoiceValue currencyIso:MFCurrencyISOKuwait_KWD];
        [[MFPaymentRequest shared] initiatePaymentWithRequest:initiatePayment apiLanguage:MFAPILanguageEnglish completion:^(MFInitiatePaymentResponse * initiatePaymentResponse, MFFailResponse * failResponse) {
            if (initiatePaymentResponse != NULL) {
                if ([initiatePaymentResponse.paymentMethods count] > 0) {
                    NSLog(@"%@",initiatePaymentResponse);
                }
            } else {
                    NSLog(@"%@",failResponse);
                    
                }
            }
        }];
    
        MFExecutePaymentRequest* request = [[MFExecutePaymentRequest alloc] initWithInvoiceValue:invoiceValue paymentMethod:_paymentMethodId];
        //         Uncomment this to add ptoducts for your invoice
        // NSMutableArray* productList = [[NSMutableArray alloc] init];
        // MFProduct* product = [[MFProduct alloc] initWithName:@"ABC" unitPrice:1 quantity:2];
        // [productList addObject:product];
        // request.invoiceItems = productList;
        [[MFPaymentRequest shared] executePaymentWithRequest:request apiLanguage:MFAPILanguageEnglish completion:^(MFPaymentStatusResponse * paymentStatusResponse, MFFailResponse * failResponse, NSString* invoiceId) {
            if (paymentStatusResponse != NULL) {
                NSLog(@"%@",paymentStatusResponse);
            } else {
                NSLog(@"%@",failResponse);
            }
        }];


// ```MFPaymentDelegate```
// You can conform this protocol to listen for invoice status, now this protocol has `didInvoiceCreated`
// method to get the invoice id immediately after creating the invoice. 

// ViewController.h
@interface ViewController : UIViewController<MFPaymentDelegate>
.
.
@end


// ViewController.m
@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    [MFSettings shared].delegate = self;
}

// conforms `MFPaymentDelegate`
- (void)didInvoiceCreatedWithInvoiceId:(NSString * _Nonnull)invoiceId {
    NSLog(@"invoice id: %@", invoiceId);
}

Direct Payment/Tokenization

As we have explained earlier in the [Direct Payment] integration and how it works, it also has the same scenario for the SDK implementation, you have to know the following steps to understand how it works:

  • Get the payment method that allows Direct Payment by calling initiatePayment to get paymentMethodId
  • Collect card info from user MFCardInfo(cardNumber: "51234500000000081", cardExpiryMonth: "05", cardExpiryYear: "21", cardSecurityCode: "100", saveToken: false)
  • If you want to save your credit card info and get a token for next payment you have to set saveToken: true and you will get the token in the response read more in Tokenization
  • If you want to execute a payment through a saved token you have use MFCardInfo(cardToken: "put your token here")
  • Now you are ready to execute the payment, please check the following sample code
let card = MFCardInfo(cardNumber: "51234500000000081", cardExpiryMonth: "05", cardExpiryYear: "21", HolderName: "John", cardSecurityCode: "100", saveToken: true) //MFCardInfo(cardToken: "token")
         // card.bypass = false // default is true
        let invoiceValue = 5.0
        
        let paymentMethod = 2 // if you don't Know this you have to call initiatePayment
        let request = MFExecutePaymentRequest(invoiceValue: invoiceValue, paymentMethod: 2)
        MFPaymentRequest.shared.executeDirectPayment(request: request, cardInfo: card, apiLanguage: .english) { [weak self] response, invoiceId in
            switch response {
            case .success(let directPaymentResponse):
                if let cardInfoResponse = directPaymentResponse.cardInfoResponse, let card = cardInfoResponse.cardInfo {
                    print("Status: with card number \(card.number)")
                }
                if let invoiceId = invoiceId {
                    print("Success with invoiceId \(invoiceId)")
                }
            case .failure(let failError):
                print("Error: \(failError.errorDescription)")
                if let invoiceId = invoiceId {
                    print("Fail: \(failError.statusCode) with invoiceId \(invoiceId)")
                }
            }
        }
MFExecutePaymentRequest* request = [self getExecutePaymentRequest:paymentMethodId];

    MFCardInfo* card = [self getCardInfo];

    [self startLoading];

    [[MFPaymentRequest shared] executeDirectPaymentWithRequest:request cardInfo:card apiLanguage:MFAPILanguageEnglish completion:^(MFDirectPaymentResponse * response, MFFailResponse * error, NSString * invoiceId) {


        if (response !=NULL) {

            if (response.cardInfoResponse != NULL) {

                NSLog(@"%@",[NSString stringWithFormat:@"Status: with card number: %@", response.cardInfoResponse.cardInfo.number]);

            }

            if (invoiceId != NULL) {
                NSLog(@"%@", [NSString stringWithFormat:@"Success with invoice id %@", invoiceId ]);

            }

        }

    }];

Apple Pay Payment iOS SDK

To use Apple Pay payment, your account should have the Apple Pay payment method enabled.
For iOS 13.0 and above

let invoiceValue = 5.0
    let paymentMethod = 2 // if you don't Know this you have to call initiatePayment
    let request = MFExecutePaymentRequest(invoiceValue: invoiceValue, paymentMethod: 2)
    MFPaymentRequest.shared.executeApplePayPayment(request: request, apiLanguage: .arabic) { [weak self] response, invoiceId  in
        switch response {
        case .success(let executePaymentResponse):
            if let invoiceStatus = executePaymentResponse.invoiceStatus {
                self?.showSuccess(invoiceStatus)
            }
        case .failure(let failError):
            self?.showFailError(failError)
        }
    }
NSDecimalNumber * decimalNumber = [NSDecimalNumber decimalNumberWithString:self.amountTextField.text];
    NSDecimal invoiceValue = [decimalNumber decimalValue];
    
    MFExecutePaymentRequest* request = [[MFExecutePaymentRequest alloc] initWithInvoiceValue:invoiceValue paymentMethod:paymentMethodId];
    [[MFPaymentRequest shared] executeApplePayPaymentWithRequest:request apiLanguage:MFAPILanguageEnglish completion:^(MFPaymentStatusResponse * response, MFFailResponse * error, NSString * invoiceId) {
        [self stopLoading];
        if (response != NULL) {
            if (response.invoiceStatus != NULL) {
                [self showSuccess:response.invoiceStatus];
            } else {
                [self showFailError:error];
            }
        }  else {
                [self showFailError:error];
        }
    }];

If your app support iOS versions below iOS 13.0, follow these steps:
1- Open your project on Xcode go to your app target, click Info tab, scroll bottom, add URL type, set identifier filed with your bundle id or anything else, and add URL Schemes with saying urlScheme. Make sure it is a unique URL schema for your APP. Finally, Copy the URL for the next steps.
2- Call InitiatePayment endpoint and take Apple Pay 'PaymentMethodId'
3- Create your request and call the 'executeApplePayPayment' method, please note you have to pass the urlScheme argument with URL schemes from the first step.

let invoiceValue = 5.0
    let urlScheme = "urlschema" //urlSchema from step one 
    let paymentMethod = 2 // if you don't Know this you have to call initiatePayment
    let request = MFExecutePaymentRequest(invoiceValue: invoiceValue, paymentMethod: 2)
    MFPaymentRequest.shared.executeApplePayPayment(request: request, urlScheme: urlScheme, apiLanguage: .arabic) { [weak self] response, invoiceId  in
        switch response {
        case .success(let executePaymentResponse):
            if let invoiceStatus = executePaymentResponse.invoiceStatus {
                self?.showSuccess(invoiceStatus)
            }
        case .failure(let failError):
            self?.showFailError(failError)
        }
    }
NSDecimalNumber * decimalNumber = [NSDecimalNumber decimalNumberWithString:self.amountTextField.text];
    NSDecimal invoiceValue = [decimalNumber decimalValue];
    NSString * urlScheme = @"applepay";
    MFExecutePaymentRequest* request = [[MFExecutePaymentRequest alloc] initWithInvoiceValue:invoiceValue paymentMethod:paymentMethodId];
    [[MFPaymentRequest shared] executeApplePayPaymentWithRequest:request urlScheme:urlScheme apiLanguage:MFAPILanguageEnglish completion:^(MFPaymentStatusResponse * response, MFFailResponse * error, NSString * invoiceId) {
        [self stopLoading];
        if (response != NULL) {
            if (response.invoiceStatus != NULL) {
                [self showSuccess:response.invoiceStatus];
            } else {
                [self showFailError:error];
            }
        }  else {
                [self showFailError:error];
        }
    }];

4- Go to your AppDelegate and implement:

application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool

Add the following code inside it:

@UIApplicationMain
    class AppDelegate: UIResponder, UIApplicationDelegate {
    .
    .
    func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
        if let paymentId = url[MFConstants.paymentId] {
            NotificationCenter.default.post(name: .applePayCheck, object: paymentId)
        }
        return true
    }
    .
    }
@implementation AppDelegate
    . 
    .
        
     - (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {
            if (url[MFConstants.paymentId] != NULL) {
                [[NSNotificationCenter defaultCenter] postNotificationName:MFConstants.applePayNotificationName object:url[MFConstants.paymentId]];
            }
            return true;
        }
    .
    
    @end

Please note if your app have SceneDelegate so you should implement func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) instead of func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool

@available(iOS 13.0, *)
 func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
     if let url = URLContexts.first?.url {
        if let paymentId = url[MFConstants.paymentId] {
             NotificationCenter.default.post(name: .applePayCheck, object: paymentId)
         }
     }
 }

👍

Apple Pay Test

Use the Apple document that explains how to test Apple pays on your device.


Send Payment

We have explained in the Send Payment section earlier, the different usage cases for it and how it works, here we are going to embed some sample code for calling it through the SDK on the different platforms

let invoiceValue = 5.0
        var notificationOption : MFNotificationOption =  .all
        /*
         notificationOption = .sms
         notificationOption = .email
         notificationOption = .link
         */
        
        let invoice = MFSendPaymentRequest(invoiceValue: invoiceValue, notificationOption: notificationOption, customerName: "customerName")
        
        invoice.customerEmail = "[email protected]"// must be email Required if you choose notificationOption .all or  .email
        invoice.customerMobile = "mobile no"//Required if you choose notificationOption .all or .sms
        invoice.mobileCountryIsoCode = MFMobileCountryCodeISO.kuwait.rawValue
        
        MFPaymentRequest.shared.sendPayment(request: invoice, apiLanguage: .english) { [weak self] (result) in
            switch result {
            case .success(let sendPaymentResponse):
                if let invoiceURL = sendPaymentResponse.invoiceURL {
                    print("result: RedirectUrl is \(invoiceURL)")
                }
            case .failure(let failError):
                print("Error: \(failError)")
            }
        }
double invoiceValue = 5.0;
    MFSendPaymentRequest* request = [[MFSendPaymentRequest alloc] initWithInvoiceValue:invoiceValue notificationOption:MFNotificationOptionAll customerName:@"Test"];
    request.mobileCountryIsoCode = [MFEnumRawValue rawValueWithEnumValue:MFMobileCountryCodeISOKuwait];
    [[MFPaymentRequest shared] sendPaymentWithRequest:request apiLanguage:MFAPILanguageEnglish completion:^(MFSendPaymentResponse * sendPaymentResponse, MFFailResponse * failResponse) {
        
        if(sendPaymentResponse != NULL) {
            NSLog(@"%@",sendPaymentResponse.invoiceURL);
            
        } else {
            NSLog(@"%@",failResponse.errorDescription);
        }
        
    }];

Payment Inquiry

We have explain the main usage for the Payment Inquiry function, that will enable your application to get the full details about a certain invoice / payment. You can use this function within your application on the different platforms as well. Here we are explaining some samples of its usage through the SDK.

let paymentStatusRequest = MFPaymentStatusRequest(Key: "id", KeyType: .invoiceId)
        MFPaymentRequest.shared.getPaymentStatus(paymentStatus: paymentStatusRequest, apiLanguage: .english) { [weak self] (response) in
            self?.stopRequestLoading()
            switch response {
            case .success(let paymentStatusResponse):
                print("\(paymentStatusResponse.invoiceStatus)")
            case .failure(let failError):
                print("\(failError)")
            }
        }
MFPaymentStatusRequest* request = [[MFPaymentStatusRequest alloc]initWithKey:@"1234" KeyType:MFKeyTypeInvoiceId];
    
    [[MFPaymentRequest shared] getPaymentStatusWithPaymentStatus:request apiLanguage:MFAPILanguageEnglish completion:^(MFPaymentStatusResponse * paymentStatusResponse, MFFailResponse * failResponse) {
        if(paymentStatusResponse != NULL) {
            NSLog(@"%@",paymentStatusResponse.invoiceStatus);
        } else {
            NSLog(@"%@",failResponse);
        }
    }];

Embedded Payment for iOS

Usage*
1- Create variable from MFCardPaymentView, you can add it:
In storyboard

  • Drag view to view
  • Select the dragged view.
  • In right navigation select 'Identity Inspector'.
  • Set Class MFPaymentCardView and Module MFSDK
11621162

Or by code

let cardPaymentView = MFCardPaymentView()
view.addSubview(cardPaymentView)
cardPaymentView.translatesAutoresizingMaskIntoConstraints = false
cardPaymentView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
cardPaymentView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
cardPaymentView.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true
cardPaymentView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
cardPaymentView.heightAnchor.constraint(equalToConstant: 220).isActive = true
MFPaymentCardView * paymentCardView = [[MFPaymentCardView alloc] init];
[self.view addSubview:paymentCardView];
[[paymentCardView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor] setActive:YES];
[[paymentCardView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor] setActive:YES];
[[paymentCardView.widthAnchor constraintEqualToAnchor:self.view.widthAnchor] setActive:YES];
[[paymentCardView.heightAnchor constraintEqualToConstant:220] setActive:YES];

2- You can configure card with labels, placeholders, colors, height, border radius also by code or storyboard

// get default configure
    var configure = MFCardConfigureBuilder.default
    // but you can create yours
    // set placeholders
    configure.setPlaceholder(MFCardPlaceholder(cardHolderNamePlaceholder: "Name", cardNumberPlaceholder: "Number", expiryDatePlaceholder: "MM / YY", cvvPlaceholder: "CVV"))
//        //set labels
    configure.setLabel(MFCardLabel(cardHolderNameLabel: "Card holder name", cardNumberLabel: "Card number", expiryDateLabel: "MM / YY", cvvLabel: "CVV", showLabels: true))
//        // set theme
    configure.setTheme(MFCardTheme(inputColor: .black, labelColor: .black, errorColor: .red))
    
    
    // set labels and texts font size
    configure.setFontSize(15)
    
    // set border width
    configure.setBorderWidth(1)
    
    // set border radius for input fields
    configure.setBorderRadius(8)
    
     // create the new configure and assigned to payment card view
    paymentCardView.configure = configure.build()
// get default configure
    MFCardConfigureBuilder * configure = [MFCardConfigureBuilder default];
    // but you can create yours
    // set placeholders
    MFCardPlaceholder * placeholder = [[MFCardPlaceholder alloc] initWithCardHolderNamePlaceholder:@"Name on card" cardNumberPlaceholder:@"Card number" expiryDatePlaceholder:@"MM / YY" cvvPlaceholder:@"CVV"];
    [configure setPlaceholder:placeholder];

    // set labels
    MFCardLabel * label = [[MFCardLabel alloc] initWithCardHolderNameLabel:@"Card holder name" cardNumberLabel:@"Card Number" expiryDateLabel:@"Expiry Date" cvvLabel:@"CVV" showLabels:YES];
    [configure setLabel:label];

    // set theme
    MFCardTheme * theme = [[MFCardTheme alloc] initWithInputColor:UIColor.blackColor labelColor:UIColor.blackColor errorColor:UIColor.redColor];
    [configure setTheme:theme];


    // set labels and texts font size
    [configure setFontSize:14];

    // set border width
    [configure setBorderWidth:1];

    // set border radius
    [configure setBorderRadius:8];

    // create the new configure and assigned to payment card view
    paymentCardView.configure = [configure build];

3- Initiate session and get session id to setup MFCardPaymentView

MFPaymentRequest.shared.initiateSession(apiLanguage: .english) { response in
    switch response {
    case .success(let session):
        cardPaymentView.load(initiateSession: session)
    case .failure(let error):
        print(error)
    }
}
[[MFPaymentRequest shared] initiateSessionWithApiLanguage:MFAPILanguageEnglish completion:^(MFInitiateSessionResponse * response, MFFailResponse * error) {
            if (error == NULL) {
                [paymentCardView loadWithInitiateSession:response];
            } else {
                NSLog(error);
            }
    }];

4- Now your MFPaymentCardView was setup, so what you need to enter you card info and call pay

// create request, make sure you don't set paymentMethodId, because it override sessionId and this is wrong.
let request = MFExecutePaymentRequest(invoiceValue: 5)

// call pay method to make your order
cardPaymentView.pay(request, .english) { response, invoiceId in
    switch response {
    case .success(let paymentStatus):
        print(paymentStatus)
    case .failure(let error):
        print(error)
    }
}
// create request, make sure you don't set paymentMethodId, because it override sessionId and this is wrong.
    NSDecimalNumber * decimalNumber = [NSDecimalNumber decimalNumberWithString:self.amountTextField.text];
    NSDecimal invoiceValue = [decimalNumber decimalValue];
    MFExecutePaymentRequest * request = [[MFExecutePaymentRequest alloc] initWithInvoiceValue:invoiceValue];
    [_paymentCardView pay:request :MFAPILanguageEnglish completion:^(MFPaymentStatusResponse * response, MFFailResponse * error, NSString * invoiceId) {
        if (response != NULL) {
            if (response.invoiceStatus != NULL) {
                [self showSuccess:response.invoiceStatus];
            } else {
                [self showFailError:error];
            }
        }else {
            [self showFailError:error];
        }
    }];

Embedded Payment for iOS

1- Create variable from MFApplePayButton, you can create it from code or storyboard as you like.

let applePayButton = MFApplePayButton()
view.addSubview(applePayButton)
applePayButton.translatesAutoresizingMaskIntoConstraints = false
applePayButton.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
applePayButton.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
applePayButton.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true
applePayButton.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
applePayButton.heightAnchor.constraint(equalToConstant: 80).isActive = true

2- Initiate session and get session id to handle apple pay

let invoiceValue = Decimal(string: amountTextField.text ?? "0") ?? 0
        let request = MFExecutePaymentRequest(invoiceValue: invoiceValue, displayCurrencyIso: .kuwait_KWD)
    MFPaymentRequest.shared.initiateSession(apiLanguage: .english) { [weak self] response in
     switch response {
      case .success(let session):
        self?.applePayButton.load(session, (request, .english, completion: { response, invoiceId in
            self?.activityIndicator.stopAnimating()
            switch response {
             case .success(let executePaymentResponse):
              if let invoiceStatus = executePaymentResponse.invoiceStatus {
                self?.showSuccess(invoiceStatus)
              }
             case .failure(let error):
                    self?.showFailError(error)
                    }
                })
      case .failure(let error):
                print("#initiate session", error.localizedDescription)
        }
}