NHN Cloud ID Card Recognizer operates in Android 5.1 or higher (API level 22 or higher).
Add dependencies of nhncloud-idcard-recognizer to the build.gradle file of the app.
dependencies {
...
// NHN Cloud ID Card Recognizer
implementation 'com.nhncloud.android:nhncloud-idcard-recognizer:1.9.4'
}
To use ID Card Recognizer, the permission Manifest.permission.CAMERA is required. You must obtain the Camera permission before using ID Card Recognizer.
Create an ID Card Recognizer instance.
val nhnCloudOcr = NhnCloudOcr.newBuilder(context)
.appKey(APP_KEY)
.secretKey(SECRET_KEY)
.build()
val idCardRecognizer = nhnCloudOcr.createIdCardRecognizer()
Initiate ID card recognition by calling the IdCardRecognizer's launch (Activity, IdCardRecognitionCallback) method.
IdCardRecognizer.launch(activity) { result, data ->
if (result.isSuccess) {
// Success.
} else {
// Failure.
}
}
When ID recognition is successful, ID recognition data is passed to an object that inherits and implements IdCardData. Depending on the ID type, a social security card is returned as an IdCardResidentData object, and a driver's license is returned as an IdCardDriverData object.
For privacy reasons, ID data is returned as a SecureString object rather than a plain string. The SecureString.charAt(index) method returns the character at the specified index.
It is vulnerable to security when you create and use the ID card recognition data that is returned as IdCardData as a String object.
See Use SecureTextView to display on screen.
when (data) {
//ID card data is a SecureString object.
is IdCardResidentData -> {
//Use resident card's data.
nameSecureTextView.setText(data.name);
residentNumberSecureTextView.setText(data.residentNumber);
}
//Use driver license's data.
is IdCardDriverData -> {
...
}
}
Create an IdCardAuthenticator instance to verify the authenticity of an ID. You can request authenticity verification using IdCardData, which is the identification result.
The ID verification result is returned as a Boolean type.
IdCardData's RequestKey used for authenticity verification is a one-time value and cannot be reused.
Request-Key is valid for 1 hour after issuance and cannot be used after that.
val authenticator = nhnCloudOcr.createIdCardAuthenticator()
viewModelScope.launch(Dispatchers.IO) {
try {
//Use authenticity result
isAuthenticity = authenticator.authenticate(idCardData)
} catch (e : OcrException) {
//Authenticity Error
}
}
If you want to make a call with the authenticateAsync method, you can implement IdCardAuthenticityCallback to receive the result.
nhnCloudOcr.createIdCardAuthenticator()
.authenticateAsync(idCardData) { result, isAuthenticity ->
if (result.isSuccess) {
//Use authenticity result
} else {
//Authenticity Error
}
}
You can customize and use the ID card recognition screen. You must use IdCardRecognitionService instead of IdCardRecognizer to configure your custom screen.
Create an IdCardRecognitionService instance.
val ocrServices = NhnCloudOcrServices.newBuilder(context)
.appKey(APP_KEY)
.secretKey(SECRET_KEY)
.build()
val IdCardRecognitionService = ocrServices.createIdCardRecognitionService()
Register a listener using the setIdCardRecognitionListener() method. When an ID card is recognized, the result is notified via the IdCardRecognitionListener.
IdCardRecognitionService.setIdCardRecognitionListener { result, data ->
if (result.isSuccess) {
// Recognition success.
IdCardRecognitionService.stop()
} else {
// Recognition failure.
}
}
You must stop the service by calling the IdCardRecognitionService.stop() after ID card recognition.
IdCardRecognitionData passed to IdCardRecognitionListener will return all results regardless of confidence rating. Therefore, more accurate results can be used by checking the confidence rating as shown below.
IdCardRecognitionService.setIdCardRecognitionListener { result, data ->
if (result.isSuccess && isConfident(data)) {
// Recognition success.
IdCardRecognitionService.stop()
} else {
// Recognition failure.
}
}
private fun isConfident(data: IdCardRecognitionData): Boolean {
//Returns success if the format of the data is correct and all confidences is 0.4 or higher
when (data) {
is IdCardResidentRecognitionData -> {
//Resident number is in "123456-1234567" format.
val residentNumbers = data.residentNumber.value.split('-')
if (residentNumbers.size != 2 ||
residentNumbers[0].length != 6 ||
residentNumbers[1].length != 7) {
return false
}
//Issued Date is in "yyyy.mm.dd." or "yyyy.mm.dd" format.
//the month and day can be single digits, such as "yyyy.m.d".
val dates = data.issueDate.value.split('.')
if (!(dates.size == 3 || dates.size == 4)) {
return false
}
return data.name.confidence>= 0.4 &&
data.residentNumber.confidence >= 0.4 &&
data.issueDate.confidence >= 0.4 &&
data.issuer.confidence >= 0.4
}
is IdCardDriverRecognitionData -> {
//Resident number is in "123456-1234567" format.
val residentNumbers = data.residentNumber.value.split('-')
if (residentNumbers.size != 2 ||
residentNumbers[0].length != 6 ||
residentNumbers[1].length != 7) {
return false
}
//driver license number has the format of "12-12-123456-78".
val driverLicenseNumbers = data.driverLicenseNumber.value.split('-')
if (driverLicenseNumbers.size != 4 ||
driverLicenseNumbers[0].length != 2 ||
driverLicenseNumbers[1].length != 2 ||
driverLicenseNumbers[2].length != 6 ||
driverLicenseNumbers[3].length != 2) {
return false
}
//Issued Date is in "yyyy.mm.dd." or "yyyy.mm.dd" format.
//the month and day can be single digits, such as "yyyy.m.d".
val dates = data.issueDate.value.split('.')
if (!(dates.size == 3 || dates.size == 4)) {
return false
}
//The driver type additionally checks the driver license number, serial number, and license type.
//condition is not checked because there is a case where the value does not exist.
return data.name.confidence>= 0.4 &&
data.residentNumber.confidence >= 0.4 &&
data.issueDate.confidence >= 0.4 &&
data.issuer.confidence >= 0.4 &&
data.driverLicenseNumber.confidence >= 0.4 &&
data.licenseType.confidence >= 0.4 &&
data.serialNumber.confidence >= 0.4
}
else -> error("Invalid data.")
}
}
When ID recognition is successful, ID recognition data is passed to an object implementing IdCardRecognitionData inheritance. Depending on the ID type, a social security card is returned as an IdCardResidentRecognitionData object, and a driver's license is returned as an IdCardDriverRecognitionData object.
For privacy reasons, ID data is returned as a SecureString object rather than a plain string. The SecureString.charAt(index) method returns the character at the specified index.
It is vulnerable to security when you create and use the ID card recognition data that is returned as IdCardRecognitionData as a String object.
See Use SecureTextView to display on screen.
when (data) {
//ID card data is a SecureString object.
is IdCardResidentRecognitionData -> {
//Use resident card's data.
nameSecureTextView.setText(data.name.value);
residentNumberSecureTextView.setText(data.residentNumber.value);
}
is IdCardDriverRecognitionData -> {
//Use driver license's data.
...
}
}
Create an IdCardAuthenticityService instance to verify the authenticity of an ID card. You can request authenticity verification using IdCardRecognitionData, which is the ID recognition result.
The ID verification result is returned as a Boolean type.
The RequestKey of IdCardRecognitionData used for authenticity verification is a one-time value and is not reusable.
Request-Key is valid for 1 hour after issuance and cannot be used after that.
val service = ocrServices.createIdCardAuthenticityService()
viewModelScope.launch(Dispatchers.IO) {
try {
//Use authenticity result
isAuthenticity = service.authenticate(idCardRecognitionData)
} catch (e : OcrException) {
//Authenticity Error
}
}
If you want to make a call with the authenticateAsync method, you can implement IdCardAuthenticityCallback to receive the result.
ocrServices.createIdCardAuthenticityService()
.authenticateAsync(idCardRecognitionData) { result, isAuthenticity ->
if (result.isSuccess) {
//Use authenticity result
} else {
//Authenticity Error
}
}
Add IdCardRecognitionCameraPreview to Activity or Layout of Fragment as follows to configure Camera Preview.
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.nhncloud.android.ocr.idcard.view.IdCardRecognitionCameraPreview
android:id="@+id/camera_preview"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
Areas except for the scan guide area appear translucent. Configure their colors using the "app:guideBackgroundColor" property.
<com.nhncloud.android.ocr.idcard.view.IdCardRecognitionCameraPreview
android:id="@+id/camera_preview"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:guideBackgroundColor="#33000000" />
You can freely define the scan guide view by placing it as a subview of the IdCardRecognitionCameraPreview. Configure the user-defined guide view using the "app:guideView" property.
IdCardRecognitionCameraPreview is implemented by inheriting ConstraintLayout.
The size of the scan guide view is automatically adjusted.
<com.nhncloud.android.ocr.idcard.view.IdCardRecognitionCameraPreview
android:id="@+id/camera_preview"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:guideView="@id/guide_view">
<com.yourapp.view.CustomGuideView
android:id="@+id/guide_view"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginTop="80dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent">
</com.nhncloud.android.ocr.idcard.view.IdCardRecognitionCameraPreview>
You can change the color or shape of the scan guide view when an ID card is detected. Change the color or shape of the guide view according to the value passed to setDetected(Boolean) after implementation inheritance of the OcrDetectable interface.
class CustomGuideView(
context: Context, attrs: AttributeSet?
): View(context, attrs), OcrDetectable {
override fun setDetected(detected: Boolean) {
if (detected) {
color = Color.GREEN
} else {
color = Color.WHITE
}
}
...
}
Start IdCardRecognitionService by obtaining the instances of IdCardRecognitionCameraPreview.
val cameraPreview = findViewById<IdCardRecognitionCameraPreview>(R.id.camera_preview)
try {
idCardRecognitionService.start(cameraPreview)
} catch (e: IOException) {
// Camera is not available (in use or does not exist)
}
Stop IdCardRecognitionService when the app enters the background or ID card recognition is successful.
idCardRecognitionService.stop()
Release IdCardRecognitionService when Activity or Fragment's View is destroyed.
idCardRecognitionService.release();
Call as follows according to Activity or the lifecycle of Fragment.
override fun onResume() {
super.onResume()
idCardRecognitionService.start(cameraPreview)
}
override fun onPause() {
super.onPause()
idCardRecognitionService.stop()
}
override fun onDestroy() {
super.onDestroy()
idCardRecognitionService.release()
}
override fun onResume() {
super.onResume()
idCardRecognitionService.start(cameraPreview)
}
override fun onPause() {
super.onPause()
idCardRecognitionService.stop()
}
override fun onDestroyView() {
super.onDestroyView()
idCardRecognitionService.release()
}
To prevent screen capture, add WindowManager.LayoutParams.FLAG_SECURE before setContentView() is called from onCreate() of Activity.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
window.addFlags(WindowManager.LayoutParams.FLAG_SECURE)
setContentView(R.layout.activity_main)
...
}
For more details, see WindowManager.LayoutParams.FLAG_SECURE.
Before starting the ID Card Recognition service, you can check whether the ID Card Recognition service is available is on the device running the application. To perform this check, use the IdCardRecognitionService.isAvailable(Context) method.
if (IdCardRecognitionService.isAvailable(context)) {
// ID card recognition service is available.
} else {
// ID card recognition service is not available.
}
For privacy reasons, ID data is returned as a SecureString object rather than a plain string. If ID recognition information is created and used as a String object, security is vulnerable, and SecureTextView can be used to display the data on the screen.
<com.nhncloud.android.ocr.SecureTextView
android:id="@+id/id_card_name_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:com_nhncloud_text_color="#ffffff"
app:com_nhncloud_text_size="15sp"
app:com_nhncloud_text_style="bold"/>
Set the text to be displayed via the setText method of SecureTextView.
val name = idCardData.name
val idCardNameView = findViewById<SecureTextView>(id_card_name_view)
idCardNameView.setText(name)
If you need to display multiple lines of text, you can use SecureTextGroup.
<com.nhncloud.android.ocr.SecureTextGroup
android:id="@+id/id_card_license_type_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:com_nhncloud_text_color="#ffffff"
app:com_nhncloud_text_size="15sp"
app:com_nhncloud_text_style="bold"/>
SecureTextGroup's addTextViews method takes an array as a parameter and sets each element to one line of text.
//The license type is a SecureString array.
val licenseType = idCardData.idCardLicenseType.split('/')
val idCardLicenseTypeView = findViewById<SecureTextGroup>(id_card_license_type_view)
idCardLicenseTypeView.addTextViews(licenseType)
Method | Returns | Parameters | Descriptions |
---|---|---|---|
getRequestKey | SecureString | Return the RequestKey used to verify the authenticity of the ID. | |
getIdType | String | Return the ID type. ("resident" or "driver") |
Method | Returns | Parameters | Descriptions |
---|---|---|---|
getName | SecureString | Return the name. | |
getResidentNumber | SecureString | Return the resident registration number. | |
getIssueDate | SecureString | Return the issue date. | |
getIssuer | SecureString | Return the issuer. |
Method | Returns | Parameters | Descriptions |
---|---|---|---|
getName | SecureString | Return the name. | |
getResidentNumber | SecureString | Return the resident registration number. | |
getIssueDate | SecureString | Return the issue date. | |
getIssuer | SecureString | Return the issuer. | |
getDriverLicenseNumber | SecureString | Return the driver's license number. | |
getLicenseType | SecureString | Return the license type. If there are two or more license types, they are separated by "/" within the string. |
|
getCondition | SecureString | Return the license conditions. Depending on your driver's license, if that value doesn't exist, it will return blank. |
|
getSerialNumber | SecureString | Return the password sequence number. |
Method | Returns | Parameters | Descriptions |
---|---|---|---|
getOriginBitmap | Bitmap | Return the original image. | |
getDetectedBitmap | Bitmap | Return the detected image. (The image of the guide area is returned.) |
|
getResolution | String | Return the resolution information. (Normal when over the recommended resolution, low when below the recommended resolution) |
|
getRequestKey | String | Return the RequestKey used to verify the authenticity of the ID. | |
getIdType | String | Return the ID type. ("resident" or "driver") | |
getOriginJsonData | String | Return the server response result. |
Method | Returns | Parameters | Descriptions |
---|---|---|---|
getValue | SecureString | Return the ID recognition result. | |
getConfidence | String | Return the confidence of ID card recognition results. |
Method | Returns | Parameters | Descriptions |
---|---|---|---|
getName | IdCardValue | Return the name. | |
getResidentNumber | IdCardValue | Return the resident registration number. | |
getIssueDate | IdCardValue | Return the issue date. | |
getIssuer | IdCardValue | Return the issuer. |
Method | Returns | Parameters | Descriptions |
---|---|---|---|
getName | IdCardValue | Return the name. | |
getResidentNumber | IdCardValue | Return the resident registration number. | |
getIssueDate | IdCardValue | Return the issue date. | |
getIssuer | IdCardValue | Return the issuer. | |
getDriverLicenseNumber | IdCardValue | Return the driver's license number. | |
getLicenseType | IdCardValue | Return the license type. If there are two or more license types, they are separated by "/" within the string. |
|
getCondition | IdCardValue | Return the license conditions. Depending on your driver's license, if that value doesn't exist, it will return blank. |
|
getSerialNumber | IdCardValue | Return the password sequence number. |
Method | Returns | Parameters | Descriptions |
---|---|---|---|
setText | SecureString | Set the text to be displayed in SecureTextView. | |
setTextSize | float | Set the text size. The size unit is sp and defaults to 14sp. |
|
setTextColor | int | Set the text color. The default setting is Color.Black (0xFF000000). |
|
setTypefaceStyle | Typeface, int | Set the text font and style. The default style setting is Typeface.NORMAL. |
Method | Returns | Parameters | Descriptions |
---|---|---|---|
addTextView | SecureString | Add text to be displayed in the SecureTextGroup. | |
addTextViews | SecureString[] | Add text to be displayed in the SecureTextGroup. | |
setTextSize | float | Set the text size. The size unit is sp and defaults to 14sp. |
|
setTextColor | int | Set the text color. The default setting is Color.Black (0xFF000000). |
|
setTypefaceStyle | Typeface, int | Set the text font and style. The default style setting is Typeface.NORMAL. |
|
setLetterSpacing | float | 텍스트의 문자 간격을 설정합니다. 기본 설정은 0em입니다. |