App Studio developer docs

Make your website feel native inside your Tekservix app — the JavaScript bridge, push notifications, payments, deep links and publishing.

Overview

Apps built with App Studio load your website inside a fast native shell and add a JavaScript bridge, window.tekservix, so your pages can use native features: share sheet, haptics, QR and document scanners, biometrics, secure storage, push notifications, in-app purchases, background location and more.

Quick start

  1. Create the app. In App Studio choose Website to App (pay once per platform) or Native App (monthly plan with native features), then paste your website address. We read its name, colours, icon and menu.
  2. Design it. Set the icon and splash screen, tabs or side menu, colours, and which links stay inside the app. The phone preview updates as you type.
  3. Try it free. Build a free Android test app (APK) and install it from the QR code. Website-to-App trials last 7 days; the test app stops opening when the trial ends.
  4. Go live. Buy the platforms you need or choose a Native plan, then build the store-ready Android app (APK + AAB) and the iOS app, signed in your own Apple account and uploaded to TestFlight.
Tip: anything you change on your website shows in the app straight away — you only rebuild when the app itself changes (icon, name, menus, native features).

Builds, trial and plans

Website to AppNative App
PaymentOne-time per platform: Android, iOS or bothMonthly or yearly plan (Starter, Pro, Agency)
Free trial7 days of Android test builds (watermarked)Android test builds while you set up
Store buildsFor the platforms you own; free updates for a year, then a small fee per rebuildUnlimited, iOS and Android
Native featuresPush, QR scanner, rate prompt, AdMob, analyticsPlus offline mode, dark mode, Face ID, in-app purchases, background tasks, NFC, document scanner

iOS apps have no free trial. Builds that didn’t finish (failed, cancelled or never started) can be deleted from Builds and are removed automatically after 3 days.

Detect the app

Inside the app, your pages get three signals:

  • The <html> element has the classes tekservix-app and tekservix-android.
  • The user agent contains TekservixApp plus the suffix you set in App Studio.
  • window.tekservix.isApp is true once the bridge is ready.
/* Hide your "Download our app" banner inside the app */
.tekservix-app .get-the-app { display: none; }

// JavaScript
const inApp = /TekservixApp/.test(navigator.userAgent);
window.addEventListener('tekservix', e => {
  if (e.detail.event === 'ready') console.log('bridge ready');
});

JavaScript bridge

Every call returns a Promise. Calls are only accepted from the domains you list in App Studio (Links → domains inside the app). If a feature isn't switched on for the app, the Promise rejects with a message saying so.

try {
  const info = await tekservix.device.info();
  console.log(info.model, info.language);
} catch (err) {
  console.warn(err.message); // e.g. "'qr' is not enabled in this app…"
}

// Generic form, same as the helpers below
await tekservix.call('haptic', { type: 'success' });

Events

Listen with tekservix.on(name, fn) (returns an unsubscribe function) or the tekservix DOM event.

EventWhenData
readyThe bridge is loaded on a page{ platform }
push.receivedA push arrives while the app is open{ title, body, url, data }
purchases.updatedA purchase finished or changedarray of purchases
locationBackground location fix{ latitude, longitude, accuracy, … }
nfc.tagAn NFC tag was read{ id, techs, records }
qrFloating button scan that isn't a link{ text, format }

Native UI

CallWhat it does
tekservix.share({ title, text, url })Native share sheet. Share a file with { file: base64, filename, mime }.
tekservix.toast(text, long)Short native message at the bottom.
tekservix.banner(text, { position, bg, fg, duration })Banner at the top or bottom that hides itself.
tekservix.haptic(type)light, medium, heavy, success, warning, error, selection.
tekservix.vibrate(ms | pattern[])Vibrate for a time, or a pattern like [0, 200, 100, 200].
tekservix.statusBar.set({ color, style, hidden })Status bar colour, light/dark icons, hide/show.
tekservix.navigationBar.set({ color })Bottom system bar colour.
tekservix.screen.keepOn(true)Stop the screen from sleeping (recipes, tickets, maps).
tekservix.screen.brightness(1)Full brightness for a QR ticket; -1 restores.
tekservix.screen.fullscreen(true)Hide system bars (games, video).
tekservix.screen.orientation('landscape')portrait, landscape or auto.
tekservix.datePicker({ mode, value, min, max })Native date/time picker. mode: date, time, datetime. Resolves to an ISO string.
tekservix.print()Android print dialog (also replaces window.print()).
tekservix.screenshot({ save, share, scale })Image of the page as a data URL; optionally saves or shares it.
tekservix.page.loader(true)Show/hide the loading bar.
tekservix.app.rate()Google Play review prompt (or opens your store page).

Device

CallNeedsResult
tekservix.device.info()—{ platform, osVersion, sdk, manufacturer, model, language, timezone, darkMode, width, height, deviceId, online }
tekservix.app.info()—{ name, package, version, build, features }
tekservix.scanner.qr({ formats, prompt, front, torch })QR scanner{ text, format }
tekservix.scanner.document({ pages, gallery, pdf })Document scanner{ pages: [dataUrl], pdf: dataUrl, pageCount }
tekservix.nfc.read({ timeout }) / nfc.stop()NFC reader{ id, techs, records: [{ type, text, uri, payload }] }
tekservix.location.current({ highAccuracy })Location{ latitude, longitude, accuracy, altitude, speed, heading, timestamp }
tekservix.contacts.pick()—{ name, phone } — no contacts permission needed
tekservix.calendar.add({ title, description, location, start, end, allDay, timezone })—Opens the calendar's “new event” screen
tekservix.clipboard.copy(text) / read()——
tekservix.open.external(url) / inAppBrowser(url) / app(url)—Browser, in-app browser tab, or another app (intent:, whatsapp:…)
tekservix.app.openSettings()—The app's system settings (permissions)
tekservix.audio.background({ title, text }) / audio.stop()Background audioKeeps your web audio playing with the screen off
tekservix.download({ data, filename, mime })—Saves base64 data to Downloads

Camera, microphone and the browser's navigator.geolocation work as on the web once you switch those permissions on in App Studio.

Storage & security

// Native storage (survives cache clears; good for settings)
await tekservix.storage.set('theme', 'dark');
const theme = await tekservix.storage.get('theme');

// Keystore-encrypted storage for tokens
await tekservix.secureStorage.set('refresh_token', token);

// Biometric unlock before reading the token
const { available } = await tekservix.biometric.available();
if (available) {
  await tekservix.biometric.authenticate({ title: 'Sign in', subtitle: 'Use your fingerprint' });
  const token = await tekservix.secureStorage.get('refresh_token');
}

const rooted = await tekservix.device.isRooted();

Push notifications

Push notifications run on your own Firebase Cloud Messaging or OneSignal project: you own the subscriber list and send from your console or your server. Choose the provider in App Studio → Push notifications, add your Firebase or OneSignal details and rebuild. In your pages:

await tekservix.push.permission();          // Android 13+ asks the user
tekservix.push.setUser(String(user.id));    // after sign-in; setUser(null) on sign-out
tekservix.push.subscribe('promotions');     // topics
const token = await tekservix.push.token();   // FCM token: save it on your server with the signed-in user
tekservix.on('push.token', e => saveToken(e.token)); // fires when Firebase issues a new token
tekservix.on('push.received', n => showInAppMessage(n.title, n.body));

A notification with a url in its data opens that page in the app when tapped. With OneSignal, push.setUser(id) sets the OneSignal external ID so you can target that user from OneSignal.

Sending notifications

Campaigns: Firebase console → Messaging → New campaign, or the OneSignal dashboard → Messages. Add a custom data key url to open a page.

Automatic alerts from your server (order shipped, new message) with the Firebase Admin SDK and the tokens your site saved:

// Node.js — npm install firebase-admin  (service account from Firebase → Project settings → Service accounts)
import admin from 'firebase-admin';
admin.initializeApp({ credential: admin.credential.cert(serviceAccount) });

await admin.messaging().send({
  token: user.pushToken,
  notification: { title: 'Order shipped', body: 'Order #1042 is on its way' },
  data: { url: 'https://yoursite.com/orders/1042' },
});

// Everyone subscribed to a topic (tekservix.push.subscribe('promotions'))
await admin.messaging().send({ topic: 'promotions', notification: { title: 'Weekend sale', body: '20% off everything' } });

OneSignal: call the OneSignal REST API from your server with your REST API key and include_aliases: { external_id: [userId] }. Keep server keys on your server — never put them in your website or app.

Analytics

tekservix.analytics.event('purchase', { value: 25000, currency: 'RWF' });
tekservix.analytics.setUser(String(user.id));

Events go to every analytics tool switched on for the app (Firebase Analytics, Meta App Events, AppsFlyer). Firebase also records a screen view for each page automatically.

Ads & purchases

// AdMob (units set in App Studio)
await tekservix.ads.showInterstitial();
const reward = await tekservix.ads.showRewarded();   // { type, amount }
tekservix.ads.hideBanner();

// Google Play Billing
const products = await tekservix.purchases.products({ ids: ['premium_monthly'], type: 'subs' });
const purchases = await tekservix.purchases.buy({ id: 'premium_monthly', type: 'subs', accountId: user.id });
// Send purchases[0].token to your server and verify it with the Google Play Developer API.
await tekservix.purchases.restore({ type: 'subs' });
await tekservix.purchases.consume({ token });        // one-time consumables

Google requires Play Billing for digital goods sold in Android apps; physical goods and services can keep using your normal web checkout.

Background location

For delivery and field-team apps. A notification shows while tracking runs. Each fix is POSTed as JSON to your URL:

await tekservix.location.startBackground({
  url: 'https://yoursite.com/api/driver-location',   // optional, defaults to App Studio
  interval: 30, distance: 20,
  data: { driver_id: 17 },
  headers: { Authorization: 'Bearer ' + driverToken }
});
// your server receives:
{ "driver_id": 17, "latitude": -1.9441, "longitude": 30.0619, "accuracy": 8.5,
  "speed": 6.2, "heading": 270, "altitude": 1567, "timestamp": 1760670000000,
  "provider": "gps", "device_id": "…" }
await tekservix.location.stopBackground();

Firebase set-up (push, Analytics, Crashlytics)

  1. Open Firebase console and create a project (free).
  2. Add an Android app with exactly your app's package name from App Studio.
  3. Download google-services.json and upload it in App Studio → Push notifications.
  4. For iOS push, upload your APNs key in Firebase → Project settings → Cloud Messaging.
  5. Rebuild the app.

OneSignal instead? Create a OneSignal app, connect your Firebase credentials there (OneSignal's guide), then paste your OneSignal App ID in App Studio. Your REST API key stays on your own server.

Google & social sign-in

Google doesn't allow its sign-in page inside embedded web views. Add a link rule for accounts\.google\.com that opens in the in-app browser tab, and have your sign-in redirect back to your site. Facebook and Apple sign-in work the same way. For native one-tap sign-in, order a custom integration.

iOS builds & TestFlight

iOS apps are compiled on cloud Macs and signed in your Apple Developer account, so the app is published under your name.

  1. In App Store Connect → Users and Access → Integrations, create a Team API key with the App Manager role and download the .p8 file.
  2. In App Store Connect → Apps, create the app with the bundle ID shown in App Studio (iOS & App Store).
  3. Paste the Issuer ID and Key ID in App Studio and upload the .p8 file, then click Build iOS app.

Each build is uploaded to TestFlight automatically (about 10–30 minutes after it finishes, once Apple has processed it). From TestFlight you test on your iPhone and submit to App Review. The signed .ipa is also available to download.

Store-review tips

  • Give the app native value: a tab bar or menu, push notifications and at least one device feature.
  • Hide website-only parts in the app (cookie banners, “download our app”, desktop footers) with the hide-elements box.
  • Provide a test account for reviewers if your app needs sign-in, and a privacy policy URL.
  • Only switch on permissions your site really uses — the stores ask why you need each one.
  • Digital subscriptions in the app must use in-app purchases on both stores.