simple_eif_phone

Write an Android app in Eiffel, and get a signed APK from one command.

MIT License Android 8.0 or later Design by Contract

What you need

  • Windows, with EiffelStudio to build the eifphone tool.
  • Gobo gec 26.10.
  • The Android SDK and NDK: NDK 30.0.16248370, build-tools 36.0.0, platform android-36.
  • A JDK.
  • simple_mml 1.0.3 or later.

Run eifphone doctor to see what it found.

How the tool finds things

It looks in this order:

  1. The standard variables: JAVA_HOME, ANDROID_HOME or ANDROID_SDK_ROOT, ANDROID_NDK_HOME, GOBO, GOBO_LIBRARY, ISE_LIBRARY, SIMPLE_EIFFEL.
  2. The D:\android and D:\prod layout.
  3. A project's [tools] table, which overrides both.

Making a project

eifphone doctor                                       # are all the tools there?
eifphone new myapp --id io.github.me.myapp --label "My App"
eifphone build myapp                                  # signed APK in myapp/build/
eifphone run myapp                                    # install on the device, start, show the log
eifphone log myapp --crash                            # crash lines only
eifphone test examples/phone_tests                    # on-device tests (start drive.sh first)

eifphone.toml

[app]
id = "io.github.me.myapp"
label = "My App"
version_code = 1
version_name = "0.1.0"

[eiffel]
ecf = "app.ecf"
target = "app"

[android]
abis = ["arm64-v8a", "x86_64"]
min_sdk = 26
target_sdk = 36
java_helper = false

# [signing] omitted = the shared debug key (its password is public by design).
# debug_keystore = "keys/debug.jks"   # alone: keeps a project's debug key elsewhere
# Release: all three keys, and the password only through an environment variable.
# keystore = "D:/keys/myapp.jks"
# alias = "myapp"
# password_env = "MYAPP_KS_PASS"

An icon goes under [app] as icon. A missing icon file is a settings error.

Rules worth knowing

  • One thread. Android's lifecycle and input reach Eiffel through a pulled queue. Threads and SCOOP are not supported on the phone yet.
  • One Eiffel system per process. If Android starts the app again while it is ending, the process ends and Android starts it fresh.
  • Finish frames before waiting. wait_for_event requires not screen.in_frame.
  • Apps save their own state on paused. examples/touch_pad shows how.
  • Back: by default Android also handles it. set_back_policy (Back_app) keeps it for the app.
  • Keep work between waits short. Android's UI thread can be waiting on your poll.
  • Take frames while input keeps coming. Limit the events you take between frames, as examples/touch_pad does.

Contracts and speed

eifphone new writes two targets:

  • app has every contract on, for development.
  • app_fast has them off, for live drawing and other time-sensitive work. Set target = "app_fast" in eifphone.toml.

Write the assertion setting on the target and on each library, as the template does. A target using extends kept contracts on.

Why it matters: on the emulator, one stroke segment of the touch pad took 17 ms at first. Removing a system call that Android's setjmp makes brought it to 1.4 ms, for every phone build. Turning contracts off brought it to 6 microseconds.

Signing

  • Debug: with no [signing] table, the tool uses a shared debug key. Its password is public by design, so never use it for a release.
  • Release: give keystore, alias and password_env. The password travels only through that environment variable, never in a file or on a command line.

Testing on a phone over Wi-Fi

  1. Settings, About phone, Software information: tap Build number 7 times.
  2. Settings, Developer options, Wireless debugging: turn it on, then choose Pair device with pairing code.
  3. On the PC: adb pair <IP:port> <code>, then adb connect <IP:port>, using the port on the Wireless debugging screen.
  4. eifphone run myapp --device <IP:port>
If the phone is on a VPN, Wireless debugging may show the VPN's address, which the PC can't reach. Turn the VPN off while pairing.

When something goes wrong

  • A build stage failed: the tool prints the stage and its first error, and exits with code 4.
  • A device is not ready: the tool names it, for example a phone that has not allowed this PC.
  • More than one device: choose with --device <serial>.
  • The app crashed: eifphone log myapp --crash.
  • The pad or a live app feels slow: check that you built the app_fast target.

Known limitations

  • The tool runs on Windows only. Phone apps run on Android 8.0 (API 26) or later, on ARM64 and x86_64.
  • One thread. Threads and SCOOP are not supported on the phone yet.
  • Not yet: text entry (the keyboard), read-aloud, the file picker, SQLite, and running cairo, shaping and widgets on the phone.
  • An adb that never answers hangs the tool. The runner has no timeout. Stop the tool by hand if that happens.
  • eifphone run shows the first 3 seconds of the log. Use eifphone log for the rest.
  • On-device tests have run on the emulator only. Speed, multi-touch, Home and return, and rotation were checked by hand on one real ARM phone.
  • Two one-off failures are unexplained. tap_arrives failed once, in the first run after a stress session on a fresh emulator, then passed. One stress run stopped on a crash from a process that was not identified, and the same run passed when repeated.