# Multi-instância de emulador Android: farm com grupos

> Farm multi-instância de emulador Android no MAS: adicione cada instância do BlueStacks ou LDPlayer pela porta, agrupe-as e dê a cada um seu perfil e proxy.

Source: https://automationmacro.com/pt-BR/docs/guides/multi-instance (Guias, updated 2026-09-05)

Uma macro, cinco contas, um clique: isso é farm multi-instância de emulador Android. O Macro Automation Studio (MAS) trata toda instância de emulador como um dispositivo separado. Um grupo de dispositivos então roda a mesma macro em todas elas, com argumentos por dispositivo, um proxy para cada uma e um armazenamento que nunca mistura contadores. Este guia monta essa configuração no BlueStacks, LDPlayer, MuMu Player ou MEmu. Ele é para quem roda mais de uma conta.

## Antes de começar

- O MAS está instalado e você fez login com um plano cuja contagem de dispositivos cobre as instâncias que você quer rodar ao mesmo tempo. Veja [Cobrança](/docs/billing).
- O gerenciador de multi-instâncias do emulador criou as instâncias e cada uma tem o ADB ativado. Os guias do [BlueStacks](/docs/bluestacks-setup-guide), do [LDPlayer](/docs/ldplayer-setup-guide), do [MuMu Player](/docs/mumu-setup-guide) e do [MEmu](/docs/memu-setup-guide) mostram onde ficam a opção e a porta.
- Toda instância usa a mesma resolução e o mesmo DPI daquela em que você capturou os templates.
- A macro funciona em uma instância a partir do Code Editor. Veja o [guia de loops](/docs/guides/loops-and-scheduling).

## Cada instância de um emulador Android multi-instância é um dispositivo

Uma instância de emulador escuta o adb na própria porta TCP local. O MAS encontra as instâncias escaneando os processos em execução e mantendo as portas dentro da faixa conhecida de cada emulador. Duas janelas do BlueStacks aparecem, portanto, como duas entradas na lista **Porta**. O dispositivo é a porta; o grupo é a lista de portas.

| Emulador | Portas que o MAS aceita |
|---|---|
| BlueStacks | 5555 a 8500 |
| LDPlayer | Portas ímpares de 5555 a 5599 |
| MuMu Player | Portas ímpares de 5555 a 5599, 7555, 16384 a 16576, 26624 a 27264 |
| MEmu | 21503 e toda porta terminada em 3 acima dela, abaixo de 30000 |

Mantenha toda instância aberta enquanto a adiciona; uma instância parada não tem porta para encontrar. A página [Dispositivos](/docs/devices) tem as regras completas de descoberta.

## Criar um grupo de dispositivos

1. Abra **Grupos de dispositivos** e clique em **Criar novo grupo**.
2. Digite um **Nome**, mantenha o tipo **Local** e clique em **Criar grupo**.
3. Abra o grupo e clique em **Adicionar dispositivo**.
4. Digite um **Nome do dispositivo** que diga qual conta é, por exemplo `farm-alt-2`.
5. Escolha a porta da instância em **Porta**. Clique em **Atualizar** se ela não aparecer, ou escolha **Porta personalizada** e digite-a.
6. Clique em **Adicionar dispositivo** e repita para cada instância.
7. Em cada card de dispositivo, escolha a macro no seletor **Macro**.

Uma porta pode pertencer a um único dispositivo. Adicioná-la duas vezes falha com "Port is already in use". Veja [Grupos de dispositivos](/docs/device-groups).

## Dê a cada dispositivo os próprios argumentos

A maioria dos bots precisa de um valor que muda por conta: um nome, um alvo, um número de rodadas. Há duas formas de passá-lo.

**Perfis de configurações (sem mudar o código).** Se a macro tem um formulário de argumentos do UI Builder, cada card de dispositivo tem **Editar argumentos**. A caixa de diálogo traz uma barra **Perfil**: informe os valores, escolha **Salvar os valores atuais como novo perfil**, dê um nome e clique em **Criar perfil**. Um dispositivo segue um perfil, e editar o perfil atualiza todo dispositivo que o segue na próxima execução. O "Padrão" sempre existe e não pode ser excluído. Veja [Perfis de configurações](/docs/settings-profiles) e [UI Builder](/docs/ui-builder).

**A porta no código.** O script pode perguntar em qual instância está e escolher as próprias configurações. Isso não precisa de formulário e é o que o exemplo do final faz.

```python
import mas

port = mas.get_current_device_port()   # 5555, 5557, 5559 ...
```

Use perfis quando os valores mudam com frequência ou outra pessoa roda o bot; use a porta quando o mapeamento é fixo e vive junto com o código.

## Dê a cada dispositivo o próprio proxy

Contas que compartilham um IP compartilham o mesmo destino. O MAS anexa um proxy por dispositivo e roteia o tráfego daquela instância por ele.

1. Abra **Proxies**. Em **Adicionar um proxy**, preencha a aba **Conta do gateway**, ou a aba **Outro provedor** para um proxy seu (`http`, `https` ou `socks5`), e clique em **Adicionar e testar**.
2. Aguarde o teste. Ele confirma que o proxy responde e detecta o país; **Testar** o repete depois.
3. Clique em **Atribuir** e escolha o dispositivo, ou abra o card do dispositivo em **Grupos de dispositivos** e escolha o proxy em **Proxy**.

O card do dispositivo mostra o estado do proxy a cada execução, e os webhooks de execução carregam `proxy_exit_ip` e `proxy_country`. Um dispositivo tem um proxy; anexar outro substitui o anterior. Veja [Proxies](/docs/proxies).

## Iniciar todos: sincronização multi-instância no LDPlayer ou BlueStacks

Clique em **Iniciar todos** no topo do grupo. O MAS inicia os dispositivos um após o outro, com meio segundo de intervalo, cada um com a própria execução, o próprio log e o próprio código de saída. Um dispositivo sem macro é pulado com um erro e o resto continua. **Parar todos** encerra toda execução do grupo. A aba **Logs** de cada card mostra só aquele dispositivo, e a aba **Dashboard** mostra a interface de execução dele se a macro tiver uma.

## Mantenha o estado por dispositivo com o armazenamento

`mas.save`, `mas.retrieve` e `mas.clear` são indexados por este computador, pela porta do dispositivo e por um nome de tarefa. Duas instâncias rodando a mesma macro mantêm, portanto, contadores separados sem código extra. Para somá-los, `mas.retrieve_all(task_name)` retorna uma entrada por porta com `machine_id`, `port`, `data` e `updated_at`.

```python
TASK = "collector"

mine = mas.retrieve(TASK)                          # this instance only
everyone = mas.retrieve_all(TASK)                  # every instance on this computer
total = sum(entry["data"].get("done", 0) for entry in everyone)
```

Veja [Armazenamento](/docs/sdk/storage).

## Webhooks por grupo

Para ser avisado quando qualquer conta terminar ou falhar, adicione um endpoint na página **Webhooks**, escolha os eventos em **Me envie**, e em **Me envie eventos de** escolha **Grupos específicos** e marque o grupo. Os dispositivos que você adicionar ao grupo depois também ficam cobertos. Cada evento carrega `device_name`, `device_port`, `group_id`, `status` e `exit_code`, então um único endpoint consegue distinguir as contas. Veja [Webhooks](/docs/webhooks).

## Fique de olho nos limites de recursos de uma farm de bots no BlueStacks

Toda instância é um sistema Android completo. Antes de escalar, confira três coisas:

- **CPU e RAM por instância.** Cada instância consome os núcleos e a memória definidos nas configurações de instância do emulador. Some tudo e deixe folga para o MAS, que roda o template matching e o OCR de toda instância na mesma máquina. Quando os toques começam a atrasar, você passou do limite.
- **Dispositivos do seu plano.** Um plano é dimensionado por quantos dos seus dispositivos podem rodar ao mesmo tempo. **Iniciar todos** roda quantos o plano permitir; veja [Cobrança](/docs/billing) e a [página de preços](/pricing).
- **Jobs agendados.** O Agendador roda até 20 jobs de uma vez, um por porta.

Menos instâncias rodando limpas valem mais do que muitas instâncias errando templates.

## Agende o grupo

O Agendador tem uma porta como alvo por job, então um agendamento de grupo é um job por dispositivo.

1. Abra o **Agendador** e clique em **Criar novo agendamento**.
2. Escolha a **Macro**, clique em **Escanear** em **Porta do emulador** e escolha a primeira instância.
3. Defina **Data**, **Hora** e **Recorrência**, depois clique em **Criar agendamento**.
4. Repita para cada porta. Dê aos jobs o mesmo horário; portas diferentes nunca colidem.

As execuções agendadas usam os argumentos salvos em cada card de dispositivo, ou o perfil que o dispositivo segue, então os valores por conta são mantidos. O app precisa ficar aberto. Veja [Agendador](/docs/scheduler) e o [guia de loops](/docs/guides/loops-and-scheduling).

## Um exemplo completo

A macro lê a própria porta, escolhe as configurações da conta, mantém um contador por porta e registra no fim o total de todas as instâncias. Troque as portas e os IDs de imagem pelos seus.

```python
import random
import sys
import time

import mas

images = mas.images({
    "collect": 501,
    "close_popup": 502,
})

SETTINGS = {   # per instance, keyed by the emulator's adb port
    5555: {"account": "main", "rounds": 20},
    5557: {"account": "alt-1", "rounds": 10},
    5559: {"account": "alt-2", "rounds": 10},
}
DEFAULT = {"account": "unknown", "rounds": 5}
TASK = "collector"
TIME_BUDGET_S = 15 * 60


def main():
    port = mas.get_current_device_port()
    settings = SETTINGS.get(port, DEFAULT)
    account = settings["account"]
    mas.log(f"Port {port}: account {account}, {settings['rounds']} rounds")

    done = mas.retrieve(TASK).get("done", 0)
    started = time.monotonic()
    misses = 0

    while done < settings["rounds"]:
        if time.monotonic() - started > TIME_BUDGET_S:
            mas.log(f"{account}: time budget reached", level="warning")
            break
        popup = mas.find_object(images.close_popup)
        if popup:
            mas.click(popup.x, popup.y, delay_ms=800)
            continue
        button = mas.find_object_retry(images.collect, total_tries=3, time_sleep=2.0)
        if button is None:
            misses += 1
            if misses >= 5:
                mas.log(f"{account}: five misses, giving up", level="error")
                sys.exit(2)
            continue
        misses = 0
        mas.click(button.x, button.y, delay_ms=1000)
        done += 1
        mas.save(TASK, {"done": done, "account": account})
        time.sleep(random.uniform(0.8, 2.5))

    total = sum(entry["data"].get("done", 0) for entry in mas.retrieve_all(TASK))
    mas.log(f"{account}: {done} rounds done; {total} across all instances")
    mas.webhook("account.finished", {"account": account, "port": port, "done": done})


if __name__ == "__main__":
    main()
```

`mas.webhook` envia um evento `custom.account.finished` aos endpoints inscritos em eventos personalizados; tire a linha se você não tiver nenhum. Quando o mapeamento crescer, mova-o para um formulário de argumentos e leia `args.<tab>.<key>` em vez do dicionário.

## O que pode dar errado

### A porta já está em uso

Outro dispositivo em um dos seus grupos é dono dessa porta. Cada porta pode ser adicionada uma vez; remova a entrada antiga ou escolha a porta da outra instância.

### Uma instância roda, as outras ficam em Conectando

As outras instâncias estão com o ADB desligado, ainda estão iniciando, ou escutam em portas fora da faixa do emulador. Abra as configurações de cada instância, confirme o ADB e a porta, e clique em **Atualizar** em **Adicionar dispositivo**. Se a porta fica fora da tabela acima, use **Porta personalizada**. Veja [Solução de problemas de ADB](/docs/adb-troubleshooting).

### Os templates correspondem em uma única instância

Aquela instância tem outra resolução ou DPI. O template matching é baseado em pixels; coloque toda instância na resolução da captura nas configurações de instância do emulador e reinicie. O [guia de reconhecimento de imagem](/docs/guides/image-recognition-macros) explica o resto.

### Toda instância compartilha um contador

O script passa um `port` ou `machine_id` explícito a `mas.save`, ou usa um arquivo em disco em vez do armazenamento. Chame `mas.save(TASK, data)` com os padrões; a porta atual é adicionada para você.

Nenhuma ferramenta de automação é 100% livre de riscos, por isso automatize com responsabilidade e a seu próprio critério.
