안드로이드 앱 자동화 (상점 스크랩, 도어락 자동화) – 3편
[ 2편보기 ]
1. 대충 제어기 핵심 구상은 해놨고..
Commander
구조를 대충 작성 했으니 테스트 케이스를 만들어서 마우스 움직여 보고 키보드 눌러보고 해 보자.
.. 라고 하기 전에 안드로이드 셋팅부터 보고 가자
일단은 외관 보다는 정확도가 중요하기 때문에 애니메이션 효과는 다 꺼주고
(안드로이드 개발자 옵션 어떻게 켜는지는 다들 알고 있겠..... ?)
작동시 어디가 클릭되었는지 보기위해 마우스 이동 경로와 클릭위치를 보여주는 옵션을 켠다
(이렇게 마우스를 클릭하고 이동하는데로 좌표가 화면에 "끄적여"....진다)
또 꺼짐방지앱 과 기타 필요한 앱들을 미리 설치해 준다.
개발자옵션 -> 화면켜짐상태유지 : 활성화
개발자옵션 -> 입력 -> 탭한항목표시 : 활성화
개발자옵션 -> 입력 -> 포인터위치 : 활성화
개발자옵션 -> 그림 -> 창애니메이션배율 : 애니메이션 사용안함
개발자옵션 -> 그림 -> 전환애니메이션배율 : 애니메이션 사용안함
개발자옵션 -> 그림 -> Animator길이배율 : 애니메이션 사용안함
Impactator unroot
설치 (루팅 해제 /com.andreacioccarelli.impactor
)
Don't sleep
설치 (화면꺼짐 방지 /com.ilieinc.dontsleep
)
ADBKeyboard
설치 (한글 입력 / https://github.com/senzhk/ADBKeyBoard 나중에 다시언급)
Clipper
설치 (클립보드 복사 / https://github.com/majido/clipper 나중에 다시 언급)
자 이정도 해 놓고나니..
겁나 피곤하다.... (때리칠까? ㅋㅋ)
2. 구체적인 제어 프로그래밍 해 보자
우선. 본 글에 포함된 전체 소스는 git 저장소 에 저장되어 있으며, 글 작성 시점에도 계속 업데이트 하고 있다.
(실제 친구매장에 적용된것이 아닌 범용 프로젝트로 새로 만듬...)
전체 소스는 분량이 많으니 중요한 부분만 짚어 보겠다.
-
안드로이드 에뮬레이터는
qemu
를 통해 실행된다. -
qmp
라는 프로토콜을 통해Host-Machine
에서Guest-Machine
으로 제어 신호를 보낼수 있다. -
qmp
는 소켓통신을 수행하며json
타입의 데이터를 주고 받는다. -
더 자세한 사항은 아래 링크를 참고하자
https://qemu-project.gitlab.io/qemu/interop/qemu-qmp-ref.html
qmp
소켓을 열고 초기화 신호를 보내는 소스는 다음과 같다.
/** 소켓접속 */
sock = new Socket("127.0.0.1", 4444);
/** 소켓에서 input / output 스트림을 생성한다. */
reader = reader(sock.getInputStream(), UTF8);
writer = writer(sock.getOutputStream(), UTF8);
/** 데이터 주고받기용 버퍼 */
byte[] buf = new char[8192];
read(buf);
/** qmp 초기화 신호 전송 */
execCmd("qmp_capabilities", null);
- 이제 마우스를 움직이는 코드를 짜 보자, 아래는
mouseMove
메소드
/** 마우스 이동 이벤트 전송 */
public String mouseMove(int x, int y) throws Exception {
/** 마우스의 하드웨어 해상도는 32768 x 32768 이며 이를 화면 해상도에 맞추어 주어야 한다.*/
int xv = (int)Math.round((x * 1000.0d) * 32768 / 1024) / 1000;
int yv = (int)Math.round((y * 1000.0d) * 32768 / 768) / 1000;
log.trace("MOUSE-MOVE:{}.{} = {}.{} / {}", x, y, xv, yv, scrWidth);
/**
* qmpMouseMove(_xv_, _yv_) 호출시 다음과 같은 데이터를 생성한다.
* [
* { "type" : "abs", "data" : { "axis" : "x", "value" : _xv_ } },
* { "type" : "abs", "data" : { "axis" : "y", "value" : _yv_ } }
* ]
*
* qmpevt(_data_) 호출시 다음과 같은 데이터를 생성한다.
* { "events" : [ _data_ ] }
*
* execCmd("input-send-event", _argument_) 호출시 다음과 같이 데이터를 조합하여 소켓으로 보낸다.
* { "execute" : "input-send-event", "arguments": _argument_ }
*/
return this.execCmd("input-send-event", qmpevt(qmpMouseMove(xv, yv)));
}
adb
는 쉘스크립트로 데이터를 전달하며 아래 링크에서 상세 사용방법 확인이 가능하다.
- 초기화는 다음과 같이 수행한다.
public AdbCommander() throws Exception {
/** rtm = adb 커맨드를 실행할 런타임 */
Runtime rtm = Runtime.getRuntime();
/** /resource 에 포함된 adb 바이너리 경로 */
String adb = AAProjApplication.class.getClassLoader().getResource("adb").getFile();
/** 데이터 주고받기용 버퍼 */
byte[] buf = new byte[8192];
/**
* 다음과 같이 실행된다
* adb connect 127.0.0.1:5555
* adb adb devices
**/
execRawCmd(rtm, arr(adb, "connect", "127.0.0.1:5555"), buf);
execRawCmd(rtm, arr(adb, "devices"), buf);
String result = new String(buf);
if (result != null && result.indexOf("127.0.0.1:5555\tdevice") == -1) {
throw new RuntimeException ("ERROR DURING INIT ADB :" + result);
}
}
- 네이버 앱을 실행하는 코드는 다음과 같다.
/** 네이버 앱 구동 */
public String startNaverApp() throws Exception {
/** adb shell 'am start com.nhn.android.search/.ui.pages.SearchHomePage' */
return this.shell("am start com.nhn.android.search/.ui.pages.SearchHomePage");
}
자. 기본 제어 프로그래밍도 어느정도 되었으니.
3. 본격적으로 테스트 케이스를 만들어서 돌려보자
- 마우스로 사인파 곡선을 드래그 하는 소스를 짜 보았다.
--- 중략 ---
@Test void testMouseMove() throws Exception {
Commander cmd = null;
try {
/** qmp / adb 를 연결한다. */
cmd = new Commander("127.0.0.1", 4444, "127.0.0.1", 5555);
/** 마우스 최초지점 */
cmd.mouseMove(70, 300);
/** 마우스 버튼을 누른다 */
cmd.mouseDown();
for (double x = 0; x < 100; x += 1) {
/** 사인파 곡선을 마우스로 드래그 한다.. */
double y = Math.sin(x);
cmd.mouseMove((int)(x * 10 + 70), (int)(y * 50 + 300));
cmd.sleep(50);
}
/** 마우스 버튼을 뗀다 */
cmd.mouseUp();
/** 최초지점으로 이동해서 클릭한번 수행 */
cmd.mouseMove(70, 300);
cmd.click();
} finally {
safeclose(cmd);
}
}
--- 중략 ---
안드로이드 에뮬레이터에 그림판을 틀어놓고 실행해 보면...
sh gradlew cleanTest test -Daaproj.build.test=MANUAL -Dspring.profiles.active=local -i --no-watch-fs --tests "project.atmt.android.SimpleTests.testMouseMove"
짜잔!! 다음과 같이 실행된다.
별 쓰잘데기 없지만. 만들어 놓고 보니
재미지다!!!. ㅋㅋㅋ 개발자들이 이맛에 개발하는거지 머. ㅋㅋ
4편에서는 단위기능들을 묶어서 Work(업무)로 만들어 볼거다.
[ 쉬어가는 3-2편 보기 ]
[ 4편에서 계속 ]
[ 관련 소스 저장소 ]