DEV Community

Cover image for Como emular um iOS no Linux utilizando Docker
Iaan Mesquita
Iaan Mesquita

Posted on • Edited on

Como emular um iOS no Linux utilizando Docker

English version: How to emulate iOS on Linux with Docker

Depois de várias tentativas sem sucesso, enfim consegui virtualizar um macOS para fazer testes em um aplicativo iOS no qual eu estava trabalhando.

Mas antes de continuar, é necessário saber que essa não é uma solução estável e possue diversos problemas de desempenho, porém, para meu propósito consegui fazer o que queria.

Nós utilizaremos o QEMU para emular um macOS e dentro dele, utilizaremos o xCode para emular um iOS, só nisso você já consegue perceber que não vai ser uma coisa leve.

O repositório no github do Docker OSX tem uma explicação de como usar um iPhone via usb ao invés de emular, mas eu não tenho iPhone :p

Sumário

O que é o Docker OSX

O Docker OSX é uma docker image que utiliza por debaixo dos panos o QEMU para que possamos emular um sistema operacional.

Leia mais: O que é docker?

Minhas especificações de hardware

As especificações do meu computador são consideradas OK pra fazer isso, porém, ainda consegui perceber algumas engasgadas enquanto utilizava o Docker OSX + xCode + Visual Studio Code + Dev Server. (Consegui até aquecer meu quarto com esse tanto de coisa.)

  • OS: Manjaro Linux x86_64
  • Kernel: 4.19.220-1-MANJARO
  • Shell: zsh 5.8
  • Resolution: 1440x900
  • DE: GNOME 41.2
  • WM: Mutter
  • WM Theme: Orchis-orange-compact
  • Icons: Win11-purple-dark [GTK2/3]
  • Terminal: gnome-terminal
  • CPU: Intel i7-3770 (8) @ 3.900GHz
  • GPU: NVIDIA GeForce GTX 1050 Ti
  • Memory: 4105MiB / 15985MiB
  • SSD: Crucial BX500 240gb (Altamente recomendado um SSD)

Instalação

Primeiramente, é necessário ter o docker instalado no seu computador. No meu caso eu utilizo Manjaro, então basta abrir o terminal e digitar:

Instalação docker
pacman -S docker

Ativando os serviços do docker
systemctl start docker.service

Ativando os serviços do docker para iniciar junto com o sistema
systemctl enable docker.service

Testando o docker:
docker run hello-world

Docker run hello-world

Certo, agora iremos baixar a imagem e executa-la utilizando o comando abaixo:
docker run -it --device /dev/kvm -p 50922:10022 -e DEVICE_MODEL="iMacPro1,1" -e WIDTH=1440 -e HEIGHT=900 -e RAM=8 -e INTERNAL_SSH_PORT=23 -e AUDIO_DRIVER=alsa -e CORES=2 -v /tmp/.X11-unix:/tmp/.X11-unix -e "DISPLAY=${DISPLAY:-:0.0}" -e GENERATE_UNIQUE=true -e MASTER_PLIST_URL=https://raw.githubusercontent.com/sickcodes/osx-serial-generator/master/config-custom.plist sickcodes/docker-osx:big-sur

Você pode conferir o que cada flag significa olhando o repositório no github do docker osx, mas resumidamente, especifiquei a resolução, memória ram, cores do processador, versão big-sur do macOS e etc.

Em seguida, ele irá baixar a imagem e executar.

Quando abrir o emulador, de enter na opção macOS Base System

Emulador Docker OSX

Quando carregar o sistema, clicaremos em Disk Utility
Emulador Docker OSX

Agora, procuraremos a partição que está com mais espaço de armazenamento e clicaremos na opção Erase
Docker OSX apagando sistema

Para formatar é preciso que as opções estejam estritamentes iguais a esta:
Formatação opções

Clique em Erase, aguarde e pode fechar a janela do Disk Utility.

Em seguida, iremos em Reinstall macOS Big Sur aceitamos os termos, selecionamos a partição que acabamos de criar macOS e nisso, ele começará a instação do sistema. (Esse processo geralmente leva 30min ~ 1h).
Docker OSX Instalação

Aguardado esse tempo, o sistema deve reiniciar (ou não), no meu caso, eu tive que fazer isso de forma manual pois ele não reiniciou. Nesse caso, feche a janela do QEMU.

Qemu error

Novamente no terminal, digitaremos:

docker ps -a

Para saber qual o ID do nosso container, e em seguida iremos inicia-lo com:

docker start ID

Docker IDS

Selecione o macOS Installer e deixe que a instalação continue.
Docker OSX Instalação

Após o processo, ele irá reiniciar automaticamente (ou não), sendo assim, feche novamente o emulador e dê start no container mais uma vez.

Docker OSX Instalação

Ao iniciar, novamente selecione a opção macOS Installer e aguarde o processo terminar, feito isso ele irá reiniciar. (Agora é verdade).

Nosso macOS foi instalado, com isso, vamos selecionar a opção macOS.
Docker OSX Inicialização

Feito isso, irá reiniciar novamente e você selecione a mesma opção macOS.

Show, nossa tela de bem vindo apareceu. Essa parte é bastante lenta, mas após isso irá ficar normal.

Tela de bem vindo macOS

Configure a sua maneira, mas não faça login no AppleID agora.

Após esse processo, nossa área de trabalho aparecerá e então iremos aguardar até a dock aparecer, pois após isso o sistema fica mais fluído.

Tela de instalação mac OS Sem dock

Tela de instalação mac OS Com dock

Agora iremos utilizar o gerenciador brew para instalar as coisas mais rapidamente.

Abra o terminal no macOS e instale o brew com o comando:
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

Irá pedir sua senha definida anteriormente para instalar.

Agora iremos instalar o xcode na apple store.

Apple store xcode

Agora sim, podemos fazer o login da nossa conta AppleID.

Login apple store

Feito isso, aguarde a instalação.
Em seguida, abra o xcode e aceite os termos e aguarde instalar as dependências.

Em seguida, vá em Preferences -> Locations -> Command-Line Tools vai estar vazio, selecione a opção com a versão do xcode.

Quando a instalação terminar, abriremos o terminal novamente e instalaremos o cocoapods. Ele serve como um gerenciador de dependências do xCode.

brew install cocoapods

Feito isso, nosso macOS está instalado e configurado para rodar os projetos.

Rodando um app com React Native

Vamos rodar um hello world do React Native para ver se está tudo certo, lembrando que não irei testar o android somente o iOS.

Abra o terminal

Instalação no node:
brew install node

Instalação do yarn (opcional):
npm install -g yarn

Criando um projeto react native:
npx react-native init teste

Se pedir pra instalar o cocoapods novamente, selecione a opção com brew.

Entrando no diretório do react native:
cd teste

Entrando no diretório do ios:
cd ios

Instalando as dependências:
pod install

Voltando para o diretório raiz:
cd ..

Listando os simuladores disponíveis: (Opcional)
xcrun simctl list devices

Rodando o projeto utilizando xcode:
npx react-native run-ios --simulator="iPhone 13"
App rodando react native

Para uma experiência melhor, veja a seção: Criando uma conexão de pastas utilizando o sshfs

Rodando um app com Cordova

Vamos rodar um hello world do Quasar para ver se está tudo certo, lembrando que não irei testar o android somente o iOS.

Lembrando que o Quasar usa o Cordova/Capacitor pro iOS e Android.

Instalação no node:
brew install node

Instalação do yarn (opcional):
npm install -g yarn

Instalação do quasar:
yarn global add @quasar/cli

Instalação do cordova:
yarn global add cordova

Criando um projeto com Quasar-CLI:
quasar create teste

Entrando no diretório do projeto:
cd teste

Adicionando cordova ao projeto:
quasar mode add cordova

Entrar no diretório do cordova:
cd src-cordova

Adicionar o iOS ao projeto:
cordova platform add ios

Verificar se está tudo certo:
cordova requirements

Listar emuladores disponíveis: (Opcional)
cordova emulate iOS --list

Instalar as dependências do projeto:
yarn

Voltar ao diretório raiz:
cd ..

Instalar as dependências do projeto:
yarn

Rodar o quasar no modo desenvolvimento ioS:
quasar dev -m iOS -e "iPhone 8, 15.2"
macOS quasar

Para uma experiência melhor, veja a seção: Criando uma conexão de pastas utilizando o sshfs

Criando uma conexão de pastas utilizando o sshfs

Agora que fizemos tudo e nosso app já está rodando no macOS, temos um problema: Abrir nosso editor de código ou IDE dentro do macOS é uma experiência muito ruim por causa da lentidão, glitches, mapping do teclado e etc. Dessa forma, eu pesquisei uma solução para criar uma conexão de arquivos utilizando o SSH.

Ou seja, eu posso abrir o servidor de desenvolvimento dentro do macOS e criar uma conexão em que eu possa alterar os arquivos direto do meu linux ou do macOS, de forma que atualize em ambos os lados, como uma via dupla. Isso nos garante tirar o proveito de algumas coisas que existem no modo desenvolvimento, como o fast refresh.

Conexão do Linux para o Mac

Primeiramente, precisamos permitir a conexão via ssh por login no mac. Para isso, abriremos o terminal e digitaremos:

Comando para abrir editar o arquivo de configuração do ssh:
sudo nano /etc/ssh/sshd_config

Busque por PasswordAuthentication e coloque a configuração como yes e remova o # no começo da linha.

Configuração sshd

Salve o arquivo.
Vá para em System Preferences -> Sharing -> Remote Login e ative para todos os usuários:

macOS configuração

Comando para reiniciar o ssh:
sudo launchctl stop com.openssh.sshd && sudo launchctl start com.openssh.sshd

Agora, no terminal do nosso Linux:

Instalação do sshfs:
sudo pacman -S sshfs

Pegando o IP do nosso container
docker inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' ID_CONTAINER

Criar uma pasta:
mkdir projeto

Comando para abrir a conexão:
sudo sshfs USER_MAC@IP_CONTAINER:/CAMINHO/DO/PROJETO/NO/MAC /CAMINHO/NO/LINUX -p 23

Exemplo:

Exemplo de conexão

Pronto, agora eu posso abrir o visual studio code no meu Linux e atualizar diretamente no Mac.

Se você tiver um outro computador, pode fazer essa conexão também e deixar o seu principal apenas pra emular.

Conexão do Mac para o Linux

Mesmo processo anteriormente, só que o pacote do ssfs no mac pode ser instalado pelo comando abaixo.

Instalação sshfs no mac
brew install --cask macfuse && brew install gromgit/fuse/sshfs-mac

No Linux:

Comando para abrir editar o arquivo de configuração do ssh:
sudo nano /etc/ssh/sshd_config

Busque por PasswordAuthentication e coloque a configuração como yes e remova o # no começo da linha.

Configuração sshd

Salve o arquivo.

Comando para reiniciar o SSH no Manjaro:
sudo systemctl restart sshd.service

De volta ao mac, criaremos uma pasta e abriremos a conexão.

Criar uma pasta:
mkdir projeto

Comando para abrir a conexão:
sudo sshfs USER_LINUX@IP_HOST:/CAMINHO/LINUX /CAMINHO/MAC -p 23

Após rodar o comando, irá acontecer um erro:

Erro MAC

Abra as prefêrencias e clique em Allow

MacOS Preferencias

Reincie o mac.

Agora podemos abrir nossa conexão: (Meu SSH está com uma porta diferente, mas a padrão é 22)

Conexão SSH OK

Feito isso, podemos atualizar de qualquer lado que também irá atualizar.

Considerações finais

Muito obrigado por ler este tutorial, que aliás, é o primeiro que publico depois de anos. Qualquer dúvida ou sugestão é sempre bem vinda.

Ah, nunca atualize o mac.

:)

Top comments (12)

Collapse
 
duard profile image
Carlos Eduardo

Excelente post camarada... único porém é que minha memória de vídeo ficou bem lenta. Com 7mb apenas.

Collapse
 
ianito profile image
Iaan Mesquita • Edited

Olá, muito obrigado mano.
Então, suas config são boas? Pq não sei como funciona no Mac, se ele pega a memória ram q passamos e dedica uma parte ao vídeo. Mesmo eu usando 8gb dava uns lags bem pequenos.

Collapse
 
duard profile image
Carlos Eduardo • Edited

A minha máquina é razoávelmente boa cara... Achei muito lento dar boot tanto quando carrega o install quanto quando carrega o processo de boot do macos ...
AMD Ryzen 9 5900X
48GB ram 3600mhz
gtx 1050 ti
ASUS TUF Gaming X570-PLUS
Corsair mp600 pro gen4 pcie x4 nvme m.2 ssd 1tb

PC

Collapse
 
duard profile image
Carlos Eduardo

um detalhe é que eu tentei fazer via Windows 11 (com e sem wsl2), quando estiver com paciência booto no Ubuntu e tento novamente.

Thread Thread
 
ianito profile image
Iaan Mesquita

Estranho mesmo, aqui comigo deu 41 segundos desde a inicialização do container até a tela de loading da apple e até a tela de login foi +4 segundos. Depois tenta lá e da o feedback pra gente. Se tua máquina é razoavelmente boa, tadinha da minha...

Thread Thread
 
duard profile image
Carlos Eduardo

Acabei de bootar no Ubunto e testar... diferença gritante, muiiiiito rápido, e estou em um SSD sata 3 de 450GB

Thread Thread
 
ianito profile image
Iaan Mesquita

Show!!!

Thread Thread
 
duard profile image
Carlos Eduardo

o problema maior é a resolução ... e também tentei com o Moterey, ai sim fica muito ruim.

Collapse
 
buriti97 profile image
buridev

Post muito bom, man

Collapse
 
ianito profile image
Iaan Mesquita

Obrigado!!

Collapse
 
kenjimaeda54 profile image
Kenji

Quando desejo iniciar novamente meu macOs qual comando seria?

Collapse
 
ianito profile image
Iaan Mesquita

Oi, você vai listar os container novamente:
docker ps -a

É vai iniciá-lo com docker start ID

Feito isso, ele vai abrir o emulador e basta você selecionar o macOS novamente.
:D