Grundlagen zum Ausführen von NoxPlayer in Python

Hintergrund

Da die Verteilung und Unterstützung von UWSC beendet ist, habe ich das Makro, das ich zuvor in Python in UWSC geschrieben habe, neu geschrieben. Von den umgeschriebenen Inhalten habe ich beschlossen, die wichtigen Inhalte für die Ausführung von NoxPlayer mit Makros zusammenzufassen.

Der Inhalt umfasst das Senden von ADB-Befehlen, die für den Nox-Betrieb erforderlich sind, den bidirektionalen Betrieb zwischen dem Programm und Nox sowie die Fuzzy-Bilderkennungsmethode. Ich habe den Quellcode eingefügt, aber es kann falsch sein, weil ich ihn beim Ändern geschrieben habe

Umgebung

NoxPlayer 6.6.0.0 Python 3.6 opencv-python 4.1.2.30

Senden und Bedienen von ADB-Befehlen

Bei der Automatisierung des Android-Betriebs mit NoxPlayer ist es schwierig, die Maus einzeln zu bedienen Daher ist es notwendig, im Hintergrund zu arbeiten, aber dafür ist es notwendig, den ADB-Befehl zu verwenden. → Nox wird standardmäßig mit nox_adb.exe geliefert. Verwenden Sie diese Option

Erstens kann in Python die Funktion, die der DOSCMD von UWSC entspricht, wie folgt geschrieben werden

Code


from subprocess import run, PIPE
def doscmd(directory, command):
    completed_process = run(command, stdout=PIPE, shell=True, cwd=directory, universal_newlines=True, timeout=10)
    return completed_process.stdout

Beim Senden von ADB-Befehlen mit diesem doscmd, z. B. bei Tap-Betrieb

Code


def send_cmd_to_adb(cmd):
    _dir = "D:/Program Files/Nox/bin"
    return doscmd(_dir, cmd)

def tap(x, y):
    _cmd = "nox_adb shell input touchscreen tap " + str(x) + " " + str(y)
    send_cmd_to_adb(_cmd)

Kann kurz beschrieben werden Andere ADB-Befehle werden ausgegeben, wenn Sie sie überprüfen (obwohl Sie sie später einfügen können).

Siehe das Verhalten mit logcat

Bei der Automatisierung ist es besser, wenn Sie das Verhalten der Anwendung und von Android mit logcat dynamisch sehen können, aber zu diesem Zeitpunkt

Code


def show_log():
    _cmd = "nox_adb logcat -d"
    _pipe = send_cmd_to_adb(_cmd)
    return _pipe

Gibt logcat aus Zum Beispiel, um den Nox-Standarddateimanager mit dem ADB-Befehl zu öffnen und zu bestätigen, dass er geöffnet wurde

Code


def start_app():
    _cmd = "nox_adb shell am start -n com.cyanogenmod.filemanager/.activities.NavigationActivity"
    _pipe = send_cmd_to_adb(_cmd)
    print(_pipe)


start_app()

Terminal


Starting: Intent { cmp=com.cyanogenmod.filemanager/.activities.NavigationActivity }

Aber mit logcat

Code


def clear_log():
    _cmd = "nox_adb logcat -c"
    send_cmd_to_adb(_cmd)

def get_log():
    _cmd = "nox_adb logcat -v raw -d -s ActivityManager:I | find \"com.cyanogenmod.filemanager/.activities.NavigationActivity\""
    _pipe = send_cmd_to_adb(_cmd)
    print(_pipe)


clear_log()
start_app()
get_log()

Terminal


START u0 {act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.cyanogenmod.filemanager/.activities.NavigationActivity bnds=[334,174][538,301](has extras)} from pid 681
Start proc com.cyanogenmod.filemanager for activity com.cyanogenmod.filemanager/.activities.NavigationActivity: pid=14454 uid=10018 gids={50018, 1028, 1015, 1023}
Displayed com.cyanogenmod.filemanager/.activities.NavigationActivity: +691ms
START u0 {act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.cyanogenmod.filemanager/.activities.NavigationActivity bnds=[334,174][538,301](has extras)} from pid 681
Start proc com.cyanogenmod.filemanager for activity com.cyanogenmod.filemanager/.activities.NavigationActivity: pid=14562 uid=10018 gids={50018, 1028, 1015, 1023}
Displayed com.cyanogenmod.filemanager/.activities.NavigationActivity: +604ms
START u0 {flg=0x10000000 cmp=com.cyanogenmod.filemanager/.activities.NavigationActivity} from pid 14665
Start proc com.cyanogenmod.filemanager for activity com.cyanogenmod.filemanager/.activities.NavigationActivity: pid=14675 uid=10018 gids={50018, 1028, 1015, 1023}
Displayed com.cyanogenmod.filemanager/.activities.NavigationActivity: +584ms
START u0 {flg=0x10000000 cmp=com.cyanogenmod.filemanager/.activities.NavigationActivity} from pid 14771
START u0 {act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.cyanogenmod.filemanager/.activities.NavigationActivity bnds=[334,174][538,301](has extras)} from pid 681
Start proc com.cyanogenmod.filemanager for activity com.cyanogenmod.filemanager/.activities.NavigationActivity: pid=14792 uid=10018 gids={50018, 1028, 1015, 1023}
Displayed com.cyanogenmod.filemanager/.activities.NavigationActivity: +589ms

Sie können das Verhalten so sehen

Bei der Automatisierung von Anwendungsvorgängen können Sie verschiedene Dinge tun, indem Sie den Zeitpunkt des Aktivitätsübergangs und des GC-Vorgangs (Speicherfreigabe) betrachten. clear_log → Spezifische Operation → get_log → Diskriminierung, Sie können den Bildschirmstatus ohne Bilderkennung bestimmen </ font>

Tippen Sie auf das angegebene Bild auf dem Bildschirm

Bei der Automatisierung einer App, ~~ in Spielen usw. ~~ bewegen sich Objekte dynamisch, daher ist es notwendig, die Objekte programmgesteuert zu erkennen. Daher kann das Objekt durch Erkennen im Objekt im Programm verarbeitet werden. Als konkrete Methode

  1. Machen Sie mit dem ADB-Befehl einen Screenshot des Bildschirms Lassen Sie OpenCV anhand des Screenshots in 2.1 das Bild (Vorlage) für das entsprechende Bild erkennen.
  2. Bestimmen Sie den Vorgang anhand der Bilderkennung

War die einfachste Methode

Als Vorteil

  • Funktioniert im Hintergrund, auch wenn das Fenster minimiert ist </ font> -Bilderkennung funktioniert unabhängig von der Fenstergröße und es ist einfacher, Koordinaten zu nehmen.

Schritt 1

Wenn Sie mit dem ADB-Befehl einen Screenshot im Bild aufnehmen und im PC speichern möchten

Code


_DIR_ANDROID_CAPTURE = "/sdcard/_capture.png "
_NAME_INTERNAL_CAPTURE_FOLDER = "pics"

def capture_screen(dir_android, folder_name):
    _cmd = "nox_adb shell screencap -p " + dir_android
    _pipe = send_cmd_to_adb(_cmd)
    
    _cmd = "nox_adb pull " + dir_android+ " " + folder_name
    send_cmd_to_adb(_cmd)


capture_screen(_DIR_ANDROID_CAPTURE, _NAME_INTERNAL_CAPTURE_FOLDER)

Erzeugt D: / Programme / Nox / bin / pics / _capture.png Wenn Sie beim Erstellen einer Vorlage diese basierend auf diesem Bild erstellen, können Sie sie unabhängig von der Fenstergröße von Nox erstellen.

Schritt 2

Insbesondere kann, wie unten gezeigt, eine Methode zum Zurückgeben der Mittelkoordinaten des Teils in Betracht gezogen werden, die mit der Vorlage im Bild übereinstimmt. Wenn sich eine Vorlage von img / temp.png im selben Verzeichnis wie main.py befindet

Code


import cv2
import numpy as np

_DIR_INTERNAL_CAPTURE = "D:/Program Files/Nox/bin/pics/_capture.png "
_DIR_TEMP = "img/temp.png "
_THRESHOLD = 0.9 #Ähnlichkeitsgrad

def get_center_position_from_tmp(dir_input, dir_tmp):
    _input = cv2.imread(dir_input)
    _temp = cv2.imread(dir_tmp)

    gray = cv2.cvtColor(_input, cv2.COLOR_RGB2GRAY)
    temp = cv2.cvtColor(_temp, cv2.COLOR_RGB2GRAY)

    _h, _w = _temp.shape

    _match = cv2.matchTemplate(_input, _temp, cv2.TM_CCOEFF_NORMED)
    _loc = np.where(_match >= _THRESHOLD)
    try:
        _x = _loc[1][0]
        _y = _loc[0][0]
        return _x + _w / 2, _y + _h / 2
    except IndexError as e:
        return -1, -1


get_center_position_from_tmp(_DIR_INTERNAL_CAPTURE , _DIR_TEMP)

Kann geschrieben werden

Schritt 3

Wenn Sie auf die in Schritt 2 erhaltenen Koordinaten tippen möchten, verwenden Sie die oben beschriebene Tap-Methode und die Methode get_center_position_from_tmp.

Code


_DIR_INTERNAL_CAPTURE = "D:/Program Files/Nox/bin/pics/_capture.png "
_DIR_TEMP = "img/temp.png "

x,y = get_center_position_from_tmp(_DIR_INTERNAL_CAPTURE, _DIR_TEMP)
tap(x, y)

Kann beschrieben werden als

Als konkretes Beispiel der folgende Bildschirm Vorlage temp.png Wenn Sie mit tippen möchten, drücken Sie das Bild zusammen, schneiden Sie das entsprechende Teil mit GIMP aus und fügen Sie es in img / tmp.png </ font> ein Führen Sie danach die Methode capture_screen → get_center_position_from_tmp aus → tippen Sie im Programm </ font> in dieser Reihenfolge auf die Methode Mit anderen Worten, um die Vergangenheit zusammenzufassen

Code


from subprocess import run, PIPE
import cv2
import numpy as np

_DIR_NOX = "D:/Program Files/Nox/bin"
_DIR_ANDROID_CAPTURE = "/sdcard/_capture.png "
_NAME_INTERNAL_CAPTURE_FOLDER = "pics"
_DIR_INTERNAL_CAPTURE = "D:/Program Files/Nox/bin/pics/_capture.png "
_DIR_TEMP = "img/temp.png " #Ich habe das Lesezeichenbild hier platziert
_THRESHOLD = 0.9 #Ähnlichkeitsgrad

def main():
   capture_screen(_DIR_ANDROID_CAPTURE, _NAME_INTERNAL_CAPTURE_FOLDER)
   x, y = get_center_position_from_tmp(_DIR_INTERNAL_CAPTURE, _DIR_TEMP)
   tap(x, y)

def capture_screen(dir_android, folder_name):
    _cmd = "nox_adb shell screencap -p " + dir_android
    _pipe = send_cmd_to_adb(_cmd)

    _cmd = "nox_adb pull " + dir_android+ " " + folder_name
    send_cmd_to_adb(_cmd)

get_center_position_from_tmp(_DIR_INTERNAL_CAPTURE , _DIR_TEMP)

def get_center_position_from_tmp(dir_input, dir_tmp):
    _input = cv2.imread(dir_input)
    _temp = cv2.imread(dir_tmp)

    gray = cv2.cvtColor(_input, cv2.COLOR_RGB2GRAY)
    temp = cv2.cvtColor(_temp, cv2.COLOR_RGB2GRAY)

    _h, _w = _temp.shape

    _match = cv2.matchTemplate(_input, _temp, cv2.TM_CCOEFF_NORMED)
    _loc = np.where(_match >= _THRESHOLD)
    try:
        _x = _loc[1][0]
        _y = _loc[0][0]
        return _x + _w / 2, _y + _h / 2
    except IndexError as e:
        return -1, -1

def doscmd(directory, command):
    completed_process = run(command, stdout=PIPE, shell=True, cwd=directory, universal_newlines=True, timeout=10)
    return completed_process.stdout

def send_cmd_to_adb(cmd):
    return doscmd(_DIR_NOX, cmd)

def tap(x, y):
    _cmd = "nox_adb shell input touchscreen tap " + str(x) + " " + str(y)
    send_cmd_to_adb(_cmd)


if __name__ == '__main__':
   main()

Und das tatsächliche Verhalten ist Sollte sein

Bonus

Verhindern Sie, dass das Protokoll verschwindet

Wenn das Protokoll sofort nach der Ausführung verschwindet, können Sie nicht sehen, was Sie gedruckt haben. Stellen Sie daher sicher, dass das Protokoll erhalten bleibt. Schreiben Sie dazu am Ende des Makros a = input ()

Code


def main():
    print("Start")

    #Verarbeitungseinheit
    
    print("Finish")
    _a = input()

if __name__ == "__main__":
    main()

Die im ADB-Befehl verwendete

Code


##Zapfhahn
def tap(x, y):
    _cmd = "nox_adb shell input touchscreen tap " + str(x) + " " + str(y)
    send_cmd_to_adb(_cmd)

##Wischen Sie
def swipe(x1, y1, x2, y2, seconds):
    _millis = seconds * 1000
    _cmd = "nox_adb shell input touchscreen swipe " + str(x1) + " " + str(y1) + " " \
           + str(x2) + " " + str(y2) + " " + str(_millis)
    send_cmd_to_adb(_cmd)

##Langes Tippen
def long_tap(x, y, seconds):
    swipe(x, y, x, y, seconds)

##App (Aktivität) starten
def start_app():
    _cmd = "nox_adb shell am start -n com.hoge.fuga/.MyActivity"
    send_cmd_to_adb(_cmd)

##App stoppen
def start_app():
    _cmd = "nox_adb shell am force-stop com.hoge.fuga"
    send_cmd_to_adb(_cmd)

##Nach Hause zurückkehren
def return_home():
    _cmd = "nox_adb shell input keyevent KEYCODE_HOME"
    send_cmd_to_adb(_cmd)

##Ändern Sie das Datum des Terminals (ich habe es geschrieben, weil die Informationen nicht nur mit dieser Methode gesammelt wurden)
import datetime

def set_date(delta_days):
    _ANDROID_DATE_FORMAT = "%Y%m%d.%H%M%S"
    _day = datetime.datetime.today() - datetime.timedelta(days=delta_days)
    _days_ago = _day.strftime(_ANDROID_DATE_FORMAT)
    _cmd = "nox_adb shell date -s " + date_2days_ago
    send_cmd_to_adb(_cmd)

Erstellen Sie eine exe-Datei

Das Erstellen einer Exe mit Pyinstaller macht Fortschritte

Bitte beziehen Sie sich auf die folgende Seite (es ist mühsam zu schreiben) ・ Exe-Datei mit PyInstaller --Qiita erstellen

Siehe auch unten, wenn Sie Pycharm verwenden. Die richtige Antwort ist die Verwendung externer Werkzeuge von Aerobiomat

Erstellen Sie eine Konfigurationsdatei

Das Verzeichnis von Nox selbst kann sich je nach Umgebung ändern. Wenn es jedoch in eine exe-Datei konvertiert wird, kann das Programm nicht geändert werden. Daher muss im Voraus eine config.ini-Datei erstellt werden. In diesem Beispiel wird davon ausgegangen, dass sich die exe-Datei und die Datei config.ini im selben Verzeichnis befinden

main.py


import configparser

def main():
    config_ini = configparser.ConfigParser()
    config_ini.read('config.ini', encoding='utf-8')

    _ADB_DIR = config_ini['DEFAULT']['NoxDirectory']

    print("start macro")

    #Verarbeitungseinheit

    print("finish macro")
    _a = input()

if __name__ == "__main__":
    main()

config.ini


[DEFAULT]
NoxDirectory = D:/Program Files/Nox/bin

Kann geschrieben werden als

Recommended Posts