Zxing 라이브러리로 QR 코드 스캐너 날로 만들기 + 커스텀
728x90
반응형

갑자기 QR 코드 스캐너를 만들어야 했다.

순간 막막했다.

카메라 모듈도 잘 못다루는데.

그래서 자료를 찾아보니깐 묘한 단어가 눈에 띈다.


Zxing. Zebra Crossing

Barcode scanning library for Java, Android




"이런건(QR 코드 스캐너) 날로 먹어도 된다고 허락받은 느낌이다."



튜토리얼에 해당하는게 정말 많다.

그래서 쉽게 찾을 수 있는 것들은 아주 심플하게 작성하고 넘어가겠다.



1. build.gradle (app)


1
2
3
// Zxing android embedded. From version 3.6.0, only Android SDK 19+ is supported by default.
implementation 'com.journeyapps:zxing-android-embedded:3.6.0'
// implementation 'com.google.zxing:core:3.3.0' // if Android 14+ support
cs




2. AndroidManifest.xml

hardwareAccelerated 부분 추가


1
2
3
4
<application
    android:allowBackup="true"
    android:hardwareAccelerated="true"
    android:icon="@mipmap/ic_launcher"
cs




3. WebViewActivity

본 Activity에서 카메라 버튼을 누르면 Scanner Activity로 넘어간다.

카메라 버튼을 누르면 다음과 같은 method가 작동되도록 하였다.


1
2
3
4
5
6
7
8
9
10
private void onQrcodeScanner() {
    LogcatLogger.d(TAG, "* * * * Camera");
    Toast.makeText(this"Camera", Toast.LENGTH_SHORT).show();
 
    IntentIntegrator integrator = new IntentIntegrator(this);
    integrator.setBeepEnabled(false);
    integrator.setCaptureActivity(CustomScannerActivity.class);
    integrator.initiateScan();
}
 
cs


CustomScannerActivity이 바로 Scanner activity 이다.

CustomScannerActivity에서 정상적으로 Scan이 완료되면 다시 본 activity로 돌아온다.

이 때, onActivityResult로 결과를 받는다.


1
2
3
4
5
6
7
8
9
10
11
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if(resultCode == Activity.RESULT_OK) {
        IntentResult scanResult = IntentIntegrator.parseActivityResult(requestCode, resultCode, data);
        String re = scanResult.getContents();
        LogcatLogger.d(TAG, "* * * * onActivityResult: ." + re);
        Toast.makeText(this"Zxing Custom operating :::: " + re, Toast.LENGTH_LONG).show();
    } else {
        super.onActivityResult(requestCode, resultCode, data);
    }
}
cs


4. CustomScannerActivity

이 부분부터는 dolsanta님 github를 거의 copy하다싶이 하였다.

(이 자리를 빌어서 감사드립니다.)


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
public class CustomScannerActivity extends BaseActivity implements DecoratedBarcodeView.TorchListener {
 
    protected final String TAG = "CustomScannerActivity";
 
    private CaptureManager capture;
    private DecoratedBarcodeView barcodeScannerView;
    private ImageButton btnSetting,btnSwitchFlash;
    private Boolean switchFlashlightButtonCheck;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_custom_scanner);
 
        switchFlashlightButtonCheck = true;
 
        btnSetting = findViewById(R.id.btn_setting);
        btnSwitchFlash = findViewById(R.id.btn_switch_flash);
        barcodeScannerView = findViewById(R.id.zxing_barcode_scanner);
 
 
        if (!hasFlash()) {
            btnSwitchFlash.setVisibility(View.GONE);
        }
 
        barcodeScannerView.setTorchListener(this);
        capture = new CaptureManager(this, barcodeScannerView);
        capture.initializeFromIntent(getIntent(), savedInstanceState);
        capture.decode();
 
        btnSwitchFlash.setOnClickListener(v -> {
            if (switchFlashlightButtonCheck) {
                barcodeScannerView.setTorchOn();
            } else {
                barcodeScannerView.setTorchOff();
            }
        });
    }
 
    @Override
    protected String createTag() {
        return TAG;
    }
 
    @Override
    protected void onResume() {
        super.onResume();
        capture.onResume();
    }
 
    @Override
    protected void onPause() {
        super.onPause();
        capture.onPause();
    }
 
    @Override
    protected void onDestroy() {
        super.onDestroy();
        capture.onDestroy();
    }
 
 
    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        capture.onSaveInstanceState(outState);
    }
 
    private boolean hasFlash() {
        return getApplicationContext().getPackageManager()
                .hasSystemFeature(PackageManager.FEATURE_CAMERA_FLASH);
    }
 
    /**
     * TorchListener
     */
    @Override
    public void onTorchOn() {
        btnSwitchFlash.setImageResource(R.drawable.ic_menu_flash);
        switchFlashlightButtonCheck = false;
    }
 
    @Override
    public void onTorchOff() {
        btnSwitchFlash.setImageResource(R.drawable.ic_menu_flash);
        switchFlashlightButtonCheck = true;
    }
}
 
cs


다음은 zxing에서 지원되는 기능이다.
  • TorchListener : flash를 관리한다. override된 곳에서 turn on/off별 상태를 제어할 수 있다.
  • CaptureManager : BarcodeView를 제어한다. 여기서는 DecoratedBarcodeView를 제어한다.
  • DecoratedBarcodeView : Custom된 스캐너 레이아웃을 넣기 위한 뷰


5. activity_custom_scanner.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    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"
    tools:context=".webview.CustomScannerActivity">
 
    <com.journeyapps.barcodescanner.DecoratedBarcodeView
        android:id="@+id/zxing_barcode_scanner"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:zxing_scanner_layout="@layout/custom_barcode_scanner">
    </com.journeyapps.barcodescanner.DecoratedBarcodeView>
 
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:background="#578e5d">
    </LinearLayout>
 
    <ImageButton
        android:padding="7dp"
        android:background="@null"
        android:src="@drawable/ic_menu_manage"
        android:id="@+id/setting_btn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true" />
 
    <ImageButton
        android:onClick="switchFlashlight"
        android:padding="7dp"
        android:background="@null"
        android:src="@drawable/ic_menu_flash"
        android:id="@+id/switch_flashlight"
        android:scaleType="fitXY"
        android:layout_width="@dimen/dp_42"
        android:layout_height="@dimen/dp_42"
        android:layout_alignParentTop="true"
        android:layout_alignParentRight="true"
        android:layout_alignParentEnd="true" />
 
    <LinearLayout
        android:gravity="center_horizontal"
        android:layout_width="match_parent"
        android:layout_height="250dp"
        android:background="#578e5d"
        android:layout_alignParentBottom="true"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true">
 
        <TextView
            android:id="@+id/zxing_status_view"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@color/zxing_transparent"
            android:text="@string/zxing_msg_default_status"
            android:textColor="@color/zxing_status_text" />
    </LinearLayout>
</RelativeLayout>
cs


6. custom_barcode_scanner.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <com.journeyapps.barcodescanner.BarcodeView
        android:layout_marginBottom="200dp"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/zxing_barcode_surface"
        app:zxing_framing_rect_width="250dp"
        app:zxing_framing_rect_height="100dp"/>
 
    <com.journeyapps.barcodescanner.ViewfinderView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/zxing_viewfinder_view"
        app:zxing_possible_result_points="@color/zxing_custom_possible_result_points"
        app:zxing_result_view="@color/zxing_custom_result_view"
        app:zxing_viewfinder_laser="@color/zxing_custom_viewfinder_laser"
        app:zxing_viewfinder_mask="@color/zxing_custom_viewfinder_mask"/>
 
</merge>
cs



  • BarcodeView : 스캐너 화면, zxing_framing_rect_width/height로 바코드 애니메이션 효과존을 설정 할 수 있다.
  • ViewfinderView : 카메라의 뷰파인더와 같은 역할. 일반적으로 BarcodeView보다 큰 사이즈를 가진다.





728x90
반응형