Zestaw natywnych pluginów Capacitor dla Androida. Sieć, ekran, bateria, audio, locale, sensory, Bluetooth/NFC i stan systemu — jednym wywołaniem, w czystym JSON-ie, bez próśb o uprawnienia.
Testy obejmują apkę demonstracyjną prezentującą mój autorski zestaw pluginów Capacitor — żadne dane nie są wysyłane na żaden serwer.
{
"network": { "connectionSummary": "WiFi", "validated": true },
"screen": { "resolution": "1220×2429", "refreshHz": 120 },
"battery": { "percent": 86, "charging": "ac" },
"device": { "model": "2412DPC0AG", "codename": "rodin" }
// + 6 kolejnych gałęzi, patrz rejestr pluginów niżej
}
Każdy plugin ma dokładnie jedną metodę get…Info(),
bez argumentów, zwraca jeden obiekt JSON podzielony na tematyczne sekcje
(np. wifi, capabilities, battery).
Kliknij nazwę, żeby zobaczyć pełną
sygnaturę, realny response i przykład wywołania.
Transport, walidacja internetu, link speed, DNS, szczegóły WiFi, operator komórkowy.
network// npm install @tojestproste/caplab-network-info import { NetworkInfo } from '@tojestproste/caplab-network-info'; const data = await NetworkInfo.get(); console.log(data.connectionSummary); // "WiFi"
{
"timestamp": 1785703415362,
"sdkInt": 36,
"hasActiveNetwork": true,
"transport": {
"wifi": true, "cellular": false, "ethernet": false,
"vpn": false, "bluetooth": false, "wifiAware": false,
"lowpan": false, "usb": false
},
"capabilities": {
"internet": true, "validated": true, "notMetered": true,
"notRoaming": true, "notVpn": true, "captivePortal": false,
"notSuspended": true, "temporarilyNotMetered": false,
"linkDownstreamKbps": 66421, "linkUpstreamKbps": 260421,
"signalStrengthDb": -43
},
"linkProperties": {
"interfaceName": "wlan0", "mtu": 0, "domains": "home",
"dnsServers": ["192.168.1.1", "2a01:110f:4f00:3f00:ba8c:2bff:fe2b:28"],
"linkAddresses": ["192.168.1.12/24", "..."]
},
"wifi": {
"ssidRaw": "", // wymaga location, patrz notatka niżej
"bssidRaw": "02:00:00:00:00:00",
"rssi": -27, "linkSpeedMbps": 2401, "frequencyMHz": 5500,
"wifiStandard": 6, "signalLevel0to4": 4, "wifiEnabled": true,
"wifi5GHzSupported": true, "wifi6GHzSupported": true
},
"cellular": {
"networkOperatorName": "Orange", "networkCountryIso": "pl",
"dataNetworkType": 0, "error": "SecurityException: getDataNetworkTypeForSubscriber"
},
"connectionSummary": "WiFi"
}
Rozdzielczość realna vs. app-usable, gęstość, jasność, refresh rate, cutout/notch, paski systemowe.
screen// npm install @tojestproste/caplab-screen-info import { ScreenInfo } from '@tojestproste/caplab-screen-info'; const data = await ScreenInfo.get(); console.log(data.systemBars.systemBarsTotalHeightPx); // 283
{
"appUsableResolution": { "widthPx": 1220, "heightPx": 2429 },
"realResolution": { "widthPx": 1220, "heightPx": 2712 },
"density": {
"density": 3.25, "densityDpi": 520, "densityBucket": "xxxhdpi"
},
"orientation": "portrait",
"brightness": { "value0to255": 88, "percent": 35, "automatic": true },
"refreshRate": { "currentHz": 120, "supportedHz": [30, 60, 90, 120] },
"colorCapabilities": { "isWideColorGamut": true, "hdrSupported": true },
"cutout": {
"present": true, "safeInsetTop": 130,
"boundingRects": [{ "left": 577, "top": 0, "right": 643, "bottom": 130 }]
},
"systemBars": {
"statusBarHeightPx": 130, "navigationBarHeightLegacyPx": 153,
"navigationBarInsetsModern": { "bottom": 153 },
"likelyGestureNavigation": false,
"systemBarsTotalHeightPx": 283
}
}
Opcje deweloperskie, USB debugging, build apki, kto zainstalował paczkę.
devMode// npm install @tojestproste/caplab-dev-mode import { DevMode } from '@tojestproste/caplab-dev-mode'; const data = await DevMode.get(); console.log(data.appBuildInfo.isDebugBuild); // true
{
"developer": { "developerOptionsEnabled": true },
"adb": { "usbDebuggingEnabled": true },
"mockLocation": {
"note": "Android 12+ usunął globalny switch - per-app wybór, nieodczytywalny."
},
"stayAwakeWhileCharging": { "enabled": false, "rawValue": 0 },
"appBuildInfo": {
"isDebugBuild": true, "packageName": "com.tojestproste.caplab",
"versionName": "1.0", "versionCode": 1, "targetSdkVersion": 34,
"installerPackageName": "adb / sideload (brak installera)"
},
"systemBuild": {
"androidVersion": "16", "sdkInt": 36, "manufacturer": "Xiaomi",
"fingerprint": "POCO/rodin_eea/rodin:16/BP2A.250605.031.A3/.../release-keys",
"isEmulator": false
}
}
Model, nazwa kodowa, build fingerprint, wersja Androida, patch bezpieczeństwa, RAM, storage, Google Play Services.
device// npm install @tojestproste/caplab-device-info import { DeviceInfo } from '@tojestproste/caplab-device-info'; const data = await DeviceInfo.get(); console.log(data.identity.codename); // "rodin"
{
"identity": {
"manufacturer": "Xiaomi", "brand": "POCO", "model": "2412DPC0AG",
"device": "rodin", "codename": "rodin", "hardware": "mt6899"
},
"build": {
"fingerprint": "POCO/rodin_eea/rodin:16/BP2A.250605.031.A3/.../release-keys",
"type": "user", "tags": "release-keys"
},
"androidVersion": { "release": "16", "sdkInt": 36, "codename": "REL" },
"security": { "securityPatchLevel": "2026-06-01" },
"googlePlayServices": {
"installed": true, "versionName": "26.29.31 (260400-952280416)"
},
"memory": {
"totalRamGB": 11.05, "availableRamGB": 3.53, "isLowRamDevice": false
},
"storage": {
"totalGB": 479.35, "availableGB": 206.8, "usedPercent": 57
},
"cpu": { "supportedAbis": ["arm64-v8a"], "numberOfCores": 8 },
"uptime": { "uptimeHours": 107.97 }
}
Poziom, status ładowania, typ ładowarki, temperatura, health, napięcie, technologia ogniwa.
battery// npm install @tojestproste/caplab-battery-info import { BatteryInfo } from '@tojestproste/caplab-battery-info'; const data = await BatteryInfo.get(); console.log(data.level.percent); // 86
{
"level": { "percent": 86, "rawLevel": 86, "rawScale": 100 },
"charging": {
"isCharging": true, "statusName": "charging", "plugType": "ac",
"usbCharge": false, "acCharge": true, "wirelessCharge": false
},
"health": { "code": 2, "name": "good" },
"temperature": { "rawTenthsOfCelsius": 350, "celsius": 35 },
"voltage": { "millivolts": 4307, "volts": 4.31 },
"technology": "Li-poly", "batteryPresent": true,
"batteryManagerExtra": {
"capacityPercentFromManager": 86, "chargeCounterMicroAh": 5016000,
"currentNowMicroA": -30000
}
}
Język, region, strefa czasowa, tryb ciemny/jasny systemowy, format daty/liczb, kierunek pisma.
locale// npm install @tojestproste/caplab-locale-info import { LocaleInfo } from '@tojestproste/caplab-locale-info'; const data = await LocaleInfo.get(); console.log(data.uiMode.isDarkModeActive); // false
{
"locale": {
"language": "pl", "country": "PL", "displayName": "polski (Polska)",
"toLanguageTag": "pl-PL", "allSystemLocales": ["pl-PL"]
},
"timezone": {
"id": "Europe/Warsaw", "rawOffsetHours": 1, "currentlyInDST": true
},
"uiMode": {
"nightMode": "light", "isDarkModeActive": false,
"uiModeTypeName": "vendor_extension_15"
},
"formatting": {
"sampleDateFormatted": "niedziela, 2 sierpnia 2026, 21:53",
"decimalSeparator": ",", "currencySymbol": "zł", "is24HourFormat": true
},
"layoutDirection": { "isRtl": false }
}
Pełna lista fizycznych czujników — nazwa, vendor, zasięg, pobór mocy. Bez odczytu danych na żywo.
osobne wywołanie// npm install @tojestproste/caplab-sensor-info import { SensorInfo } from '@tojestproste/caplab-sensor-info'; const data = await SensorInfo.get(); console.log(data.totalSensorCount); // 43 console.log(data.commonSensorsPresence.stepCounter); // true
{
"totalSensorCount": 43,
"sensors": [
{
"name": "lsm6dsvq_acc", "vendor": "st", "stringType": "android.sensor.accelerometer",
"maxRange": 78.45, "power": 0.001, "reportingMode": "continuous"
},
{ "name": "tsl2522_als", "stringType": "android.sensor.light", "reportingMode": "on_change" },
{ "name": "Fod Wakeup", "vendor": "xiaomi", "stringType": "xiaomi.sensor.fod" }
// ... pozostałe 40 czujników
],
"commonSensorsPresence": {
"accelerometer": true, "gyroscope": true, "proximity": true,
"stepCounter": true, "heartRate": false
}
}
Celowo poza domyślnym scalonym JSON-em w apce testowej — 43 czujniki potrafią przekroczyć limit schowka telefonu. Plugin jest w pełni gotowy, wywołaj go osobno.
Głośność per-stream, tryb dzwonienia, wyciszenie mikrofonu, podłączone urządzenia wyjściowe.
audio// npm install @tojestproste/caplab-audio-info import { AudioInfo } from '@tojestproste/caplab-audio-info'; const data = await AudioInfo.get(); console.log(data.volumes.music.percent); // np. 60
{
"volumes": {
"music": { "current": 9, "max": 15, "percent": 60, "isMuted": false },
"ring": { "current": 5, "max": 7, "percent": 71 },
"alarm": { "current": 6, "max": 7 }
},
"ringerMode": { "modeCode": 2, "modeName": "normal" },
"audioMode": { "code": 0, "name": "normal" },
"isMicrophoneMute": false, "isSpeakerphoneOn": false,
"audioDevices": {
"wiredHeadsetConnected": false, "bluetoothA2dpOn": false,
"outputDevices": [{ "type": "builtin_speaker", "isSink": true }]
},
"flags": { "musicActive": false, "volumeFixed": false }
}
Power save mode, Doze/idle, czy ekran interaktywny, zwolnienie z optymalizacji baterii.
powerState// npm install @tojestproste/caplab-power-state import { PowerState } from '@tojestproste/caplab-power-state'; const data = await PowerState.get(); console.log(data.batteryOptimization.isExemptFromOptimization);
{
"powerSave": { "isPowerSaveMode": false, "locationPowerSaveMode": 0 },
"doze": { "isDeviceIdleMode": false, "isInteractive": true },
"screenState": { "isInteractive": true },
"batteryOptimization": {
"isExemptFromOptimization": false,
"note": "Apka podlega standardowym ograniczeniom Doze/App Standby."
},
"supportsSustainedPerformanceMode": true
}
Stan Bluetooth (on/off, adapter) i NFC (obecność, on/off). Bez skanowania/parowania.
connectivity// npm install @tojestproste/caplab-connectivity-state import { ConnectivityState } from '@tojestproste/caplab-connectivity-state'; const data = await ConnectivityState.get(); console.log(data.bluetooth.isEnabled);
{
"bluetooth": {
"hardwareSupported": true, "isEnabled": true,
"stateName": "on",
"adapterNameError": "Wymaga BLUETOOTH_CONNECT (API 31+)"
},
"nfc": { "hardwareSupported": true, "isEnabled": true }
}
Wszystkie 10 pluginów działa na ACCESS_NETWORK_STATE i ACCESS_WIFI_STATE —
obie to uprawnienia „normal”, przyznawane automatycznie przy instalacji, bez dialogu.
Efekt uboczny: wifi.ssidRaw zawsze wróci puste (system wymaga lokalizacji, żeby
pokazać nazwę sieci od Androida 8). To ograniczenie systemowe, nie błąd pluginu.
Apka demonstracyjna konsumuje wszystkie 10 pluginów jako realne zależności npm (nie lokalne pliki Java) — najprostszy sposób, żeby zobaczyć każdy plugin w działaniu bez pisania linijki kodu.
Google wymaga bycia w grupie, żeby zobaczyć apkę w testach zamkniętych.
⚠ Po otwarciu strony grupy kliknij przycisk „Dołącz do grupy” (Join) — samo wejście na stronę nie wystarczy.
Otwórz grupę testerówLink opt-in aktywuje Twoje konto Google do pobrania wersji testowej.
Dołącz do testówPo aktywacji apka pojawi się jak każda inna, ze stałymi aktualizacjami.
⚠ Jeśli apka nie pojawia się od razu, poczekaj — Google Play potrzebuje czasem od kilkunastu minut do 2–3 godzin, żeby udostępnić dostęp po dołączeniu do testów.
Otwórz w Google PlayApka jest w fazie testów zamkniętych (closed testing) — liczba miejsc jest ograniczona przez Google, a każdy krok powyżej jest wymagany w tej kolejności. Jeśli krok 3 pokazuje błąd braku dostępu, wróć do kroku 1 lub 2 i odczekaj chwilę.
npm install @tojestproste/caplab-xxx, potem npx cap sync android — Capacitor rejestruje plugin automatycznie, bez ręcznej edycji MainActivity.java.
Standardowy import ES module — każdy plugin eksportuje jedną nazwaną klasę z metodą get().
gradlew assembleDebug → adb install -r app-debug.apk, albo standardowy release build pod Google Play.
npm install @tojestproste/caplab-network-info @tojestproste/caplab-battery-info npx cap sync android
import { BatteryInfo } from '@tojestproste/caplab-battery-info'; const data = await BatteryInfo.get(); console.log(data.level.percent); // 86 console.log(data.charging.plugType); // "ac"
import { NetworkInfo } from '@tojestproste/caplab-network-info'; import { ScreenInfo } from '@tojestproste/caplab-screen-info'; import { BatteryInfo } from '@tojestproste/caplab-battery-info'; const [network, screen, battery] = await Promise.all([ NetworkInfo.get(), ScreenInfo.get(), BatteryInfo.get() ]); const merged = { network, screen, battery }; document.getElementById('output').textContent = JSON.stringify(merged, null, 2);
@tojestproste/caplab-*, więc możesz zainstalować
tylko te, których potrzebujesz.
AndroidManifest.xml.
Jedyny wyjątek to NetworkInfo, który wymaga
ACCESS_NETWORK_STATE i ACCESS_WIFI_STATE — obie to
uprawnienia „normal”, przyznawane automatycznie przy instalacji, bez dialogu
proszącego użytkownika o zgodę. Świadomie pominięte funkcje (np. realny SSID
WiFi, dokładny sygnał komórkowy) wymagałyby dodatkowego dostępu do lokalizacji
lub telefonu — patrz notatka w rejestrze pluginów wyżej.
npm install @tojestproste/caplab-battery-info instaluje
wyłącznie ten jeden plugin, bez ciągnięcia pozostałych dziewięciu.