uiautomator2로 android에서 자동화를 해보기위해서 이것저것 해보고 있습니다. 도움이 될만한 내용들을 정리해 보았습니다.
1. 현재앱 알아내기
print(d.app_current())
출력 형태
{'package': 'com.android.settings', 'activity': '.homepage.SettingsHomepageActivity', 'pid': 14781}
2. 앱 실행키시기
app_start로 실행합니다. 이때인자는 패키지 이름입니다. 앱을 실행 시킨 후 app_wait로 pid를 얻어 올 수 있습니다.
d.app_start(test_package) pid = d.app_wait(test_package, timeout=20.0) if not pid: print(f"{test_package} is not running") else: print(f"{test_package} pid is {pid}")
3. 화면 구성값 가져오기
xml 형태로 저장됩니다.
xml = d.dump_hierarchy() print("saving xml") write_file("hierarchy.xml",str(xml))
형태가 복잡해서 전체 예제를 실행시키면 저장하도록 해놨습니다. 파일을 열어보시길 추천합니다.
4. 스크린샷 찍어 저장하기
확장자에 따라서 png, jpg 형태로 저장이 가능합니다.
image = d.screenshot() if not exists(test_image_name): image.save(test_image_name) print("save screenshot")
5. 키보내기
여러 종류의 키를 보낼 수 있습니다.
d.press("home")
숫자값으로 보낼때는 여기 참고
https://developer.android.com/reference/android/view/KeyEvent
텍스트는 아래 참고
home
back
left
right
up
down
center
menu
search
enter
delete ( or del)
recent (recent apps)
volume_up
volume_down
volume_mute
camera
power
6. 종합 screenshot 찍어서 이전 저장된 사진과 비교하기
전체 소스
from os.path import exists import uiautomator2 as u2 import adbutils import time from PIL import Image from PIL import ImageChops import math, operator test_image_name = "testimage.png" test_package = "com.android.settings" def write_file(filename,str_data): with open(filename, 'w', encoding="utf-8") as fp: fp.write(str_data) fp.close() def images_are_similar(img1, img2, error=90): print(img1.size[0],img1.size[1]) # xsize, ysize diff = ImageChops.difference(img1, img2).histogram() # [ r 256 , g 256 , b 256 ] = 768 list print(len(diff)) print(diff) sq = (value * (i % 256) ** 2 for i, value in enumerate(diff)) sum_squares = sum(sq) print(sum_squares) rms = math.sqrt(sum_squares / float(img1.size[0] * img1.size[1])) print(rms) return rms < error if __name__ == "__main__": d = None for dev in adbutils.adb.device_list(): print("Dev:", dev) d = u2.connect(dev.serial) if d==None: print("please check connected devices (adb devices)") else: d.screen_on() d.unlock() d.press("home") print(d.app_current()) d.app_start(test_package) pid = d.app_wait(test_package, timeout=20.0) if not pid: print(f"{test_package} is not running") else: print(f"{test_package} pid is {pid}") xml = d.dump_hierarchy() print("saving xml") write_file("hierarchy.xml",str(xml)) image = d.screenshot() if not exists(test_image_name): image.save(test_image_name) print("save screenshot") else: # compare image.save("new"+test_image_name) pimage = Image.open(test_image_name) #for test sdiff = images_are_similar(image,image) sdiff = images_are_similar(image,pimage) print(sdiff) print(d.app_current()) d.press("home")
7.이미지 비교 함수 설명
images_are_similar
여기에 넘어가는 이미지는 PIL type입니다. size[0], size[1]은 각각 가로 세로 크기입니다.
기본 원리는 image의 diff를 구하는것입니다. 이것은 ImageChops.difference(img1, img2) 와 같은 형태로 구할 수 있습니다.
다음으로는 histogram()을 취하게 되는데 histogram은 R, G, B 각각 256개로 모두 768 개를 지닙니다.
일반적으로 delta를 수치로 표현할때 표준편차를 구해서 비교하는데 여기에서는 이미지 histogram의 표준 편차를 구해서 특정값보다 크게 되면 차이가 난다고 판단합니다. 임의의 기준을 여기에서는 90으로 정했으며 조정 가능한 값입니다.
같은 이미지로 시험하면 아래와 같은 histogram을 얻게 됩니다. 여기에 들어가 있는 2592000 는 가로*세로 즉 점의 갯수가 됩니다. 1080 2400 화면에서는 아래와 같습니다.
[2592000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2592000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2592000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
그리고 첫번째는 R의 0번값이며 2592000 수치를 나타낸다는 의미는 점을 빼줬기 때문에 0을 가진다는 의미입니다.
만약 다른 이미지로 테스트했다면 아래와 같은 형태가 될것입니다.
중간이미지가 diff(차)연산으로 나온 이미지인데 이것을 histogram을 해서 표준 편차를 구한다는 의미입니다.
여기에서는 이미지가 같게 되면 rms 수치가 작아지게 되고 images_are_similar True값이 리턴됩니다.
댓글 없음:
댓글 쓰기