Principes de base pour exécuter NoxPlayer en Python

Contexte

La distribution et le support d'UWSC étant terminés, j'ai réécrit la macro que j'avais écrite dans UWSC auparavant en Python. Ainsi, du contenu réécrit, j'ai décidé de résumer le contenu important pour exécuter NoxPlayer avec des macros.

Le contenu comprend comment envoyer les commandes ADB requises pour le fonctionnement Nox, le fonctionnement bidirectionnel entre le programme et Nox et la méthode de reconnaissance d'image floue. J'ai mis le code source, mais c'est peut-être faux car je l'ai écrit en le modifiant

environnement

NoxPlayer 6.6.0.0 Python 3.6 opencv-python 4.1.2.30

Envoyer et utiliser des commandes ADB

Lors de l'automatisation du fonctionnement d'Android avec NoxPlayer, il est difficile d'utiliser la souris une par une Par conséquent, il est nécessaire d'opérer en arrière-plan, mais pour cela, il est nécessaire d'utiliser la commande ADB. → Nox est livré avec nox_adb.exe en standard, utilisez donc ceci

Premièrement, en Python, la fonction correspondant au DOSCMD de UWSC peut être écrite comme suit

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

Lors de l'envoi de commandes ADB à l'aide de ce doscmd, par exemple, dans le cas d'une opération tap

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)

Peut être décrit de manière concise D'autres commandes ADB sortiront si vous les vérifiez (bien que vous puissiez les mettre plus tard)

Voir le comportement avec logcat

Lors de l'automatisation, ce sera mieux si vous pouvez voir dynamiquement le comportement de l'application et d'Android avec logcat, mais à ce moment-là

code


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

Sortira logcat Par exemple, pour ouvrir le gestionnaire de fichiers standard Nox avec la commande ADB et confirmer qu'il a été ouvert

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 }

Mais en utilisant 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

Vous pouvez voir le comportement comme celui-ci

Lors de l'automatisation des opérations d'application, vous pouvez effectuer diverses opérations en examinant le moment de la transition d'activité et du fonctionnement du GC (libération de la mémoire). clear_log → Opération spécifique → get_log → Discrimination, vous pouvez déterminer l'état de l'écran sans reconnaissance d'image </ font>

Appuyez sur l'image spécifiée sur l'écran

Lors de l'automatisation d'une application, l'objet se déplace dynamiquement dans ~~ jeux, etc., donc l'objet doit être reconnu par programme. Par conséquent, en reconnaissant l'objet comme une image, il peut être traité sur le programme. Comme méthode concrète

  1. Prenez une capture d'écran de l'écran avec la commande ADB Sur la base de la capture d'écran en 2.1, laissez OpenCV reconnaître l'image (modèle) pour l'image correspondante.
  2. Déterminez l'opération en fonction de la reconnaissance d'image

C'était la méthode la plus simple

Comme un avantage

  • Fonctionne en arrière-plan même lorsque la fenêtre est réduite </ font> -La reconnaissance d'image fonctionne quelle que soit la taille de la fenêtre et il est plus facile de prendre des coordonnées.

étape 1

Si vous souhaitez prendre une capture d'écran dans l'image avec la commande ADB et l'enregistrer dans le PC

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)

Générera D: / Program Files / Nox / bin / pics / _capture.png De plus, lors de la création d'un modèle, si vous le créez à partir de cette image, vous pouvez le créer quelle que soit la taille de la fenêtre de Nox.

Étape 2

Plus précisément, comme indiqué ci-dessous, une méthode de renvoi des coordonnées du centre de la pièce qui correspond au modèle dans l'image peut être envisagée. Quand il y a un modèle de img / temp.png dans le même répertoire que main.py

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 #Degré de similitude

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)

Peut être écrit

Étape 3

Si vous souhaitez appuyer sur les coordonnées obtenues à l'étape 2, utilisez la méthode tap et la méthode get_center_position_from_tmp ci-dessus.

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)

Peut être décrit comme

A titre d'exemple concret, l'écran suivant modèle temp.png Si vous souhaitez appuyer avec, Appuyez sur l'image, découpez la partie appropriée avec GIMP et placez-la dans img / tmp.png </ font> Après cela, exécutez la méthode capture_screen → méthode get_center_position_from_tmp → appuyez sur la méthode dans cet ordre sur le programme </ font> En d'autres termes, pour résumer le passé

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 " #J'ai mis l'image du signet ici
_THRESHOLD = 0.9 #Degré de similitude

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()

Et le comportement réel est Devrait être

prime

Empêcher le journal de disparaître

Si le journal disparaît immédiatement après l'exécution, vous ne pourrez pas voir ce que vous avez imprimé, vous devez donc vous assurer que le journal reste. Pour ce faire, écrivez a = input () à la fin de la macro

code


def main():
    print("Start")

    #Unité de traitement
    
    print("Finish")
    _a = input()

if __name__ == "__main__":
    main()

Celui utilisé dans la commande ADB

code


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

##Glisser
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)

##Longue pression
def long_tap(x, y, seconds):
    swipe(x, y, x, y, seconds)

##Démarrage de l'application (activité)
def start_app():
    _cmd = "nox_adb shell am start -n com.hoge.fuga/.MyActivity"
    send_cmd_to_adb(_cmd)

##Arrêt de l'application
def start_app():
    _cmd = "nox_adb shell am force-stop com.hoge.fuga"
    send_cmd_to_adb(_cmd)

##Retourner à la maison
def return_home():
    _cmd = "nox_adb shell input keyevent KEYCODE_HOME"
    send_cmd_to_adb(_cmd)

##Changer la date du terminal (je l'ai écrit car les informations n'ont pas été collectées uniquement par cette méthode)
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)

Créer un fichier exe

Faire un exe en utilisant Pyinstaller progressera

Veuillez vous référer au site suivant (il est difficile d'écrire) ・ Créer un fichier exe avec PyInstaller --Qiita

Voir également ci-dessous lors de l'utilisation avec Pycharm, la bonne réponse est d'utiliser les outils externes d'aerobiomat

Créer un fichier de configuration

Le répertoire de Nox lui-même peut changer en fonction de l'environnement, mais s'il est converti en fichier exe, il ne sera pas possible de changer le programme. Par conséquent, il est nécessaire de créer un fichier config.ini à l'avance. Dans cet exemple, en supposant que le fichier exe et config.ini se trouvent dans le même répertoire

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")

    #Unité de traitement

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

if __name__ == "__main__":
    main()

config.ini


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

Peut être écrit comme

Recommended Posts