@khmyznikov/pwa-install
Version:
PWA install dialog provide more convenience user experience and fix lack of native dialogs in some browsers.
88 lines (79 loc) • 3.58 kB
text/typescript
import { WebAppManifest } from 'web-app-manifest';
import { IRelatedApp } from './types/types';
const _eventDispatcher = (_element: Element, name: string, message: string) => {
const event = new CustomEvent(name, {
detail: {
message
}
});
_element.dispatchEvent(event);
}
export default class Utils {
static isAppleMobile(): boolean {
if (
(
['iPhone', 'iPad', 'iPod'].includes(navigator.platform) ||
(navigator.userAgent.match(/Mac/) && navigator.maxTouchPoints && navigator.maxTouchPoints > 2)
)
&& ('serviceWorker' in navigator)
)
return true;
return false;
}
static isAppleDesktop(): boolean {
// check if it's a mac
const userAgent = navigator.userAgent.toLowerCase();
if (navigator.maxTouchPoints || !userAgent.match(/macintosh/))
return false;
// check safari version >= 17
const version = /version\/(\d{2})\./.exec(userAgent)
if (!version || !version[1] || !(parseInt(version[1]) >= 17))
return false;
// hacky way to detect Sonoma
const audioCheck = document.createElement('audio').canPlayType('audio/wav; codecs="1"') ? true : false;
const webGLCheck = new OffscreenCanvas(1, 1).getContext('webgl') ? true : false;
return audioCheck && webGLCheck;
}
static isStandalone() {
if (window.matchMedia('(display-mode: standalone)').matches || ('standalone' in navigator && (navigator as any).standalone === true))
return true;
return false;
}
static async getInstalledRelatedApps(): Promise<IRelatedApp[]> {
if ('getInstalledRelatedApps' in navigator)
try{
return await (navigator as any).getInstalledRelatedApps().then((relatedApps: IRelatedApp[]) => {
return relatedApps;
});
} catch (e) {}
return [];
}
static async isRelatedAppsInstalled(): Promise<boolean> {
const _relatedApps = await this.getInstalledRelatedApps();
return _relatedApps.length? true : false;
}
static eventInstalledSuccess(_element: Element) {
_eventDispatcher(_element, 'pwa-install-success-event', 'App install success (Chromium/Android only)');
}
static eventInstalledFail(_element: Element) {
_eventDispatcher(_element, 'pwa-install-fail-event', 'App install failed (Chromium/Android only)');
}
static eventUserChoiceResult(_element: Element, message: string) {
_eventDispatcher(_element, 'pwa-user-choice-result-event', message);
}
static eventInstallAvailable(_element: Element) {
_eventDispatcher(_element, 'pwa-install-available-event', 'App install available');
}
static eventInstallHowTo(_element: Element) {
_eventDispatcher(_element, 'pwa-install-how-to-event', 'App install instruction showed');
}
static eventGallery(_element: Element) {
_eventDispatcher(_element, 'pwa-install-gallery-event', 'App install gallery showed');
}
static normalizeManifestAssetUrls(manifest: WebAppManifest, manifestUrl: string) {
const normalizedManifestUrl = new URL(manifestUrl, document.location.href);
[...manifest.icons || [], ...manifest.screenshots || []].forEach(asset => {
asset.src = new URL(asset.src, normalizedManifestUrl).href;
})
}
}