A runnable tour of the Android Solid Services client SDK. One screen, a list of features, and about a hundred demonstrations — each one a real call against a real pod, shown next to the code that made it.
It is two things at once: a cookbook you can copy from, and the manual test bed for the parts of a
Solid pod no unit test can reach — that a stale If-Match really comes back 412, that an
Append-only receiver really is refused a PUT, that five megabytes really do stream past the
binder transaction limit.
- The Android Solid Services app installed. It owns the sign-in and the tokens; this app never
sees a credential. Without it every call fails with
SolidAppNotFoundException. - A Solid account signed in inside that app.
- Optionally, a second account you control — set it as the peer WebID in settings. Sharing and notification demonstrations are skipped without one, because granting yourself access demonstrates nothing about access control.
To switch accounts, revoke access in the header and sign in again — Android Solid Services shows its account picker. The harness then starts over for the new account: the test container is re-derived from its profile, and results, logs and session details from the previous account are cleared. Nothing carries across, which is also why nothing 403s after a switch.
The demonstrations run against real servers. Community Solid Server and Inrupt PodSpaces (ESS) are both exercised regularly; where the two disagree — ESS accepts only SPARQL Update for PATCH, CSS takes N3 — the SDK negotiates, so the same demonstrations pass on either.
One dependency:
implementation("com.erfangholami.androidsolidservices:client:0.6.0")That is the whole setup. In particular you do not need a <queries> entry for package
visibility — the library's own manifest declares it and the merger folds it into yours.
// Sign-in is an ActivityResult contract: the account picker launches from YOUR foreground,
// so Android Solid Services needs no overlay permission.
private val authorize = registerForActivityResult(AuthorizeWithSolid()) { result ->
when (result) {
is SolidSignInResult.Authorized -> onSignedIn(result.webId)
SolidSignInResult.Dismissed -> Unit
is SolidSignInResult.Failed -> show(result.exception)
}
}
SignInButton(onClick = { authorize.launch(Unit) })
// Every call takes the WebID, so one app can act for several accounts.
val resources = Solid.getResourceClient(context)
val profile = resources.getWebId(webId)By default the app resolves the published artifact. Put an Android Solid Services checkout beside
this one — or set assLocalPath in gradle.properties — and Gradle substitutes that build's
:client project instead, so SDK edits are picked up on the next build with nothing to publish.
# gradle.properties, or ~/.gradle/gradle.properties
assLocalPath=/path/to/AndroidSolidServicesUnset it and you get exactly what a third-party developer gets.
| Feature | What it covers |
|---|---|
| Setup & session | Installation, binding, authorization, the WebID profile |
| Containers | Create, HEAD, read and list the folders of a pod |
| RDF resources | Create/read/update/patch/delete, both conditional-write cases; patch negotiates N3 or SPARQL per server |
| Binary resources | Store, read and replace an image |
| Streaming | Five megabytes each way, past the binder transaction limit |
| Raw HTTP & placement | putRaw, post, server-allocated URIs, copy/move/rename, public reads |
| Contacts | Address books, contacts and groups as vCard-shaped RDF |
| Tickets | A wallet of schema:Ticket documents with their original files |
| Sharing | Grant, change and revoke access; track it in both directions |
| Notifications | The LDN inbox: offers, requests, decisions |
| Errors & resilience | The typed failures, and recovering from a killed service |
| Cleanup | Remove everything the app created |
catalog/ one file per feature — pure declarations, no Compose, no Android UI
runner/ the models, the test context, and the serial runner
ui/ the single screen and its bottom sheets
data/ persisted settings and the payloads written to the pod
catalog/ is where the value is. It reads as a document of how to call the SDK that happens to be
executable — adding a demonstration means editing one file there and nothing in the UI.
Everything is created under the test container shown in the header, and nothing outside it is ever touched. The Cleanup feature removes that container and everything in it.
Destructive demonstrations never run from "Run all" or a feature run — they report as skipped with the reason, and each runs individually from its own sheet. Every run starts from a clean slate over exactly the tests it executes, and Stop marks whatever was in flight as stopped rather than failed.