iOS SDK
SDK Guide for iOS
Demo project
- Use iOS source files for the 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;
}
Updating Your System:
Starting from release '2.0.132', MyFatoorah will not call the callbackurl or errorurl. To update your system, share the invoiceId with the backend side, and call GetPaymentStatus to receive the updated status.
Moreover, It is highly recommended to implement the webhook as well to receive events for all transaction status changes directly from MyFatoorah side.
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
Initiate 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)
}
}
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);
}
}
}];
Execute Payment
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)
}
}
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
// ```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)")
}
}
// ```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);
}
In-App Apple Pay 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 sessionId 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, startLoading: {
self?.activityIndicator.startAnimating()
}, 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)
}
}
3- (Optional) Configure Apple Pay Button
let applePayConfigure = MFInApplePayConfigureBuilder.default
applePayConfigure.setHeight(50) // set height to Apple Pay Button
applePayConfigure.setBorderRadius(20) // set border radius to Apple Pay Button
applePayConfigure.setButtonText("Buy with") // set the text before Apple icon
applePayConfigure.hideLoadingIndicator(true) // hide loading indicator, default is false
For the button text which is before the Apple icon you should choose one from those texts ["", "Buy with", "Pay with", "Check Out with", "Continue with", "Book with", "Donate with", "Subscribe with", "Reload with", "Add Money with", "Top Up with", "Order with", "Rent with", "Support with", "Contribute with", "Tip with", "Set Up"],
Apple Pay Test
Use the Apple document that explains how to test Apple pays on your device.
Embedded Payment for iOS
Usage
1- Create a variable from MFCardPaymentView
, you can add it:
In storyboard
- Drag view to view
- Select the dragged view.
- In the right navigation select 'Identity Inspector'.
- Set Class
MFPaymentCardView
and ModuleMFSDK
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 the card with labels, placeholders, colors, height, and 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, fontWeight: .normal))
// set theme
let theme = MFCardTheme(inputColor: .black, labelColor: .black, errorColor: .red, borderColor: .black)
theme.language = .english // select .arabic for rtl vie
configure.setTheme(theme)
// set height and margin of card inputs
configure.setCardInput(MFCardInput(inputHeight: 32, inputMargin: 15))
// set labels and texts font size
configure.setFontSize(15)
// set border width
configure.setBorderWidth(1)
// set border radius for input fields
configure.setBorderRadius(8)
// set the display of card icons
configure.setHideCardIcon(false)
// set Font Family
configure.setFontFamily(.timesNewRoman)
// set box shadow
configure.setBoxShadow(MFBoxShadow(hOffset: 0, vOffset: 0, blur: 0, spread: 0, color: .gray))
// 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):
self.paymentCardView.load(initiateSession: session)
case .failure(let error):
self.showFailError(error)
}
}
[[MFPaymentRequest shared] initiateSessionWithApiLanguage:MFAPILanguageEnglish completion:^(MFInitiateSessionResponse * response, MFFailResponse * error) {
if (error == NULL) {
[paymentCardView loadWithInitiateSession:response];
} else {
NSLog(error);
}
}];
(Alternative Option) You can call the function including onCardBinChanged closure to receive the card bin
MFPaymentRequest.shared.initiateSession(apiLanguage: .english) { [weak self] response in
switch response {
case .success(let session):
self?.paymentCardView.load(initiateSession: session) { bin in
print("bin", bin)
}
case .failure(let error):
self?.showFailError(error)
}
}
4- Now your MFPaymentCardView
is set up, so once the customer entered the card details you need to 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];
}
}];
(Alternative Option) You can validate the session first and complete the payment if the session is valid
// create request, make sure you don't set paymentMethodId, because it override sessionId and this is wrong.
let request = MFExecutePaymentRequest(invoiceValue: 5)
// call calidate method
paymentCardView.validate{ [weak self] result in
switch result {
case .success(let cardBrand):
// 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)
}
}
case .failure(let failError):
}
}
Payment Inquiry
We have explained the main usage for the Payment Inquiry function, which will enable your application to get the full details about a certain invoice/payment. You can use this function within your application on 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);
}
}];
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);
}
}];
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 your 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 payment through a saved token you have to 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 ]);
}
}
}];
Updated 4 months ago