Open suvam0451 opened 1 month ago
Ooh, issue number is niiiiiice. 🤣
@IzzySoft Hey 👋
I would like to work towards making this app available on IzzyOnDroid.
Any idea whom I can reach out to scan my apks for any dependencies that might need removal?
The releases are available on the project page itself. Latest version is v0.4.0
I would like to work towards making this app available on IzzyOnDroid.
:star_struck:
Any idea whom I can reach out to scan my apks for any dependencies that might need removal?
See e.g. Identify modules in apps which introduces my library scanner, where to get it (it's FOSS of course), and how to use it :smiley:
The releases are available on the project page itself
I'll take a look now. Oof… 150 MB? That's 5 times the per-app limit at IzzyOnDroid. What size would be expected for the Lite version it seems you have in mind? Let me take a look at that 150 MB APK nevertheless to get a clue…
Ah. Per-ABI builds would help a lot. Native libraries are just "stored" and not even compressed – ao sticking to e.g. arm64-only that would already drop around 80 MB, sticking with armeabi even around 90 MB. That would leave 70 resp. 60 MB in size. Running the scanner on the APK, the results look pretty good – I can see no "offending libs". The only thing reported is:
SigningBlock blobs:
-------------------
0x504b4453 (DEPENDENCY_INFO_BLOCK; GOOGLE)
which can easily be avoided by a minor adjustment to your build.gradle
:
android {
dependenciesInfo {
// Disables dependency metadata when building APKs.
includeInApk = false
// Disables dependency metadata when building Android App Bundles.
includeInBundle = false
}
}
For some background: that BLOB is supposed to be just a binary representation of your app's dependency tree. But as it's encrypted with a public key belonging to Google, only Google can read it – and nobody else can even verify what it really contains. More details can be found e.g. here: Ramping up security: additional APK checks are in place with the IzzyOnDroid repo.
Still quite a load of libs (my scanner counts 98). Not sure how you will "lighten" it, but we can take another look then – preferably with per-ABI builds so we can get an idea of the "real size".
@IzzySoft 100MB is pretty standard for an expo app. For example, graysky (bluesky client) is 93MB, and its' dev has significantly more experience building expo apps than me.
This project is extra chonky, because I need to fit an entire DBMS (realm.so
) for offline capabilities.
^ 90% of these are non-negotiable dependencies, and these are almost 30MB already.
One simple way to cut it is to "eject" from expo
(i.e. - make it a react native app, just like pixelfed-rn
).
But, that is not EAS friendly, and would incur additional maintenance effort on my part. I would prefer not to eject.
The second way is to look at per-ABI builds, as you say. Will experiment and get back to you.
FYI, the .aab
files come out to be 80MB. So, maybe that could be held as benchmark for the expected size of the app?
Funnily, the app store download size fits the <30MB criteria, but I have no idea what sorcery they pull off for this 🤣
From my understanding, the reason for so many libs (98) is because once you include a library like expo-av
, it will just bundle everything needed for it (audio, video, gif processing) to run in the native apk, whether I use it in my project or not. There is no way to pick and choose.
@IzzySoft I would be pretty surprised that anyone could fit a React Native, especially Expo project within 30MB, even the most barebone ones with zero deps.
Is this a technical limit or generally imposed rule for the IzzyOnDroid repository? 🤔
100MB is pretty standard for an expo app.
That might well be. Also Flutter orr RN apps turn up being quite big. Still, the per-app limit at IoD is 30 MB. There are very few exceptions, but definitely not in the area of 3-digit MB.
The second way is to look at per-ABI builds, as you say. Will experiment and get back to you.
Thanks! I guess that will be the most promising approach, bringing down the size most effectively. If from there it could be shrunk further, we might get into an area of compromise.
it will just bundle everything needed for it (audio, video, gif processing) to run in the native apk, whether I use it in my project or not. There is no way to pick and choose.
There might be a way to clean it up after it has been pulled, so it doesn't get included with the app – similar to removing unwanted permissions, see Removing Unwanted Manifest Permissions With tools:node. I don't know, I'm no Android dev and definitely no Expo specialist.
I would be pretty surprised that anyone could fit a React Native, especially Expo project within 30MB, even the most barebone ones with zero deps.
Ah, you want to be surprised? Let me check… I cannot spot RN directly, but Github usually shows them as something with Typescript or Javascript, right? Though that could be Cordova or other stuff as well. But here's one that's definitely RN, and the APK size is 25 MB: xyz.commanderred.opendtuapp
, to be found at (nomen est omen) https://github.com/OpenDTU-App/opendtu-react-native (25 MB applies to the arm64-only build here). And I wouldn't exactly call 78 libs a "barebone one with zero deps".
Is this a technical limit or generally imposed rule for the IzzyOnDroid repository?
Yes. And it (currently) does not stand to discussion, sorry.
@IzzySoft hey again 👋
I ran some tests based on your feedback. This is what I have so far.
TL;DR - 55MB tested to work 🥳
, could reduce to <50MB
in coming days.
Some configurations might get as low as ~40MB
,
but that is not something I can achieve with my current skill level.
Realm remains the biggest cuprit (12-15 MB).
Removing (or, replacing it with sqlite) is not an option. I just can't built the app I want (offline-first fedi client) without it 😞
I am looking at stripping a few extra unused libs (e.g. -libreact_codegen_rnsvg
),
^ but that would save 2-5 MBs
at best. Can save more, but would need to drop features.
It's just JS. I could maybe strip off 2-5 MBs
by removing fonts or icons? 🤔
I can also strip unused permissions. Not an issue.
It works ! Reduces size by 6 MBs.
...but, it makes the app not boot anymore. Then there are very recent issues like this:
@IzzySoft So, I just want to hear your thoughts about a ~50MB client.
Going smaller than that would involve either removing features from the app, or stepping into risky territory (handling breaking expo updates, heavy maintenance debt).
I only have a couple month exp building RN apps. If that size range does not work with IzzyOnDroid, I'll just have to re-apply once I have more experience optimising this stuff.
Here is the build.
Here is the scanner results.
Well, 50 MB are a lot better than 150 MB I'd say – a great achievement already! And as you wrote, you're planning to get more experience there and might further reduce the size in the future.
Of course it makes no sense to have parts of the app broken for some squeezing. So if the APK stays around 50 MB for now, and you'll work on more size reduction later to make sure it at least doesn't grow more, I'd say we could make an exception here.
For setting it up in a way that auto-updates work, we need to agree on a consisting file naming pattern. By what's there currently, I could tell the updater to only pick APKs matching the RegEx /NoProGuard/i
for example. But you might wish to rather call it "lite" or something, I don't know. We can also pin it to /NoProGuard/i
now, and should you later decide for a different file name update the config. Just be aware that, if there's no matching APK found, updates would be missed.
Next, we'd need some metadata. Ideally in Fastlane structures (see e.g. the IzzyOnDroid Fastlane Documentation). It's rather easy once you grasped the idea (just placing the right files in the right places), but I could also make a PR with a starter package once I have the files needed for that. Which are, for a minimum:
All else is "nice to have" and can be added later.
PS: those deprecation warnings (PHP ${var}
) surprise me, as I didn't see them before (and yes, I'm also on PHP 8.x). Searched the web, there are literally hundreds of mentions – but not one of them for official announcements at php.net, strange (ah, there with just 3 words: "Deprecated ${} string interpolation.", oof). Now, finding all those occurences will be fun…
@IzzySoft Awesome !
If you have a quick way to raise a PR with the fastlane stuff, that would be welcome.
Can the fastlane stuff be configured to be stored/read from inside .github folder somehow? That would be extra nice but ignore if not possible.
I am planning to start adding the lite editions and fastlane stuff from my end starting next release (as an exercise).
^ I will contact you after a couple releases (ETA 1-2 week later), and there should be an easy trail for you to follow to configure the pipelines from your end.
^ We can make the app generally available on IzzyOnDroid following that timeline.
Just a few questions regarding what would trigger Anti-Features among the following:
This project has some level of financial incentive to build and maintain the main app (io.suvam.dhaaga
) in a certain way.
While doing all that sort of community/product building is exciting for me,
I would like to keep the lite edition (io.suvam.dhaaga.lite
) be the go-to alternative for folks who are not interested in such services, or worry about me dissappearing and/or dropping support one day.
I would love to hear your opinion on whether to include/exclude the following planned features onto the lite edition: (I know it is pretty stupid to think of all this while having no userbase. But, I like to keep things fair from the start. 😉)
host and offer free OpenAI translation services
(OSS under this repo itself), will that count as NonFreeNet
?
tipping services
and self-endorsement to my own mastodon/github account
from within the app considered inappropriate?host and offer configuration files as a free service
(OSS under this repo itself), will that count as NonFreeNet
?
^ Since all of these services are all free (beer) and OSS, and anyone else can also host their own copy, this should not count as NonFreeAdd
joinmastodon.org
is considered NonFreeNet
by F-Droid. Do I need to toggle this off?The app is expected to directly link to https://dhaaga.app to provide project documentation and guides.
Given that I must keep the app size to a minimum, this would become a requirement, rather than a consideration.
Does this count under TetheredNet
?
Can the fastlane stuff be configured to be stored/read from inside .github folder somehow?
Depends on what grade of compatibility you aim for. To my knowledge, IzzyOnDroid is the only place where it could be used from there. If you aim for F-Droid.org one day, that won't work as they'd expect the fastlane/
directory in the root.
what would trigger Anti-Features among the following:
FUNDING.yml
will even be evaluated with your app listing here :smiley:NonFreeNet
is only if the network is non-free (in the sense of non-libre, i.e. the software used is non-free). If it runs on free/libre software but cannot be self-hosted, or it theoretically could be self-hosted but the app doesn't allow to have the link configured, it's TetheredNet
. If it's free/libre and can be self-hosted and the URL can be specified in the app, none of the two applies.joinmastodon.org is considered NonFreeNet by F-Droid.
You're speaking of the official Mastodon app here – which if you want it or not, on its first start automatically reaches out to that site to get a list of instances. So if your app by itself, without alternatives and without consent reaches out to such a site, it's NonFreeNet
alright. If it just offers the possibility (e.g. as some optional feature), but also works without it, it's not.
The app is expected to directly link to dhaaga.app to provide project documentation and guides.
That runs on free/libre software, right? So if it's "required" by the app, it's TetheredNet
. If it's an optional feature used with consent (i.e. the user is aware it will be called to when clicking the link/button/menu-item for documentation), it's not.
@IzzySoft Thanks.
#1
-- I'll save and maintain the fastlane stuff in it's own branch (I would need to create one to maintain the lite edition anyways).
#2.1
-- Understood. Will remove the AI dependencies
^ Just want to clarify that my decision to include OpenAI stuff is to specifically solve the challenges around language barrier in communication. (I know that LibreTranslate and DeepL are alternatives. But, they don't nearly come close.)
I am anti-AI myself, otherwise. (I know the current logo is AI gen, but that's a budget issue 🤣)
That said, the users of IzzyOnDroid are your users first and mine second. So, I will respectfully strip all AI dependencies from the Lite edition. Mastodon people will still be able to use their instance hosted DeepL services, as usual. 💯
#2.2
-- Will keep tipping links (Patreon + Ko-Fi).
#2.3
-- I'll go for this --> If it's free/libre and can be self-hosted and the URL can be specified in the app, none of the two applies.
#3
-- Will remove the feature.
#4
-- Will keep the webviews. Documentation is not required at all to run the app.
@IzzySoft You can raise a PR with the fastlane skeleton if it does not take too much of your time.
Either way, I will ping you back in a couple of weeks, once I get the hang of this across couple releases and address all the issues above. 👋
Sounds good to me, thanks!
As for the PR: Give me the details to start it (shortdesc, fulldesc, icon, 1+ screenshots) and I can do it.
@IzzySoft Oh, if it is that much work, then just let me do it.
I can copy one of your PRs from any other existing project, and use it as reference.
From what I understand, the only thing I need to worry about is that F-Droid does not support markdown, so I would need to keep it pure HTML.
If you want it on F-Droid.org at one point: either that or "Markdown lite". See the IzzyOnDroid Fastlane Documentation I already linked :stuck_out_tongue_winking_eye: And yes, for starters it would just be something like this, from the root of your project:
mkdir -p fastlane/metadata/android/en-US/images/phoneScreenshots
cd fastlane/metadata/android/en-US
echo "an opinionated mobile client for Mastodon and Misskey" > short_description.txt
vi full_description.txt # copy-paste or edit your full description here
cp /path/to/icon.png images/icon.png
cp /path/to/screenshots/* images/phoneScreenshots/ # just the phone screenshots, for starters
All else after you got more familiar with it and see the results. That would at least be my suggestion.
@IzzySoft hey again 👋
I have finished working on all the changes I expected were necessary for store listing.
You can have a look at the lite editions being included for the last couple releases (v0.5.0, v0.5.1)
Let me know what other step would need to be taken.
lite
branch.Also, can I support v8a architecture only? I will add more architecture if the users request.
I've picked the arm64 lite APK and ran them through the scanners here. Library-wise it looks absolutely clean, congrats! Permission-wise I'd need a short explanation for the bold ones here to add them to the app's "green list":
plain-text version for easier copy-paste:
Permissions:
------------
* android.permission.INTERNET
* android.permission.READ_EXTERNAL_STORAGE
* android.permission.RECORD_AUDIO
* android.permission.SYSTEM_ALERT_WINDOW
* android.permission.VIBRATE
* android.permission.WRITE_EXTERNAL_STORAGE
* android.permission.ACCESS_NETWORK_STATE
* android.permission.CAMERA
* android.permission.READ_MEDIA_IMAGES
* android.permission.READ_MEDIA_VIDEO
* android.permission.FOREGROUND_SERVICE
* android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK
* io.suvam.dhaaga.lite.DYNAMIC_RECEIVER_NOT_EXPORTED_PERMISSION
Explanations for the others (non-bold) are welcome, too, if you want to give them. You can ignore the very last one which is rather a "fake permission".
Signature check looks clear as well: a fine release-key signing without any "signing block blobs", excellent! A pity this is made in Typescript, so no chance for Reproducible Builds anytime soon (see Reproducible bulds, special client support and more in our repo for details)…
APK Size is hard on the border (another side-effect of Typescript, and caused by the native libs it requires to work), but I'll close an eye on that – though it definitely means we cannot keep any historical versions at IzzyOnDroid, just always the latest release.
Fastlane: May I ask you to replace the graphical bullet-points by asterisks (*
)? Then it would render fine as Markdown, which would make it look much better (e.g. text flow depending on screen width). For now I'll have to render it as "plain text", which doesn't look half as good, especially due to additional line breaks on smaller screens. Further, unfortunately the updater here cannot pull fastlane from a branch. Please see the IzzyOnDroid Fastlane Documentation for how to provide fastlane for a build flavor (works for F-Droid.org as well that way then). You could e.g. place it in /src/<buildFlavor>/fastlane/metadata/android/<locale>/
or, as it has a dedicated packageName, in /metadata/<packageName>/<locale>
, but it must be in the main branch. Plus, full-description.txt
must be full_description.txt
(underscore; a dash is what triple-t would use). And, all your graphics are on LFS; the updater here cannot deal with that.
You should also consider a much simpler icon. The one you currently use will just look like a colorful blob on smaller screens (as well as in the smaller variants in app lists etc).
For the initial listing, I've pulled fastlane in manually (and already integrated above suggestions). But please fix this before you make the next release, and give me a ping so I can adjust the config here. Thanks!
The listing will take effect with the next sync around 6 pm UTC. Welcome aboard!
PS: and yes, arm64 only here. The app already is too big, thanks to Typescript native libs…
@IzzySoft
Using a separate signing key was intentional. But, it comes with downsides.
The users may be prompted by Google Play Protect, as shown in screenshot.
I already have a developer account. If getting the app verified via google (which probably would need a non-FOSS key) will create a better experience for Izzy/F-droid users, then I am happy to get it verified from google.
^ Just let me know what is the community sentiment around it.
It's fiiiine. I am at least half a year away from building a half-decent fedi client 😆 Not worried about perception/branding for now. If the goofy icon grabs their curiosity, my screenshots will earn their attention. So, win win for the project, overall 😏
Done. Asterists added. Information tweaked based on your preview screenshot.
Done. You can use main
. I switched my default branch to develop
.
Also, replaced the LFS items with binary blobs, as requested.
Thanks! Some clarification:
You can use main. I switched my default branch to develop.
Well, not sure if that works. Afraid Github API always fetches from the default branch. But let me check… yupp, sorry, no dice. It must be in your default branch – sorry for the ambiguity.
So for permissions, I've now set up:
android.permission.INTERNET: to reach your Fediverse instance
android.permission.CAMERA: qr code scanning & taking photos for posts
android.permission.RECORD_AUDIO: to record audio posts
android.permission.READ_MEDIA_VIDEO: to attach videos from the gallery
android.permission.READ_MEDIA_IMAGES: to attach photos from the gallery
If you could fill in this way for the other permissions, I'll add them too.
@IzzySoft Ok, will remove READ_EXTERNAL_STORAGE
and WRITE_EXTERNAL_STORAGE
in next release and see how it goes. The relevant features are months away from being designed/built.
android.permission.INTERNET: to reach your Fediverse instance
android.permission.CAMERA: qr code scanning & taking photos for posts
android.permission.RECORD_AUDIO: to record audio posts
android.permission.READ_MEDIA_VIDEO: to attach videos from the gallery
android.permission.READ_MEDIA_IMAGES: to attach photos from the gallery
android.permission.ACCESS_NETWORK_STATE: to show errors when accessing online-only modules
android.permission.SYSTEM_ALERT_WINDOW: to request permissions, if not already granted
android.permission.VIBRATE: to provide haptic feedback when actions complete
android.permission.FOREGROUND_SERVICE: to show progress for long running tasks (e.g. - bookmark sync)
android.permission.READ_EXTERNAL_STORAGE: will be removed next release
android.permission.WRITE_EXTERNAL_STORAGE: will be removed next release
android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK: will be removed next release
done. back to main
android.permission.SYSTEM_ALERT_WINDOW: to request permissions, if not already granted
Why does that require SYSTEM_ALERT_WINDOW
? I'm no Android dev, but AFAIK there's a standard permission request dialog.
The others I've copied over – thanks for even putting them into YAML format!
Permission to be Removed
I've skipped those (did not copy), so the next update should trigger a warning should one have been forgotten to be removed. Are you sure you don't need FOREGROUND_SERVICE_MEDIA_PLAYBACK
? If I guess correctly (the documentation is not very specific there), that's to have media playing even if your app is not in foreground.
back to main
YESSS! That works fine now:
$ iod repo fastlane io.suvam.dhaaga.lite
io.suvam.dhaaga.lite: check if repo contains FUNDING.yml
io.suvam.dhaaga.lite: looking for 'https://api.github.com/repos/suvam0451/dhaaga/contents/.github'
io.suvam.dhaaga.lite: FUNDING.yml already up-to-date.
io.suvam.dhaaga.lite: calling 'getFastlaneMeta(github,[host:github.com,owner:suvam0451,repo:dhaaga,path:/fastlane/metadata/android])'
io.suvam.dhaaga.lite: FastlaneFeatures title,shortdesc,fulldescMD,changelogs,icon,screenshots
io.suvam.dhaaga.lite: looking for 'https://api.github.com/repos/suvam0451/dhaaga/contents/fastlane%2Fmetadata%2Fandroid'
io.suvam.dhaaga.lite: looking for 'https://api.github.com/repos/suvam0451/dhaaga/contents/fastlane%2Fmetadata%2Fandroid%2Fen-US'
io.suvam.dhaaga.lite: looking for 'https://api.github.com/repos/suvam0451/dhaaga/contents/fastlane%2Fmetadata%2Fandroid%2Fen-US%2Fchangelogs'
io.suvam.dhaaga.lite: looking for 'https://api.github.com/repos/suvam0451/dhaaga/contents/fastlane%2Fmetadata%2Fandroid%2Fen-US%2Fimages'
io.suvam.dhaaga.lite: looking for 'https://api.github.com/repos/suvam0451/dhaaga/contents/fastlane%2Fmetadata%2Fandroid%2Fen-US%2Fimages%2FphoneScreenshots'
io.suvam.dhaaga.lite: checking locale 'en-US'
io.suvam.dhaaga.lite: replacing 'metadata/io.suvam.dhaaga.lite/en-US/full_description.txt' with fromMD
io.suvam.dhaaga.lite: updating 'metadata/io.suvam.dhaaga.lite/en-US/short_description.txt'
io.suvam.dhaaga.lite: updating 'metadata/io.suvam.dhaaga.lite/en-US/title.txt'
io.suvam.dhaaga.lite: updating 'metadata/io.suvam.dhaaga.lite/en-US/changelogs/6.txt' from '6.txt'
io.suvam.dhaaga.lite: updating 'repo/io.suvam.dhaaga.lite/en-US/icon.png'
io.suvam.dhaaga.lite: updating 'repo/io.suvam.dhaaga.lite/en-US/phoneScreenshots/1.jpg'
io.suvam.dhaaga.lite: updating 'repo/io.suvam.dhaaga.lite/en-US/phoneScreenshots/2.jpg'
io.suvam.dhaaga.lite: updating 'repo/io.suvam.dhaaga.lite/en-US/phoneScreenshots/3.jpg'
io.suvam.dhaaga.lite: updating 'repo/io.suvam.dhaaga.lite/en-US/phoneScreenshots/4.jpg'
io.suvam.dhaaga.lite: updating 'repo/io.suvam.dhaaga.lite/en-US/phoneScreenshots/5.jpg'
io.suvam.dhaaga.lite: cross-checking for obsolete screenshots
io.suvam.dhaaga.lite: screenshots in Fastlane: 1,2,3,4,5
io.suvam.dhaaga.lite: local screenshots checked: 1,2,3,4,5
@IzzySoft Sure, can remove those as well, and see how it goes.
android.permission.SYSTEM_ALERT_WINDOW: will be removed next release
As for FOREGROUND_SERVICE_MEDIA_PLAYBACK
, yes, it is generally used for music/video playback in bg.
Since I have no plan to support PeerTube, all media viewing can be done within the app itself. Won't need this.
can remove those as well, and see how it goes.
Please test before releasing then, just to make sure :wink:
Since I have no plan to support PeerTube
Eh, what a pity. Already thought this becomes the all-in Fedi app :smile: But sure, your app, so as you plan. And I rarely use any video platform on mobile anyway, so no personal interest either.
Thanks again!
@IzzySoft Heyy, I noticed that the last update v0.8.0 did not go through yesterday.
I think I made a typo while typing arm64-v8a
. Probably because of that.
If it goes not go through again today, can you please manually sync it?
While we are at it, can we remove the validation for arm64-v8a
and change the convention to just Dhaaga-v0.8.0-Lite.apk
👆 I get the architecture part wrong way too often.
v0.8.0 was picked up and is available meanwhile. And while it would be preferable to have the APK name state what's inside (a single arch here), we can of course agree on a different matching pattern. Currently the matching pattern is /Lite-arm64/i
. If there won't be other files using Lite
in their name, I can reduce it to that – so accidental mis-spellings in the arch part would not be a problem anymore.
I've set it to /Lite/i
now. Please make sure that stay "unique" :wink:
@IzzySoft I plan to add a couple of NonFreeNet-ish features to the app in the near future.
Wanted to check with you if they would be flagged (in consideration for F-Droid in the future)
If I disable these features out of the box, but let the user enable it, I wonder whether it would still be considered "promotion".
If they are going to get flagged regardless of this, I suppose the only way forward is to remove those for Lite edition.
In general: yes, they would be flagged (Giphy is Meta, right? I'd personally even consider that Tracking). But if it's not essential for the application and is clearly opt-in, it IMHO would not fall under NonFreeNet, as the definition says "promotes or entirely depends" – the "entirely depends" part would be gone then. "Promotes" might be a bit subjective; of course, if there's a popup every minute reminding me I should opt-in, that's clearly "promoting" (abusively even) – and if you have to search 7 levels deep in settings just to discover there is such an option, it's clearly not. But where exactly to draw the line? IMHO if you make it opt-in and easy to discover in the settings, even on top-level settings, without and nagging/popups/"heavy pointers", that should be good enough to not make it "promoting".
MusicBrainz is not the right example in this context I'd say: it depends on the service, which is partly non-free (parts are CC BY-NC-SA). Not opt-in, but fixed.
Purpose
Introduce and Maintain a Lite edition of the app for privacy enthusiasts and DIY folks.
Summary
Standard Edition:
Dev Client:
Lite Edition:
Dependencies in Consideration
Here is how the Lite edition will differ from a standard build:
These services will be removed:
These services will be feature toggled:
These services are available via web and can be removed upon request:
These services are available via web, but do not affect the app directly
F-Droid vs IzzyOnDroid
I have strong reasons to continue using Expo EAS to build and ship my apps in perpetuity.
F-Droid does not support this configuration atm. So, unless a contributor figures out a way to reliably produce android builds using a script, I would prefer to keep the app on IzzyOnDroid, for the QoL.
^ It's more headache prone that you can imagine 😆