안녕하세요.
ZXing 라이브러리를 이용하여 QR 코드 리더기 앱을 만들어 보도록 하겠습니다.
개발 순서는 다음과 같습니다.
1. 라이브러리 추가 및 권한 설정
2. 화면 만들기(XML)
3. 코드 작성하기(QrCodeActivity.kt)
1. 라이브러리 추가 및 권한 설정
1-1) ZXing 라이브러리
github.com/journeyapps/zxing-android-embedded
Build, Gradle에 Zxing 라이브러리 추가하기
SDK 버전에 따라 라이브러리를 다르게 설정해줘야 합니다.
- SDK Version 24 미만 일 때 사용 가능
implementation('com.journeyapps:zxing-android-embedded:4.1.0') { transitive = false }
implementation 'androidx.appcompat:appcompat:1.0.2'
implementation 'com.google.zxing:core:3.3.0'
- SDK Version 24 이상 일 때 사용 가능
implementation 'com.journeyapps:zxing-android-embedded:4.1.0'
implementation 'androidx.appcompat:appcompat:1.0.2'
그리고 추가로 자바의 호환성 지정을 해줘야 합니다. 안 그러면 다음과 같은 에러가 발생하게 됩니다.
java.lang.NoSuchMethodError: No static method metafactory
(declaration of 'java.lang.invoke.LambdaMetafactory' appears in /apex/com.android.runtime/javalib/core-oj.jar
그래서 다음과 같이 app:gradle.build에 다음과 같이 작성해줍시다.
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
easypermissions 라이브러리 추가
안드로이드의 권한 정책으로 "위엄한 권한" 경우 반드시 사용자로 부터 권한을 사용하겠다는 것을 허락을 받아야 합니다. 이를 런타임 퍼미션이라고 불리며 이를 쉽게 구현할 수 있도록 돕는 라이브러리입니다.
github.com/googlesamples/easypermissions
dependencies {
implementation 'pub.devrel:easypermissions:3.0.0'
}
cardview 라이브러리 추가
이번 예제에서는 cardview를 이용했는데요. 이를 사용하실려면 아래 라이브러리를 추가해주셔야 합니다.
developer.android.com/jetpack/androidx/releases/cardview
dependencies {
implementation "androidx.cardview:cardview:1.0.0"
}
1-2) 매니패스트(manifext.xml)
qr코드를 사용하기 위해서 카메라 권한을 설정해줍시다.
<uses-permission android:name="android.permission.CAMERA" />
2. 화면 만들기(XML)
여기서 사용한 resource는 입맛대로 사용하시면 되나 혹시나 찾는데 번거로움이 있을까 사용한 이미지는 아래 첨부파일로 올려놓겠습니다.
<?xml version="1.0" encoding="utf-8"?>
<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"
android:background="@color/colorWhite"
tools:context=".QrCodeActivity">
<TextView
android:id="@+id/tvText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="50dp"
android:text=""
android:textColor="@color/colorBlack"
android:textSize="20sp"
android:textStyle="bold"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.cardview.widget.CardView
android:id="@+id/cardView1"
android:layout_width="300dp"
android:layout_height="wrap_content"
android:layout_marginTop="50dp"
android:visibility="gone"
app:cardBackgroundColor="@color/colorWhite"
app:cardCornerRadius="10dp"
app:cardElevation="10dp"
app:layout_constraintBottom_toTopOf="@+id/linearLayout"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/tvText">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:padding="10dp"
android:orientation="horizontal">
<EditText
android:id="@+id/edtCode"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:background="@color/colorWhite"
android:padding="10dp"
android:layout_weight="1"
android:hint="Enter Code here"
android:textColor="@color/colorBlack"
android:textColorHint="@color/colorBlack"
android:visibility="visible" />
<Button
android:id="@+id/btnEnter"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:layout_weight="0.5"
android:background="@color/colorPurple"
android:text="Enter"
android:textColor="@color/colorWhite" />
</LinearLayout>
</androidx.cardview.widget.CardView>
<androidx.cardview.widget.CardView
android:id="@+id/cardView2"
android:layout_width="300dp"
android:layout_height="300dp"
android:visibility="gone"
app:cardBackgroundColor="@color/colorWhite"
app:cardCornerRadius="10dp"
app:cardElevation="10dp"
app:layout_constraintBottom_toTopOf="@+id/linearLayout"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tvText">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="30dp"
android:src="@drawable/ic_qr_code" />
</androidx.cardview.widget.CardView>
<LinearLayout
android:id="@+id/linearLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="50dp"
android:orientation="horizontal"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent">
<Button
android:id="@+id/btnScan"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:layout_weight="1"
android:background="@color/colorPurple"
android:text="Scan Code"
android:textColor="@color/colorWhite" />
<Button
android:id="@+id/btnEnterCode"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:layout_weight="1"
android:background="@color/colorOrange"
android:text="Enter Code"
android:textColor="@color/colorWhite" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
3. 코드 작성하기(QrCodeActivity.kt)
3-1. 권한 설정하기
// 3-1. 권한 설정하기
class QrCodeActivity : AppCompatActivity(), EasyPermissions.PermissionCallbacks,
EasyPermissions.RationaleCallbacks {
// 3-2. View Inflate 및 클릭 이벤트 리스너 설정
// var cardView1: CardView? = null
// ...
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_qr_code)
// 3-3. ZXing 설정 및 받은 데이터 처리
// private fun cameraTask() {
// ...
//EasyPermissions 콜백메서드
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this)
}
override fun onPermissionsDenied(requestCode: Int, perms: MutableList<String>) {
if (EasyPermissions.somePermissionPermanentlyDenied(this, perms)) {
AppSettingsDialog.Builder(this).build().show()
}
}
override fun onPermissionsGranted(requestCode: Int, perms: MutableList<String>) {
}
override fun onRationaleDenied(requestCode: Int) {
}
override fun onRationaleAccepted(requestCode: Int) {
}
}
3-2. View Inflate 및 클릭 이벤트 리스너 설정
// 3-1. 권한 설정하기
class QrCodeActivity : AppCompatActivity(), EasyPermissions.PermissionCallbacks,
EasyPermissions.RationaleCallbacks {
// 3-2. View Inflate 및 클릭 이벤트 리스너 설정
var cardView1: CardView? = null
var cardView2: CardView? = null
var btnScan: Button? = null
var btnEnterCode: Button? = null
var btnEnter: Button? = null
var edtCode: EditText? = null
var tvText: TextView? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_qr_code)
// View Infalte 작업
cardView1 = findViewById(R.id.cardView1)
cardView2 = findViewById(R.id.cardView2)
btnScan = findViewById(R.id.btnScan)
btnEnterCode = findViewById(R.id.btnEnterCode)
btnEnter = findViewById(R.id.btnEnter)
edtCode = findViewById(R.id.edtCode)
tvText = findViewById(R.id.tvText)
tvText!!.setText("Scan QR Code")
cardView2!!.visibility = View.VISIBLE
btnScan!!.setOnClickListener {
cardView2!!.visibility = View.VISIBLE
cardView1!!.visibility = View.GONE
tvText!!.setText("Scan QR Code Here")
}
cardView2!!.setOnClickListener {
cameraTask()
}
btnEnter!!.setOnClickListener {
if (edtCode!!.text.toString().isNullOrEmpty()) {
Toast.makeText(this, "Please enter code", Toast.LENGTH_SHORT).show()
} else {
var value = edtCode!!.text.toString()
Toast.makeText(this, value, Toast.LENGTH_SHORT).show()
}
}
btnEnterCode!!.setOnClickListener {
cardView2!!.visibility = View.GONE
cardView1!!.visibility = View.VISIBLE
tvText!!.setText("Enter QR Code")
}
}
// 3-3. ZXing 설정 및 받은 데이터 처리
// private fun cameraTask() {
// ...
//EasyPermissions 콜백메서드
// override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
// ...
}
3-3. ZXing 설정 및 받은 데이터 처리
// 3-1. 권한 설정하기
class QrCodeActivity : AppCompatActivity(), EasyPermissions.PermissionCallbacks,
EasyPermissions.RationaleCallbacks {
// 3-2. View Inflate 및 클릭 이벤트 리스너 설정
// var cardView1: CardView? = null
// ...
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_qr_code)
// 3-3. ZXing 설정 및 받은 데이터 처리
private fun cameraTask() {
if (hasCameraAccess()) {
var qrScanner = IntentIntegrator(this)
qrScanner.setPrompt("QR코드를 인증해주세요.") // 원하는 문구 기입
qrScanner.setCameraId(0)
qrScanner.setOrientationLocked(false) // 세로,가로 모드를 고정 시켜주는 역할
qrScanner.setBeepEnabled(true) // QR코드 스캔시 소리 나게 하려면 true 아니면 false로 지정
qrScanner.captureActivity = CaptureActivity::class.java
qrScanner.initiateScan() //QR코드 스캔의 결과 값은 onActivityResult 함수로 전달
} else {
EasyPermissions.requestPermissions(
this,
"QR 코드 기능을 사용하기 위해서는 카메라 권한 설정을 허용해 주셔야 합니다.",
123,
android.Manifest.permission.CAMERA
)
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
var result = IntentIntegrator.parseActivityResult(requestCode, resultCode, data)
if (result != null) {
if (result.contents == null) {
Toast.makeText(this, "결과를 찾을 수 없습니다", Toast.LENGTH_SHORT).show()
edtCode!!.setText("")
} else {
try {
// cardView1!!.startAnimation(reveal)
// cardView2!!.startAnimation(hide)
cardView1!!.visibility = View.VISIBLE
cardView2!!.visibility = View.GONE
edtCode!!.setText(result.contents.toString())
} catch (exception: JSONException) {
Toast.makeText(this, exception.localizedMessage, Toast.LENGTH_SHORT).show()
edtCode!!.setText("")
}
}
} else {
super.onActivityResult(requestCode, resultCode, data)
}
if (requestCode == AppSettingsDialog.DEFAULT_SETTINGS_REQ_CODE) {
Toast.makeText(this, "Permission Granted", Toast.LENGTH_SHORT).show()
}
}
//EasyPermissions 콜백메서드
// override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
// ...
}
저는 ZXing 설정 부분과 카메라로 인식 값을 받아오는 부분을 스틱코드로 올려놔서 필요할 때마다 쉽게 가져다 사용하고 있습니다. 필요하신 분들은 아래 링크를 참고해주세요.
stickode.com/detail.html?no=2188
결과 화면입니다.
'안드로이드 코틀린' 카테고리의 다른 글
[Kotlin][Android] 구글맵 빠르게 적용하기 (1) | 2021.07.12 |
---|---|
[Kotlin][Android] 검색어 자동완성 기능 만들기 (0) | 2021.07.02 |
[Kotlin][Android] 이미지 확대, 축소 기능 만들기 (0) | 2021.06.29 |
[Kotlin][Android] 앱 위젯 만들기 (3) | 2021.06.28 |
[Kotlin][Android] OCR 기능을 만들어보자 (3) | 2021.06.24 |