TapQRCode-iOS
A SDK that provides an interface to generate and scan different types of QR codes.
Requirements
To use the SDK the following requirements must be met:
- Xcode 11.0 or newer
- Swift 4.2 or newer (preinstalled with Xcode)
- Deployment target SDK for the app: iOS 12.0 or later
Installation
Installation with CocoaPods
CocoaPods is a dependency manager, which automates and simplifies the process of using 3rd-party libraries in your projects. You can install it with the following command:
$ gem install cocoapods
Podfile
To integrate goSellSDK into your Xcode project using CocoaPods, specify it in your Podfile
:
platform :ios, '12.0'
use_frameworks!
source 'https://github.com/CocoaPods/Specs.git'
target 'MyApp' do
pod 'TapQRCode-iOS'
end
Then, run the following command:
$ pod update
Features
TapQRCode-iOS
provides extensive ways for both generating and scanning a QR code, making it one of the most inclusive pods in the market, yet one of the easiest to integrate with.
Generating a QR Code
You can generate different type of QR codes with the same interface, including:
- Text based QR codes.
- URL based QR codes.
- EMVCO push payment based QR codes.
Also, the TapQRCodeGenerator
provides an interface to style the generated code as follows:
- Foreground color.
- Backgrond color.
- Centered icon.
Scanning a QR Code
You can scan different type of QR codes with the same interface from different sources, including:
- Scan a code within an image.
- Provide a scanner inline as SubView in your UIView.
- Show a full screen scanner.
Also, the TapQRCodeScanner
provides an interface to style the scanner as follows:
- Showing accessory buttons like flip camera and torch button.
- Torch button icons.
- Overlay scanning frame.
Usage
This section descripes how to call and initate different generators and scanners using SWIFT and Objective C languages.
Generating a QR Code
Below the different ways you can attach a certain theme file to the shared ThemeManager and how to change the theme at run time.
Text based QR Code
TapQRCodeGenerator
can generate QR codes that holds pure text as follows
Swift:
import TapQRCode_iOS
let tapGeneratedQRImage:UIImage = TapQRCodeGenerator.generateQrCode(with: .init(withText: "Hello from Tap Payments"), foreGroundColor: .red, backgroundColor: .white, waterMark: UIImage(named: "Tap"))
Objective-C:
@import TapQRCode_iOS;
UIImage* tapGeneratedQRImage = [TapQRCodeGenerator generateQrCodeWith:[[TapQrCodeContent alloc]initWithText:@"Hello from Tap Payments"] foreGroundColor:UIColor.redColor backgroundColor:UIColor.whiteColor waterMark:[UIImage imageNamed:@"Tap"]];
Parameters:
Parameter name | Parameter type | Required | Default vale | Description |
---|---|---|---|---|
qrCodeContent | TapQrCodeContent.init(withText) | Yes | none | The TapQrCodeContent which holds the type and content of the required qr code |
foreGroundColor | UIColor | No | .black | The colour of the qr code dots and blocks. |
backgroundColor | UIColor | No | .clear | The colour of the qr code background. |
waterMark | UIImage | No | none | Watermark image appears in the center of the qr code. |
URL based QR Code
TapQRCodeGenerator
can generate QR codes that holds pure URL as follows
Swift:
import TapQRCode_iOS
let tapGeneratedQRImage:UIImage = TapQRCodeGenerator.generateQrCode(with: .init(withUrl: URL(string: "https://tap.company")), foreGroundColor: .red, backgroundColor: .white, waterMark: UIImage(named: "Tap"))
Objective-C:
@import TapQRCode_iOS;
UIImage* tapGeneratedQRImage = [TapQRCodeGenerator generateQrCodeWith:[[TapQrCodeContent alloc]initWithUrl:[NSURL URLWithString:@"https://tap.company"]] foreGroundColor:UIColor.redColor backgroundColor:UIColor.whiteColor waterMark:[UIImage imageNamed:@"Tap"]];
Parameters:
Parameter name | Parameter type | Required | Default vale | Description |
---|---|---|---|---|
qrCodeContent | TapQrCodeContent.init(withUrl) | Yes | none | The TapQrCodeContent which holds the type and content of the required qr code |
foreGroundColor | UIColor | No | .black | The colour of the qr code dots and blocks. |
backgroundColor | UIColor | No | .clear | The colour of the qr code background. |
waterMark | UIImage | No | none | Watermark image appears in the center of the qr code. |
Emvco Push Payment based QR Code
TapQRCodeGenerator
can generate QR codes that holds an Emvco Push Payment code, that can be read from any acceptable EMVCO parser as follows
Swift:
import TapQRCode_iOS
do {
let image = try TapQRCodeGenerator.generateQrCode(with: .init(withEmv:
TapEmvcoPushData(pointOfInitiation: .Dynamic,
merchantPaymentTags: [.init(with: .VisaTag02, value: "4600678934521435")],
transactionAmount: 10,
transactionCurrency: .KWD,
extraFeesMode: .FixedFees,
extraFeesAmount: 5,
countryCode: .KW,
merchantCategoryCode: "1171",
merchantName: "Tap Payments",
merchantCity: "Kuwait City",
postalCode: nil,
additionData: TapEmvcoAdditionalData(
billNumber: "Bill 123",
customerLabel: "Tap Customer",
loyaltyNumber: "123",
mobileNumber: "0096599999999",
purposeForTransaction: "Tap Transaction",
storeLabel: "Store 1",
terminalLabel: "Terminal 1",
additionalCustomerDataCollection: .addressPhone))))
}catch {
print(error.localizedDescription)
}
Objective-C:
@import TapQRCode_iOS;
NSError* error;
UIImage* tapGeneratedQRImage = [TapQRCodeGenerator generateQrCodeWith:[[TapQrCodeContent alloc]initWithEmv:[[TapEmvcoPushData alloc]
initWithPointOfInitiation:TapEmvcoOfInitiationDynamic
merchantPaymentTags:@[[[TapEmvcoPaymentNetwork alloc]initWith:TapEmvcoNetworkTagsVisaTag02 value:@"4600678934521435"]]
transactionAmount:10
transactionCurrency:TapEmvcoCurrencyCodeKWD
extraFeesMode:TapEmvcoExtraFeesFixedFees
extraFeesAmount:5
countryCode:TapEmvcoCountryCodeKW
merchantCategoryCode:@"1171"
merchantName:@"Tap Payments"
merchantCity:@"Kuwait City"
postalCode:nil
additionData:[[TapEmvcoAdditionalData alloc]
initWithBillNumber:@"123"
customerLabel:@"Tap Customer"
loyaltyNumber:@"123"
mobileNumber:@"0096599999999"
purposeForTransaction:@"Tap Transaction"
storeLabel:@"Store 1"
terminalLabel:@"Terminal 1"
additionalCustomerDataCollection:TapEmvcoAdditionalDataCollectionPhoneEmail]
error:&error]] foreGroundColor:UIColor.redColor backgroundColor:UIColor.whiteColor waterMark:[UIImage imageNamed:@"Tap"]];
Parameters:
Parameter name | Parameter type | Required | Default vale | Description |
---|---|---|---|---|
qrCodeContent | TapQrCodeContent.init(initWithEmv) | Yes | none | The TapQrCodeContent which holds the type and content of the required qr code. To generate an EMVCO push payment please look at the parameters for **TapEmvcoPushData,TapEmvcoPaymentNetwork and TapEmvcoAdditionalData ** below |
foreGroundColor | UIColor | No | .black | The colour of the qr code dots and blocks. |
backgroundColor | UIColor | No | .clear | The colour of the qr code background. |
waterMark | UIImage | No | none | Watermark image appears in the center of the qr code. |
TapEmvcoPushData
This model represents a much easier and understandable wrapper for the Standard EMVCO data. We at Tap wanted to provide an interface so entities can generate EMVCO accepted codes without the need of understanding and reading the complicated EMVCO standard.
TapEmvcoPushData init with direct data
TapEmvcoPushData can be initiated by providing the data inline as follows:
Swift:
import TapQRCode_iOS
do {
let tapEmvcoData:TapEmvcoPushData = try TapEmvcoPushData.init(
pointOfInitiation: .Dynamic,
merchantPaymentTags: [.init(with: .VisaTag02, value: "4600678934521435")],
transactionAmount: 10,
transactionCurrency: .KWD,
extraFeesMode: .FixedFees,
extraFeesAmount: 5,
countryCode: .KW,
merchantCategoryCode: "1171",
merchantName: "Tap Payments",
merchantCity: "Kuwait City",
postalCode: nil,
additionData: TapEmvcoAdditionalData(
billNumber: "Bill 123",
customerLabel: "Tap Customer",
loyaltyNumber: "123",
mobileNumber: "0096599999999",
purposeForTransaction: "Tap Transaction",
storeLabel: "Store 1",
terminalLabel: "Terminal 1",
additionalCustomerDataCollection: .addressPhone),
alternateLanguageData: TapEmvcoAlternateLanguage(
with: .ar,
alternatLanguageMerchantName: "تاب",
alternatLanguageMerchantCityName: "الكويت"))
}catch{
print(error.localizedDescription)
}
Objective-C:
@import TapQRCode_iOS;
NSError* error;
TapEmvcoPushData* tapEmvcoData = [[TapEmvcoPushData alloc]
initWithPointOfInitiation:TapEmvcoOfInitiationDynamic
merchantPaymentTags:@[[[TapEmvcoPaymentNetwork alloc]initWith:TapEmvcoNetworkTagsVisaTag02 value:@"4600678934521435"]]
transactionAmount:10
transactionCurrency:TapEmvcoCurrencyCodeKWD
extraFeesMode:TapEmvcoExtraFeesFixedFees
extraFeesAmount:5
countryCode:TapEmvcoCountryCodeKW
merchantCategoryCode:@"1171"
merchantName:@"Tap Payments"
merchantCity:@"Kuwait City"
postalCode:nil
additionData:[[TapEmvcoAdditionalData alloc]
initWithBillNumber:@"Bill 123"
customerLabel:@"Tap Customer"
loyaltyNumber:@"Loyal Number 1"
mobileNumber:@"+96599999999"
purposeForTransaction:@"Tap Transaction"
storeLabel:@"Tap Store # 1"
terminalLabel:@"Tap Terminal # 1"
additionalCustomerDataCollection:TapEmvcoAdditionalDataCollectionPhoneEmail]
alternateLanguageData:[[TapEmvcoAlternateLanguage alloc]
initWith:TapAlternateLanguageEnumAr
alternatLanguageMerchantName:@"تاب"
alternatLanguageMerchantCityName:@"الكويت"]
error:&error];
Parameters:
Parameter name | Parameter type | Required | Default vale | Description |
---|---|---|---|---|
pointOfInitiation | TapEmvcoOfInitiation | Yes | none | Defines whether the QR code is a static or a dynamic one. Static is payable multiple while dynamic is payable once. Provides a descriptive way for EMVCO Point of Initiation Method (ID "01") |
merchantPaymentTags | [TapEmvcoPaymentNetwork] | Yes | none | Provides a list of merchant global identifers for different payment network tags. At least one payment tag should be provided |
transactionAmount | Float | No | 0 | The amount of the transaction, please note that the decimal part should match the official decimal part of the given currency code |
transactionCurrency | TapEmvcoCurrencyCode | Yes | none | The currency of the transaction. Provides a descriptive way for EMVCO Transaction Currency (ID "53") |
extraFeesMode | TapEmvcoExtraFees | No | .FixedFees | Defines the extra fees collection mode, whether NONE, or a fixed fee or a percentage of the total amount or promop the user to enter whatever he wants. Provides a descriptive way for EMVCO Tip or Convenience Indicator (ID "55") |
extraFeesAmount | Float | No | 0 | Defines the value of the extra fees, if NONE or Promopt no need to pass it, if fixed then a number > 0 and if percentage "00.01” and “99.99” shall be used |
countryCode | TapEmvcoCountryCode | Yes | none | Defines the country code where the merchant transacts.Provides a descriptive way for EMVCO Country Code (ID "58") |
merchantCategoryCode | String | Yes | none | Defines the code of the merchant nature as defined in the ISO 18245. For more information, see ISO 18245 |
merchantName | String | Yes | none | Defines the merchant's name up to 25 |
merchantCity | String | Yes | none | Defines the city of the merchant up to 25 |
postalCode | String | No | none | Defines postal code address of he merchant up to 25 |
additionData | TapEmvcoAdditionalData | No | none | Defines the Additional Data Field Template (ID "62"). Details below |
alternateLanguageData | TapEmvcoAlternateLanguage | No | none | Defines the Language Template (ID "64"). Which displays the merchant name and city in a localised language of his choice. |
TapEmvcoAdditionalData
This model represents a much easier and understandable wrapper for the Additional Data Field Template (ID "62") found in Standard EMVCO data. We at Tap wanted to provide an interface so entities can generate EMVCO accepted codes without the need of understanding and reading the complicated EMVCO standard.
Parameters:
Parameter name | Parameter type | Required | Default vale | Description |
---|---|---|---|---|
billNumber | String | No | none | The invoice number or bill number, will always be truncated to first 25 charachters. Write it as *** if you want the mobile app to gather it |
customerLabel | String | No | none | This value could be provided by the merchant, if known, or could be an indication to the mobile application to provide a prompt that will allow the consumer to input their Customer Label, will always be truncated to first 25 charachters Write it as *** if you want the mobile app to gather it |
loyaltyNumber | String | No | none | Typically a loyalty card number., will always be truncated to first 25 charachters Write it as *** if you want the mobile app to gather it |
mobileNumber | String | No | none | Mobile phone number to be used for multiple use cases, such as mobile top- up and bill payment, will always be truncated to first 25 charachters Write it as *** if you want the mobile app to gather it |
purposeForTransaction | String | No | none | Any value as defined by the merchant or acquirer in order to define the purpose of the transaction, will always be truncated to first 25 charachters Write it as *** if you want the mobile app to gather it |
storeLabel | String | No | none | A distinctive id associated to a store, will always be truncated to first 25 charachters Write it as *** if you want the mobile app to gather it |
terminalLabel | String | No | none | A distinctive id associated to a terminal inside a store, will always be truncated to first 25 charachters Write it as *** if you want the mobile app to gather it |
additionalCustomerDataCollection | TapEmvcoAdditionalDataCollection | No | .None | Contains indications that the mobile application should include the requested information in order to complete the transaction. The information requested should be provided by the mobile application in the authorization without unnecessarily prompting the consumer. If present, the Additional Consumer Data Request (ID "09") shall contain any combination of the characters: "A", "M" and/or "E", and there shall only be a single instance of each of these characters. |
TapEmvcoPushData init with Dictionary
TapEmvcoPushData can be initiated by providing the dictionary which can be loaded from JSON file or JSON response from backend as follows:
Swift:
import TapQRCode_iOS
let url = Bundle.main.url(forResource: "EmvcoJson", withExtension: "json")!
let data = try! Data(contentsOf: url)
let emvcoDataFromJson:[String:Any] = try! JSONSerialization.jsonObject(with: data, options:.allowFragments) as! [String : Any]
do {
let tapEmvcoData:TapEmvcoPushData = try TapEmvcoPushData.init(withDictionary: emvcoDataFromJson)
}catch{
print(error.localizedDescription)
}
Objective-C:
@import TapQRCode_iOS;
NSError* error;
NSError* jsonError;
NSURL* url = [[NSBundle mainBundle] URLForResource:@"EmvcoJson" withExtension:@"json"];
NSData* data = [NSData dataWithContentsOfURL:url];
NSDictionary* emvcoDataFromJson = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:&jsonError];
if(!jsonError)
{
TapEmvcoPushData* tapEmvcoData = [[TapEmvcoPushData alloc]initWithDictionary:emvcoDataFromJson error:&error];
NSLog(@"%@",@"");
}
Accepted JSON format:
{
"pointOfInitiation": "12",
"merchantCategoryCode": "1711",
"merchantName": "Tap Payments",
"merchantCity": "Kuwait City",
"paymentNetworks": [
{
"tag": "VisaTag02",
"value": "4600678934521435"
},
{
"tag": "VisaTag03",
"value": "4600678934521467"
},
{
"tag": "MasterTag04",
"value": "555544443333111"
},
{
"tag": "MasterTag05",
"value": "555544443333222"
},
{
"tag": "NPCITag06",
"value": ""
},
{
"tag": "NPCITag07",
"value": ""
},
{
"tag": "AmexTag011",
"value": ""
},
{
"tag": "AmexTag012",
"value": ""
}
],
"countryCode": "KW",
"transactionCurrencyCode": "414",
"transactionAmount": 10,
"extraFeesMode": "02",
"extraFeesAmount": 5,
"billNumber": "123093133",
"customerLabel": "Tap Customer",
"terminalLabel": "POS 1",
"storeLabel": "Kuwait City",
"loyaltyNumber": "78876",
"mobileNumber": "0096599999999",
"purposeForTransaction": "Tap Transaction",
"additionalCustomerDataCollection": "ME",
"alternateLanguageLocale": "ar",
"alternateLanguageMerchantName":"تاب للمدفوعات",
"alternateLanguageMerchantCityName":"الكويت"
}
Scanning a QR Code
Below the different ways you can scan a QR code using different ways.
Extract QR Code from a static Image
TapQRCodeScanner
can scan a QR code from a given Image without using the camera.
Swift:
import TapQRCode_iOS
let tapQRCodeScannerResult:TapQRCodeScannerResult = TapQRCodeScanner().scan(from: pickedImage)
Objective-C:
@import TapQRCode_iOS;
TapQRCodeScannerResult* tapQRCodeScannerResult = [[[TapQRCodeScanner alloc]init] scanFrom:pickedImage];
Parameters:
Parameter name | Parameter type | Required | Default vale | Description |
---|---|---|---|---|
from | UIImage | Yes | none | The UIImage you want to extract a qr code from |
Inline QR Code scanner
TapQRCodeScanner
can scan a QR code from a camera stream inside a given UIView. So you can fit a scanner inside your layout
Swift:
import TapQRCode_iOS
let tapBarCodeScanner:TapQRCodeScanner = TapQRCodeScanner()
tapBarCodeScanner.scan(inside: inlineView,
shouldHideUponScanning: true,
erroCallBack: { [weak self] error in
print (error)
},scannedCodeCallBack: { [weak self] tapScanResult in
print (tapScanResult.scannedText!)
},scannerRemovedCallBack: { [weak self] in
print("scannerStopped")
},introFadeIn: false,
outroFadeOut: false,
top:0, bottom:0, right:0, left:0)
Objective-C:
@import TapQRCode_iOS;
TapQRCodeScanner* tapQRCodeScanner = [[TapQRCodeScanner alloc]init];
[tapQRCodeScanner scanInside:inlineView
shouldHideUponScanning:YES
erroCallBack:^(NSString * error) {
NSLog(@"%@",error);
} scannedCodeCallBack:^(TapQRCodeScannerResult * scannerResult) {
NSLog(@"%@",scannerResult.scannedText);
} scannerRemovedCallBack:^{
NSLog(@"%@",@"Scanner removed");
} introFadeIn:NO outroFadeOut:NO
top:0 bottom:0 right:0 left:0];
Parameters:
Parameter name | Parameter type | Required | Default vale | Description |
---|---|---|---|---|
holdingView | UIView | Yes | none | The subview the caller wants to show the scanner in |
shouldHideUponScanning | Bool | No | true | if true, then the scanner will dismiss itself after reading a code. Default True |
erroCallBack | ((String) -> ()) | No | nil | Closure used to send a string description of any error prevented the scannr to start |
scannedCodeCallBack | ((TapQRCodeScannerResult) -> ()) | No | nil | Closure used to send a string description of the scanned code |
scannerRemovedCallBack | (() -> ()) | No | nil | Closure used to inform when the scanner is removed |
introFadeIn | Bool | No | false | When set tthe scanner will fade in when ready |
outroFadeOut | Bool | No | false | When set the scanner will fde out upon completion |
top | CGFloat | No | 0 | Top margin from the holder uiview. Default is 0 |
bottom | CGFloat | No | 0 | Bottom margin from the holder uiview. Default is 0 |
right | CGFloat | No | 0 | Right margin from the holder uiview. Default is 0 |
Left | CGFloat | No | 0 | Left margin from the holder uiview. Default is 0 |
Modal Full Screen QR Code scanner
TapQRCodeScanner
can scan a QR code from a camera stream in a full screen mode by showing the scanner as model from a given UIViewController
Swift:
import TapQRCode_iOS
TapQRCodeScanner().scan(fullScreen: self,
showTorchButton: true,
showOverlay: true,
showSwitchCameraButton: true,
statusBar: .default,
cancelButtonTitle: "Cancel",
torchButtonIcon: UIImage(named: "torchIcon"),
erroCallBack: { (error) in
print(error)
}, scannedCodeCallBack: { scannedValue in
print(scannedValue.scannedText ?? "")
}) {
print("Scanner Canceled")
}
Parameters:
Parameter name | Parameter type | Required | Default vale | Description |
---|---|---|---|---|
fromController | UIViewController | Yes | none | The view controller the scanner will be presented from |
showTorchButton | Bool | No | true | Determine if the torch button will be visible on the scanner. Default true |
showOverlay | Bool | No | true | Determine if the overlay will be visible on the scanner. Default true |
showSwitchCameraButton | Bool | No | False | Determine if the switch button will be visible on the scanner. Default false |
statusBar | UIStatusBarStyle | No | .default | Determine what UIStatusbar stule you want. Default .default |
cancelButtonTitle | String | No | Cancel | Determine the title of the cancel button. Default Cancel |
torchButtonIcon | UIImage | No | none | If you want to set a specific icon for the torch button |
erroCallBack | ((String) -> ()) | No | nil | Closure used to send a string description of any error prevented the scannr to start |
scannedCodeCallBack | ((TapQRCodeScannerResult) -> ()) | No | nil | Closure used to send a string description of the scanned code |
scannerCanceledCallBack | (() -> ()) | No | nil | Closure used to inform when the scanner is cancelled |