Skip to content

Replace embedded Kubo (mobile.aar) with the freedom-ipfs Rust reader #3

Description

@meinharrd

Motivation

IPFS/IPNS currently comes from an embedded Kubo node: mobile.aar (built in solardev-xyz/freedom-node-mobile, gomobile) wrapped by swarmnode/src/main/java/baby/freedom/swarm/IpfsNode.kt. iOS instead embeds solardev-xyz/freedom-ipfs, a read-only Rust IPFS reader with a loopback gateway. Moving Android to freedom-ipfs:

  • drops the Go runtime + full Kubo daemon (APK size, memory, battery),
  • since the bee→ant swap we only use the Kubo half of mobile.aar, so this removes the freedom-node-mobile dependency entirely,
  • unifies retrieval behaviour with iOS (verified blocks, delegated routing + light-DHT fallback, bounded cache),
  • gains real mobile lifecycle hooks (background/foreground, low-memory, network-change) that Kubo never exposed,
  • deletes the Kubo config-JSON DNS patching hack in IpfsNode.kt (ensureDnsConfigPatched) — freedom-ipfs speaks DoH natively.

Blocked on: solardev-xyz/freedom-ipfs#16 (freedom-ipfs has no Android export yet — iOS xcframework only).

Integration plan (mirrors the ant integration)

1. Vendor the native lib. Build libfreedom_ipfs_mobile.so per ABI in the freedom-ipfs repo (cargo xtask build-android-arm64 / -x86_64, per #16) → copy into swarmnode/src/main/jniLibs/{arm64-v8a,x86_64}/. Vendor freedom_ipfs.h into swarmnode/src/main/cpp/ next to ant.h.

2. JNI shim. New swarmnode/src/main/cpp/freedom_ipfs_jni.c (same pattern as ant_jni.c), added to CMakeLists.txt. Minimum surface:

  • freedom_ipfs_node_new_with_data_dir / freedom_ipfs_node_free
  • freedom_ipfs_node_start_gateway_online_with_config_v3 with addr = "127.0.0.1:0" (ephemeral port, same trick as today) — params: delegated router URL(s), routing mode, max concurrent requests, DHT query timeout, DHT max providers, request queue timeout
  • freedom_ipfs_node_gateway_url (replaces Kubo's gatewayAddr() for IpfsInfo.gatewayUrl)
  • freedom_ipfs_node_stop_gateway
  • freedom_ipfs_node_diagnostics (+ retrieval_stats / routing_stats) for the status UI
  • lifecycle: enter_background, enter_foreground, handle_low_memory, handle_network_change, trim_cache / clear_cache
  • freedom_ipfs_version for logging
  • string/buffer frees (freedom_ipfs_string_free, freedom_ipfs_buffer_free)

The native gateway request API (freedom_ipfs_gateway_request_*) is not needed — we consume the HTTP loopback gateway, as the browser already does with ant and Kubo.

3. Rewrite IpfsNode.kt, keep its public shape. Same state: StateFlow<IpfsInfo> + start()/stop()/dispose() contract so NodeService (maybeStartIpfs/maybeStopIpfs), the AIDL broadcast, and Settings UI stay untouched. Changes inside:

  • construct node with dataDir = filesDir/ipfs-reader (new dir; delete the old Kubo repo at filesDir/ipfs on first successful start — it's just a cache + keys, nothing user-owned)
  • delete ensureDnsConfigPatched and the offline-init dance
  • peer count: freedom-ipfs has no connectedPeerCount. Repoll diagnostics instead and surface cache hits / provider blocks / bitswap blocks (or drop the peers row from the IPFS status card). Touches IpfsInfo.kt / Settings status UI.

4. Settings mapping (NodeSettings.kt, Settings screen):

  • ipfs_routing_mode (Kubo "autoclient"/"dht") → freedom-ipfs routing-mode enum (auto / delegated-only / light-DHT / offline). Pick new default = auto; migrate stored values.
  • ipfs_low_power (Kubo lowpower profile) has no direct equivalent → either drop the toggle or map it to conservative config-v3 values (lower max concurrent requests / DHT fanout / shorter timeouts).
  • Bonus over Kubo: config changes can apply via restart_gateway_online_with_config_v3 instead of requiring an off/on cycle.

5. Wire the lifecycle hooks (new capability, do it in this pass): handle_network_change from a ConnectivityManager callback in NodeService, handle_low_memory/trim_cache from onTrimMemory, background/foreground from the service's foreground state.

6. Verify ENS/DNSLink .eth coverage. The Kubo integration patched eth.https://dns.eth.limo/dns-query for .eth DNSLink. freedom-ipfs defaults to Cloudflare DoH for DNSLink; confirm the in-app EnsResolver path covers all ens:// flows, otherwise we need per-TLD resolver config upstream (would extend #16).

7. Cleanup. Delete swarmnode/libs/mobile.aar + its Gradle dep, drop the gomobile classes from consumer-rules.pro if referenced, update README build recipe (freedom-node-mobile section → freedom-ipfs section).

Testing

  • ipfs://<cid> file + directory (index.html fallback, listing) on emulator (x86_64) and arm64 device
  • ipns://<key> and DNSLink (ipns://en.wikipedia-on-ipfs.org)
  • ens:// site that resolves to an IPFS contenthash
  • Range requests (seek in a video) — gateway supports bounded streaming + Content-Range
  • Toggle off/on in Settings; kill :node process and restart; airplane-mode → network-change recovery
  • Error pages for bad CIDs / unreachable content still render via ErrorPage.kt
  • APK size and idle battery before/after (expect both to improve)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions