안드로이드 앱 자동화 (상점 스크랩, 도어락 자동화) – 3-2편

Table of Contents

안드로이드 앱 자동화 (상점 스크랩, 도어락 자동화) – 3-2편

※ 이번 편은 모듈 개발의 실패한 케이스로 외전 격으로 봐주시면 되겠네요. ㅋㅋ

[ 3편보기 ]

1. 저번편 에서..

안드로이드 에뮬레이터 게스트머신의 마우스 움직임을 제어 했었고. 업무 개발 이전에 키보드제어 도 다루어야 할 거 같아서 끼움 편을 만들어 보았다.

키보드나 마우스나.. 처음에는 같은부류라 생각했다. 똑같이 evdev (event-device) 이고 통신구조도 거의 대동소이 한 터라 비슷하게 넘어가려 했는데...

2. 그래 세상일이 어디 그렇게 쉽게 되던?

일단 간단하게 키보드 입력 테스트케이스를 만들어 시험해 보았다.

@Test void testKeyboard() throws Exception {
  if (!TestUtil.isEnabled("testKeyboard", TestLevel.MANUAL)) { return; }
  Commander cmd = null;
  try {
    /** qmp / adb 를 연결한다. */
    cmd = new Commander("172.17.0.1", 4444, "172.17.0.1", 5555);
    cmd.sleep(1000);
    /** a 부터 d 까지 순차적으로 입력 */
    for (char c = 'a'; c <= 'd'; c++) {
      cmd.sendKeys(String.valueOf(c), "ret");
      cmd.sleep(500);
    }
    /** a ~ d 까지 한꺼번에 입력 */
    cmd.sendKeys("a", "b", "c", "d", "ret");
  } finally {
    safeclose(cmd);
  }
}

훗. 뭐야 잘 되잖아! ㅋ. 괜히걱정했.....

하는 순간 무언가 뇌리를 스쳐갔다.

그런데 한글은?....되.던....가?.......

(한글입력기로 전환하고 한글 입력 위치에 맞는 영문 키보드 입력 데이터를 전송해야.... 하나?)

(사실 한글은 컴퓨터에서 우리가 너무 자연스레 썼지만. raw-device 입장에서는 전혀 자연스럽지 못하다....)

3. ..그래서 시작된 삽질

일단 별도 프로젝트인 ntiple-utilsHangul.java 파일을 만들고

한글을 두,세벌식 키보드로 스크로트 할 수 있는 테이블을 만들었다.

(원래는 다른 목적으로 만든 프로그램 이었다.)

/** 키보드 한글 스트로크 테스트 */
@Test public void testHangulInput() throws Exception {
  String test = "한글테스트중입니다";
  String kbst = "";
  kbst = new String(Hangul.extractkbst(test, Hangul.TB_2BUL));
  log.info("두벌식스트로크 {} -> {}", test, kbst);

  kbst = new String(Hangul.extractkbst(test, Hangul.TB_3BULF));
  log.info("세벌식(최종)스트로크 {} -> {}", test, kbst);
}

/** 키보드 한글 스트로크 안드로이드 입력 테스트 */
@Test void testHangulKeyboard() throws Exception {
  if (!TestUtil.isEnabled("testHangulKeyboard", TestLevel.MANUAL)) { return; }
  Commander cmd = null;
  try {
    /** qmp / adb 를 연결한다. */
    cmd = new Commander("172.17.0.1", 4444, "172.17.0.1", 5555);
    cmd.sleep(1000);
    String test = "한글테스트중입니다";
    String kbst = new String(Hangul.extractkbst(test, Hangul.TB_2BUL));
    for (int inx = 0; inx < kbst.length(); inx++) {
      cmd.sendKeys(kbst.substring(inx, inx + 1));
      cmd.sleep(500);
    }
  } finally {
    safeclose(cmd);
  }
}

실행결과 (testHangulInput)

두벌식스트로크 한글테스트중입니다 -> gksrmfxptmxmwnddlqslek
세벌식(최종)스트로크 한글테스트중입니다 -> mfskgw'cng'glbajd3hduf

이제 PC 에서 한글 로 맞춰놓고 영문키보드 위치의 gksrmfxptmxmwnddlqslek 를 타이핑 해 보면
한글테스트중입니다 라고 출력될 거다. 안드로이드에서 테스트해 보면.. (testHangulKeyboard)

로 정상적으로 실행된다... 하지만....

4. 아! 또!! 왜~!!

"문제는 반드시 혼자 오지 않는다!"... 분량상 결과만 말하자면..

  1. 안드로이드 입력기의 현재 상태파악이 어렵다. (현재 입력기가 한글상태 인지 아닌지 파악 불가)

  2. 한글 + 영숫자, 특수기호등이 혼용되는 경우 타입별로 분리해서 입력해 주어야 한다.

  3. 타이밍 문제등(입력기 변환시) 오타가 발생하는경우 대처가 어렵다.

등의 문제로 요약해 볼 수 있겠다..

삽질한게 아깝지만 일단은 다른 방법을 찾아야 겠다.

다행히 stack overflow 를 뒤지다 보니 나와 비슷한걸 하려는 사람이 있었나보다

https://stackoverflow.com/questions/14224549/adb-shell-input-unicode-character

첫번째 답변으로 제시된 ADBKeyboard 를 사용해 보기로 했다.

우선은 AdbKeyboard 를 설치하고 (AdbKeyboard 다운로드)

$ adb -s 127.0.0.1:5555 install ADBKeybaord.apk
Performing Streamed Install
Success

게스트머신에서 입력키보드를 설정해 주어야 한다

시스템 -> 언어 및  입력 -> 가상키보드 -> 키보드관리 -> ADBKeyboard 활성화

그리고 제어기를 구현한다.

/** 키보드입력 문자열 전송(한글 등 유니코드) */
public String inputUniStr(String str) throws Exception {
  String term = "";
  String ret = "";
  for (; str.length() > 0;) {
    log.trace("FSTR:{} / {}", str, term);
    term = new String(str);
    /** 
     * 프로그램문제인지 간혹 긴문장 전송시 잘린다. 
     * 해서 안정화 문제로 5글자씩 분할하여 전송한다
     **/
    if (term.length() > 5) {
      term = str.substring(0, 5);
      str = str.substring(5);
    } else {
      str = "";
    }
    // log.debug("INPUT-UNI:{}", term);
    String cmdstr = joinStr(AM, BROADCAST, _A, ADB_INPUT_TEXT, __ES, MSG, dquot(term));
    String[] cmdarr = arr(adb, _S, cat(server, ":", port), SHELL, SH, _C, quot(cmdstr));
    ret = execRawCmd(rtm, cmdarr, buf);
    log.trace("CMD:{}{} / {}", "", cmdarr, ret);
    msleep(100);
  }
  return ret;
}

테스트 케이스 도 구현하고

@Test void testAdbKeyboard() throws Exception {
  if (!TestUtil.isEnabled("testAdbKeyboard", TestLevel.MANUAL)) { return; }
  Commander cmd = null;
  try {
    /** qmp / adb 를 연결한다. */
    cmd = new Commander("172.17.0.1", 4444, "172.17.0.1", 5555);
    /** Adb 입력기로 전환 */
    cmd.chImeAdb();
    cmd.sleep(300);
    cmd.inputUniStr("한글과 English 를 같이 테스트 중입니다.");
    cmd.sendKeys("ret");
  } finally {
    safeclose(cmd);
  }
}

실행결과

(너무나도 허무하게...) 아무런 부작용 없이 깔끔하게 잘 된다

5. 결론! (라떼는 말이야...)

어렸을때 대학 강의시간에 교수님께 들었던. 20년도 넘게 지나 아직까지 기억나는 인상적인 말씀이 있었다.

"앞으로는 know-how 보다 know-where 가 중요한 시기가 올것이다."

그 때 당시에는 C언어 알고리즘 같은 know-how에 열중해 공부하느라 가볍게 들었는데.

실제 IT 프로젝트들에 뛰어들어보니, 내가 구상하고 작성한 것 보다 월등히 뛰어난 코드들이 넘쳐나고 있었다.

그때 당시 그 교수님은 이미 집단지성의 의미를 파악하고 학생들한테 전파했던 듯..

뭐.. 여튼 무언가 바닥부터 만들어야 할 때에는 코딩에 앞서 비슷한게 먼저 구현된 것이 있는지 구글에 검색부터 해 보도록 하자!

이제 다음편은 진짜 진짜!! Work 를 만들어 볼거다!

[ 4편에서 계속 ]

[ Hangul.java 소스 ]

[ Commands.java 소스 ]

[ 관련 소스 저장소 ]

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다