Skip to content

Commit

Permalink
feat(deploy_beta): выровнял импорты необходимы модулей
Browse files Browse the repository at this point in the history
  • Loading branch information
Aliaksandr Pashkevich committed Feb 18, 2024
1 parent 5df3687 commit b5c9d02
Show file tree
Hide file tree
Showing 12 changed files with 248 additions and 243 deletions.
8 changes: 5 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
"changelog": "bash bin/fill-changelog-file-and-notify-github.sh",
"compile": "yarn compile:clean && yarn compile:ts && yarn compile:copy-resources",
"compile:copy-package-json": "shx cp package.json .publish/package.json",
"compile:copy-resources": "yarn copyfiles -e \"**/*.{[jt]s*(x),snap}\" -e \"**/*.json\" -e \"src/mock/**/*\" -u 1 \"src/**/*\" .publish",
"compile:copy-resources": "yarn copyfiles -e \"**/*.{[jt]s*(x),snap}\" -e \"**/*.json\" -u 1 \"src/**/*\" .publish",
"compile:clean": "shx rm -rf .publish",
"compile:ts": "tsc --project tsconfig.build.json",
"lint:scripts": "eslint \"**/*.{js,jsx,ts,tsx}\" --ext .js,.jsx,.ts,.tsx",
Expand Down Expand Up @@ -67,13 +67,15 @@
],
"coveragePathIgnorePatterns": [
"/node_modules/",
"/test/"
"/test/",
"/src/index.ts"
],
"transformIgnorePatterns": [
"node_modules/(?!(uuid)/)"
],
"testPathIgnorePatterns": [
"/node_modules/"
"/node_modules/",
"/test/mock"
],
"reporters": [
"jest-junit",
Expand Down
228 changes: 228 additions & 0 deletions src/bridge-to-native.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,228 @@
/* eslint-disable no-underscore-dangle */

import {
CLOSE_WEBVIEW_SEARCH_KEY,
CLOSE_WEBVIEW_SEARCH_VALUE,
nativeFeaturesFromVersion,
PREVIOUS_B2N_STATE_STORAGE_KEY,
versionToIosAppId,
} from './constants';
import { NativeFallbacks } from './native-fallbacks';
import { NativeNavigationAndTitle } from './native-navigation-and-title';
import type {
Environment,
HandleRedirect,
NativeFeatureKey,
NativeParams,
Theme,
WebViewWindow,
} from './types';
import { PreviousBridgeToNativeState } from './types';
import { isValidVersionFormat } from './utils';

/**
* Этот класс — абстракция для связи веб приложения с нативом и предназначен ТОЛЬКО
* для использования в вебвью окружении.
*/
export class BridgeToNative {
// Webview, запущенное в Android окружении имеет объект `Android` в window.
public readonly AndroidBridge = (window as WebViewWindow).Android;

public readonly environment: Environment = this.AndroidBridge ? 'android' : 'ios';

public readonly nativeFallbacks: NativeFallbacks;

private nextPageId: number | null;

private _nativeNavigationAndTitle: NativeNavigationAndTitle;

private _originalWebviewParams: string;

// В формате `x.x.x`.
private _appVersion: string;

// Необходимо для формирования диплинка.
private _iosAppId?: string;

private _theme: Theme;

private readonly _blankPagePath: string;

private readonly _handleRedirect: HandleRedirect;

constructor(
handleRedirect: HandleRedirect,
blankPagePath: string,
nativeParams?: NativeParams,
) {
const previousState = !!sessionStorage.getItem(PREVIOUS_B2N_STATE_STORAGE_KEY);

if (previousState) {
this.restorePreviousState();
this.nativeFallbacks = new NativeFallbacks(this);
this._blankPagePath = blankPagePath;

return;
}

this._appVersion =
nativeParams && isValidVersionFormat(nativeParams?.appVersion)
? nativeParams.appVersion
: '0.0.0';
this._iosAppId = this.getIosAppId(nativeParams?.iosAppId);
this._theme = nativeParams?.theme === 'dark' ? 'dark' : 'light';
this._originalWebviewParams = nativeParams?.originalWebviewParams || '';
this._nativeNavigationAndTitle = new NativeNavigationAndTitle(
this,
nativeParams ? nativeParams.nextPageId : null,
nativeParams?.title,
handleRedirect,
);
this._handleRedirect = handleRedirect;

this.nextPageId = nativeParams ? nativeParams.nextPageId : null;
this.nativeFallbacks = new NativeFallbacks(this);
this._blankPagePath = blankPagePath;
}

get theme() {
return this._theme;
}

get appVersion() {
return this._appVersion;
}

get iosAppId() {
return this._iosAppId;
}

get nativeNavigationAndTitle() {
return this._nativeNavigationAndTitle;
}

get originalWebviewParams() {
return this._originalWebviewParams;
}

/**
* Метод, проверяющий, можно ли использовать нативную функциональность в текущей версии приложения.
*
* @param feature Название функциональности, которую нужно проверить.
*/
public canUseNativeFeature(feature: NativeFeatureKey) {
const { fromVersion } = nativeFeaturesFromVersion[this.environment][feature];

return this.isCurrentVersionHigherOrEqual(fromVersion);
}

/**
* Метод, отправляющий сигнал нативу, что нужно закрыть текущее вебвью.
*/
// eslint-disable-next-line class-methods-use-this
public closeWebview() {
const originalPageUrl = new URL(window.location.href);

originalPageUrl.searchParams.set(CLOSE_WEBVIEW_SEARCH_KEY, CLOSE_WEBVIEW_SEARCH_VALUE);
window.location.href = originalPageUrl.toString();
}

/**
* Сравнивает текущую версию приложения с переданной.
*
* @param versionToCompare Версия, с которой нужно сравнить текущую.
* @returns `true` – текущая версия больше или равняется переданной,
* `false` – текущая версия ниже.
*/
public isCurrentVersionHigherOrEqual(versionToCompare: string) {
if (!isValidVersionFormat(versionToCompare)) {
return false;
}

const matchPattern = /(\d+)\.(\d+)\.(\d+)/;

type ExpectedTupple = [string, string, string, string];

const [, ...appVersionComponents] = this._appVersion.match(matchPattern) as ExpectedTupple; // Формат версии проверен в конструкторе, можно смело убирать `null` из типа.

const [, ...versionToCompareComponents] = versionToCompare.match(
matchPattern,
) as ExpectedTupple;

for (let i = 0; i < appVersionComponents.length; i++) {
if (appVersionComponents[i] !== versionToCompareComponents[i]) {
return appVersionComponents[i] >= versionToCompareComponents[i];
}
}

return true;
}

/**
* Сохраняет текущее состояние BridgeToNative в sessionStorage.
* Так же сохраняет текущее состояние nativeNavigationAndTitle.
*/
private saveCurrentState() {
// В nativeNavigationAndTitle этот метод отмечен модификатором доступа private дабы не торчал наружу, но тут его нужно вызвать
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
this._nativeNavigationAndTitle.saveCurrentState();

const currentState: PreviousBridgeToNativeState = {
appVersion: this._appVersion,
theme: this._theme,
nextPageId: this.nextPageId,
originalWebviewParams: this._originalWebviewParams || '',
iosAppId: this._iosAppId,
};

sessionStorage.setItem(PREVIOUS_B2N_STATE_STORAGE_KEY, JSON.stringify(currentState));
}

/**
* Возвращает схему приложения в iOS окружении, на основе версии.
*
* @param knownIosAppId Тип iOS приложения, если он известен.
* @returns Тип приложения, `undefined` для Android окружения.
*/
private getIosAppId(knownIosAppId?: string) {
if (this.environment !== 'ios') {
return undefined;
}

if (knownIosAppId) {
return knownIosAppId;
}

const keys = Object.keys(versionToIosAppId);

const rightKey =
[...keys].reverse().find((version) => this.isCurrentVersionHigherOrEqual(version)) ||
keys[0];

return atob(versionToIosAppId[rightKey as keyof typeof versionToIosAppId]);
}

/**
* Восстанавливает свое предыдущее состояние из sessionStorage
*/
private restorePreviousState() {
const previousState: PreviousBridgeToNativeState = JSON.parse(
sessionStorage.getItem(PREVIOUS_B2N_STATE_STORAGE_KEY) || '',
);

this._appVersion = previousState.appVersion;
this._iosAppId = previousState.iosAppId;
this._theme = previousState.theme;
this._originalWebviewParams = previousState.originalWebviewParams;
this.nextPageId = previousState.nextPageId;
this._nativeNavigationAndTitle = new NativeNavigationAndTitle(
this,
previousState.nextPageId,
'',
this._handleRedirect,
);

sessionStorage.removeItem(PREVIOUS_B2N_STATE_STORAGE_KEY);
}
}
Loading

0 comments on commit b5c9d02

Please sign in to comment.