21. December 2022

Rust Bare Metal application for ESP32, desktop, Android and iOS

Rust language and tooling are very powerful. It makes it easy to build for different platforms and architectures and still have performance close to C language.

It’s possible to write the same application for ESP32 with Xtensa architecture or ESP32-C3 RISC-V architecture. The portability of Rust code is high. Changing the target and adding a few wrapper functions makes it possible to build the same application for the desktop or web browser with WebAssembly. Once the WebAssembly is ready, it’s possible to turn the application into Progressive Web App (PWA) which can be installed on Android or iOS.

ESP32 Spooky Maze game is example of application which can work on ESP32 and also on mobile device. The shared core code contains the main part of the implementation, and each platform has its tiny wrapper.

The example Rust application uses Embedded Graphics to draw images. When the app is running on real HW, it’s transferred to the display via SPI using ESP-HAL. The desktop version is using SDL2 to interact with Linux, macOS, or Windows. The web version is using WASM, and framebuffer is serialized to HTML5 canvas. PWA application for Android also supports access to Accelerometer, so it can simulate similar behavior like IMU on ESP32-C3-DevKit-RUST or ESP32-S3-BOX where user can tilt the device to move the character in the maze.

Web version of the application with PWA support: Spooky (full-screen mode)

Embedded version of the application: ESP32-S3-BOX, M5CORE-FIRE (M5Stack) and many more.

Thanks to cloud development IDEs, it’s possible to build the application on GitPod.io or GitHub Codespaces and run it even without real HW using Wokwi simulator.

16. February 2020

Unable to upload Xamarin app with C/C++ code to Google Play – solution

After finishing release build of your Android application with Xamarin – Visual Studio 2019 you may experience the following error when uploading the app to Google Play Console:

Warning!
This release is not compliant with Google Play 64-bit requirement.

The following APKS or App Bundles are available to 64-bit devices, 
but they only have 32-bit native code: 1000.

Even when your application contains ARM and ARM64, it might still happen that Google refuses to accept your app and returns just the same error message.

The reason is simple: Google requires that your app with native code bundled as AAB (which is ZIP) contains also libraries for 64-bit platform. It does not matter which architecture.

The error is often caused by building application also for Intel platform because emulators on Intel are faster. There are two options to resolve the issue:

  • remove Intel platform from release build
  • add also 64-bit version for Intel platform to release build

Google is checking each platform and your .so files should be mirrored for 32-bit and 64-bit. If your bundle is not consistent then Google will refuse your application.

To fix this problem open Visual Studio 2019. Click your project in Solution Explorer. Open Properties (ALT+Enter).

Click Android Options, scroll down to Advanced button. Click Advanced button.

Uncheck all Intel platform (or check them all, based on your preference) and click Close.

Press CTRL+S to save changes. Create a new archive of your application (menu Build – Archive…)

Upload the new AAB.

If you don’t know how to switch to AAB, just go back to Android Options. Search for Android Package Format and select ‘bundle’.

19. September 2019

Xamarin Visual Studio – Error ADB0020 Android ABI mismatch

Following error message might pop-up when you to run Xamarin app on Android:

Error ADB0020: Android ABI mismatch. You are deploying an app supporting ‘armeabi-v7a’ ABIs to an incompatible device of ABI ‘x86’. You should either create an emulator matching one of your app’s ABIs or add ‘x86’ to the list of ABIs your app builds for.

Here is how you can resolve it.

In Solution Explorer select your project.

Right-click and select Properties or press Alt+Enter.

Select Android Options, scroll down. In right bottom corner click Advanced button.

From the drop down menu select desired architecture, e.g. x86_x64.

Note: After changing any checkbox it is necessary to wait a bit so that Visual Studio syncs the preferences.

Now you should be able to run the project.

8. June 2019

How to add custom mapping of a hostname to IP address in Android Emulator

There is a simple trick which allows your application to resolve a hostname to IP address defined by you even in cases when you do not have access to DNS server. This trick could be also used when you’re connected via VPN and the emulator is not able to resolve DNS record available only in private network.

Let’s add following hostname record which should be resolved by application on Android:

192.168.1.2 test.georgik.rocks

First of all, you need to start your AVD with parameter ‘-writable-system’, because emulator’s filesystem is by default read-only.

Let’s get names of available AVDs.

Example for macOS:

cd ~/Library/Android/sdk/tools
./emulator -avd -list

The output might look like:

Pixel_2_API_23
Pixel_2_API_24

Start the emulator:

./emulator -avd "Pixel_2_API_23" -writable-system

You should see the following warning:

emulator: WARNING: System image is writable

The emulator will start. Now you need to remount the filesystem so it will become writable. This could be done via adb tool which is in platform-tools directory.

Version for macOS:

cd ~/Library/Android/sdk/platform-tools
./adb remount

Now you can start the shell and append the line with configuration to /etc/hosts:

./adb shell 'echo "192.168.1.2 test.georgik.rocks" >> /etc/hosts'

Now you can test the configuration by ping:

root@generic_x86_64:/etc # ping test.georgik.rocks
PING test.georgik.rocks (192.168.1.2) 56(84) bytes of data.

7. June 2019

How to solve Android Emulator java.io.FileNotFoundException open failed: EACCES (Permission denied)

Following error in Android application is very annoying and you may waste several hours by hunting the root cause:

D/file: java.io.FileNotFoundException: /storage/emulated/0/Download/20190604_084533.jpg: 
open failed: EACCES (Permission denied)

It might occur even when the manifest is correct and contains proper permission:

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

Here is sample code which will pass on file existence check, but the execution will fail on readBytes:

var file:File = File("/storage/emulated/0/Download/20190604_084533.jpg")
if (file.exists()) {
    val content:ByteArray;
    Log.d("file", "exist")
    try {
        content = f.readBytes()
     } catch (FileNotFoundException) {
        Log.d("file", e.toString())
     }

} else {
     Log.d("file", "does not exist")
}

To fix this problem it is necessary to go to Settings – Apps – My App – Permission.

Access to Storage is probably disabled. Tap Storage to enable it:

With enabled Storage option, the application was able to read the file.

To solve this problem in a proper way, it’s necessary to add a request for permission to the code. Here is a sample in Kotlin:

val MY_READ_EXTERNAL_REQUEST : Int = 1
if (checkSelfPermission(
    Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
        requestPermissions(arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE), MY_READ_EXTERNAL_REQUEST)
}

You can find more details about requesting permissions in Android documentation.