@alfalab/bridge-to-native 1.4.0 → 1.4.1-beta.4145945

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -127,6 +127,20 @@ export declare class BridgeToNative {
127
127
  * Применимо для всех версий на iOS и в новых версиях на Android (>=12.30.0), в более старых WV закрывается всегда автоматически.
128
128
  */
129
129
  handleNativeDeeplink(deeplink: string, closeWebviewBeforeCallNativeDeeplinkHandler?: boolean): void;
130
+ /**
131
+ * Открывает dashboard экран NA.
132
+ *
133
+ * Полезно для сценария возврата из WV на dashboard экран приложения,
134
+ * когда обычный deeplink требует специальной обработки.
135
+ *
136
+ * ВАЖНО!
137
+ * В NA на Android до версии `12.30.0` текущее WV закрывается при открытии нового экрана,
138
+ * поэтому в закрытое WV невозможно вернуться back-навигацией.
139
+ *
140
+ * @param closeWebviewBeforeOpen Флаг принудительного закрытия текущего WV перед открытием dashboard экрана.
141
+ * Применимо для всех версий на iOS и в новых версиях на Android (>=12.30.0), в более старых WV закрывается всегда автоматически.
142
+ */
143
+ openNativeAppDashboard(closeWebviewBeforeOpen?: boolean): void;
130
144
  /**
131
145
  * Сравнивает текущую версию приложения с переданной.
132
146
  *
@@ -159,6 +159,22 @@ class BridgeToNative {
159
159
  handleNativeDeeplink(deeplink, closeWebviewBeforeCallNativeDeeplinkHandler = false) {
160
160
  this.externalLinksService.handleNativeDeeplink(deeplink, closeWebviewBeforeCallNativeDeeplinkHandler);
161
161
  }
162
+ /**
163
+ * Открывает dashboard экран NA.
164
+ *
165
+ * Полезно для сценария возврата из WV на dashboard экран приложения,
166
+ * когда обычный deeplink требует специальной обработки.
167
+ *
168
+ * ВАЖНО!
169
+ * В NA на Android до версии `12.30.0` текущее WV закрывается при открытии нового экрана,
170
+ * поэтому в закрытое WV невозможно вернуться back-навигацией.
171
+ *
172
+ * @param closeWebviewBeforeOpen Флаг принудительного закрытия текущего WV перед открытием dashboard экрана.
173
+ * Применимо для всех версий на iOS и в новых версиях на Android (>=12.30.0), в более старых WV закрывается всегда автоматически.
174
+ */
175
+ openNativeAppDashboard(closeWebviewBeforeOpen = false) {
176
+ this.externalLinksService.openNativeAppDashboard(closeWebviewBeforeOpen);
177
+ }
162
178
  /**
163
179
  * Сравнивает текущую версию приложения с переданной.
164
180
  *
@@ -6,10 +6,13 @@ import { type NativeParamsService } from './native-params-service';
6
6
  */
7
7
  export declare class ExternalLinksService {
8
8
  private nativeParamsService;
9
+ private navigationByNativeAppInProgress;
9
10
  constructor(nativeParamsService: NativeParamsService);
10
11
  handleNativeDeeplink(deeplink: string, closeWebviewBeforeCallNativeDeeplinkHandler?: boolean): void;
12
+ openNativeAppDashboard(closeWebviewBeforeOpen?: boolean): void;
11
13
  getHrefToOpenInBrowser(link: string): string;
12
14
  openInBrowser(link: string): void;
13
15
  openInNewWebview(link: string, nativeTitle?: string, closeCurrentWebview?: boolean): void;
14
16
  openPdf(url: string, type?: PdfType, title?: string): void;
17
+ private navigateByNativeApp;
15
18
  }
@@ -3,7 +3,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ExternalLinksService = void 0;
4
4
  const query_and_headers_keys_1 = require("../../query-and-headers-keys");
5
5
  const constants_1 = require("../constants");
6
- const close_webview_util_1 = require("./close-webview-util");
6
+ const utils_1 = require("./utils");
7
+ const CANCEL_NEW_CALLS_TO_NA_TIME = 150;
7
8
  const QUERY_OPEN_IN_BROWSER_KEY = 'openInBrowser';
8
9
  const QUERY_OPEN_IN_BROWSER_VALUE = 'true';
9
10
  /**
@@ -13,18 +14,42 @@ const QUERY_OPEN_IN_BROWSER_VALUE = 'true';
13
14
  class ExternalLinksService {
14
15
  constructor(nativeParamsService) {
15
16
  this.nativeParamsService = nativeParamsService;
17
+ this.navigationByNativeAppInProgress = false;
16
18
  }
17
19
  handleNativeDeeplink(deeplink, closeWebviewBeforeCallNativeDeeplinkHandler = false) {
20
+ if (this.navigationByNativeAppInProgress) {
21
+ return;
22
+ }
18
23
  const clearedDeeplinkPath = deeplink.replace(constants_1.DEEP_LINK_PATTERN, '');
24
+ const originalNativeUrl = `${this.nativeParamsService.appId}://${clearedDeeplinkPath}`;
25
+ const preparedNativeUrl = this.nativeParamsService.environment === 'ios'
26
+ ? (0, utils_1.appendFromCurrentQueryParamForIos)(originalNativeUrl)
27
+ : originalNativeUrl;
19
28
  if (closeWebviewBeforeCallNativeDeeplinkHandler &&
20
29
  this.nativeParamsService.canUseNativeFeature('savedBackStack')) {
21
- (0, close_webview_util_1.closeWebviewUtil)();
30
+ (0, utils_1.closeWebviewUtil)();
22
31
  // Проверено, ОС получает диплинк и передаёт его NA, не смотря на то,
23
32
  // что это происходит в следующей макрозадаче после команды на закрытие WV.
24
- setTimeout(() => window.location.replace(`${this.nativeParamsService.appId}://${clearedDeeplinkPath}`), 0);
33
+ setTimeout(() => window.location.replace(preparedNativeUrl), 0);
34
+ return;
35
+ }
36
+ this.navigateByNativeApp(preparedNativeUrl);
37
+ }
38
+ openNativeAppDashboard(closeWebviewBeforeOpen = false) {
39
+ if (this.navigationByNativeAppInProgress) {
40
+ return;
41
+ }
42
+ const originalNativeUrl = `${this.nativeParamsService.appId}:///`;
43
+ const preparedNativeUrl = this.nativeParamsService.environment === 'ios'
44
+ ? (0, utils_1.appendFromCurrentQueryParamForIos)(originalNativeUrl)
45
+ : originalNativeUrl;
46
+ if (closeWebviewBeforeOpen &&
47
+ this.nativeParamsService.canUseNativeFeature('savedBackStack')) {
48
+ (0, utils_1.closeWebviewUtil)();
49
+ setTimeout(() => window.location.replace(preparedNativeUrl), 0);
25
50
  return;
26
51
  }
27
- window.location.replace(`${this.nativeParamsService.appId}://${clearedDeeplinkPath}`);
52
+ this.navigateByNativeApp(preparedNativeUrl);
28
53
  }
29
54
  getHrefToOpenInBrowser(link) {
30
55
  if (!this.nativeParamsService.canUseNativeFeature('linksInBrowser')) {
@@ -35,13 +60,16 @@ class ExternalLinksService {
35
60
  return url.href;
36
61
  }
37
62
  openInBrowser(link) {
63
+ if (this.navigationByNativeAppInProgress) {
64
+ return;
65
+ }
38
66
  if (!this.nativeParamsService.canUseNativeFeature('linksInBrowser')) {
39
67
  this.openInNewWebview(link);
40
68
  return;
41
69
  }
42
70
  const url = new URL(link);
43
71
  url.searchParams.append(QUERY_OPEN_IN_BROWSER_KEY, QUERY_OPEN_IN_BROWSER_VALUE);
44
- window.location.replace(url.href);
72
+ this.navigateByNativeApp(url.href);
45
73
  }
46
74
  openInNewWebview(link, nativeTitle = '', closeCurrentWebview = false) {
47
75
  const url = new URL(link);
@@ -51,6 +79,9 @@ class ExternalLinksService {
51
79
  this.handleNativeDeeplink(`/webFeature?type=recommendation&url=${encodeURIComponent(url.toString())}`, closeCurrentWebview);
52
80
  }
53
81
  openPdf(url, type = 'pdfFile', title) {
82
+ if (this.navigationByNativeAppInProgress) {
83
+ return;
84
+ }
54
85
  let replaceUrl = url;
55
86
  if (this.nativeParamsService.environment === 'ios') {
56
87
  const params = new URLSearchParams();
@@ -62,10 +93,18 @@ class ExternalLinksService {
62
93
  const paramsStr = params.toString();
63
94
  replaceUrl = `${this.nativeParamsService.appId}:///dashboard/pdf_viewer?${paramsStr}`;
64
95
  }
65
- const windowObjectReference = window.open(replaceUrl);
66
- if (windowObjectReference === null) {
67
- window.location.replace(replaceUrl);
68
- }
96
+ replaceUrl =
97
+ this.nativeParamsService.environment === 'ios'
98
+ ? (0, utils_1.appendFromCurrentQueryParamForIos)(replaceUrl)
99
+ : replaceUrl;
100
+ this.navigateByNativeApp(replaceUrl);
101
+ }
102
+ navigateByNativeApp(url) {
103
+ this.navigationByNativeAppInProgress = true;
104
+ window.location.replace(url);
105
+ setTimeout(() => {
106
+ this.navigationByNativeAppInProgress = false;
107
+ }, CANCEL_NEW_CALLS_TO_NA_TIME);
69
108
  }
70
109
  }
71
110
  exports.ExternalLinksService = ExternalLinksService;
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
4
  exports.NativeNavigationAndTitleService = void 0;
5
5
  const query_and_headers_keys_1 = require("../../query-and-headers-keys");
6
- const close_webview_util_1 = require("./close-webview-util");
6
+ const utils_1 = require("./utils");
7
7
  const NativeHistoryStackStub = 0;
8
8
  /**
9
9
  * Сервис, отвечающий за взаимодействие WA с WV компонентами NA —
@@ -39,7 +39,7 @@ class NativeNavigationAndTitleService {
39
39
  }
40
40
  // eslint-disable-next-line class-methods-use-this -- удобней использовать метод в контексте экземпляра.
41
41
  closeWebview() {
42
- (0, close_webview_util_1.closeWebviewUtil)();
42
+ (0, utils_1.closeWebviewUtil)();
43
43
  }
44
44
  goBack() {
45
45
  if (this.isGoBackLocked) {
@@ -57,7 +57,7 @@ class NativeNavigationAndTitleService {
57
57
  const maxStepsToBack = this.nativeHistoryStack.length - 1;
58
58
  if (stepsToBack > maxStepsToBack) {
59
59
  if (autoCloseWebview) {
60
- (0, close_webview_util_1.closeWebviewUtil)();
60
+ (0, utils_1.closeWebviewUtil)();
61
61
  return;
62
62
  }
63
63
  this.numOfBackSteps = maxStepsToBack;
@@ -154,7 +154,7 @@ class NativeNavigationAndTitleService {
154
154
  }
155
155
  this.numOfBackSteps = 1;
156
156
  if (this.nativeHistoryStack.length < 1) {
157
- (0, close_webview_util_1.closeWebviewUtil)();
157
+ (0, utils_1.closeWebviewUtil)();
158
158
  return;
159
159
  }
160
160
  this.saveNativeHistoryStack();
@@ -0,0 +1,2 @@
1
+ export declare function appendFromCurrentQueryParamForIos(nativeUrl: string): string;
2
+ export declare const closeWebviewUtil: () => void;
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.closeWebviewUtil = void 0;
4
+ exports.appendFromCurrentQueryParamForIos = appendFromCurrentQueryParamForIos;
5
+ const QUERY_CLOSE_WEBVIEW_KEY = 'closeWebView';
6
+ const QUERY_CLOSE_WEBVIEW_VALUE = 'true';
7
+ const QUERY_FROM_CURRENT_KEY = 'fromCurrent';
8
+ const QUERY_FROM_CURRENT_VALUE = 'true';
9
+ function appendFromCurrentQueryParamForIos(nativeUrl) {
10
+ const qIndex = nativeUrl.indexOf('?');
11
+ if (qIndex === -1) {
12
+ return `${nativeUrl}?${QUERY_FROM_CURRENT_KEY}=${QUERY_FROM_CURRENT_VALUE}`;
13
+ }
14
+ const base = nativeUrl.slice(0, qIndex);
15
+ const query = nativeUrl.slice(qIndex + 1);
16
+ const params = new URLSearchParams(query);
17
+ params.set(QUERY_FROM_CURRENT_KEY, QUERY_FROM_CURRENT_VALUE);
18
+ return `${base}?${params.toString()}`;
19
+ }
20
+ const closeWebviewUtil = () => {
21
+ const originalPageUrl = new URL(window.location.href);
22
+ originalPageUrl.searchParams.set(QUERY_CLOSE_WEBVIEW_KEY, QUERY_CLOSE_WEBVIEW_VALUE);
23
+ window.location.href = originalPageUrl.toString();
24
+ };
25
+ exports.closeWebviewUtil = closeWebviewUtil;
package/package.json CHANGED
@@ -1,121 +1,121 @@
1
1
  {
2
- "name": "@alfalab/bridge-to-native",
3
- "version": "1.4.0",
4
- "license": "MIT",
5
- "description": "Утилита для удобной работы веб приложения внутри нативного приложения и коммуникации с ним.",
6
- "engines": {
7
- "node": ">=20.19.2",
8
- "npm": "please-use-yarn"
2
+ "name": "@alfalab/bridge-to-native",
3
+ "version": "1.4.1-beta.4145945",
4
+ "license": "MIT",
5
+ "description": "Утилита для удобной работы веб приложения внутри нативного приложения и коммуникации с ним.",
6
+ "engines": {
7
+ "node": ">=20.19.2",
8
+ "npm": "please-use-yarn"
9
+ },
10
+ "repository": {
11
+ "type": "git",
12
+ "url": "git+https://github.com/core-ds/bridge-to-native.git"
13
+ },
14
+ "exports": {
15
+ "./client": {
16
+ "import": "./client/index.js",
17
+ "require": "./client/index.js",
18
+ "types": "./client/index.d.ts"
9
19
  },
10
- "repository": {
11
- "type": "git",
12
- "url": "git+https://github.com/core-ds/bridge-to-native.git"
20
+ "./server": {
21
+ "import": "./server/index.js",
22
+ "require": "./server/index.js",
23
+ "types": "./server/index.d.ts"
24
+ }
25
+ },
26
+ "sideEffects": false,
27
+ "bugs": {
28
+ "url": "https://github.com/core-ds/bridge-to-native/issues"
29
+ },
30
+ "scripts": {
31
+ "build": "yarn build:clean && yarn build:ts",
32
+ "build:clean": "shx rm -rf .publish",
33
+ "build:copy-package-json": "shx cp package.json .publish/package.json",
34
+ "build:ts": "tsc --build",
35
+ "format": "arui-presets-lint format",
36
+ "format:check": "arui-presets-lint format:check",
37
+ "lint": "yarn lint:scripts && yarn format:check",
38
+ "lint:fix": "yarn lint:scripts --fix && yarn format",
39
+ "lint:scripts": "arui-presets-lint scripts",
40
+ "pub": "npm publish .publish --userconfig \"../.npmrc\" --tag \"$TAG\"",
41
+ "release": "yarn build && yarn build:copy-package-json && yarn pub",
42
+ "test": "arui-scripts test --silent --collect-coverage"
43
+ },
44
+ "devDependencies": {
45
+ "@happy-dom/jest-environment": "18.0.1",
46
+ "@types/jest": "29.5.14",
47
+ "@types/node": "20.19.1",
48
+ "arui-presets-lint": "8.7.0",
49
+ "arui-scripts": "19.0.7",
50
+ "copyfiles": "2.4.1",
51
+ "jest-junit": "10.0.0",
52
+ "lint-staged": "^12.5.0",
53
+ "promisify-child-process": "4.1.1",
54
+ "shx": "0.3.4",
55
+ "typescript": "5.5.4"
56
+ },
57
+ "commitlint": {
58
+ "extends": "./node_modules/arui-presets-lint/commitlint"
59
+ },
60
+ "eslintConfig": {
61
+ "extends": "./node_modules/arui-presets-lint/eslint",
62
+ "parserOptions": {
63
+ "project": [
64
+ "./__tests__/tsconfig.json",
65
+ "./src/client/tsconfig.json",
66
+ "./src/server/tsconfig.json"
67
+ ]
13
68
  },
14
- "exports": {
15
- "./client": {
16
- "import": "./client/index.js",
17
- "require": "./client/index.js",
18
- "types": "./client/index.d.ts"
19
- },
20
- "./server": {
21
- "import": "./server/index.js",
22
- "require": "./server/index.js",
23
- "types": "./server/index.d.ts"
24
- }
25
- },
26
- "sideEffects": false,
27
- "bugs": {
28
- "url": "https://github.com/core-ds/bridge-to-native/issues"
29
- },
30
- "scripts": {
31
- "build": "yarn build:clean && yarn build:ts",
32
- "build:clean": "shx rm -rf .publish",
33
- "build:copy-package-json": "shx cp package.json .publish/package.json",
34
- "build:ts": "tsc --build",
35
- "format": "arui-presets-lint format",
36
- "format:check": "arui-presets-lint format:check",
37
- "lint": "yarn lint:scripts && yarn format:check",
38
- "lint:fix": "yarn lint:scripts --fix && yarn format",
39
- "lint:scripts": "arui-presets-lint scripts",
40
- "pub": "npm publish .publish --userconfig \"../.npmrc\" --tag \"$TAG\"",
41
- "release": "yarn build && yarn build:copy-package-json && yarn pub",
42
- "test": "arui-scripts test --silent --collect-coverage"
43
- },
44
- "devDependencies": {
45
- "@happy-dom/jest-environment": "18.0.1",
46
- "@types/jest": "29.5.14",
47
- "@types/node": "20.19.1",
48
- "arui-presets-lint": "8.7.0",
49
- "arui-scripts": "19.0.7",
50
- "copyfiles": "2.4.1",
51
- "jest-junit": "10.0.0",
52
- "lint-staged": "^12.5.0",
53
- "promisify-child-process": "4.1.1",
54
- "shx": "0.3.4",
55
- "typescript": "5.5.4"
56
- },
57
- "commitlint": {
58
- "extends": "./node_modules/arui-presets-lint/commitlint"
59
- },
60
- "eslintConfig": {
61
- "extends": "./node_modules/arui-presets-lint/eslint",
62
- "parserOptions": {
63
- "project": [
64
- "./__tests__/tsconfig.json",
65
- "./src/client/tsconfig.json",
66
- "./src/server/tsconfig.json"
67
- ]
68
- },
69
- "overrides": [
70
- {
71
- "files": [
72
- "__tests__/**/*"
73
- ],
74
- "rules": {
75
- "max-lines": "off"
76
- }
77
- }
78
- ]
79
- },
80
- "jest": {
81
- "projects": [
82
- {
83
- "displayName": "client-tests",
84
- "testEnvironment": "@happy-dom/jest-environment",
85
- "testPathIgnorePatterns": [
86
- "/__tests__/server/"
87
- ]
88
- },
89
- {
90
- "displayName": "server-tests",
91
- "testEnvironment": "node",
92
- "testPathIgnorePatterns": [
93
- "/__tests__/client/"
94
- ]
95
- }
96
- ],
97
- "testRegex": [
98
- "__tests__/.*\\.test\\.ts"
69
+ "overrides": [
70
+ {
71
+ "files": [
72
+ "__tests__/**/*"
99
73
  ],
100
- "coveragePathIgnorePatterns": [
101
- "/node_modules/",
102
- "/src/(client|server)/index.ts"
103
- ],
104
- "reporters": [
105
- "default",
106
- "jest-junit"
74
+ "rules": {
75
+ "max-lines": "off"
76
+ }
77
+ }
78
+ ]
79
+ },
80
+ "jest": {
81
+ "projects": [
82
+ {
83
+ "displayName": "client-tests",
84
+ "testEnvironment": "@happy-dom/jest-environment",
85
+ "testPathIgnorePatterns": [
86
+ "/__tests__/server/"
107
87
  ]
108
- },
109
- "prettier": "arui-presets-lint/prettier",
110
- "stylelint": {
111
- "extends": "arui-presets-lint/stylelint",
112
- "ignoreFiles": [
113
- "coverage/**/*.js",
114
- ".yarn/releases/*"
88
+ },
89
+ {
90
+ "displayName": "server-tests",
91
+ "testEnvironment": "node",
92
+ "testPathIgnorePatterns": [
93
+ "/__tests__/client/"
115
94
  ]
116
- },
117
- "publishConfig": {
118
- "registry": "https://registry.npmjs.org"
119
- },
120
- "packageManager": "yarn@4.12.0"
95
+ }
96
+ ],
97
+ "testRegex": [
98
+ "__tests__/.*\\.test\\.ts"
99
+ ],
100
+ "coveragePathIgnorePatterns": [
101
+ "/node_modules/",
102
+ "/src/(client|server)/index.ts"
103
+ ],
104
+ "reporters": [
105
+ "default",
106
+ "jest-junit"
107
+ ]
108
+ },
109
+ "prettier": "arui-presets-lint/prettier",
110
+ "stylelint": {
111
+ "extends": "arui-presets-lint/stylelint",
112
+ "ignoreFiles": [
113
+ "coverage/**/*.js",
114
+ ".yarn/releases/*"
115
+ ]
116
+ },
117
+ "publishConfig": {
118
+ "registry": "https://registry.npmjs.org"
119
+ },
120
+ "packageManager": "yarn@4.12.0"
121
121
  }
@@ -1 +0,0 @@
1
- export declare const closeWebviewUtil: () => void;
@@ -1,11 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.closeWebviewUtil = void 0;
4
- const QUERY_CLOSE_WEBVIEW_KEY = 'closeWebView';
5
- const QUERY_CLOSE_WEBVIEW_VALUE = 'true';
6
- const closeWebviewUtil = () => {
7
- const originalPageUrl = new URL(window.location.href);
8
- originalPageUrl.searchParams.set(QUERY_CLOSE_WEBVIEW_KEY, QUERY_CLOSE_WEBVIEW_VALUE);
9
- window.location.href = originalPageUrl.toString();
10
- };
11
- exports.closeWebviewUtil = closeWebviewUtil;