JavaScript API
Приложения, созданные в Free HTML to APK, добавляют встроенный мост как window.FreeApp. Вызывайте его из обычного JavaScript, из React или Vue, а также из игрового движка. Ваша страница продолжит работать и в обычном браузере, если вы защитите вызовы проверкой.
Начало работы
Мост может появиться чуть позже запуска ваших скриптов, поэтому выполняйте настройку в событии freeappready и сразу же, если window.FreeApp уже существует. Всегда предусматривайте запасной вариант для браузера.
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');
Вызовы, требующие разрешения (камера, микрофон, местоположение, уведомления), запрашивают его у пользователя при первом использовании. Включите нужное разрешение на шаге Разрешения в конструкторе; шаблоны включают то, что использует их код.
Обратная связь и интерфейс
FreeApp.brightness(level: number): voidОт 0.0 до 1.0 для этого окна, отрицательное значение возвращает системную яркость.
FreeApp.fullscreen(on: boolean): voidСкрыть системные панели (полноэкранный режим).
FreeApp.keepAwake(on: boolean): voidНе выключать экран.
FreeApp.notify(title: string, body?: string): voidМгновенное локальное уведомление (на Android 13+ запрашивает разрешение).
FreeApp.orientation(value: 'portrait' | 'landscape' | 'sensor_portrait' | 'sensor_landscape' | 'sensor' | 'unspecified'): voidFreeApp.print(): voidПечать страницы или сохранение в PDF.
FreeApp.scheduleNotification(title: string, body: string, delayMs: number, opts?: {id?: number, url?: string, repeatMs?: number, exact?: boolean}): numberВозвращает id.
FreeApp.speak(text: string, lang?: string): voidВстроенный синтез речи, язык вида 'en-US'.
FreeApp.statusBar(hexColor: string): voidНапример, '#2563EB'.
FreeApp.stopSpeaking(): voidFreeApp.toast(message: string): voidКороткое встроенное всплывающее сообщение.
FreeApp.vibrate(ms?: number | number[]): voidОдиночная вибрация (по умолчанию 50 мс) или шаблон [пауза, вибрация, пауза, вибрация…].
Камера и сканирование
FreeApp.camera.capture(opts?: {maxSize?: number, quality?: number, mirror?: boolean}): Promise<{dataUrl, facing}>Снимок из работающего предпросмотра.
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(): booleanFreeApp.compressImage(dataUrl: string, opts?: {maxSize?: number, quality?: number}): Promise<{dataUrl, width, height, bytes}>Встроенный, быстро работает на слабых телефонах.
FreeApp.saveToGallery(dataUrl: string, fileName?: string): Promise<{uri}>Сохраняет изображение в «Фото».
FreeApp.scanCode(opts?: {formats?: string[] /* e.g. ['QR_CODE','EAN_13','CODE_128'] */, facing?: 'back' | 'front'}): Promise<{text, format}>Полноэкранный сканер QR-кодов и штрихкодов с подсветкой; отклоняется с 'cancelled'.
FreeApp.torch(on: boolean): booleanФонарик, возвращает false, если вспышки нет.
Местоположение и датчики
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Возвращает функцию остановки.
FreeApp.location(opts?: {maxAge?: number}): Promise<{lat, lng, accuracy, altitude, speed, provider, time, fromLastKnown}>FreeApp.maps(query: string): voidОткрывает место или «lat,lng» в приложении карт.
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Возвращает функцию остановки или null, если недоступно.
FreeApp.sensors.stop(type: string): voidFreeApp.watchLocation(cb: (p) => void, opts?: {interval?: number, distance?: number}): () => voidВозвращает функцию остановки.
Устройство и приложение
FreeApp.app(): {packageName, versionName, versionCode, name, firstInstall}FreeApp.battery(): {level: number /* 0-100 */, charging: boolean}FreeApp.biometric(title: string, subtitle?: string): Promise<boolean>Разблокировка по отпечатку пальца или лицу.
FreeApp.device(): {manufacturer, model, brand, androidVersion, sdkInt, language, screenWidth, screenHeight, density, isTablet, darkMode}FreeApp.launchUrl(): string | nullГлубокая ссылка, которой было открыто приложение.
FreeApp.network(): 'wifi' | 'cellular' | 'ethernet' | 'vpn' | 'other' | 'none' | 'unknown'FreeApp.on('deeplink', (d: {url}) => void): () => voidСсылки, открытые во время работы приложения.
FreeApp.online(): booleanФайлы, отправка и хранилище
FreeApp.copy(text: string): voidКопирование в буфер обмена.
FreeApp.open(url: string): voidОткрыть во внешнем браузере или приложении.
FreeApp.paste(): stringПрочитать текст из буфера обмена.
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>Сохраняет в «Загрузки»; FreeApp.on('saved', d => …) возвращает {name, ok, location}.
FreeApp.store.get(key: string): any | nullFreeApp.store.set(key: string, value: any): voidПостоянное встроенное хранилище «ключ — значение» (JSON).
NFC
FreeApp.nfc.read(): Promise<{tagId, techs: string[], writable, maxSize, records: Array<{type: "text" | "uri" | "mime" | "unknown", value, mime?, lang?}>}>Ждёт метку; FreeApp.nfc.stop() отменяет ожидание.
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}>Разрешения
FreeApp.hasPermission(name: string): booleanFreeApp.openSettings(): voidОткрывает страницу системных настроек этого приложения.
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}>Реклама
Доступно, если в конструкторе включён AdMob. В тестовом режиме показывается тестовая реклама Google.
FreeApp.ads.loadBanner(unit?: string, position?: 'top' | 'bottom'): voidЗагружает и показывает баннер. Без аргументов используются блок и позиция, заданные в конструкторе.
FreeApp.ads.showBanner(position?) / hideBanner() / isBannerLoaded()Показать, скрыть или проверить баннер.
FreeApp.ads.loadInterstitial(unit?) / showInterstitial() / isInterstitialLoaded()Полноэкранная реклама между экранами. Между показами полноэкранной рекламы соблюдается минимальный интервал.
FreeApp.ads.loadRewarded(unit?) / isRewardedLoaded()Заранее загрузить рекламу с вознаграждением.
FreeApp.ads.showRewarded(): Promise<{ok, amount, type}>Показывает рекламу с вознаграждением; выполняется, когда пользователь получил награду, и отклоняется, если он закрыл рекламу раньше.
FreeApp.ads.privacyOptionsRequired(): boolean / showPrivacyOptions()Позволяет пользователям изменить свой выбор по согласию (в некоторых регионах это обязательно).
FreeApp.ads.adapterStatus(): {[network]: {installed, configured, ready, description, latencyMs}}При медиации: какие партнёрские сети есть в приложении и какие настроены в вашем аккаунте AdMob.
FreeApp.ads.openAdInspector(): voidОткрывает Ad Inspector от Google на тестовых устройствах.
FreeApp.ads.on(cb: (event) => void): () => voidСобытия рекламы, такие как initialized, bannerLoaded, interstitialDismissed или rewardedFailed. Возвращает функцию отписки.
После покупки «Убрать рекламу» баннерная и полноэкранная реклама отключается и срабатывает событие adFree. Реклама с вознаграждением продолжает работать, потому что люди сами решают её смотреть.
Покупки в приложении
Доступно, когда в конструкторе включены «Покупки». Продавайте разовые товары, расходуемые товары вроде монет и подписки через собственный аккаунт Google Play. Сначала создайте товары в Play Console с теми же идентификаторами. Покупки работают в копии, установленной из Google Play, поэтому проверяйте через тестовый трек и тестировщика лицензий.
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[]>Актуальные данные Google Play о ваших товарах: название, местная цена, валюта, а для подписок — период оплаты и предложения. Идентификаторы, которых Play не знает, пропускаются.
FreeApp.billing.buy(id: string, opts?: {offer?: string}): Promise<Purchase>Открывает окно оплаты Google Play. Для подписки offer выбирает базовый план или идентификатор предложения. Отклоняется с ошибкой с кодом cancelled, pending, not_found, unavailable, busy, network или developer_error.
FreeApp.billing.owned(): string[] / isOwned(id): booleanЧем владеет пользователь, сохранённое на телефоне, поэтому ответ приходит сразу и без интернета. Используйте при запуске, чтобы открыть платные функции.
FreeApp.billing.restore(): Promise<{purchases, owned}>Заново запрашивает у Google Play всё, чем владеет пользователь, — для кнопки «Восстановить покупки».
FreeApp.billing.consume(idOrToken: string): PromiseРасходует разовый товар, чтобы его можно было купить снова. Товары, отмеченные в конструкторе как расходуемые, расходуются автоматически.
FreeApp.billing.isAdFree(): booleanTrue, если у пользователя есть один из товаров «Убрать рекламу», заданных в конструкторе. Тогда приложение само отключает баннерную и полноэкранную рекламу.
FreeApp.billing.manageSubscriptions(id?: string): voidОткрывает экран подписок Google Play, где пользователи отменяют или меняют тариф.
FreeApp.billing.on(cb: (event) => void): () => voidСобытия покупок: purchase (открывайте доступ здесь), pending, owned (изменился список купленного: покупка, возврат или истёкшая подписка), failed и unavailable. Возвращает функцию отписки.
Слой совместимости
Страницы, написанные для других инструментов HTML-to-APK, которые вызывают window.AndroidAPI, продолжают работать: поддерживаются те же названия методов, ID обратных вызовов и названия событий, а вызовы рекламы безопасно ничего не делают в приложениях без рекламы.