Buscar

Guias

Tutorial ADB Python: controlar um emulador Android

Um tutorial de adb com Python para o MAS: toque, deslize, digite, aperte teclas e tire capturas de tela no BlueStacks, com o adb gerenciado pelo app.

  • Windows
  • Mac
  • Emulador
  • Dispositivo na nuvem
  • Celular
  • SDK Python
Intermediário Atualizado em 7 min de leitura
Nesta página
  1. Antes de começar
  2. Como as peças se encaixam
  3. Criar o projeto
  4. Tamanho da tela e coordenadas
  5. Tirar uma captura de tela com adb em Python
  6. Tocar
  7. Deslizar
  8. Digitar
  9. Apertar teclas
  10. Abrir e verificar apps
  11. Um script completo
  12. Onde o adb entra neste tutorial Python
  13. O que pode dar errado
  14. Could not discover RPC port
  15. Os toques caem no lugar errado
  16. input_text não digitou nada
  17. Dispositivo não encontrado ou offline

A maioria dos tutoriais de adb com Python termina em um wrapper de subprocess em volta de adb shell input tap. Este tutorial de adb Python para o Macro Automation Studio (MAS) segue outro caminho: o app é dono do adb, e o seu script fala com o app pelo pacote mas. Este guia vai de um projeto novo até um script que abre um app, pesquisa um termo, rola a tela e salva uma captura. Ele é para desenvolvedores Python que querem controlar BlueStacks, LDPlayer, MuMu Player ou MEmu sem escrever chamadas de adb.

Antes de começar

  • O MAS está instalado e você fez login com o teste ou um plano. Veja Instalar o MAS.
  • Um emulador está aberto com o ADB ativado e adicionado como dispositivo em Grupos de dispositivos. Veja Dispositivos.
  • Você conhece o básico de Python. Você não instala mais nada: o MAS traz o próprio ambiente Python 3.13 com o mas dentro.

Como as peças se encaixam

O MAS inicia o seu script como python -u -m src.app com a pasta do projeto como diretório de trabalho. Ele passa os dados de conexão em variáveis de ambiente (MAS_RPC_PORT, MAS_RPC_HOST, MAS_DEVICE_ID, MAS_SESSION_TOKEN). Toda chamada mas.* vira uma requisição JSON-RPC 2.0 para o app. O app roda o comando adb, a busca de template ou o OCR, e devolve o resultado. O dispositivo é vinculado antes de a sua primeira linha rodar, então não há chamada connect() nem serial para gerenciar. Veja Conceitos.

Criar o projeto

  1. Abra Macros e clique em Criar novo projeto.
  2. Escolha Baseado em código, defina Dispositivo alvo como mobile, dê um nome ao projeto e clique em Criar projeto.
  3. Abra o projeto. O Code Editor mostra src/app.py.
  4. Escolha o emulador no seletor de dispositivo e clique em Executar (F5) sempre que quiser testar um trecho. Parar é Shift+F5.

Tamanho da tela e coordenadas

Toda coordenada que você passa ao SDK é um deslocamento em pixels a partir do canto superior esquerdo da tela do dispositivo, na resolução do próprio dispositivo. O tamanho da janela do emulador no seu monitor não importa.

python
import mas

size = mas.get_screen_size()
print(f"Screen: {size.width}x{size.height}")

center = (size.width // 2, size.height // 2)
mas.click(*center)

get_screen_size() retorna um ScreenSize com width e height. get_device_info() retorna o mesmo mais o name, o type e a flag connected do dispositivo. Quando um script precisa sobreviver a uma mudança de resolução, calcule as posições como frações do tamanho, como o exemplo do final faz. Imagens template e regiões de OCR não sobrevivem a isso; veja o guia de reconhecimento de imagem.

Tirar uma captura de tela com adb em Python

python
import base64
import mas

shot = mas.take_screenshot()
print(shot.width, shot.height, shot.timestamp)

with open("screen.png", "wb") as f:
    f.write(base64.b64decode(shot.base64))

take_screenshot() retorna um Screenshot: base64 contém um PNG, width e height são o tamanho em pixels, e timestamp é uma string ISO 8601. O arquivo acima cai na pasta do projeto porque esse é o diretório de trabalho. Passe o mesmo objeto a várias chamadas de find_object com screenshot=shot e todas buscam em um único quadro em vez de capturar de novo.

Tocar

python
mas.click(270, 800)                 # tap, then wait 1000 ms
mas.click(270, 800, delay_ms=300)   # shorter pause for tight loops

click(x, y, delay_ms=1000) toca uma vez e espera delay_ms depois para o app reagir. Não há duração de pressionamento em um toque; para um toque longo, use key_press com duration_ms.

Deslizar

python
mas.swipe((270, 750), (270, 300), duration_ms=400)    # scroll a list down: drag from lower to upper
mas.swipe((100, 500), (400, 500), duration_ms=1000)   # drag and drop: slow and deliberate

swipe(from_coords, to_coords, duration_ms=1000) recebe duas tuplas (x, y). Uma duração curta é um flick; uma longa é um arrasto. Gestos de pinça são chamadas separadas: zoom_in() e zoom_out() usam por padrão o centro da tela com percent=50.

Digitar

python
mas.click(270, 120, delay_ms=500)          # focus the field first
mas.input_text("hello world")
mas.input_text("new value", clear=True)    # replace what is there

input_text(text, delay_ms=0, clear=False) digita no campo em foco, então toque no campo antes. clear=True move o cursor para o fim e apaga os caracteres existentes antes de digitar.

Apertar teclas

python
from mas import KeyCode

mas.key_press(KeyCode.BACK)
mas.key_press(KeyCode.HOME)
mas.key_press(KeyCode.ENTER)
mas.key_press(KeyCode.DELETE, repeat=10)          # ten presses in one command
mas.key_press(KeyCode.POWER, duration_ms=3000)    # long press

key_press(key_code, modifiers=None, duration_ms=100, repeat=1) envia um evento de tecla do Android. Um duration_ms de 500 ou mais vira um toque longo; o número exato de milissegundos além disso não é respeitado. repeat vai de 1 a 100 e é muito mais rápido que um loop em Python. KeyCode também tem as teclas do D-pad, de volume, de mídia e numéricas.

Abrir e verificar apps

python
mas.open_app("com.android.settings", timeout_ms=5000)
print(mas.get_current_app())                        # package name in front
print(mas.is_app_focused("com.android.settings"))   # True or False

if mas.get_app_state("com.android.chrome") == mas.NOT_RUNNING:
    mas.open_app("com.android.chrome")

mas.close_app("com.android.settings")

open_app(package_name, timeout_ms=2000) abre pelo nome do pacote e espera timeout_ms. Para descobrir o nome de um pacote, abra o app à mão e imprima mas.get_current_app(). get_app_state retorna NOT_INSTALLED, NOT_RUNNING, RUNNING_IN_BACKGROUND_SUSPENDED, RUNNING_IN_BACKGROUND ou RUNNING_IN_FOREGROUND. close_app força a parada do pacote.

Um script completo

O script abre as Configurações do Android, pesquisa um termo, rola os resultados, salva uma captura de tela e confere com OCR que o termo está na tela. A caixa de pesquisa é um template que você recorta no Asset Lab; troque o ID pelo seu. O deslize usa frações do tamanho da tela para funcionar em qualquer resolução.

python
import base64
import sys
import time

import mas
from mas import KeyCode

PACKAGE = "com.android.settings"
TERM = "Display"

images = mas.images({"search_box": 301})


def main():
    size = mas.get_screen_size()
    mas.log(f"Screen {size.width}x{size.height}")

    mas.open_app(PACKAGE, timeout_ms=5000)
    if not mas.is_app_focused(PACKAGE):
        mas.log(f"{PACKAGE} did not come to the front", level="error")
        sys.exit(2)

    box = mas.find_object_retry(images.search_box, total_tries=3, time_sleep=2.0)
    if box is None:
        mas.log("Search box not found; crop it in Asset Lab", level="error")
        sys.exit(2)
    mas.click(box.x, box.y, delay_ms=800)
    mas.input_text(TERM, clear=True)
    mas.key_press(KeyCode.ENTER)
    time.sleep(2)

    x = size.width // 2
    mas.swipe((x, int(size.height * 0.75)), (x, int(size.height * 0.35)), duration_ms=600)
    time.sleep(1)

    shot = mas.take_screenshot()
    with open("search_results.png", "wb") as f:
        f.write(base64.b64decode(shot.base64))
    mas.log(f"Saved search_results.png ({shot.width}x{shot.height})")

    text = mas.read_text(screenshot=shot, psm=11)
    mas.log(f"Term on screen: {TERM.lower() in text.text.lower()}")

    mas.key_press(KeyCode.HOME)


if __name__ == "__main__":
    main()

read_text com psm=11 lê texto esparso pelo quadro inteiro, o que serve para uma lista de resultados. O guia de OCR cobre regiões e modos para ler um único contador. Se preferir descrever a tarefa em vez de escrevê-la, o MAS Agent escreve esse tipo de script para você.

Onde o adb entra neste tutorial Python

Você nunca chama o adb, mas ele está fazendo o trabalho por baixo.

  • Binário. O instalador traz o adb. No Windows, ele fica em C:\ProgramData\MacroAutomationStudio\3rdparty, com uma cópia embutida como alternativa. No Mac, fica dentro do pacote do app, com o adb do Homebrew como alternativa. Nada entra no seu PATH. A página Instalação tem os detalhes.
  • Conexão. Os emuladores expõem o adb em uma porta TCP local. Quando você clica em Iniciar ou Executar, o MAS roda adb connect 127.0.0.1:<port> para a porta do card do dispositivo e mantém essa sessão pela execução.
  • Entrada. click vira adb shell input tap, swipe vira adb shell input touchscreen swipe, input_text vira adb shell input text, e key_press vira adb shell input keyevent. Gestos de pinça são escritos direto no dispositivo de entrada de toque do emulador.
  • Tela. take_screenshot e todo find_object capturam com adb exec-out screencap -p, a forma segura para binário que não corrompe o PNG no Windows. get_screen_sizewm size; get_current_app lê o gerenciador de janelas.
  • Apps. open_app dispara a intent do launcher pelo monkey e recorre a am start; close_app roda am force-stop.
  • Servidores. O MAS roda o próprio servidor adb. Se um segundo adb no seu PATH iniciar o dele, os dois se substituem e o seu dispositivo cai para Conectando. A página Solução de problemas de ADB lista as correções, porta por porta.

Como o app faz tudo isso, um script escrito no BlueStacks roda sem alterações no LDPlayer, em um dispositivo na nuvem ou no seu próprio celular por uma porta local.

O que pode dar errado

Could not discover RPC port

O script foi iniciado de um terminal em vez de pelo MAS, então as variáveis de ambiente estão faltando. Rode com Executar no Code Editor ou por um card de dispositivo.

Os toques caem no lugar errado

Você está usando pixels da janela em vez de pixels do dispositivo, ou a resolução do emulador mudou. Imprima mas.get_screen_size() e compare com as coordenadas que você passa. As coordenadas do Asset Lab já são pixels do dispositivo.

input_text não digitou nada

Nenhum campo tinha foco. Toque no campo com click e dê a ele delay_ms=500 antes de digitar. Alguns apps abrem um teclado que cobre o campo; key_press(KeyCode.BACK) o fecha depois de digitar.

Dispositivo não encontrado ou offline

O ADB está desligado no emulador, a porta no card do dispositivo está errada, ou outro servidor adb assumiu. Siga a Solução de problemas de ADB.

Se o app que você controla é um jogo, trate-o com o mesmo cuidado que qualquer outra conta automatizada. Nenhuma ferramenta de automação é 100% livre de riscos, por isso automatize com responsabilidade e a seu próprio critério.

Próximos passos

Páginas relacionadas

Esta página foi útil?

Dúvidas? Pergunte no Discord