So my app development journey is going ... ok.
I've spent a bunch of hours at this point staring at Android permission/library/compilation errors and I'm still about as annoyed about it as ever. It'd be really nice if, once I had a project that ran and tested fine with
python main.py, also ran equally fine on my target Android device.
This is not a thing.
So far, I've had a few headdesk situations where I just left out an import when trying to reproduce a minimal error, but a few things strike me as not exactly my fault that I still had to crunch through. This SO answer was the friggin' MVP in diagnosing all of them; the TLDR is
adb logcat -s python and use
scrcpy to mirror your Android devices' screen on your development machine. You can install them with the obvious
sudo apt install adb scrcpy in Ubuntu. The partial, still very probably incomplete list of the errors in question is
- You can't just add new requirements to
requirements.txt, you also need to add them to the
- If you want to deploy some static files, you need to add those to the
buildozer.spec. This bit me when I wanted to include some custom fonts. The line's value defaults to
py,png,jpg,kv,atlas, so if you're trying to include anything else in your bundle, you need to add it.
- As of this writing,
cython's latest is
3.1.0. So you have to add the admittedly adorable
cython<3.0.0to your requirements rather than latest or unpinned.
- If you're dealing with any library that uses BeautifulSoup in the dependency tree, you need to manually and explicitly add
soupsieveto the requirements line in
buildozer.specotherwise you'll get mysterious build errors.
cssselectis one such library, just in case you didn't realize that.
UrlRequestdoesn't transparently work on Android. It looks like it's got something to do with SSL and network permissions. See here and here for details; in particular it looks like you might need to add
buildozer.spec. What do you think? Does it work now?
No. Of course not. You knew that as soon as you saw there was a header in the middle of that last bullet point. But you don't get the answer that easily, motherfucker, you're coming with me on this one. According to StackOverflow and Google Groups, the answer might be
- You need to shadow
- Or maybe, you need to make an Android permission request at runtime to get the OS to grant you
- Possibly, given that this seems like it might be an SSL certificate issue, you might need to install
certifiand then pass
UrlRequestwhen you start it
- Or maybe you need to handle the response body with kid gloves if it is/isn't JSON?
I was also told that I should possibly add
openssl or a hundred other things to the
requirements line in
None. Of. That. Bullshit. Works. OR. MATTERS. AT ALL.
And nobody fucking knew this or documented it anywhere. So if you're reading this post, and it eventually enlightens you, you're welcome. Pay it forward.
What you actually have to do is
buildozer.spec. You don't have to explicitly ask for either of these at runtime; it's possible that other permissions require that treatment, but these two just need to be declared once in the
specfile and don't require user interaction later.
- That's it.
You don't need
hostpython3, and some permissions might need runtime requests but it ain't
INTERNET, and you definitely, absolutely shouldn't rebind subcomponents of
ssl to equivalent-but-less-secure subcomponents. Once you've done that one specific thing,
buildozer android debug deploy run logcat will show green, and you'll successfully get HTTP responses to work with.
I have no idea why this isn't a default, why
ACCESS_NETWORK_STATE are separate permissions at all if you need both to generate network requests, or why this doesn't seem to be documented anywhere including the
permissions docs or the
UrlRequest example page. The state of the universe is; you'd better just spontaneously know that this is what you need to do.
Given the amount of debugging I've been doing here, I haven't done much actual work. But other than that debugging, Kivy and python-markdownify are treating me pretty well. They're both relatively simple to work with and flexible enough that I've been able to bend them to my purposes. I'll have a fuller update on what I'm actually up to later. For now, just know that it's coming along reasonably well, and only temporarily reduced me to apoplectic rage.