2018년 6월 4일 월요일

Analysis of QR Code Reader(zxing) source in Android(QR Code 소스 분서)


서론

zxing는 대표적으로 유명한 QR Code decoder입니다.
https://github.com/zxing/zxing
해당 코드를 보던중 폴더구조가 복잡한것 같아서 정리해 보았습니다.

전체 소스
https://github.com/zxing/zxing/wiki/Getting-Started-Developing


예제

Android 빌드를 위해서는 gradle에 단순히 라이브러리를 추가하기만 하면 쉽게 사용이 가능합니다.
아래 간단 예제 링크를 참고하세요.
https://github.com/seongchan/Sample_QRCodeReader

아래와 같은 오류 발생시 permission 을 추가하여야 합니다. (아래 줄친 runtime permission 획득 부분 코드)

1. 오류 내용

Cannot open camera "0" without camera permission'

2. 추가 코드

@Overrideprotected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    mReadBtn = (Button)findViewById(R.id.capture);
    mResult = (TextView)findViewById(R.id.result);

    mReadBtn.setOnClickListener(this);

    if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
            != PackageManager.PERMISSION_GRANTED) {
        ActivityCompat.requestPermissions(this,
                new String[]{Manifest.permission.CAMERA}, 0);
    }
}

AndroidManifest.xml 카메라 권한 추가

<uses-permission android:name="android.permission.CAMERA"/>


폴더 구조

소스 폴더의 구조는 아래와 같이 간단하게 설명은 되어 있으나, android 로 된 3개 부분이 뭘 의미하는지 왜 나누어 놨는지 궁금 하였습니다.
(core 말그대로 핵심이 되는 라이브러리가 들어있을겁니다., javase는 javaSE를 위한 것이라 봤을때 안드로이드에서는 몰라 됩니다. ^^;)

Active

ModuleDescription
coreThe core image decoding library, and test code
javaseJavaSE-specific client code
androidAndroid client Barcode Scanner 
android-integrationSupports integration with Barcode Scanner via Intent
android-coreAndroid-related code shared among android, other Android apps
zxingorgThe source behind zxing.org
zxing.appspot.comThe source behind web-based barcode generator at zxing.appspot.com

android 

이것은 마켓에 올려져 있는 Barcode scanner 앱입니다. 해당앱의 소스 코드라고 보시면 됩니다. 소스가 많고 상당히 복잡한 구조로 되어 있습니다. 또한 안드로이드를 구성하는 main 소스라고 보면됩니다.

android-integration

이 부분이 일반 앱에서 호출 되는 코드가 있습니다.

android-core

이 부분은 정확하게 뭔지 모르겠습니다. 아직 제대로 분석전입니다.



샘플 코드 분석


@Overridepublic void onClick(View view) {
    mResult.setText("");
    IntentIntegrator integrator = new IntentIntegrator(this);
    integrator.setDesiredBarcodeFormats(IntentIntegrator.QR_CODE_TYPES);

    // QR Code Capture Activity Orientation Set : degree unit    integrator.setOrientation(90);

    // Scan View finder size : pixel unit    integrator.addExtra(Intents.Scan.HEIGHT, 300);
    integrator.addExtra(Intents.Scan.WIDTH, 300);

    // Capture View Start    integrator.initiateScan();
}

import com.google.zxing.integration.android.IntentIntegrator; 를 하게 되는데 IntentIntegrator class를 사용하게 됩니다.

코드는 https://github.com/zxing/zxing/blob/master/android-integration/src/main/java/com/google/zxing/integration/android/IntentIntegrator.java 링크에 소스가 있으며 아래 간단하게 내용을 보면, new Intent(BS_PACKAGE + ".SCAN");
BS_PACKAGE 인텐트를 보내게 됩니다.

private static final String BS_PACKAGE = "com.google.zxing.client.android";

  public final AlertDialog initiateScan(Collection<String> desiredBarcodeFormats, int cameraId) {
    Intent intentScan = new Intent(BS_PACKAGE + ".SCAN");
    intentScan.addCategory(Intent.CATEGORY_DEFAULT);

    // check which types of codes to scan for
    if (desiredBarcodeFormats != null) {
      // set the desired barcode types
      StringBuilder joinedByComma = new StringBuilder();
      for (String format : desiredBarcodeFormats) {
        if (joinedByComma.length() > 0) {
          joinedByComma.append(',');
        }
        joinedByComma.append(format);
      }
      intentScan.putExtra("SCAN_FORMATS", joinedByComma.toString());
    }

    // check requested camera ID
    if (cameraId >= 0) {
      intentScan.putExtra("SCAN_CAMERA_ID", cameraId);
    }

    String targetAppPackage = findTargetAppPackage(intentScan);
    if (targetAppPackage == null) {
      return showDownloadDialog();
    }
    intentScan.setPackage(targetAppPackage);
    intentScan.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
    intentScan.addFlags(FLAG_NEW_DOC);
    attachMoreExtras(intentScan);
    startActivityForResult(intentScan, REQUEST_CODE);
    return null;
  }

이것만 놓고보면 om.google.zxing.client.android.SCAN 인텐트를 받는 부분이 필요한데 해당 소스는 android 폴더에 있습니다.
https://github.com/zxing/zxing/tree/master/android

android 폴더를 보면 intent filter로 SCAN을 받을 수 있게 되어 있습니다.

CaptureActivity
androidmanifest.xml
      <intent-filter>
        <action android:name="com.google.zxing.client.android.SCAN"/>
        <category android:name="android.intent.category.DEFAULT"/>
      </intent-filter>

아래 소스를 분석 해야 합니다.
https://github.com/zxing/zxing/blob/master/android/src/com/google/zxing/client/android/CaptureActivity.java

댓글 없음:

댓글 쓰기