QR코드의 정체를 알려주마!

얼 마 전 모 방송사의 예능 프로그램에서 출연자들에게 미션을 전달하는 방법으로 특이하게 생긴 코드를 사용하는 장면이 나왔다. 출연자가 이 코드를 스마트폰으로 찍으니 미션이 폰 화면에 표시됐다. 편의점이나 마트에서 흔히 볼 수 있는 길쭉한 막대기 모양의 바코드가 아니라 다양한 정사각형 무늬로 이뤄진 코드. 대체 이 코드의 정체는 무엇일까?

이 프로그램에서 사용한 코드는 ‘QR(Quick Response)코드’라고 하는 2차원 바코드다. 1994년 일본 덴소사(社)의 개발 부서(현재는 덴소 웨이브사(社))가 개발한 이 코드에는 다양한 정보를 저장할 수 있다. 우리가 많이 사용하는 일반 바코드는 세로 방향으로만 정보를 저장할 수 있지만, QR코드는 가로와 세로 두 방향으로 정보를 저장할 수 있기 때문이다. 1950년대에 개발된 바코드는 새로운 2차원 바코드인 QR코드의 등장으로 그 생명력을 연장할 수 있게 됐다.

QR코드에 저장할 수 있는 숫자는 최대 7089자, 문자(ASCII)는 최대 4296자, 한자 같은 아시아 문자는 최대 1817자까지 담을 수 있다. 작은 정사각형의 점이 많을수록 더 많은 정보를 기록할 수 있으나, 점이 많아지면 필요한 면적이 넓어진다. 또 인식속도와 인식률, 복원력에서도 일반 바코드보다 뛰어나다. 이름처럼 ‘빠른 응답’이 가능한 셈이다.

덴소 웨이브가 QR코드에 대한 특허권을 행사하지 않겠다고 선언해 이 코드는 다양한 분야에서 널리 활용되고 있다. 또 PDF417, 데이터매트릭스(DataMatrix), 맥시코드(MaxiCode)처럼 국제 표준으로 채택돼 있어 누구나 사양을 확인하고 사용할 수 있다.

QR코드를 다양한 사업 영역에서 활발하게 사용하는 곳은 일본이다. 일본은 자국에서 판매되는 대부분의 휴대폰에 QR코드 리더기를 탑재하고 있고, 이 기능이 있는 휴대폰 소지자의 80% 이상이 QR코드를 사용한 경험이 있는 것으로 알려져 있다. 몇 가지 활용 사례를 살펴보면 다음과 같다.

노스웨스트사(社)는 QR코드를 기업 홍보에 이용했다. 도쿄 긴자의 건물에 대형 QR코드를 걸고 사람들이 이를 휴대폰으로 읽으면 각종 쿠폰이나 게임, 상품 상세 정보를 얻을 수 있는 웹사이트로 연결되게 만든 것이다. 은행이나 신용카드 회사는 QR코드를 사용한 결제서비스를 제공하고 있다. 특히 청구서에 인쇄된 QR코드를 읽으면 자동으로 결제를 수행하는 서비스가 인기다.

일본의 유통업체인 자스코(JASCO)는 우수한 일본 내 농가와 계약을 맺어 ‘톱 밸류(TOP Value)’라는 브랜드를 붙인 상품을 출시했다. 이 상품에는 생산부터 유통에 이르는 전 과정의 정보를 담고 있는 QR코드가 부착돼 있다. 또 비석판매 회사는 비석에 QR코드를 부착해 고인의 사진이나 생전의 기록을 볼 수 있는 모델을 출시하기도 했다.

이 밖에 보관소에 맡겨진 길 잃은 애완동물의 주인을 찾는 서비스도 진행되고 있다. 애완동물 주인의 주소와 연락처를 담은 QR코드를 목걸이로 만들어 애완동물에 달아 두면, 정보를 빠르게 확인할 수 있어 쉽게 주인을 찾을 수 있다.

QR 코드가 이렇게 다양한 분야에서 활용되고 있지만 장점만 있는 것은 아니다. 가장 일반적으로 겪을 수 있는 문제가 호환성이다. 단순한 홈페이지 URL 주소를 담고 있는 QR코드라면 별 문제가 없다. 그러나 QR코드가 많이 사용되는 분야인 명함의 경우, 현재 코드 생성기와 리더기 사이에 호환성 문제가 있다. 특정 생성기로 만든 QR코드 명함은 특정 리더기에서만 정상적으로 인식되는 것이다.



옆의 QR코드는 스캐니(scany)라는 QR코드 애플리케이션 홈페이지에서 만든 것인데, 이것을 scany에서 다운받은 애플리케이션으로 읽으면 잘 정리된 명함이 나오지만 다른 리더기에서는 정상적인 명함으로 인식되지 않는다.

현재 QR코드 명함으로 많이 사용되는 포맷은 ‘meCard’와 ‘vCard’인데, 리더기 애플리케이션끼리 호환이 잘 되지 않는 것으로 생각된다. QR코드가 더 널리 사용되기 위해서 반드시 해결돼야 할 문제다.

또 다른 문제는 보안이다. QR코드는 이전의 바코드에 비해 많은 정보를 담을 수 있는데, 이 점을 악용해 QR코드에 악성코드나 유해 웹사이트 주소를 담을 수도 있다. 이러한 유해 정보가 담긴 QR코드를 별다른 의심 없이 리더기로 읽는다면 악성코드에 노출되거나 유해 사이트로 이동할 수 있다. 이 때문에 검증된 곳이나 기업에서 제공하는 QR코드가 아닌 경우 주의가 필요하다.

하지만 이러한 단점에도 불구하고 QR코드는 현재 다양한 분야에서 활용되고 있다. 스마트폰의 보급이 늘어날수록 그 사용범위는 더 넓어질 것으로 예상된다.

QR 코드가 얼마나 오랫동안 사용될지는 미지수다. 하지만 RFID(Radio-Frequency Identification)와 같이 바코드를 대체할 수 있는 기술은 시간이 조금 더 필요하다. 비용이나 기술적인 문제 때문에 바코드를 완전히 대체하기 어려워서다.

또한 기업 서비스에 주로 사용되고 있는 RFID와 달리, QR코드는 ‘누구나 간단하게 만들 수 있고 프린트해 사용할 수 있다’는 장점을 갖고 있다. 이러한 생활밀착형 서비스를 제공할 수 있다는 장점 때문에 QR코드의 생명력은 계속 유지되지 않을까 한다.

글 : 김성현 동아사이언스 기술지원팀장

출처 : http://click.ndsl.kr/servlet/LinkingDetailView?cn=4569&dbt=SCENT&service_code=03&user_id=

[Android] No configs match configSpec

ndk 샘플 소스의 opengl을 에뮬레이터에서 실행하면 다음과 같이 에러가 나오는데 에뮬레이터에서 지원이 되지
않기 떄문에 발생하는 에러이다. 이런경우 실제 폰 이나 테스트 보드에서 실행하면 정상 동작한다.
1. 에러 내용
    08-20 15:33:25.097: ERROR/AndroidRuntime(378):
                           java.lang.IllegalArgumentException: No configs match configSpec

[Android] TextView 내용중간에 이벤트 넣기!!!

TextView는 하나이고, 여기에 들어가는 문자열도 하나.
그런데 중간에 링크경로가 들어있다.
다른 문자열은 그대로 두고, 링크경로에만 이벤트를 주고 싶은거지.
어떻게 해야 하는걸까?

내가 테스트한 환경은 총 3개의 클래스이다.
메인클래스/서비클래스/ClickableSpan을 상속한 새로운 클래스.

<메인 클래스>

import android.app.Activity;
import android.os.Bundle;
import android.text.Spannable;
import android.text.method.LinkMovementMethod;
import android.widget.TextView;
import android.widget.TextView.BufferType;

public class MainActivity extends Activity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
       
        String str = "Some text http://twitpic.com/3701kz Mac is very good.";
        TextView mainTextView = (TextView) findViewById(R.id.mainTextView);

        mainTextView.setMovementMethod(LinkMovementMethod.getInstance());
        mainTextView.setText(str, BufferType.SPANNABLE);

        Spannable spans = (Spannable) mainTextView.getText();
       
        //string parsing...
  int startIndex = str.indexOf("http://twitpic.com/");
  String resultSubString = str.substring(startIndex);
  int endIndex = resultSubString.indexOf(" ");        
       
  //clickable processing...
        MyClickable clickable = new MyClickable(MainActivity.this);
 spans.setSpan(clickable, startIndex, (endIndex + startIndex), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
     }
}

<ClickableSpan을 상속한 새로운 클래스>

import android.app.Activity;
import android.content.Intent;
import android.text.TextPaint;
import android.text.style.ClickableSpan;
import android.view.View;

class MyClickable extends ClickableSpan {
 private Activity activity;
 
 public MyClickable(Activity activity) {
  super();
  this.activity = activity;
 }

 public void updateDrawState(TextPaint ds) {
  super.updateDrawState(ds);
  ds.setUnderlineText(false);
 }

 @Override
 public void onClick(View widget) {
  Intent intent = new Intent(this.activity, SubActivity.class);
  this.activity.startActivity(intent);
 }
}
<서브클래스>

알아서 구현하자 -_-;

<결과이미지>

002

[Android] Installation error: INSTALL_FAILED_INSUFFICIENT_STORAGE

회사 동료가 아래와 같은 메시지를 받고 난감해하고 있었다.
Installation error: INSTALL_FAILED_INSUFFICIENT_STORAGE
Please check logcat output for more details.
Launch canceled!

에뮬레이터의 용량이 부족하다는 메시지인 것 같음;;;
대충 검색질을 해보았더니, 두 가지 해결방법이 있는 것 같다.

1. log 데이터를 삭제(http://devbible.tistory.com/22 참조)
/>adb shell

# cd data
cd data
# cd log
cd log
# rm *
rm *


2. 에뮬레이터의 용량 크게 설정(http://kheru.tistory.com/53 참조)
- 콘솔을 사용하여 설정하기
    emulator -partition-size 256 @AVD명

- 이클립스의 Run 실행에서 설정하기
    Run > Run configuration > 해당 프로젝트 > Target >
    Additional Emulator Command Line Options 에 아래 코드를 입력;
    -partition-size 256

먼저 첫번째 방법을 써보았는데 SDK 2.1에서는 해당 폴더가 보이지 않았다.
로그가 저장이 안된건지..원..
어쨋든..그래서 두번째 방법을 사용해서 성공!!
SDCard의 용량을 설정하지 않아도 저런 문제가 발생할 수 있다고 함으로 확인해본 뒤에
안되면 위의 두 방법을 사용해 보자.

참고 : http://futureworker.tistory.com/9


3. 간단한 요약정리...

- 이클립스 툴바에서 벌래 아이콘 드롭다운 메뉴 클릭

- Debug Configurations 선택

- Target tab 선택

 

하단의 Additional Emulator Command Line Options에 아래와 같이 넣어줍니다

-partition-size 1024 -memory 128

 그래도 부족하면 -memory 256 등으로 대체한다.

 

[Android] EditText 정규식으로 한글제한 체크하기

public class MainActivity extends Activity {
 String myText = null;
 
 EditText myIDEditText = null;
 Button okButton = null;
 
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
       
        myIDEditText = (EditText) findViewById(R.id.myID);
       
        okButton = (Button) findViewById(R.id.ok);
        okButton.setOnClickListener(new OnClickListener(){

   @Override
   public void onClick(View v) {
          myText = myIDEditText.getText().toString();       
         
          if(checkFormValid(myText)){
           Log.d(myText + " >>> ", "find!!");
          }else{
           Log.d(myText + " >>> ", "not find~~~~~~~~~~~~~");
          }
   }

        });
    }

    private boolean checkFormValid(String str) { 
     boolean result = Pattern.matches("^[a-zA-Z0-9]*$", str); //영어, 숫자
     
     if(str.length() > 0 && result ) {
      return true;
     } 
     return false;
    }
}

정규식 참고 : http://blog.daum.net/question0921/419