New app: Lean

Required

  • The app complies with the inclusion criteria
  • The original app author has been notified (and does not oppose the inclusion) — I am the author.
  • All related fdroiddata and RFP issues have been referenced in this merge request — there are none.
  • Builds with fdroid build and all pipelines pass
  • There is an issue tracker and contact info of the author so that we can report bugs and contact the author.
  • The upstream app source code repo contains the app metadata in a Fastlane folder structure — fastlane/metadata/android/{en-US,ru}, with title, summary, description, icon, four screenshots and changelogs.
  • Releases are tagged and auto update is enabled

Suggested

  • External repos are added as git submodules instead of srclibs — neither is used. The native sources are pinned tarballs verified by sha256 in native/versions.lock.
  • Enable Reproducible Builds — No, I don't want this.
  • Multiple apks for native code — the build produces one universal APK. Splitting is possible and I am happy to do it if you would prefer; -PsingleApk is what currently collapses the split, because fdroid build refuses a build that emits more than one APK.

About the app

Lean is a VPN client for Android with its own interface, routing and subscription handling. It works with any server or subscription and requires no account.

  • Source: https://github.com/Th3Nekit/Lean
  • License: GPL-3.0-or-later
  • Builds the foss flavour, which carries no promotion of my paid service. The build I distribute myself does.

Answers to your questions

Why libcore from NekoBox rather than sing-box directly?

libcore is the Android binding layer: it wraps sing-box in a Java API through gomobile, and adds the platform plumbing an Android VPN needs — the TUN owner, protect() for sockets, per-app routing, the status/stats interface. Upstream sing-box ships the engine, not those bindings. The app was written against that API from the start; moving to another one is a rewrite of the whole core layer rather than a dependency swap. Both are GPL-3.0, and native/build-linux.sh compiles libcore from pinned sources — nothing prebuilt enters the APK.

Why AmneziaWG-Go, Mieru, Xray and olcRTC as separate components?

Because the core does not implement them.

  • AmneziaWG is a modified WireGuard with obfuscation of the handshake (junk packets, magic headers). It is a separate Go implementation with its own JNI glue; sing-box's WireGuard is the plain protocol.
  • Xray is needed only for VLESS over XHTTP, a transport sing-box does not have.
  • Mieru and olcRTC are independent projects with their own protocols; olcRTC tunnels through a video call.

Each runs as its own process behind a local SOCKS endpoint. All four are compiled from pinned sources by the same script.

Why is NaiveProxy absent?

Only because this flavour does not build it. I did not mean to claim it is impossible, and I have removed that wording from the description. If you would like it included, I will look at what SFA does with cronet and add it in a later version.

The build

native/build-linux.sh runs as the build command, after the scanner, and compiles everything from sources pinned by sha256 in native/versions.lock: the sing-box core through gomobile, AmneziaWG-Go, and the Mieru, Xray and olcRTC helpers.

It needs two NDKs — r25 for the core, because that is what the pinned gomobile expects, and r26b for AmneziaWG-Go. Only one can be declared in ndk:, so the script installs the other through the sdkmanager on PATH, which verifies checksums; it honours ANDROID_NDK_HOME only when that is the version being asked for.

sudo installs patch alone, which the build needs to apply the pinned patches to the core sources.

Edited by Th3Nekit

Merge request reports

Loading
Loading