com.plugchoice:plugchoice, for Kotlin apps. It shows Link, the hosted flow at connect.plugchoice.com, in a full-screen activity, and does what a web page can’t: join a charger’s Wi-Fi, find and reach chargers on the local network, talk Bluetooth to them and scan a QR code.
Install
Requirements: Android 10 (API 29) or later (minSdk 29), compileSdk 36, and JDK 17. Bluetooth on Android 12 and later needs your app to target API 31 or later. Scanning a charger’s QR code uses Google Play services; on a device without them, the user types the code instead.
The library is com.plugchoice:plugchoice on Maven Central. Make sure mavenCentral() is in your repositories (it usually is), then add the dependency to your app module:
com.plugchoice.
Configure your app
Permissions
The library’s manifest adds every permission it uses to your app’s manifest. You don’t add any. The SDK asks for the runtime ones only when the flow needs them.
Bluetooth LE is declared as an optional feature, so devices without it can still install your app. To leave Bluetooth out, remove the four Bluetooth permissions in your manifest with
tools:node="remove"; the SDK then doesn’t offer it. Bluetooth on Android 12 and later also needs your app to target API 31 or later.
Plain HTTP to chargers
Some chargers serve their local API over plain HTTP on their own Wi-Fi: Peblar answers athttp://172.16.0.1. Android blocks plain HTTP by default, and the SDK’s requests follow your app’s network security configuration, so allow it for that address only:
res/xml/network_security_config.xml
AndroidManifest.xml
domain-config to it. Without this, Peblar chargers can’t be set up in your app. The other chargers the SDK sets up today use HTTPS or Bluetooth.
Google Play data safety
Scanning a charger’s QR code uses Google’s code scanner from Google Play services. It needs no camera permission, but its ML Kit components send usage data to Google. Mention it in your app’s data safety form.Create the SDK
Create onePlugchoice instance and keep it for your app’s lifetime, for example in your Application or a singleton. Give it a callback that fetches a client secret from your server:
fetchClientSecret when Link opens, while the hosted flow loads. It calls it again, with the same action, whenever the secret expires (after 60 minutes), so a user can take as long as they need. The secret never goes into a URL or an intent, and the SDK never logs it.
Open Link
Register the SDK’s activity result contract, then launch it with an action:plugchoice.link.intent(context, action) for a result, and read it in onActivityResult with plugchoice.link.parseResult(resultCode, data).
The actions:
The SDK passes the action to the hosted flow without reading it, so a new action works through
custom before it gets a helper. Your client session’s scope must cover the action’s charger or site. Actions explains each one.
Link handles rotation, dark mode and keyboard changes itself, so the flow never reloads. It keeps the screen on while it’s open, because a charger’s Wi-Fi connection drops when the phone locks.
Handle the result
The contract returns aLinkResult:
LinkResult.Status
SUCCESS, CANCELLED or ERROR.String
The action the link session did. The user may have picked another one from the list of what a charger can do; otherwise it’s the action you opened.
String?
The link session, when the hosted flow started one.
null when Link closed before that.List<Device>
The devices the link session reported, each
Device(type, id). On SUCCESS, the devices it finished. type is "charger" (Device.TYPE_CHARGER) today; ignore types you don’t know.LinkError?
On
ERROR: a code, and a message for your logs.GET /sdk/v1/link-sessions/{id}). Link sessions explains why.
Errors
OnERROR, result.error?.code says why. The SDK sets two codes itself:
Every other code comes from the hosted flow. The one to know is
clientSecretUnavailable (LinkError.CLIENT_SECRET_UNAVAILABLE): your fetchClientSecret threw, returned an empty string or took longer than 30 seconds. The user then sees this screen, with Try again, and the result reports clientSecretUnavailable if they close it.
The same screen shows when Android recreated Link after your app’s process died: the Plugchoice instance is gone, so the user starts again from your app.
Other codes are for your logs; don’t branch on them. Errors lists them.
Show actions where they work
Not every charger can do every action, and not every phone has what an action needs. Show a button only when both are true:- The charger’s capability for it is
capable. Your server reads it with Get a charger. - Every transport in the capability’s
needsis inPlugchoice.transports(context).
Plugchoice.transports(context) asks for no permission. It returns wifi (on a device with Wi-Fi), http, socket and lan, and ble when the device has Bluetooth LE and your app kept the SDK’s Bluetooth permissions.
Test on a real device
The emulator can open Link, but it can’t reach a charger. Use a phone for:- joining a charger’s Wi-Fi, and the system’s “connect to device” prompt
- finding chargers on the home Wi-Fi
- everything Bluetooth, and its permission prompts
- scanning a QR code