Developing mobile iOS applications on GNU/Linux with Re-Natal
Unfortunately, to run the iOS simulator and do any kind of iOS development you need a macOS and the XCode IDE. If you’re like me, my Linux setup is just paramount to my productivity and I can’t imagine working without e.g. a tiling window manager or keyboard shortcuts perfected by the years of practice :)
In this blog post I will show you the setup and workflow that allows you to write your code in the OS and code editor of your choice1, while still running the iOS simulator.
Re-Natal is a CLI tool to automate the setup of a React Native app running on ClojureScript. In a few simple commands it will bootstrap a skeleton application with reagent + re-frame, REPL and hot reloading (using Figwheel) directly to the simulated iOS device, just like you would if it was a web app running in a browser.
If you like the idea let’s get started.
We are going to install all the neccessary development tools on the host machine, and just the bare minimum required to run the iOS simulator on a guest macOS running in a VirtualBox, then make the two machines talk to each other via forwarded ports.
Begin by insatlling VirtualBox 6.X for your distribution, you can get it from here or directly from your OS repositories:
sudo apt install virtualbox virtualbox-dkms virtualbox-ext-pack virtualbox-guest-additions-iso virtualbox-guest-utils virtualbox-qt
Now download the vmdk with macos, for example from Techsviewer. Launch VB and create new virtual machine from the image. Make sure to name the VM without using spaces (e.g. macos). Give the machine at least 2 cores, 4GB of RAM, and 128MB of graphics with 3D acceleration turned on, set the VB Network Adapter to Bridged:
Save the script, make it executable and call it with the name of your vm and the desired resolution as the arguments:
./setup.sh -v "macos" -r 1920x1080
Launch VirtualBox again and start the MacOS VM.
Once the VM boots you can install the XCode version for the MacOS version you are running:
You can use the App Store, or for the older versions of the IDE they can be downloaded from here.
Once installed launch Xcode, select menu > Preferences > Locations and choose your Xcode version from the dropdown:
For bidirectional data communication between the Linux host and macOS guest we will use socat. MacOS doesn’t have a native package manager, therefore we will need Homebrew installed. Start the Terminal and install it:
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
then using homebrew install socat:
brew install socat
We are done with the guest for now, lets go to the host and create our project.
Lets start by installing re-natal and react-native. Both come as convenient node packages, that we can install globally:
npm install -g re-natal react-native
You will also need Leiningen and Java 8, but we won’t cover installing them here.
Once that’s done we can create the skeleton app. Mind the CamelCase in the apps name:
re-natal init AppName -i reagent6
Now execute some basic setup commands that will bootstrap the app as an iOS project:
re-natal use-ios-device simulator
Instead I opted for using the samba server. Every major Linux distro should have it in its repositories:
sudo apt-get install samba
Now create a user (samba will prompt you for the password):
sudo smbpasswd -a <user_name>
Next edit the samba config:
sudo nano /etc/samba/smb.conf
Add to the end of the config, substitutting path with the path to the just created re-natal project and user with the created samba user:
path = /home/<user_name>/<folder_name>
valid users = <user_name>
read only = no
You can test the config file for configuration errors by calling:
testparm on the command line.
If all is fine with the config, go ahead and start the Samba service daemon plus enable it at startup:
systemctl restart smbd
systemctl enable smbd
We will now start the react-native packager, binding it to port 8081 and broadcasting on 0.0.0.0:
react-native start --host 0.0.0.0 --port 8081
Next we can start Figwheel, which will give us the REPL, as well as watch and recompile on source code changes:
lein figwheel ios
Figwheel will recompile the sources and just hang for now, waiting for connection with the simulator to give us the REPL, but not before printing the port on which it is running (3449 by default).
Last piece of information we need is the local IPv4 address of the host (e.g.
192.168.1.3), which we can get with:
Now let’s go back to the guest OS.
On the guest we can now start listening on the ports occupied by the react-native and Figwheel servers:
socat tcp-listen:3449,reuseaddr,fork tcp:192.168.1.3:3449
socat tcp-listen:8081,reuseaddr,fork tcp:192.168.1.3:8081
Next lets mount the shared folder.
Click on the Go -> connect to server…, paste
smb://192.168.1.3 and click on Connect:
When prompted for the username and password use the ones created when Sharing the project folder.
by default the directory is mounted as
Open this directory in XCode, wait until it indexes the project and run it.
Once the project is up and running Figwheel on the host box should now give you a fully functional REPL, with live reloading on code edits:
From now on the workflow is quite snappy and un-obtrusive, you can for example keep you editor and the simulator tiled one next to the other and quickly iterate during development.
Thanks for reading!