Skip to content

aaronlab/SweetCardScanner

Repository files navigation

Language: Swift 5 Platform: iOS 13+ SwiftPM compatible License: MIT Release version

SweetCardScanner

SweetCardScanner is a fast and simple Card Scanner library written in Swift, based onCreditCardScannerandReglibraries by@yhkaplanso that users can pay much more easily by capturing their credit/debit card with the rear camera.

Requirements

  • iOS 13.0+ (due to SwiftUI, Vision Framework)
    • Tested on iOS 14.1 with iPhone X

Installation

  • In Xcode, add the URL of this repository in SwiftPM:

    https://github /aaronLab/SweetCardScanner.git

Usage

  1. AddNSCameraUsageDescriptionintoInfo.plistfor Camera Useage Description.
  2. import SweetCardScanneron top of theContentView.swift.
  3. Now, you can use likeSweetCardScanner()orSweetCardScanner(wordsToSkip: Array<String>?, invalidNames: Array<String>?)inside of the body.
  4. WithwordsToSkip: Array<String>?,you can add some words "in lowercase" to try to skip in recognition to improve the performance like bank names, such as "td", "td banks", "cibc", and so on.
  5. The default value ofwordsToSkipis[ "mastercard", "jcb", "visa", "express", "bank", "card", "platinum", "reward" ]
  6. WithinvalidNames: Array<String>?,you can try to add some words "in lowercase" for invalid names, such as "thru", "authorized", "signature".
  7. The default value ofinvalidNames: Array<String>?is[ "expiration", "valid", "since", "from", "until", "month", "year" ]
  8. Also, you can use completion clousures, such as.onDismiss,.onError,.onSuccessright afterSweetCardScanner()like below.
  9. If you want to turn off the camera when you move to the result view, you will need to use your own customized navigation status trick.(Check the example below)
varbody:someView{
/*
You can add some words "in lowercase" to try to skip in recognition to improve the performance like bank names,
such as "td", "td banks", "cibc", and so on.
Also you can try to add some words "in lowercase" for invalid names, such as "thru", "authorized", "signature".
Or you can just simply usw liek "SweetCardScanner()"
*/
SweetCardScanner(
wordsToSkip:["td","td bank","cibc"],
invalidNames:["thru","authorized","signature"]
)
.onDismiss{
// Do something when the view dismissed.
}
.onError{errorin
// The 'error' above gives you 'CreditCardScannerError' struct below.
print(error)
}
.onSuccess{cardin
// The card above gives you 'CreditCard' struct below.
print(card)
}
}

CreditCardScannerError

publicstructCreditCardScannerError:LocalizedError{
publicenumKind{casecameraSetup,photoProcessing,authorizationDenied,capture}
publicvarkind:Kind
publicvarunderlyingError:Error?
publicvarerrorDescription:String?{(underlyingErroras?LocalizedError)?.errorDescription}
}

CreditCard

publicstructCreditCard{
publicvarnumber:String?
publicvarname:String?
publicvarexpireDate:DateComponents?
publicvaryear:Int{expireDate?.year??0}// This returns "yyyy"
publicvarmonth:Int{expireDate?.month??0}// This returns "MM"
/*
CardVender below returns an element of an enum:
Unknown, Amex, Visa, MasterCard, Diners, Discover, JCB, Elo, Hipercard, UnionPay
*/
publicvarvendor:CardVendor{CreditCardUtil.getVendor(candidate:self.number)}
publicvarisNotExpired:Bool?{CreditCardUtil.isValid(candidate:self.expireDate)}
}

CardVendor

publicenumCardVendor:String{
caseUnknown,Amex,Visa,MasterCard,Diners,Discover,JCB,Elo,Hipercard,UnionPay
}

Example

You can customize your own view with SweetCardScanner, and SwiftUI like below.

// ContentView.swift

import SwiftUI
import SweetCardScanner

structContentView:View{
// MARK: - PROPERTIES

@StatevarnavigationStatus:NavigationStatus?=.ready
@Statevarcard:CreditCard?

// MARK: - BODY

varbody:someView{

NavigationView{

GeometryReader{geometryin

ZStack{

NavigationLink(
destination:ResultView(card:card)
.onDisappear{
/*
You will be able to turn on the camera again
when you come back to this view from the result view
by changing your own customized navigation status.
*/
self.navigationStatus=.ready
},
tag:NavigationStatus.pop,
selection:$navigationStatus){
EmptyView()
}

/*
You will be able to turn off the camera when you move to the result view
with the `if` statement below.
*/
if navigationStatus==.ready{
/*
You can add some words "in lowercase" to try to skip in recognition to improve the performance like bank names,
such as "td", "td banks", "cibc", and so on.
Also you can try to add some words "in lowercase" for invalid names, such as "thru", "authorized", "signature".
Or you can just simply usw liek "SweetCardScanner()"
*/
SweetCardScanner(
wordsToSkip:["td","td bank","cibc"],
invalidNames:["thru","authorized","signature"]
)
.onError{errin
print(err)
}
.onSuccess{cardin
self.card=card
self.navigationStatus=.pop
}
}

RoundedRectangle(cornerRadius:16)
.stroke()
.foregroundColor(.white)
.padding(16)
.frame(width:geometry.size.width,height:geometry.size.width*0.63,alignment:.center)

}//: ZSTACK

}//: GEOMETRY

}//: NAVIGATION

}
}

// MARK: - NavigationStatus
enumNavigationStatus{
caseready,pop
}
// ResultView.swift
import SwiftUI
importstructSweetCardScanner.CreditCard

structResultView:View{
// MARK: - PROPERTIES

letcard:CreditCard?

// MARK: - BODY

varbody:someView{

VStack{
Text("Card Holder Name:\(card?.name??"N/A")")
Text("Number:\(card?.number??"N/A")")
Text("Expire Year:\(String(card?.year??00))")
Text("Expire Month:\(String(card?.month??00))")
Text("Card Vendor:\(card?.vendor.rawValue??"Unknown")")

ifletisNotExpired=card?.isNotExpired{
isNotExpired?Text("Expired: Not Expired"):Text("Expired: Expired")
}

}

}

}

License

Licensed underMITlicense.