AppWrapper API

← Config · Testsida

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.

Kom igång i din site (t.ex. byggd med Lovable)

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

MetodBeskrivning
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.