Your First Android App with Fire and Water
Before You Start
This tutorial uses Fire on macOS and Water on Windows. The two IDEs use the same project format and Android toolchain, so the workflow is the same except where operating-system-specific paths or commands are shown.
Before creating your first Android app, make sure the Android SDK is installed and that you have at least one target to run on: an emulator, a USB-connected Android device, or a wireless Android device.
You can set up Android for Fire or Water in two different ways:
- Install Android Studio and let it manage the SDK and emulator.
- Skip Android Studio and install the Android command-line tools directly.
Path A: Install Android Studio
Download and install the current stable Android Studio release for your operating system from developer.android.com/studio.
On first launch, let the setup wizard finish and install the default Android components.
For this path, you do not need a separate package manager. Android Studio includes its own Java runtime and can manage the Android SDK, SDK tools, and emulator for you.
To create an emulator, open Android Studio's Welcome screen and choose More Actions → Virtual Device Manager:
For this tutorial, choose a recent Pixel phone profile. Here we use Pixel 10 Pro Fold:
Verify that the required Android components are installed. Click the gear icon in the lower-left corner and open Settings:
Then search for sdk and open Android SDK → SDK Tools:
Make sure these components are available:
- Android SDK Build-Tools
- Android SDK Command-line Tools (latest)
- Android Emulator
- Android SDK Platform-Tools
Optional: Create a Googlebook Desktop Emulator
At the time of writing, the Googlebook desktop profile is not yet consistently shown in Android Studio's device list. That will likely change, and after Google finishes rolling it out you should be able to select it directly in Device Manager. For now, if the profile is missing from the UI, create it from the command line.
Install the desktop system image first, then create the AVD with the hidden Google desktop hardware profile. Use the tab for your operating system:
macOS
ANDROID_SDK="$HOME/Library/Android/sdk"
"$ANDROID_SDK/cmdline-tools/latest/bin/sdkmanager" --channel=3 \
"system-images;android-37.0;android-desktop;arm64-v8a"
printf 'no\n' | "$ANDROID_SDK/cmdline-tools/latest/bin/avdmanager" create avd \
--name Googlebook_API_37 \
--package "system-images;android-37.0;android-desktop;arm64-v8a" \
--device desktop_api37
If you are on Intel Mac, replace arm64-v8a with x86_64.
Windows
$androidSdk = "$env:LOCALAPPDATA\Android\Sdk"
& "$androidSdk\cmdline-tools\latest\bin\sdkmanager.bat" --channel=3 `
"system-images;android-37.0;android-desktop;x86_64"
"no" | & "$androidSdk\cmdline-tools\latest\bin\avdmanager.bat" create avd `
--name Googlebook_API_37 `
--package "system-images;android-37.0;android-desktop;x86_64" `
--device desktop_api37
In the AVD's config.ini file, make sure this is set. The file is under ~/.android/avd/<YourAVD>.avd on macOS and %USERPROFILE%\.android\avd\<YourAVD>.avd on Windows:
hw.keyboard=yes
This is required if you want the emulator to accept input from the computer keyboard instead of always forcing the Android on-screen keyboard.
Then start the emulator with a clean boot:
macOS
"$ANDROID_SDK/emulator/emulator" \
-avd Googlebook_API_37 \
-no-snapshot-load
Windows
$androidSdk = "$env:LOCALAPPDATA\Android\Sdk"
& "$androidSdk\emulator\emulator.exe" -avd Googlebook_API_37 -no-snapshot-load
Path B: Command-Line Tools Only
This path installs everything needed to build and run Android apps without installing Android Studio. It uses Android API 37 and creates a Pixel 10 Pro Fold emulator.
macOS
First, install Homebrew if brew is not already available:
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
Then install JDK 21 or newer, the Android command-line tools, and the Android SDK packages Fire needs:
brew install --cask temurin@21
brew install --cask android-commandlinetools
SDK_ROOT="$HOME/Library/Android/sdk"
yes | sdkmanager --sdk_root="$SDK_ROOT" --licenses
sdkmanager --sdk_root="$SDK_ROOT" \
"platform-tools" \
"emulator" \
"platforms;android-37.0" \
"build-tools;37.0.0" \
"system-images;android-37.0;google_apis;arm64-v8a"
If you are on Intel Mac, replace arm64-v8a with x86_64.
With modern JDK layouts on macOS, the JRE folder should normally be the same path as the JDK root. Do not append /jre.
Android emulator command-line tools may not be available in Terminal by default, even if the Android SDK is installed. Locate the emulator and try it from the default SDK location:
find ~/Library/Android/sdk -name emulator -type f 2>/dev/null
~/Library/Android/sdk/emulator/emulator -list-avds
To make emulator and adb available in future Terminal sessions, add the SDK tools to your PATH:
echo 'export ANDROID_SDK_ROOT="$HOME/Library/Android/sdk"' >> ~/.zshrc
echo 'export PATH="$ANDROID_SDK_ROOT/emulator:$ANDROID_SDK_ROOT/platform-tools:$PATH"' >> ~/.zshrc
source ~/.zshrc
emulator -list-avds
adb devices
Create a phone emulator using the same Pixel 10 Pro Fold name used in Path A:
echo "no" | avdmanager create avd \
--name "Pixel_10_Pro_Fold" \
--package "system-images;android-37.0;google_apis;arm64-v8a" \
--device "pixel_10_pro_fold"
Then start it:
emulator -avd "Pixel_10_Pro_Fold"
The first boot can take a while. Leave the emulator running before switching back to Fire.
Windows
Open PowerShell and install JDK 21. Close and reopen PowerShell after winget finishes so that java is available in the new session:
winget install --exact --id EclipseAdoptium.Temurin.21.JDK `
--accept-package-agreements --accept-source-agreements
java -version
Download the current Android Command-line Tools package, verify its checksum, and install it in the standard per-user SDK folder:
$androidSdk = "$env:LOCALAPPDATA\Android\Sdk"
$toolsVersion = "15859902"
$toolsSha256 = "90ae805d20434428bffcb699c290860f19bb5f66a67e6b330067e3de801fb04a"
$archive = "$env:TEMP\commandlinetools-win-$toolsVersion.zip"
$unpackDir = "$env:TEMP\commandlinetools-win-$toolsVersion"
$toolsUrl = "https://dl.google.com/android/repository/commandlinetools-win-${toolsVersion}_latest.zip"
Invoke-WebRequest $toolsUrl -OutFile $archive
$actualSha256 = (Get-FileHash $archive -Algorithm SHA256).Hash.ToLowerInvariant()
if ($actualSha256 -ne $toolsSha256) {
throw "Command-line Tools checksum mismatch."
}
if (Test-Path "$androidSdk\cmdline-tools\latest") {
throw "Command-line Tools are already installed in $androidSdk."
}
Expand-Archive $archive -DestinationPath $unpackDir
New-Item -ItemType Directory "$androidSdk\cmdline-tools\latest" -Force | Out-Null
Copy-Item "$unpackDir\cmdline-tools\*" `
"$androidSdk\cmdline-tools\latest" -Recurse
$sdkManager = "$androidSdk\cmdline-tools\latest\bin\sdkmanager.bat"
if (-not (Test-Path $sdkManager)) {
throw "sdkmanager.bat was not installed correctly."
}
Remove-Item $archive
Remove-Item $unpackDir -Recurse
Set the Android SDK variables for the current session and persist them for future PowerShell, Water, and command-line sessions:
$androidSdk = "$env:LOCALAPPDATA\Android\Sdk"
$androidTools = @(
"$androidSdk\platform-tools",
"$androidSdk\emulator",
"$androidSdk\cmdline-tools\latest\bin"
)
$env:ANDROID_HOME = $androidSdk
$env:ANDROID_SDK_ROOT = $androidSdk
$env:Path = ($androidTools -join ";") + ";" + $env:Path
[Environment]::SetEnvironmentVariable("ANDROID_HOME", $androidSdk, "User")
[Environment]::SetEnvironmentVariable("ANDROID_SDK_ROOT", $androidSdk, "User")
$userPath = [Environment]::GetEnvironmentVariable("Path", "User")
foreach ($path in $androidTools) {
if ($userPath -notlike "*$path*") {
$userPath = "$userPath;$path"
}
}
[Environment]::SetEnvironmentVariable("Path", $userPath.Trim(";"), "User")
Accept the Android SDK licenses, then install the API 37 platform, Build-Tools, emulator, platform tools, and the x86_64 system image:
$androidSdk = "$env:LOCALAPPDATA\Android\Sdk"
$sdkManager = "$androidSdk\cmdline-tools\latest\bin\sdkmanager.bat"
(1..100 | ForEach-Object { "y" }) | `
& $sdkManager --sdk_root="$androidSdk" --licenses
& $sdkManager --sdk_root="$androidSdk" `
"platform-tools" `
"emulator" `
"platforms;android-37.0" `
"build-tools;37.0.0" `
"system-images;android-37.0;google_apis;x86_64"
Create the Pixel 10 Pro Fold emulator and verify that Windows hardware acceleration is available:
$androidSdk = "$env:LOCALAPPDATA\Android\Sdk"
"no" | & "$androidSdk\cmdline-tools\latest\bin\avdmanager.bat" create avd `
--name "Pixel_10_Pro_Fold" `
--package "system-images;android-37.0;google_apis;x86_64" `
--device "pixel_10_pro_fold"
& "$androidSdk\emulator\emulator.exe" -accel-check
& "$androidSdk\emulator\emulator.exe" -avd "Pixel_10_Pro_Fold"
If the acceleration check fails, enable CPU virtualization in the computer's BIOS/UEFI and enable Windows Hypervisor Platform in Windows Features. The first emulator boot can take a while. Leave it running before switching back to Water.
Use a Physical Android Device Instead
You can also run the app on a real Android device. For USB, enable Developer Options and USB debugging on the device, connect it to the computer with a data cable, accept the RSA debugging prompt, and verify that adb can see it:
adb devices
If the device appears as device, Fire or Water should be able to deploy to it.
On Windows, some devices also require the manufacturer's USB driver. Install it if the device does not appear in adb devices even after USB debugging is enabled.
For Wi-Fi debugging, keep the computer and Android device on the same local network. On the device, open Developer Options → Wireless debugging, choose Pair device with pairing code, and run:
adb pair IP_ADDRESS:PAIRING_PORT
adb connect IP_ADDRESS:CONNECTION_PORT
adb devices
The pairing port and connection port are usually different. Use the values shown on the Android device.
The first time you start Fire on macOS or Water on Windows, before opening or starting a new project, the IDE presents the Welcome Screen pictured below. You can also open it later with the "Window|Welcome" menu command.
In addition to logging in to your remobjects.com account, the Welcome Screen allows you to perform three tasks, two of which you will use now.


On the bottom left, you can choose your preferred Elements language. Fire and Water support writing code in Oxygene, C# and Swift. Picking an option here will select what language will show by default when you start new projects or add new files to a multi-language project (Elements allows you to mix all five languages in a project, if you like).
This tutorial will cover all languages. For code snippets, and for any screenshots that are language-specific, you can choose which language to see in the top right corner. Your choice will persist throughout the article and the website, though you can of course switch back and forth at any time.
After picking your default language (which you can always change later in Preferences), click the "Start a new Project" button to open the New Project dialog:
When Android Studio and the Android SDK are installed in their default locations, Fire and Water will usually detect them automatically. You normally only need to check the IDE's Base Paths later if the Run button stays inactive or Android targets do not appear.


You will see that your preferred language is already pre-selected at the top right – although you can of course always choose a different language just for this one project.
On the top left you will select the platform for your new application. Since you're going to build an Android app, you can select Java. This filters the third list down to show all Java-based templates only. Drop down the big popup button in the middle and choose the "Android Application" project template, then click "OK".
Next, you will select where to save the new project you are creating:
Use the standard save dialog for your operating system to pick a location and name for the project, then click "Create Project" in Fire or confirm the dialog in Water. You can ignore any additional options for now.
You might be interested to know that you can set the default location for new projects in Preferences. Setting that to the base folder where you keep all your work, for example, saves you from having to find the right folder each time you start a new project.
Note: Android projects are required to be named lowercase, and have a dotted name, usually using a reverse domain notification. By default, Fire will use org.me. as prefix for project names, but you can configure a different default,such as your company's domain, in Preferences.
When you create apps for publishing in the Google Play Store, make sure to use a unique prefix that you "own".
Once the project is created, Fire opens its main window, showing you a view of your project:
Let's have a look around this window. This is the main view of Fire or Water, where you will do most of your work.
The Fire and Water Main Window
At the top, you will see the toolbar, and above that the name MyFirstApp.sln. MyFirstApp is the name you gave your project, but what does .sln mean? Elements works with projects inside a Solution. You can think of a Solution as a container for one or more related projects. Fire and Water always open a solution, not a project – even if that solution contains only a single project, as it does here.
In the toolbar itself are buttons to build and run the project, as well as a few popup buttons that let you select various things. We'll get to those later.
The left side of the Fire or Water window is made up by what we call the Navigation Pane. This pane has various tabs at the top that allow you to quickly find your way around your project in various views. For now, we'll focus on the first view, which is active in the screenshot above, and is called the Project Tree.
You can hide the Navigation Pane at any time to let the main view (which we'll look at next) fill the whole window. You can also reopen the Project Tree from the View menu whenever the Navigation Pane is hidden or showing a different tab.
The Project Tree
The Project Tree shows you a full view of everything in your project (or projects). Each project starts with the project node itself, which is larger, and selected in the screenshot above, as indicated by its blue background. Because it is selected, the main view on the right shows the project summary. As you select different nodes in the Project Tree the main view adjusts accordingly.
Each project has three top level nodes.
-
Settings gives you access to all the project settings and options for the project. Here you can control how the project is built and run, what exact compiler options are used, etc. The project settings are covered in great detail here.
-
References lists all the external frameworks and libraries your project uses. As you can see in the screenshot, the project already references all the most crucial libraries by default (we'll have a look at these later), and you can always add more by right-clicking the References node and choosing "Add Reference" from the context menu. You can also drag references in directly from Finder on macOS or File Explorer on Windows, as well as remove unnecessary references. Please refer to the References topic for more in-depth coverage.
-
Files, finally, has the meat of your application. This is where all the files that make up your app are listed, including source files, images and other resources.
The Main View
Lastly, the main view fills the rest of the window (and if you hide the Navigation Pane, all of the window), and this is where you get your work done. With the project node selected, this view is a bit uninspiring, but when you select a source file, it will show you the code editor in that file, and it will show specific views for each file type.
When you hide the Navigation Pane, you can still navigate between the different files in your project via the Jump Bar at the top of the main view. Click on the "MyFirstApp" project name, and you can jump through the full folder and file hierarchy of your project, and more.
Your First Android Project
Let's have a look at what's in the project that was generated for you from the template. This is already a fully working app that you could build and launch now. It will not do much yet, but the basic Android project structure is already in place.
The project contains one or more activity classes. Android apps can consist of several activities, and each activity represents a screen, task, or entry point that the app exposes to the system. One activity is marked as the launcher activity, and that is the one Android opens when the user taps your app icon.
The project also contains Android resources under the res folder, such as icons, strings, and XML layout files. In current Fire Android templates, the main screen layout is typically stored as res/layout/main.xml.
Finally, there is the AndroidManifest file. This XML file provides Android and the Google Play Store with basic information about your app, such as its name, icon, permissions, and activities. For this tutorial, the pre-created manifest will do fine, but you can read more about this file format and how to change it here.
Modern Android Concepts
Modern Android UI development is Compose-first, especially for new Kotlin apps. This tutorial uses the classic Android View/XML system because it maps directly to the current Fire and Water Android templates and resource workflow.
Activities are still Android entry points, even when the UI technology changes. A launcher activity starts the app, loads the initial UI, and connects the app to Android lifecycle events.
Resources remain central to Android development. Layouts, strings, icons, and generated IDs live under res, and the build system exposes them to code through generated resource identifiers such as R.layout.main.
The Main Activity
As mentioned before, the Main Activity is the first screen the user sees when launching the app. In the Fire and Water Android templates, the activity class contains the code for that screen, while the XML layout in res/layout describes the View hierarchy that Android displays.
Depending on the exact template, Fire may load the layout directly in onCreate() or through a helper method on a shared base activity. The important idea is the same: the activity points Android at the layout resource for the screen, such as R.layout.main.
method MainActivity.onCreate(savedInstanceState: Bundle);
begin
inherited;
// Set our view from the "main" layout resource
ContentView := R.layout.main;
end;
public override void onCreate(Bundle savedInstanceState)
{
base.onCreate(savedInstanceState);
// Set our view from the "main" layout resource
ContentView = R.layout.main;
}
public override func onCreate(_ savedInstanceState: Bundle!) {
super.onCreate(savedInstanceState)
// Set our view from the "main" layout resource
ContentView = R.layout.main
}
R.layout.main refers to the generated resource ID for res/layout/main.xml. You use these generated IDs from code, but you do not edit the generated R file directly.
Layouts
Next, let's look at the res/layout/main.xml file.
Fire uses Android's standard XML View layout format for this template. XML layouts are no longer the default recommendation for brand-new Kotlin Android apps, where Jetpack Compose is the modern first choice, but they remain a supported Android UI system and are still the right model for this Fire template.
Fire and Water offer two ways to work with these layouts. The first option is to edit the XML directly in the IDE's code editor. Select res/layout/main.xml in the project tree and edit the View hierarchy, attributes, and resource references as plain text.
The second option is to use the XML visual designer provided by Android Studio. If you have Android Studio installed and set up, right-click the project node and choose "Edit User Interface Files in Android Studio".

Fire will create or update an Android Studio project wrapper and launch Android Studio for editing the layout resources. As you make changes in Android Studio, save them and switch back to Fire; the XML files in your Fire project will be updated as well.
After Android Studio starts, open the XML layout editor for res/layout/main.xml. For this tutorial, add a simple vertical layout with a text field, a button, and a text label for the greeting:

Use a vertical LinearLayout for the root or main content area. Android layouts use density-independent units, flexible containers, and resource references so the same UI can adapt across phones, foldables, tablets, and desktop-style Android devices.
Set the id property of the text field to nameField, the button to sayHelloButton, and the greeting label to helloText. These IDs will be used from code in the next step.
When you're done, press ⌘S in Fire or Ctrl+S in Water to save, then switch back to the Elements IDE. You will notice that res/layout/main.xml has changed to contain the controls you added. If you want, you can continue tweaking the layout here in plain XML:

Each control you give an ID receives an android:id attribute in the XML, with a value starting with @+id/. This tells Android to define a new resource ID that can then be used from code, for example as R.id.nameField.
Working with Views from Code
Going back to the MainActivity source, let's hook up some code to the UI you just created.
Classic Android View/XML interaction is explicit. The activity loads a layout resource, but Android does not automatically generate fields or event handlers for the controls in that layout.
Instead, you look up controls by their ID as needed with the findViewById method exposed on the Activity class. For example, to find the button, write:
var button := findViewById(R.id.sayHelloButton) as Button;
var button = findViewById(R.id.sayHelloButton) as Button;
let button = findViewById(R.id.sayHelloButton) as! Button
Note how a typecast to Button is needed to get the correct type – since findViewById() can be used to locate any type of control, it is defined to return a View, the base class of all visual controls.
Once the control is obtained, you can work with the class as you would expect. For example, you could set its Text property to a new value to change the button's caption. In the above example, the control is stored in a local variable – but if you find that you need to reference a given control a lot, you can of course also define a field or property in your class and assign that inside onCreate() for future reference.
Events
For this example, the activity assigns a handler for the button so the app can react when the user taps it. In the classic Android View system, interactive controls expose listener APIs, such as View.OnClickListener, that are called when UI events happen.
In this case, View.OnClickListener expects a single callback, so the easiest way to assign a handler is to use regular anonymous method syntax:
button.OnClickListener := method (v: View) begin
// on-Click code goes here
end;
button.OnClickListener = (View v) => {
// on-Click code goes here
};
button.OnClickListener = { (v: View!) in
// on-Click code goes here
}
Note: Oxygene and Silver provide a special syntax to define an anonymous class with more than one method, as well. C# does not have such a syntax, so other mechanisms like a nested class can be used, if needed.
button.OnClickListener := new class View.OnClickListener(onClick := method (v: View) begin
// on-Click code goes here
end);
button.OnClickListener = class View.OnClickListener {
func onClick(_ v: View!) {
// on-Click code goes here
}
}
Inside this handler, look up the remaining two controls with findViewById, read the Text property from the text field, and update the greeting label:
var nameField := findViewById(R.id.nameField) as EditText;
var helloText := findViewById(R.id.helloText) as TextView;
helloText.Text := 'Hello from Oxygene, '+nameField.Text;
var nameField = findViewById(R.id.nameField) as EditText;
var helloText = findViewById(R.id.helloText) as TextView;
helloText.Text = "Hello from C#, "+nameField.Text;
let nameField = self.findViewById(R.id.nameField) as! EditText
let helloText = self.findViewById(R.id.helloText) as! TextView
helloText.Text = "Hello from Silver, "+nameField.Text
And that's it!
The complete onCreate method should now look something like this:
method MainActivity.onCreate(savedInstanceState: Bundle);
begin
inherited;
// Set our view from the "main" layout resource
ContentView := R.layout.main;
var button := findViewById(R.id.sayHelloButton) as Button;
button.OnClickListener := method (v: View) begin
var nameField := findViewById(R.id.nameField) as EditText;
var helloText := findViewById(R.id.helloText) as TextView;
helloText.Text := 'Hello from Oxygene, '+nameField.Text;
end;
end;
public override void onCreate(Bundle savedInstanceState)
{
base.onCreate(savedInstanceState);
// Set our view from the "main" layout resource
ContentView = R.layout.main;
var button = findViewById(R.id.sayHelloButton) as Button;
button.OnClickListener = (View v) => {
var nameField = findViewById(R.id.nameField) as EditText;
var helloText = findViewById(R.id.helloText) as TextView;
helloText.Text = "Hello from C#, "+nameField.Text;
};
}
public override func onCreate(_ savedInstanceState: Bundle!) {
super.onCreate(savedInstanceState)
// Set our view from the "main" layout resource
ContentView = R.layout.main
let button = findViewById(R.id.sayHelloButton) as! Button
button.OnClickListener = { (v: View!) in
let nameField = self.findViewById(R.id.nameField) as! EditText
let helloText = self.findViewById(R.id.helloText) as! TextView
helloText.Text = "Hello from Silver, "+nameField.Text
}
}
Running Your App
You're now ready to run your app on an Android device or in the emulator.
Earlier on we looked at the top toolbar in Fire or Water. In the middle of the toolbar, you will find a popup button that is the device selector, which should by default be set to "Android Device". That is a placeholder that is available whether you have an actual device connected (and/or an emulator set up) or not. However, because "Android Device" does not represent a real device, you cannot run your app on it.
If you open the popup, you will see an entry for any real Android device connected to your computer, as well as for any emulator or remote/wireless device you have connected to, along with details about the device type and OS version.
If you do not see any devices, refer to Working with Devices to learn how to get set up with the various options.


If the Run button is inactive, open the IDE's Base Paths tab and confirm that the Android SDK and JDK were detected correctly:


Typical paths are:
- macOS JDK folder:
/Library/Java/JavaVirtualMachines/jdk-21.jdk/Contents/Home - macOS Android folder:
/Users/your-user/Library/Android/sdk - Windows JDK folder: your installed JDK, typically under
C:\Program Files\Eclipse Adoptiumwhen using Path B - Windows Android folder:
C:\Users\your-user\AppData\Local\Android\Sdk
For current JDK layouts, the JRE folder can normally use the same path as the JDK folder.
Select the device you want to run on. When done, you can hit the "Play" button in the toolbar, press ⌘R in Fire, or press Ctrl+R in Water.
Fire or Water will now build your project, deploy it, and launch the app. While the project is compiling, the Jump Bar turns blue and shows the current progress. The application icon also indicates that a build is in progress, so you can keep an eye on it from the macOS Dock or Windows taskbar after switching away from the IDE.
If there are any build errors, the Jump Bar and application icon turn red. Use the Jump Bar to open the first error message. Otherwise, a few seconds later (or minutes, if you are using the emulator), your app will appear.
Type in your name, press the "Say Hello" button, and the app will update the greeting text.