# 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.

Source: https://automationmacro.com/pt-BR/docs/guides/control-an-emulator-from-python (Guias, updated 2026-09-05)

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](/docs/install).
- Um emulador está aberto com o ADB ativado e adicionado como dispositivo em **Grupos de dispositivos**. Veja [Dispositivos](/docs/devices).
- 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](/docs/concepts).

## 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** (<kbd>F5</kbd>) sempre que quiser testar um trecho. **Parar** é <kbd>Shift</kbd>+<kbd>F5</kbd>.

## 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](/docs/guides/image-recognition-macros).

## 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](/docs/guides/ocr-text-reading) cobre regiões e modos para ler um único contador. Se preferir descrever a tarefa em vez de escrevê-la, o [MAS Agent](/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](/docs/install) 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_size` lê `wm 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](/docs/adb-troubleshooting) 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](/docs/adb-troubleshooting).

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.
