This is a log of stuff I did w/ one of my random pet projects, it’s not terribly interesting and is mostly just so I can get into the habit of writing more. You have been warned.

I spent various parts of the last 10 days trying to get GetDisciplined working on my Pixel 4 and the experience was one annoying trial after another. So basically a normal, everyday experience in mobile app development. (Honestly, it was foolish of me to think someone had finally made mobile dev pain-free.)

Anyway, here’s every annoyance I encountered:

Later android NDK versions can’t be built with cargo-mobile!

tauri uses a fork of a project called cargo-mobile (which they named tauri-mobile) to generate mobile app project files for rust applications, which are then built using the target mobile platform’s own tools. In my case, it’s used to generate Android Studio project files. Or it would have if it still worked.

When trying to build against recent versions of the Android NDK, the process failed when linking with SQLite. clang complained about some missing symbols like __extenddftf2, symbols that are available in libgcc. I guess the version of clang that ships with those versions of Android NDK doesn’t automatically link against libgcc. (I guess, because even after a couple days of research I still don’t know.) Several github issues mention this problem and there appears to be a simple way to fix/workaround the issue: adding the output of clang -print-libgcc-file-name as a linker command option.

I tried many different ways of adding this linker flag, starting w/ non-intrusive solutions like specifying extra clang options through the RUSTFLAGS environment variable, but none of them worked. Eventually I folded, and just forked the tauri and tauri-mobile repos and found a way to add the required linker argument. Which led me to the next error.

vite’s default configuration does not support using TypeScript with Vue’s Options API!

Getting the rust part of GetDisciplined to build allowed the TypeScript compilation to start failing. I generally use Vue’s Options API when working on personal projects since it’s what I use at work, but when trying to use it with GetDisciplined, the TypeScript compiler started throwing fits.

It couldn’t seem to deduce the correct type for a component’s this in the Options API and no amount of explicit typing would change things. Which is strange considering it works just fine in my other projects with webpack powered builds.

I’m not sure what the actual problem with the TypeScript config or vite config was, and given how much time I spent trying to fix the previous issue, I really didn’t want to spend the time finding out. So I just switched every component to use Vue’s Composition API.

tauri’s android build process does not predictably generate a working APK!

Now the build command worked! Sort of. It completed. But the result was an APK that I couldn’t install on my phone. Or it was an app that would immediately exit with no error message. This happened a couple times, presumably for different reasons, but I didn’t want to spend a couple days debugging each random error. So I just kept experimenting with the build.

I found the ultimate cause was that the tauri android build command did not behave the same way when executing more than once. It also didn’t appear to respect the --target=... option. The only way I could reliably build a working APK was to:

  1. delete the src-tauri/target folder entirely (which stores the built binaries and APK files)
  2. rebuild everything (including rust and the client side bundle) with tauri android build
  3. run tauri android open to open the generated Android Studio project
  4. make sure the correct target architecture is selected as the active build variant in Android Studio
  5. clean the project in Android Studio (this looks redundant, but it’s the only way I was able to fix some build issues)
  6. then build the APK in Android Studio and install it on my phone

This process takes forever, but luckily GetDisciplined is a small app, so I didn’t have to do it very often, and won’t have to in the future. Though if I eventually want to put mealplanner on mobile or another complex app, it will certainly become a problem.

tauri’s platform API does not work with every Android environment!

Once I got past the build issues, and was able to put the app on my phon, it… kept immediately crashing. Except this time, there was an error message, which as you might imagine, helps immeasurably.

The database tauri plugin I wrote which uses SQLite, saves the SQLite database on disk. To do this it has to know where exactly to do this. Tauri has an API to find operating system dependent paths, like the “application data path”, which the aforementioned plugin uses, but on my phone it wasn’t working. Which caused the plugin to try and save the data to, well, nowhere.

Digging through the tauri dependencies, it looked like the code assumed that the application would be running in a linux terminal with $XDG_ environment variables present. Looking at other crates that also provided OS dependent paths that were specifically for Android, it looked like that is not always the case. For some environments and phones the only way to get this information is to query Android’s Java API directly.

I modified tauri-plugin-database to use a different crate to get the application data path if building for mobile, one that is built for android specifcally, and this stopped being a problem.

mobile chrome triggers browser events differently than desktop chrome!

At this point, the app installed on my phone, and loaded and I was even able to start editing routines! But the actual routine editing was real wonky.

The routine management side of the app would automatically add a new task if the user typed something in “Add task” input, which worked on desktop, but not on mobile. On mobile, it resulted in a new task on every keypress. So attempting to type brush teeth would result in tasks titled b, r, u, s, etc.

I can’t remember what the exact issue was, but it seemed to have something to do with my use of Sortable.js a frontend library that makes it easy to add lists with drag-drop functionality. I originally had the add task input as part of the list Sortable managed so the focus wouldn’t jump when adding a new task. Moving the add task input out of the list of displayed tasks fixed things (though it results in a slightly poorer UX in my opinion).

There was also another problem in that the duration selects for a task were entirely unusable (again, only on mobile). This was another Sortable.js problem. Trying to use an input inside of the task immediately started Sortable.js’ drag-and-drop functionality. It would never activate the actual control you selected.

Fortunately, there are options meant to solve this problem, options that force a delay on mobile before starting to drag an item. Using these options solved this last problem.


At this point the app was finally usable, and look, here it is on my phone!

Picture of GetDisciplined running on a Pixel 4


There are a couple bugs in the app I will probably fix soon, but now that I can use it to manage my routines and consistently make tiny bits of progress towards my goals, I’m switching my focus back to mealplanner. Which I think I finally have a better name. Or possibly just marginally better.

Eventually I’ll get back to this app to see how I can better package and distribute it. Hopefully by that time, tauri’s support for android will be a bit better. If not, maybe I can find some time to contribute to the project.