TestsTested | ✗ |
LangLanguage | Obj-CObjective C |
License | Custom |
ReleasedLast Release | May 2021 |
Maintained by Muhammad Azeem, Mastercard Labs, Mani Tiwaree.
This SDK provides UI components for QR scanning that allows to modify simple attributes of the views or use custom views for display.
This SDK is developed in Objective-C and it works with Swift.
This SDK is based on QRCodeReaderViewController
In your Podfile write the following
use_frameworks!
pod 'MasterpassQRScanSDK'
Do pod install
Everything is setup now
Download the latest release of Masterpass QR Scan SDK.
Unzip the file.
Go to your Xcode project’s “General” settings. Drag MasterpassQRScanSDK.framework to the “Embedded Binaries” section. Make sure to select Copy items if needed and click Finish.
Create a new Run Script Phase in your app’s target’s Build Phases and paste the following snippet in the script text field:
bash "${BUILT_PRODUCTS_DIR}/${FRAMEWORKS_FOLDER_PATH}/MasterpassQRScanSDK.framework/strip-frameworks.sh"
This step is required to work around an App Store submission bug when archiving universal binaries.
In iOS10+, you will need first provide a reasoning about the camera use. For that you'll need to add the Privacy - Camera Usage Description (NSCameraUsageDescription) field in your Info.plist
QRReaderViewControllerBuilder
instance.QRReaderViewController
with QRReaderViewControllerBuilder
instance.QRReaderViewController
instance.Note that you should check whether the device supports the reader library by using the QRCodeReader.isAvailable()
and the QRCodeReader.supportsQRCode()
methods.
Swift
import MasterpassQRScanSDK
import AVFoundation
@IBAction func scanWithOriginalTheme(_ sender: Any) {
guard QRCodeReader.isAvailable() && QRCodeReader.supportsQRCode() else {
return
}
// Presents the readerVC
checkCameraPermission { [weak self] in
guard let strongSelf = self else {
return
}
var reader:QRCodeReader?
let qrVC = QRCodeReaderViewController(builder: QRCodeReaderViewControllerBuilder {
$0.startScanningAtLoad = false
reader = $0.reader
})
//block to read the result
reader?.setCompletionWith({ result in
reader?.stopScanning()
self?.scanResult.text = result;
self?.dismiss(animated: true, completion: nil)
})
//block when cancel is pressed
qrVC.setCompletionWith({ result in
reader?.stopScanning()
self?.dismiss(animated: true, completion: nil)
})
// Retrieve the QRCode content via delegate
qrVC.delegate = self
strongSelf.present(qrVC, animated: true, completion: {
qrVC.startScanning()
})
}
}
// Check camera permissions
func checkCameraPermission(completion: @escaping () -> Void) {
let cameraMediaType = AVMediaType.video
let cameraAuthorizationStatus = AVCaptureDevice.authorizationStatus(for: cameraMediaType)
switch cameraAuthorizationStatus {
case .denied:
showAlert(title: "Error", message: "Camera permissions are required for scanning QR. Please turn on Settings -> MasterpassQR Demo -> Camera")
break
case .restricted:
showAlert(title: "Error", message: "Camera permissions are restricted for scanning QR")
break
case .authorized:
completion()
case .notDetermined:
// Prompting user for the permission to use the camera.
AVCaptureDevice.requestAccess(for: cameraMediaType) { [weak self] granted in
guard let strongSelf = self else { return }
DispatchQueue.main.async {
if granted {
completion()
} else {
strongSelf.showAlert(title: "Error", message: "Camera permissions are required for scanning QR. Please turn on Settings -> MasterpassQR Demo -> Camera")
}
}
}
}
}
func showAlert(title: String, message: String) {
let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Ok", style: .cancel, handler: nil))
present(alert, animated: true, completion: nil)
}
// MARK: - QRCodeReaderViewController Delegate Methods
func reader(_ reader: QRCodeReaderViewController, didScanResult result: String) {
reader.stopScanning()
self.scanResult.text = result;
dismiss(animated: true, completion: nil)
}
func readerDidCancel(_ reader: QRCodeReaderViewController) {
reader.stopScanning()
dismiss(animated: false, completion: nil)
}
Objective-C
@import MasterpassQRScanSDK;
@import AVFoundation;
- (IBAction)scanAction:(id)sender {
if (![QRCodeReader isAvailable] || ![QRCodeReader supportsQRCode]) {
return;
}
__weak typeof(self) weakSelf = self;
[self checkCameraPermission: ^{
__block __weak QRCodeReader* reader;
QRCodeReaderViewController* qrVC = [QRCodeReaderViewController readerWithBuilderBlock:^(QRCodeReaderViewControllerBuilder *builder){
reader = builder.reader;
}];
//block to read the result
[reader setCompletionWithBlock:^(NSString *result) {
[reader stopScanning];
[self dismissViewControllerAnimated:YES completion: nil];
self.scanResult.text = result;
}];
//block when cancel is pressed
[qrVC setCompletionWithBlock:^(NSString *result) {
[reader stopScanning];
[self dismissViewControllerAnimated:YES completion: nil];
}];
// Retrieve the QRCode content via delegate
qrVC.delegate = weakSelf;
[weakSelf presentViewController:qrVC animated:true completion:nil];
}];
}
// Check camera permissions
- (void)checkCameraPermission:(void (^)(void))completion {
AVAuthorizationStatus status = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
if (status == AVAuthorizationStatusDenied) {
[self showAlertWithTitle:@"Error" message: @"Camera permissions are required for scanning QR. Please turn on Settings -> MasterpassQR Demo -> Camera"];
return;
} else if (status == AVAuthorizationStatusRestricted) {
[self showAlertWithTitle:@"Error" message: @"Camera permissions are restricted for scanning QR"];
return;
} else if (status == AVAuthorizationStatusAuthorized) {
completion();
} else if (status == AVAuthorizationStatusNotDetermined) {
__weak __typeof(self) weakSelf = self;
[AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) {
dispatch_async(dispatch_get_main_queue(), ^{
if (granted) {
completion();
} else {
[weakSelf showAlertWithTitle:@"Error" message: @"Camera permissions are required for scanning QR. Please turn on Settings -> MasterpassQR Demo -> Camera"];
}
});
}];
}
}
- (void)showAlertWithTitle:(NSString *)title message:(NSString *)message {
UIAlertController *controller = [UIAlertController alertControllerWithTitle:title message:message preferredStyle:UIAlertControllerStyleAlert];
[controller addAction:[UIAlertAction actionWithTitle:@"Ok" style:UIAlertActionStyleCancel handler:nil]];
[self presentViewController:controller animated:true completion:nil];
}
# pragma mark - QRCodeReaderViewControllerDelegate Methods
- (void)reader:(QRCodeReaderViewController *)reader didScanResult:(NSString *)result {
[reader stopScanning];
[self dismissViewControllerAnimated:YES completion: nil];
self.scanResult.text = result;
}
- (void)readerDidCancel:(QRCodeReaderViewController *)reader {
[reader stopScanning];
[self dismissViewControllerAnimated:YES completion: nil];
}
Using custom view controller with QRReaderViewController
embedded as child view controller.
Swift
import MasterpassQRScanSDK
class CustomViewController : UIViewController, QRCodeReaderDelegate {
lazy var reader: QRCodeReaderViewController = {
return QRCodeReaderViewController(builder: QRCodeReaderViewControllerBuilder {
let readerView = $0.readerView
// Setup overlay view
let overlayView = readerView.getOverlay()
overlayView.cornerColor = UIColor.purple
overlayView.cornerWidth = 6
overlayView.cornerLength = 75
overlayView.indicatorSize = CGSize(width: 250, height: 250)
// Setup scanning region
$0.scanRegionSize = CGSize(width: 250, height: 250)
// Hide torch button provided by the default view
$0.showTorchButton = false
// Hide cancel button provided by the default view
$0.showCancelButton = false
// Don't start scanning when this view is loaded i.e initialized
$0.startScanningAtLoad = false
$0.showSwitchCameraButton = false;
})
}()
override func viewDidLoad() {
super.viewDidLoad()
reader.delegate = self
self.addChildViewController(reader)
self.view.insertSubview(reader.view, at: 0)
let viewDict = ["reader" : reader.view as Any]
self.view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|[reader]|", options: [], metrics: nil, views: viewDict))
self.view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|[reader]|", options: [], metrics: nil, views: viewDict))
reader.didMove(toParentViewController: self)
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
reader.startScanning()
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
reader.stopScanning()
}
// MARK:- Actions
@IBAction func toggleTorch(_ sender: Any) {
reader.codeReader!.toggleTorch()
}
func reader(_ reader: QRCodeReaderViewController, didScanResult result: String) {
reader.stopScanning()
}
func readerDidCancel(_ reader: QRCodeReaderViewController) {
reader.stopScanning()
}
}
Objective-C
@import MasterpassQRScanSDK;
@interface CustomViewController () <QRCodeReaderDelegate>
@property (nonatomic, strong) QRCodeReaderViewController *qrVC;
@end
@implementation CustomViewController
@implementation CustomViewController
- (void)viewDidLoad {
[super viewDidLoad];
QRCodeReaderViewControllerBuilder *builder = [[QRCodeReaderViewControllerBuilder alloc] init];
QRCodeReaderView *readerView = (QRCodeReaderView *) builder.readerView;
// Setup overlay view
QRCodeReaderViewOverlay *overlayView = (QRCodeReaderViewOverlay *)[readerView getOverlay];
overlayView.cornerColor = UIColor.purpleColor;
overlayView.cornerWidth = 6;
overlayView.cornerLength = 75;
overlayView.indicatorSize = CGSizeMake(250, 250);
// Setup scanning region
builder.scanRegionSize = CGSizeMake(250, 250);
// Hide torch button provided by default view
builder.showTorchButton = false;
// Hide cancel button provided by default view
builder.showCancelButton = false;
// Don't start scanning when this view is loaded i.e initialized
builder.startScanningAtLoad = false;
builder.showSwitchCameraButton = false;
self.qrVC = [[QRCodeReaderViewController alloc] initWithBuilder:builder];
self.qrVC.delegate = self;
// Add the reader as child view controller
[self addChildViewController:self.qrVC];
// Add reader view to the bottom
[self.view insertSubview:self.qrVC.view atIndex: 0];
NSDictionary *dictionary = @{@"qrVC": self.qrVC.view};
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[qrVC]|" options:0 metrics:nil views:dictionary]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[qrVC]|" options:0 metrics:nil views:dictionary]];
[self.qrVC didMoveToParentViewController:self];
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[self.qrVC startScanning];
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
[self.qrVC stopScanning];
}
#pragma mark - Actions
- (IBAction)torchButtonPressed:(id)sender {
[self.qrVC.codeReader toggleTorch];
}
#pragma mark - QRCodeReaderViewControllerDelegate methods
- (void)reader:(QRCodeReaderViewController *)reader didScanResult:(NSString *)result {
[reader stopScanning];
}
- (void)readerDidCancel:(QRCodeReaderViewController *)reader {
[reader stopScanning];
}
You can subclass the QRCodeReaderViewController to create your own looks and feel, placement of the component of the class. You can modify the following component:
Swift
import UIKit
import MasterpassQRScanSDK
class QRCodeReaderViewControllerSubClass: QRCodeReaderViewController {
//Mark: - Overriden
override func setupUIComponents(withCancelButtonTitle cancelButtonTitle: String?, cameraView: QRCodeReaderView?) {
if let cameraView = cameraView {
self.cameraView = cameraView;
}else
{
self.cameraView = QRCodeReaderView()
}
view.addSubview(self.cameraView!)
}
override func setupAutoLayoutConstraints() {
let views = ["cameraView":self.cameraView!]
view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|-50-[cameraView]-50-|", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: views))
view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-50-[cameraView]-50-|", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: views))
}
}
Objective-C
#import <MasterpassQRScanSDK/MasterpassQRScanSDK.h>
@interface QRCodeReaderViewControllerSubClass : QRCodeReaderViewController
@end
@implementation QRCodeReaderViewControllerSubClass
#pragma mark - Overriden
- (void)setupUIComponentsWithCancelButtonTitle:(NSString *)cancelButtonTitle cameraView:(nullable QRCodeReaderView*) cameraView
{
self.cameraView = cameraView;
if (!self.cameraView) {
self.cameraView = [[QRCodeReaderView alloc] init];
self.cameraView.translatesAutoresizingMaskIntoConstraints = NO;
self.cameraView.clipsToBounds = YES;
}
[self.view addSubview:self.cameraView];
//setup other components
}
- (void)setupAutoLayoutConstraints
{
NSDictionary *views = @{ @"cameraView" : self.cameraView};
[self.view addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-50-[cameraView]-50-|" options:0 metrics:nil views:views]];
[self.view addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-50-[cameraView]-50-|" options:0 metrics:nil views:views]];
//setup other components
}
@end