AppWrapper API
AppWrapper är en native iOS-app (Android kommer) som visar din webbsite i fullskärm
och ger den tillgång till telefonens native-funktioner via ett JavaScript-API.
Vilken site som visas styrs av config-sidan — appen hämtar
GET /api/config vid varje start.
När siten körs inuti appen finns objektet window.AppWrapper.
I en vanlig webbläsare finns det inte — koda alltid med en koll:
if (window.AppWrapper) {
// Körs i appen — native-funktioner tillgängliga
const pos = await AppWrapper.location.get();
} else {
// Vanlig webbläsare — använd webbens API:er eller dölj funktionen
}
Alla metoder returnerar Promises. Fel (nekad behörighet,
funktion som saknas m.m.) kastas som Error med ett läsbart meddelande
— använd try/catch. Första anropet till en funktion visar iOS
behörighetsdialog för användaren.
Översikt
| Metod | Beskrivning |
|---|---|
device.info() | Enhetsmodell, OS-version, språk, appversion |
location.get() | Aktuell GPS-position |
camera.takePhoto(opts) | Öppna kameran, ta foto → base64-JPEG |
camera.recordVideo(opts) | Spela in video → base64 |
audio.startRecording() / stopRecording() | Ljudinspelning via mikrofonen → base64-m4a |
speech.startListening(opts) / stopListening() | Tal-till-text med löpande delresultat |
speech.speak(text, opts) | Text-till-tal |
motion.start(opts) / stop() | Gyro, accelerometer och attityd som eventström |
haptic(style) | Haptisk feedback |
on(event, cb) / off(event, cb) | Lyssna på events (motion, speechPartial) |
Referens
AppWrapper.device.info()
Returnerar { model, system, name, language, appVersion }.
const info = await AppWrapper.device.info();
// { model: "iPhone", system: "iOS 26.5", language: "sv-SE", ... }
AppWrapper.location.get()
Hämtar aktuell position. Returnerar
{ latitude, longitude, accuracy, altitude, speed, heading, timestamp }
(accuracy i meter, timestamp i millisekunder).
try {
const pos = await AppWrapper.location.get();
console.log(pos.latitude, pos.longitude);
} catch (e) {
// T.ex. "Behörighet nekad: plats"
}
AppWrapper.camera.takePhoto(opts?)
Öppnar kameran. Alternativ: maxSize (längsta sida i pixlar,
standard 1600) och quality (JPEG-kvalitet 0.1–1.0, standard 0.8).
Returnerar { base64, mimeType: "image/jpeg", width, height }.
const photo = await AppWrapper.camera.takePhoto({ maxSize: 1200 });
img.src = "data:image/jpeg;base64," + photo.base64;
AppWrapper.camera.recordVideo(opts?)
Öppnar videokameran. Alternativ: maxDuration (sekunder, standard 60).
Returnerar { base64, mimeType: "video/quicktime" }.
Håll inspelningarna korta — resultatet överförs som base64.
AppWrapper.audio.startRecording() / stopRecording()
startRecording() börjar spela in från mikrofonen.
stopRecording() returnerar { base64, mimeType: "audio/m4a", duration }.
await AppWrapper.audio.startRecording();
// ... användaren pratar ...
const rec = await AppWrapper.audio.stopRecording();
audio.src = "data:audio/m4a;base64," + rec.base64;
AppWrapper.speech.startListening(opts?) / stopListening()
Tal-till-text. Alternativ: locale (standard "sv-SE").
Delresultat kommer löpande som eventet speechPartial;
stopListening() returnerar { text } med sluttexten.
AppWrapper.on("speechPartial", (p) => (output.textContent = p.text));
await AppWrapper.speech.startListening({ locale: "sv-SE" });
// ... senare ...
const result = await AppWrapper.speech.stopListening();
console.log(result.text);
AppWrapper.speech.speak(text, opts?)
Läser upp texten. Alternativ: locale (standard "sv-SE"),
rate (0–1) och pitch (0.5–2). Promisen löses när uppläsningen är klar.
await AppWrapper.speech.speak("Hej! Din order är klar.");
AppWrapper.motion.start(opts?) / stop()
Strömmar rörelsedata som eventet motion. Alternativ:
interval (sekunder mellan uppdateringar, standard 0.1).
Varje event innehåller acceleration (G, utan gravitation),
rotationRate (rad/s — gyro) och attitude
(roll/pitch/yaw i radianer).
AppWrapper.on("motion", (m) => {
console.log(m.rotationRate.x, m.attitude.roll);
});
await AppWrapper.motion.start({ interval: 0.05 });
// ... senare ...
await AppWrapper.motion.stop();
Simulatorn saknar rörelsesensorer — anropet ger då ett fel.
AppWrapper.haptic(style?)
Haptisk feedback: "light", "medium" (standard),
"heavy", "success", "warning" eller "error".
AppWrapper.haptic("success");
Behörigheter & säkerhet
• iOS frågar användaren om lov första gången kamera, mikrofon, position eller taligenkänning används. Nekas behörigheten får anropet ett fel.
• Bryggan svarar bara sidor på den värd (inklusive subdomäner) som är konfigurerad som site-URL i config-sidan. Länkar ut till andra domäner fungerar, men de sidorna får inte tillgång till native-API:t.
• Konfigurera bara siter du litar på — de får tillgång till telefonens sensorer via API:t ovan.
Config-API:t (för appen)
Varje wrapper-app är knuten till ett app-ID och hämtar sin
config vid start med GET /api/config/<app-id>:
{
"siteUrl": "https://sellavo.com",
"appName": "Sellavo",
"themeColor": "#1A1A2E",
"splash": { "backgroundColor": "#F5F5F7", "text": "Sellavo" }
}
Siter skapas och redigeras i admin (kräver admin-token;
API-motsvarigheten är /api/admin/…). Appen rapporterar dessutom
en heartbeat vid varje start — POST /api/status/<app-id>
med appversion och om siten laddades OK — som visas i admin-listan, så du
ser direkt att allt kör korrekt efter en uppdatering i t.ex. Lovable.