Free HTML to APK
Desarrolladores

API de JavaScript

Las apps creadas con Free HTML to APK inyectan un puente nativo como window.FreeApp. Llámalo desde JavaScript simple, desde React o Vue, o desde un motor de juegos. Tu página sigue funcionando en un navegador normal si proteges las llamadas.

Primeros pasos

El puente puede llegar un instante después de que se ejecuten tus scripts, así que haz la configuración nativa en el evento freeappready y también de inmediato si window.FreeApp ya existe. Ofrece siempre una alternativa para el navegador.

function setup() {
  FreeApp.statusBar('#E2552A');
  FreeApp.toast('Hello from Android');
}
if (window.FreeApp) setup();
else window.addEventListener('freeappready', setup, { once: true });

document.querySelector('#buzz').onclick = () =>
  window.FreeApp ? FreeApp.vibrate(40) : console.log('Not in the app');

Las llamadas que necesitan un permiso (cámara, micrófono, ubicación, notificaciones) se lo piden al usuario la primera vez. Activa el permiso correspondiente en el paso Permisos del creador; las plantillas activan lo que usa su código.

Respuesta e interfaz

FreeApp.brightness(level: number): void

De 0.0 a 1.0 para esta ventana; un valor negativo restaura el brillo del sistema.

FreeApp.fullscreen(on: boolean): void

Oculta las barras del sistema (inmersivo).

FreeApp.keepAwake(on: boolean): void

Mantener la pantalla encendida.

FreeApp.notify(title: string, body?: string): void

Notificación local instantánea (pide permiso en Android 13+).

FreeApp.orientation(value: 'portrait' | 'landscape' | 'sensor_portrait' | 'sensor_landscape' | 'sensor' | 'unspecified'): void
FreeApp.print(): void

Imprime o guarda la página como PDF.

FreeApp.scheduleNotification(title: string, body: string, delayMs: number, opts?: {id?: number, url?: string, repeatMs?: number, exact?: boolean}): number

Devuelve el id.

FreeApp.speak(text: string, lang?: string): void

Texto a voz nativo, con idioma como 'en-US'.

FreeApp.statusBar(hexColor: string): void

Por ejemplo, '#2563EB'.

FreeApp.stopSpeaking(): void
FreeApp.toast(message: string): void

Toast nativo breve.

FreeApp.vibrate(ms?: number | number[]): void

Una vibración única (50 ms por defecto) o un patrón [apagado, encendido, apagado, encendido…].

Cámara y escaneo

FreeApp.camera.capture(opts?: {maxSize?: number, quality?: number, mirror?: boolean}): Promise<{dataUrl, facing}>

Foto fija de la vista previa en ejecución.

FreeApp.camera.start(opts?: {facing?: 'back' | 'front', element?: string | Element /* place the preview over this element */, behind?: boolean /* draw under a transparent page so HTML controls float on top */}): Promise<{facing}>
FreeApp.camera.switch(): Promise<{facing}>; FreeApp.camera.torch(on: boolean): boolean; FreeApp.camera.stop(): void; FreeApp.camera.isOpen(): boolean
FreeApp.compressImage(dataUrl: string, opts?: {maxSize?: number, quality?: number}): Promise<{dataUrl, width, height, bytes}>

Nativo, rápido en teléfonos de gama baja.

FreeApp.saveToGallery(dataUrl: string, fileName?: string): Promise<{uri}>

Guarda una imagen en Fotos.

FreeApp.scanCode(opts?: {formats?: string[] /* e.g. ['QR_CODE','EAN_13','CODE_128'] */, facing?: 'back' | 'front'}): Promise<{text, format}>

Escáner nativo de QR / códigos de barras a pantalla completa con linterna; se rechaza con 'cancelled'.

FreeApp.torch(on: boolean): boolean

Linterna; devuelve false si no hay flash.

Ubicación y sensores

FreeApp.address(lat: number, lng: number): Promise<{address, city, country, countryCode, postalCode, street}>
FreeApp.compass(cb: (d: {heading: number /* degrees */, pitch: number, roll: number}) => void): (() => void) | null

Devuelve una función para detener.

FreeApp.location(opts?: {maxAge?: number}): Promise<{lat, lng, accuracy, altitude, speed, provider, time, fromLastKnown}>
FreeApp.maps(query: string): void

Abre un lugar o "lat,lng" en la app de mapas.

FreeApp.sensors.start(type: 'accelerometer' | 'gyroscope' | 'magnetometer' | 'light' | 'proximity' | 'pressure' | 'gravity' | 'linear_acceleration' | 'rotation' | 'humidity' | 'temperature' | 'steps' | 'step_detector', cb: (d: {type, values: number[], x, y, z, accuracy, t}) => void, intervalMs?: number): (() => void) | null

Devuelve una función para detener, o null si no está disponible.

FreeApp.sensors.stop(type: string): void
FreeApp.watchLocation(cb: (p) => void, opts?: {interval?: number, distance?: number}): () => void

Devuelve una función para detener.

Dispositivo y app

FreeApp.app(): {packageName, versionName, versionCode, name, firstInstall}
FreeApp.battery(): {level: number /* 0-100 */, charging: boolean}
FreeApp.biometric(title: string, subtitle?: string): Promise<boolean>

Desbloqueo con huella o rostro.

FreeApp.device(): {manufacturer, model, brand, androidVersion, sdkInt, language, screenWidth, screenHeight, density, isTablet, darkMode}
FreeApp.launchUrl(): string | null

El enlace profundo que abrió la app.

FreeApp.network(): 'wifi' | 'cellular' | 'ethernet' | 'vpn' | 'other' | 'none' | 'unknown'
FreeApp.on('deeplink', (d: {url}) => void): () => void

Enlaces abiertos mientras la app está en ejecución.

FreeApp.online(): boolean

Archivos, compartir y almacenamiento

FreeApp.copy(text: string): void

Copiar al portapapeles.

FreeApp.open(url: string): void

Abrir en el navegador o app externos.

FreeApp.paste(): string

Lee el texto del portapapeles.

FreeApp.pickFile(opts?: {accept?: string[], multiple?: boolean}): Promise<{name, mime, size, dataUrl}>
FreeApp.saveFile(name: string, mime: string, data: string /* base64 or data: URL */ | Blob): Promise<boolean>

Guarda en Descargas; FreeApp.on('saved', d => …) entrega {name, ok, location}.

FreeApp.share(text: string, title?: string): void

Menú de compartir de Android.

FreeApp.shareFile(fileName: string, mimeType: string, base64OrDataUrl: string): boolean

Comparte un archivo real.

FreeApp.store.get(key: string): any | null
FreeApp.store.set(key: string, value: any): void

Almacenamiento nativo persistente de clave/valor (JSON).

NFC

FreeApp.nfc.read(): Promise<{tagId, techs: string[], writable, maxSize, records: Array<{type: "text" | "uri" | "mime" | "unknown", value, mime?, lang?}>}>

Espera una etiqueta; FreeApp.nfc.stop() cancela.

FreeApp.nfc.status(): 'ready' | 'disabled' | 'unsupported' | 'not_enabled_in_app'
FreeApp.nfc.write(records: string | Array<{type: 'text' | 'uri' | 'mime', value: string, mime?: string}>): Promise<{written}>

Permisos

FreeApp.hasPermission(name: string): boolean
FreeApp.openSettings(): void

Abre la página de ajustes del sistema de esta app.

FreeApp.permissionStatus(name: 'camera' | 'microphone' | 'location' | 'notifications' | 'activity'): 'granted' | 'prompt' | 'blocked' | 'unavailable'
FreeApp.requestPermission(name: 'camera' | 'microphone' | 'location' | 'notifications'): Promise<boolean>
FreeApp.requestPermissions(names: string[]): Promise<{[name]: boolean}>

Anuncios

Disponible cuando AdMob está activado en el creador. En modo de prueba se muestran los anuncios de prueba de Google.

FreeApp.ads.loadBanner(unit?: string, position?: 'top' | 'bottom'): void

Carga y muestra un banner. Sin argumentos usa la unidad y la posición definidas en el creador.

FreeApp.ads.showBanner(position?) / hideBanner() / isBannerLoaded()

Muestra, oculta o comprueba el banner.

FreeApp.ads.loadInterstitial(unit?) / showInterstitial() / isInterstitialLoaded()

Anuncios a pantalla completa entre pantallas. Se aplica un intervalo mínimo entre anuncios a pantalla completa.

FreeApp.ads.loadRewarded(unit?) / isRewardedLoaded()

Precarga un anuncio con recompensa.

FreeApp.ads.showRewarded(): Promise<{ok, amount, type}>

Muestra un anuncio con recompensa; se resuelve cuando el usuario obtuvo la recompensa y se rechaza si lo cerró antes de tiempo.

FreeApp.ads.privacyOptionsRequired(): boolean / showPrivacyOptions()

Permite a los usuarios cambiar sus opciones de consentimiento (obligatorio en algunas regiones).

FreeApp.ads.adapterStatus(): {[network]: {installed, configured, ready, description, latencyMs}}

Con mediación: qué redes asociadas están dentro de la app y cuáles ha configurado tu cuenta de AdMob.

FreeApp.ads.openAdInspector(): void

Abre el Ad Inspector de Google en dispositivos de prueba.

FreeApp.ads.on(cb: (event) => void): () => void

Eventos de anuncios como initialized, bannerLoaded, interstitialDismissed o rewardedFailed. Devuelve una función para cancelar la suscripción.

Con una compra de Quitar anuncios, los anuncios de banner y a pantalla completa se detienen y se dispara el evento adFree. Los anuncios con recompensa siguen funcionando, porque la gente elige verlos.

Compras dentro de la app

Disponible cuando Compras está activado en el creador. Vende productos de compra única, consumibles como monedas y suscripciones a través de tu propia cuenta de Google Play. Primero crea los productos en Play Console, con los mismos ID. Las compras funcionan en una copia instalada desde Google Play, así que prueba con una pista de prueba y un tester de licencias.

const billing = window.FreeApp && FreeApp.billing;
if (billing && billing.isOwned('pro_unlock')) unlockPro();

// Unlock in the purchase event: it also arrives for purchases finished while the app was closed.
billing && billing.on(e => { if (e.event === 'purchase' && e.id === 'pro_unlock') unlockPro(); });

buyButton.onclick = async () => {
  try { await billing.buy('pro_unlock'); }
  catch (err) { if (err.code === 'pending') show('Payment pending'); else if (err.code !== 'cancelled') show('Purchase failed'); }
};
FreeApp.billing.products(ids: string[]): Promise<Product[]>

Los datos en vivo de Google Play sobre tus productos: título, precio local, moneda y, para las suscripciones, el periodo de facturación y las ofertas. Los ID que Play no conoce se omiten.

FreeApp.billing.buy(id: string, opts?: {offer?: string}): Promise<Purchase>

Abre la pantalla de pago de Google Play. Para una suscripción, offer elige un plan base o un ID de oferta. Se rechaza con un error cuyo código es cancelled, pending, not_found, unavailable, busy, network o developer_error.

FreeApp.billing.owned(): string[] / isOwned(id): boolean

Lo que el usuario tiene, guardado en el teléfono, así que responde al instante y sin conexión. Úsalo al iniciar para desbloquear las funciones de pago.

FreeApp.billing.restore(): Promise<{purchases, owned}>

Vuelve a pedir a Google Play todo lo que el usuario tiene, para un botón Restaurar compras.

FreeApp.billing.consume(idOrToken: string): Promise

Consume un producto de compra única para que se pueda volver a comprar. Los productos marcados como consumibles en el creador se consumen automáticamente.

FreeApp.billing.isAdFree(): boolean

True cuando el usuario tiene uno de los productos de Quitar anuncios configurados en el creador. Entonces la app deja de mostrar por sí sola los anuncios de banner y a pantalla completa.

FreeApp.billing.manageSubscriptions(id?: string): void

Abre la pantalla de suscripciones de Google Play, donde los usuarios cancelan o cambian su plan.

FreeApp.billing.on(cb: (event) => void): () => void

Eventos de compra: purchase (desbloquea aquí), pending, owned (cambió la lista de lo que tiene el usuario: una compra, un reembolso o una suscripción vencida), failed y unavailable. Devuelve una función para cancelar la suscripción.

Capa de compatibilidad

Las páginas escritas para otras herramientas de HTML a APK que llaman a window.AndroidAPI siguen funcionando: se admiten los mismos nombres de métodos, IDs de callback y nombres de eventos, y las llamadas de anuncios son inofensivas y no hacen nada en apps sin anuncios.