Developing with chatmail-core on Android: no events coming in?

I managed to wrangle chatmail-core into an Android app I’m writing (a client). Everything builds, and System.loadLibrary successfully loads both the actual compiled libdeltachat.so (the arg is “deltachat”) and the native-utils that contains the wrapper functions, in that order (although it seems like loading libdeltachat.so isn’t necessary). It seems like the native calls to dc_accounts_add_account and dc_event_emitter_get_next_event aren’t working, though, because add_account does not result in an account being created, and get_next_event always returns null.

For context, this is a Jetpack Compose app written in Kotlin for Android. chatmail-core is in its own module, so that others don’t have to go through the pain I’m going through to get chatmail-core into their apps – they can copy (or maybe import, once I figure out how to do that) the module into their app, run the Rust build script, and they have chatmail.

I posted the source on Codeberg if you want to see what I’m doing. I’m not sure if I’m allowed to link to it here; regardless, it’s under the same username, so you can find it there if you want.

1 Like

Even just creating an account manager should already result in accounts.toml file being created. Have you checked that dc_accounts_new did not return NULL because of some error? Maybe it fails to create the directory already, returns NULL and then all the next functions you call also return NULL. There are checks for NULL pointers in most of the C API functions, so it does not crash the app, but nothing will work if dc_accounts_new failed.

Seems to be this repo: haileyscommit/thetachat: You don't want to use this, I promise. - Codeberg.org
It’s fine to post links here, but maybe Discourse prevents this by default for new users.

1 Like

I’m actually not sure whether dc_accounts_new is returning null or 0, because it’s entirely possible that it’s returning null and the C wrapper (which casts it to jlong, equivalent to int64_t) is converting it to zero. If it were an error, I’d expect it to emit an error event, or any event at all, to tell me what happened, right?

I’ve narrowed it down to an issue between the C wrapper dc_wrapper.c and chatmail-core, since I have a ping function in C that returns true and the Kotlin side picks up the return value correctly.

edit: It also doesn’t look like it’s creating any files. I’m wondering if the directory it’s asking for for dc_accounts_new needs to be absolute… that might be my culprit. I still feel like it should be reporting this as an error, if that’s what it is.

edit 2: Making the path absolute made no difference.

If dc_accounts_new() returned NULL, then you cannot get event emitter. Passing NULL to dc_accounts_get_event_emitter() will also return NULL, so there is no way to get error event even if it were emitted somewhere.

If no files are created then it means dc_accounts_new failed, likely because of permission error.

If I’m reading the Rust code right, the return value from dc_accounts_new should be at least 1, since the value of Config::inner.next_id is initialized to 1. So if it’s returning 0 (which it is), then something’s gone wrong. Also that 0 is the value of “no selected account” and that “Account manager logs events with ID 0 which is not used by any accounts.

Thanks for the nudge! I don’t get any logs from C prints at all, only from my side, so I pretty much just have to shoot in the dark and figure out what the problem is – at least the Kotlin↔C↔Rust connection seems to be in good health.

Eureka, I figured it out! It was trying to write directly to /data, which is a protected directory. It should have been writing to /data/data/com.system32labs.thetachat/files/, which is where the app is allowed to write to. To do this “correctly”, I had to get a Context, which meant that the account manager global variable had to be made lateinit and some refactors had to occur to make sure it wasn’t used before it’s initialized (i.e. in any other globals). Immediately I started receiving events and log messages from the account manager! Now onto the actual meat of the app. Thanks for your help!

1 Like

dc_accounts_new is a C function that returns a dc_accounts_t* pointer, not an integer. It is a pointer to the “account manager”.

yeah I think I got it wrong in the thread – I was using (and referring to) dc_accounts_add_account. It seemed to create the account manager (dc_accounts_new), it just couldn’t do anything?

Also regarding the Java bindings, I think it makes sense to extract them from GitHub - deltachat/deltachat-android: Decentralized private messenger with chat-shared tools and games for Android into a separate repository so they are maintained in a central place.

I wrote an issue at Publish JNI bindings to Maven Central · Issue #7286 · chatmail/core · GitHub and started something at GitHub - chatmail/jni: JNI bindings for chatmail core library, but there is even no gradle build file yet.

1 Like

If no files were created, it means dc_accounts_new falied already and returned NULL. Successful dc_accounts_new creates at least an accounts.toml file.

Normally you call dc_accounts_new, and then resulting pointer is passed to dc_accounts_add_account, dc_accounts_get_event_emitter etc. All these functions exit immediately if you pass the NULL pointer instead of the pointer to a successfully created account manager.

C functions are documented at https://c.delta.chat/ which is generated from core/deltachat-ffi/deltachat.h at 87035ff744c9c018f3176eb5a859870cdb078b1a · chatmail/core · GitHub

1 Like

I pretty much just copy-pasted them from there, but I have them kept in a separate module in my app for this reason. Beware the files I added to double-check the JNI connection though.

I feel like this is a JNI issue, since I had an accounts manager object I could use and it didn’t throw a fit about it. My blind guess is that those functions know what to do with a null pointer (nothing), so that it doesn’t panic and crash everything down.