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

Table of Contents

auto# 안드로이드 앱 자동화 (상점 스크랩, 도어락 자동화) – 4편

[ 3편보기 ] [ 3-2편보기 ]

1. 기본적인것은 거의 다 갖추었고.

기본적인 단위행동을 수행하는 Commander 클래스 구현을 했으니

이제 본격적으로 Work 를 작성할 때다.

그 전에 시스템 전체 구성을 살펴 보자면 아마 대략 다음과 같을 것이다.

  • ※ 클래스 분류표

    클래스명 역할 비고
    Commander 디바이스제어 명령 모음
    SystemSettings 시스템 설정모음
    OrderRepository 상점주문 저장 (DB)
    Worker 비즈니스로직 모음 정리
    SchedulableJob 스케쥴 단위업무 인터페이스
    OrderScrappingJob 주문수집 단위업무
    RegistDoorlockInfoJob 도어락 비밀번호 등록 단위업무
    WorkAgent 스케쥴링 된 단위업무를 정해진 시간에 수행시켜주는 역할
classDiagram
note for Commander "우리가 지금껏 만든것..."
class WorkAgent {
  + init()
  + run()
}
class Worker {
  + scrapOrder()
  + registerDoorlockInfo()
  + removeDoorlockInfo()
}
class SchedulableJob {
  + availtime()
  + execute()
}
class Commander {
  - adbCmd: AdbCommander
  - qmpCmd: QmpCommander
}
class OrderRepository { }
class SystemSettings { }
class OrderScrappingJob { }
class RegistDoorlockInfoJob { }
Worker <-- Commander
Worker <-- OrderRepository
Worker <-- SystemSettings
SchedulableJob --> WorkAgent
SchedulableJob <|-- OrderScrappingJob
SchedulableJob <|-- RegistDoorlockInfoJob
OrderScrappingJob <-- Worker
RegistDoorlockInfoJob <-- Worker

...

... 저 도표를 자세히 보고있자면.....

... 그렇다... 우린 여지껏 저 구석에 있는. 고작 Commander 하나 가지고 아둥바둥 대고 있었던 것이다....

...

.... 역시나 때려칠까? ㅋㅋ

2. 아! 됐고! 문부터 따보자!

주문수집은 나중에 살펴보고 일단 여지껏 만든것들을 모아서 중요한거 (도어락 출입고객 비밀번호 등록) 부터 해 보자
순서는 다음과 같다

stateDiagram
direction LR
  [*] --> 도어락화면:앱실행
  도어락화면 -->  메뉴:메뉴버튼-클릭
  메뉴 --> 내기기:내기기-버튼-클릭
  내기기 --> 기기선택:정,후문-클릭
  기기선택 --> 기기설정:기기설정-클릭
stateDiagram
direction LR
  기기설정 --> 임시비밀번호관리:임시비밀번호관리-클릭
  임시비밀번호관리 --> 새로등록:'+'클릭
  새로등록 --> 임시비밀번호만들기:임시비밀번호만들기-클릭
stateDiagram
direction LR
  임시비밀번호만들기 --> 이름입력
  이름입력 --> 비밀번호입력:이름입력-엔터
  비밀번호입력 --> 비밀번호확인입력:비밀번호입력-엔터
  비밀번호확인입력 --> 일정입력
stateDiagram
direction LR
  일정입력 --> 일회용선택:일회용버튼-클릭
  일회용선택 --> 날자선택:달력에서날자-클릭
  날자선택 --> 완료:만들기버튼-클릭
  완료  --> [*]

테스트 소스

@Test public void testDoorlock() throws Exception {
  if (!TestUtil.isEnabled("testDoorlock", TestLevel.MANUAL)) { return; }
  Commander cmd = null;
  try {
    cmd = new Commander("sock", "172.17.0.1", 4444, "172.17.0.1", 5555);
    /** 주문수집이 구현되지 않았으므로 가상 주문 생성 */
    Order order = Order.builder()
      .oid("test1234")
      .name("테스터")
      .goods("C룸")
      .phone("010-1234-5678")
      .fakecd("0001")
      .build();
    List<Order> list = new ArrayList<>();
    Map<String, Object> ctx = new LinkedHashMap<>();
    Worker.registerDoorlockInfo(cmd, order, list, 0, ctx);
  } finally {
    safeclose(cmd);
  }
}

Worker.java 소스

public static int registerDoorlockInfo(Commander cmd, Order order, List<Order> list, int deviceNo, Map<String, Object> ctx) throws Exception {
  int ret = 0;
  /** 도어락앱 강제 종료 */
  cmd.stopDoorLockApp();
  cmd.sleep(1000);
  /** 도어락앱 시작 */
  cmd.startDoorLockApp();
  cmd.sleep(3000);
  /** 메뉴 클릭 */
  cmd.click(27, 50);
  cmd.sleep(3000);
  cmd.click(center(31, 87), center(327, 359));
  cmd.sleep(3000);
  /** 정(후) 문 기기 */
  int[] axis = DEVICE_AXIS[deviceNo];
  log.debug("CLICK[{}]: {},{}", deviceNo, center(axis[0], axis[2]), center(axis[1], axis[3]));
  /** 정(후) 문 클릭 */
  cmd.click(center(axis[0], axis[2]), center(axis[1], axis[3]));
  cmd.sleep(3000);
  /** 기기설정 클릭 */
  cmd.click(center(axis[0] + 46, axis[0] + 94), axis[1] + 133);
  cmd.sleep(3000);
  /** 임시비밀번호관리 클릭 */
  cmd.click(144, 550);
  cmd.sleep(3000);
  /** 새번호 (+) 클릭 */
  cmd.click(567, 50);
  cmd.sleep(3000);
  /** 임시비밀번호만들기 클릭 */
  cmd.click(300, 670);
  cmd.sleep(3000);
  cmd.sendKeys(ESC);
  /** 임시키 이름 조합 */
  cmd.chImeAdb();
  cmd.sleep(500);
  String name = order.name;
  String goods = order.goods;
  if (name == null) { name = "●"; }
  if (name.length() > 3) { name = name.substring(0, 3); }
  if (goods == null) { goods = "●"; }
  goods = goods.replaceAll(FID_ROOM, "").replaceAll("[ ]+", "");
  /** 임시키 이름 입력 (이름 + 상품명1글자 + 주문번호 뒷4자리) */
  cmd.inputUniStr(reduceBLen(replaceQuot(
    cat((name), " ", goods, " ", (order.oid.substring(order.oid.length() - 4)))), 19));
  cmd.inputKey(Keys.ENTER);
  cmd.inputKey(Keys.SPACE);

  /** 비밀번호 조합 (전화번호 뒷4자리) */
  String password = "";
  if (order.phone != null && order.phone.length() > 4) {
    password = new String(order.phone).substring(order.phone.length() - 4);
  }

  /** 비번입력 */
  cmd.sendKeys(ESC);
  cmd.sleep(500);
  cmd.sendKeys("ctrl", "a");
  cmd.sendKeys("backspace");
  cmd.sleep(300);
  cmd.inputUniStr(password);
  cmd.inputKey(Keys.ENTER);
  cmd.sleep(300);
  /** 확인입력 */
  cmd.sendKeys("ctrl", "a");
  cmd.sendKeys("backspace");
  cmd.sleep(300);
  cmd.inputUniStr(password);
  cmd.inputKey(Keys.ENTER);
  cmd.inputKey(Keys.SPACE);
  cmd.sleep(300);

  /** 일회용 버튼 클릭 */
  cmd.click(108, 230);
  cmd.sleep(300);

  /** 달력 드래그 (위쪽 / 오늘날자 나올수 있게) */
  cmd.drag(
    CALENDAR_CNT_X, CALENDAR_CNT_Y,
    CALENDAR_CNT_X, CALENDAR_CNT_Y - CALENDAR_UNIT_SIZE_Y - 10);

  /** 날자 클릭 (일단은 하드코딩...) */
  cmd.click(
    center(CALENDAR_X[1][0], CALENDAR_X[1][1]), 
    center(CALENDAR_Y[2][0], CALENDAR_Y[2][1])
    );

  /** 만들기 버튼 클릭 */
  cmd.click(center(BTN_COMPLETE[0], BTN_COMPLETE[2]), center(BTN_COMPLETE[1], BTN_COMPLETE[3]));
  return ret;
}

... 소스 복잡함 무엇?.....

... 각설하고 만들었으니 실행해보자

이제 테스터 C 1234 (주문자명 + 사용방번호 + 주문번호 뒷 4자리) 이름으로 비밀번호 5678 (주문자 전화번호 뒷 4자리)오늘 날자 (글쓴시점 : 3월 18일)에 연습실을 출입할 수 있다.

3. 뭐! 일단 돌아는 가잖아!!!

쉿! 조용!조용! 알아요! 알아! 하드코딩 들어간거 안다구욧! (일단 진정하시고.)

소스 복잡도 때문에 일단은 알기쉽게 단순나열성 코드 로만 작성했다.

실제 적용된 코드는 오류발생 등으로 재시도패턴 이 무수하게 들어가 있어 step별로 분할하여 작성했다. (추후 반영 예정)

여기까지만 해도 쌍코피 터질만큼 피곤한데..

더더욱 난감한일이 발생하였으니.....

[ 5편에서 계속... ]

[ Worker.java 소스 ]

[ 관련 소스 저장소 ]

답글 남기기

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