You’ve read the phrase of the F-Droid team being „permanently understaffed“ at least once a week – and get as tired about it as those repeating it already are? Well: welcome to the … team. Yes, you. If you are an active F-Droid user loving and living the F/LOSS idea, you already have the necessary essentials for that. True, there are complicated things at F-Droid I don’t grasp myself – but at the other end of the scale there are also easy tasks not requiring much „tech-knowledge“, or can be learned easily.
This article should help you getting involved, introduce you to tasks performed during „app review“ at RFP and at Merge Requests with fdroiddata. It will hopefully also serve as reference during your own reviews. Recordings of related workshops can be found in my Peertube channel.
Let me take you through the „life-cycle“ of a review as I perform them daily to show you what tasks are involved. When I started several years ago, it was a little part of the easy steps I could cover. I was no Android developer (and still am not), nor a packager (uhm, this part still holds mostly true – though I meanwhile pushed the „Merge“ button on a few new apps and updates myself). I got more experienced by „jumping in“, trying to help, asking those already there whenever I missed to understand something. Today I’m one of the maintainers and able to give you a rough guide to follow me on this path.
So, here are the steps I usually perform when a new app was requested to be listed with F-Droid. This usually starts at RFP as an issue and then passes to fdroiddata – but sometimes directly starts as a merge request (MR) in the latter. I try to shed light on both places. For now these are just some bullet-point list, but I hopefully will refine them later:
- is the source code available? F-Droid builds everything from source – so without the source, there’s nothing we can do.
- Metadata complete? (URLs, AuthorName etc; cross-check with Upstream-ReadMe and other listings if available)
- often overlooked: donation details should be available at both sides (i.e. in our metadata as well as in the upstream repo) or not at all
- often missed: links to the app’s translation system (Weblate, Transifex, Crowdin, …) – watch the bot’s tags if it discovered some
- Fastlane or Triple-T available upstream? Structure OK? Any issues (e.g.
short_description.txtlonger than 80 chars, messy/missing
full_description.txt, featureGraphic with wrong proportions)?
- Description has enough details (so users get an idea what the app is about)?
- releases tagged? Do tag names match either
versionCode? Literal values for the two in
build.gradle(Flutter apps: see
pubspec.yamlin the project’s root)?
- Fastlane/Triple-T available at the latest tag? (else it’s not picked up with the build)
- suspicious entries in
build.gradle? (bot should report them, but sometimes misses) => watch out for things like Firebase, GMS, Crashlytics/other-Analytics, other non-FOSS libs, Maven repos (though our bot usually reports those)
- license must be one of the OSI-approved; cross-check with SPDX if unsure. Also note that, especially when mixing libraries, there might be license incompatibilities (e.g. an app licensed Apache-2.0 can not use libraries with a stricter license like GPL-2.0)
- if you have the knowledge: check the code for possible issues (oh, I didn’t mention the code must be available? Hey, we‘re talking about F/LOSS apps here, which means Free and Libre Open Source Software. Without that F/LOSS code, there’s nothing F-Droid can do
RFP: bot results
- check the labels added by the bot. Did it find git-url, gradle, fastlane or triple-t, a package name, a programming language? Any „red labels“ (these indicate issues)?
- did it report any „scanner-errors“ – like the „usual suspects“ (GMS, Firebase, Crashlytics)? These are show-stoppers.
- did it report „insecure-gradlew“ (yellow label)? This can safely be ignored as it doesn’t affect our builds (but upstream should fix it for their own)
- did it find a license? The „no-license“ label just mean the bot didn’t find it, it could still be there (cross-check with upstream repo)
- ideally, the bot also found Fastlane or Triple-T already. In this case, check that it at least picked up summary and description – you should see it in its report as Fastlane › by locale
- should it list results from Exodus, these are from the version released on Play Store (cannot be from us as at this point it‘s not yet listed here). They do not necessarily apply to what our build server will finally spit out – but give you an idea what to look for e.g. in the
build.gradleof the submitted app, see next point
- any offending libraries were reported? Check if upstream’s
build.gradlemight provide a „foss build flavor“ omitting them. If not, suggest they should, or else. Ahem, else we cannot include it.
At the end of this, metadata would be prepared (unless there’s already a related MR having them, in which case they are checked for correctness/completeness). You can find an example metadata file below.
MR: bot results, other CI pipelines
You find those results directly below the initial comment, where it says something like „pipeline #128817296 passed for e5a357b5 on johndoe:master“. Tap the symbol on the right to that string to get a popup of all pipelines, then tap the one you’re interested in. This will open the logs. Don’t be shocked, the first time this might look like gibberish – but one gets used to that… somehow.
- did lint complain? If so, watch output for „red text“. lint usually also outputs diffs of what it wants to have changed (no space here, empty line there, move stuff around…)
- did the build succeed? If not: any clues from the logs to hand back to the MR author?
- did the issue-bot report „interesting strings“? Did it pick up Fastlane/Triple-T properly?
- also check the app‘s repo for possible „blobs“ (
*.binetc) our scanners might have missed
- as at the end of above RFP run, check the YAML metadata for completeness (see below for an example metadata file.
- if the MR consists of multiple commits, it’s usually set to be squashed. When squashing, make sure it gets a reasonable commit message (like „new app XYZ“).
MR: APK test
On a successful build, the APK can be downloaded from the artifacts of either the CI build or issue-bot’s build. To find it, open the corresponding log, tap the „Browse“ box in the right-hand side-bar, enter the
unsigned folder, download the APK.
- download APK, have it cross-checked with VirusTotal (also look through the permissions and "interestring strings" on the details page there – especially be alerted when the "behavior" tab shows up: give it a thorough look!) and, if possible, other library scanners at your disposal
- (optionally?) sign it,
adb installit to the test device/emulator
- test if it starts
- right after the start, make sure to enable network monitoring/logging – e.g. in Netguard, Net Monitor (recommended: the easiest of the options to my knowledge), PCAPdroid or AFWall+ (root needed)
- watch out for outgoing network connections
- right after start, without user interaction? Uh-oh…
- while using the app at „unexpected places“?
- at „expected places“?
- where to? Critical? Sometimes it’s trivial things the author can fix (e.g. online fonts from Google & Co can be included with the app or offered to be downloaded interactively, so the user can confirm/deny), sometimes it’s a „necessary evil“ calling for the
NonFreeNetAnti-Feature – but sometimes it can indicate things we’d rather not let in.
- does the app (rawly) do what it should? No need for a complete review incl. bug tracking – but it should e.g. not crash right at the start.
- much of pre-check does not need much „tech knowledge“ and is learned pretty quickly – can be done by „average users“ (if an „average user“ cannot understand the description of a simple app, that needs improvement, right?)
- interpreting CI logs needs a bit getting-used-to but is not too hard. If you spot something and point that out to the author, some issues can be solved and don’t „eat time“ from more experienced reviewers – who then can concentrate on the „remains“.
- noone is forced to cover everything – we are a TEAM that works together, so each little bit helps Together as team we also can meet the responsibility we’ve taken upon us (users expect us to have the apps checked well so things are as safe as possible).
- don’t be afraid asking a „senior“ for insights/help. Seniors will be gladly helping out – hoping that in the long run this takes some load from their shoulders
So whether you’re a geek, a nerd or just an enthusiast – you’re welcome to join us, to help us improving (response times at) F-Droid. Thank you for considering!
I’ve collected some details over the past few years. Some of those links already have been integrated above, but let me concentrate them here:
- Fastlane Cheat Sheet
- Triple-T Cheat Sheet
- Licenses and their abbreviations: SPDX
- Helpful details around F-Droid topics, including
- Metadata Reference incl. list of AntiFeatures
- GitLab permissions – what can you do once you’ve reached reporter, developer or maintainer status?
- Video tutorials / training sessions
Example metadata file
This is how a complete metadata file would look like; what each field stands for and what it should contain is explained on the Metadata page in F-Droid’s documentation. Let’s pretend we have an app called „My Example App“, going by the packageName
com.example.app – so our file is named
AntiFeatures: - NonFreeNet Categories: - Theming License: Apache-2.0 AuthorName: John Doe AuthorEmail: email@example.com AuthorWebSite: https://www.example.com/ WebSite: https://www.example.com/myApp SourceCode: https://github.com/johndoe/my_example_app IssueTracker: https://github.com/johndoe/my_example_app/issues Translation: https://github.com/johndoe/my_example_app/wiki/Translation Changelog: https://github.com/johndoe/my_example_app/releases Donate: https://github.com/johndoe/my_example_app/wiki/Donate Liberapay: johndoe Bitcoin: <BitcoinAddressHere> RepoType: git Repo: https://github.com/johndoe/my_example_app.git Builds: - versionName: 1.0.1 versionCode: 2 commit: v1.0.1 subdir: app gradle: - yes AutoUpdateMode: Version v%v UpdateCheckMode: Tags CurrentVersion: 1.0.1 CurrentVersionCode: 2
Note that not all fields are mandatory – if there are no AntiFeatures, the entire AntiFeature block would simply be left out. Mandatory are, however: at least one category, the license,
Repo. Summary & Description shall come via Fastlane, so they are missing here. From the
versionCode must correspond to
CurrentVersionCode at the end,
commit should be the tag name. In this example, the tag name is the
versionName with a prepended
%v standing for
There are more complex definitions (e.g. with Flutter projects) – but those are for „advanced contributors“ to handle. Keep in mind that packagers will cross-check your prepared metadata, so no worries if they’re „not perfect“. And while the
Builds block as well as the last 4 lines are required as well, they can be set up with the MR – as often versions have advanced before metadata are merged, they usually need to be updated then anyway.