@react-native-ohos/react-native-webview 13.16.2-beta.5 → 13.16.2
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.
- package/CHANGELOG.md +17 -21
- package/README.md +192 -119
- package/harmony/rn_webview/BuildProfile.ets +1 -1
- package/harmony/rn_webview/oh-package.json5 +1 -1
- package/harmony/rn_webview/src/main/ets/Magic.ets +2 -0
- package/harmony/rn_webview/src/main/ets/RNCWebView.ets +241 -46
- package/harmony/rn_webview/src/main/ets/WebViewBaseOperate.ets +17 -3
- package/harmony/rn_webview/src/main/ets/WebViewTurboModule.ets +6 -2
- package/harmony/rn_webview.har +0 -0
- package/package.json +2 -2
- package/harmony/rn_webview/src/main/ets/CutomReference.ts +0 -30
- package/harmony/rn_webview/src/main/ets/ShouldRequestUrl.ts +0 -48
package/CHANGELOG.md
CHANGED
|
@@ -1,33 +1,29 @@
|
|
|
1
1
|
# Changelog
|
|
2
|
-
## 鸿蒙化Log
|
|
3
2
|
|
|
4
|
-
|
|
5
|
-
- fix: 修改web链接校验方案
|
|
3
|
+
## [13.16.2] - 2026-08-17
|
|
6
4
|
|
|
7
|
-
###
|
|
8
|
-
-
|
|
5
|
+
### Added
|
|
6
|
+
- 适配webview嵌套滚动
|
|
7
|
+
- 新增renderMode属性
|
|
8
|
+
- react-native-webview适配文本长按禁用选择框
|
|
9
|
+
- react-native-webview适配mediaCapturePermissionGrantType属性
|
|
10
|
+
- add landscape/portrait switching for video([#122](https://gitcode.com/CPF-RN/rntpc_react-native-webview/pull/122))
|
|
9
11
|
|
|
10
|
-
###
|
|
11
|
-
-
|
|
12
|
+
### Fixed
|
|
13
|
+
- 修改web链接校验方案
|
|
14
|
+
- 修改forceDarkOn属性颜色设置错误的问题([#103](https://gitcode.com/CPF-RN/rntpc_react-native-webview/issues/103))
|
|
15
|
+
- Resolve the stability issues and memory leaks ([#123](https://gitcode.com/CPF-RN/rntpc_react-native-webview/pull/123))
|
|
12
16
|
|
|
13
|
-
### 13.16.2-beta.2
|
|
14
|
-
- feat: feat:react-native-webview适配文本长按禁用选择框
|
|
15
|
-
- feat:react-native-webview适配mediaCapturePermissionGrantType属性
|
|
16
17
|
|
|
18
|
+
## [13.16.1] - 2026-03-26
|
|
17
19
|
|
|
18
|
-
###
|
|
19
|
-
-
|
|
20
|
+
### Added
|
|
21
|
+
- Upgrade to the upstream community version
|
|
22
|
+
- add OpenHarmony support for react-native-webview
|
|
20
23
|
|
|
21
|
-
###
|
|
22
|
-
- pre-release version 13.16.1-rc.1
|
|
23
|
-
- feat: Upgrade to the upstream community version
|
|
24
|
+
### Changed
|
|
24
25
|
|
|
25
|
-
###
|
|
26
|
-
- pre-release: @react-native-ohos/react-native-webview@13.15.1-rc.2
|
|
27
|
-
|
|
28
|
-
### v13.15.1-rc.1
|
|
29
|
-
- pre-release: @react-native-ohos/react-native-webview@13.15.1-rc.21
|
|
30
|
-
- feat: add OpenHarmony support for react-native-webview
|
|
26
|
+
### Fixed
|
|
31
27
|
|
|
32
28
|
## ReleaseLog
|
|
33
29
|
### v13.15.0
|
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
> 模板版本:v0.4.
|
|
1
|
+
> 模板版本:v0.4.1
|
|
2
2
|
|
|
3
3
|
<p align="center">
|
|
4
4
|
<h1 align="center"> <code>react-native-webview</code> </h1>
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
</a>
|
|
13
13
|
</p>
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
本项目基于 [react-native-webview](https://github.com/react-native-webview/react-native-webview)开发。
|
|
16
16
|
|
|
17
17
|
## 安装与使用
|
|
18
18
|
|
|
@@ -20,12 +20,9 @@
|
|
|
20
20
|
|
|
21
21
|
| 三方库名称 | 三方库版本 | 发布信息 | 支持RN版本 | Autolink | 编译API版本 | 社区基线版本 | npm地址
|
|
22
22
|
| ------------ |---------|---------------------------------------------------------------------------------------------|----------------------|--------------------|-------------------|----------------------------|----------------------------------|
|
|
23
|
-
|@react-native-ohos/react-native-webview| ~13.16.1 | [Gitcode Releases](https://gitcode.com/
|
|
24
|
-
|@react-native-ohos/react-native-webview| ~13.15.1 | [Gitcode Releases](https://gitcode.com/openharmony-sig/rntpc_react-native-webview/releases) | 0.77.* | 否 | API20+ | 13.15.0 | [Npm Address](https://www.npmjs.com/package/@react-native-ohos/react-native-webview)|
|
|
25
|
-
|@react-native-ohos/react-native-webview| ~13.10.5 | [Gitcode Releases](https://gitcode.com/openharmony-sig/rntpc_react-native-webview/releases) | 0.72.* | 是 |API20+ | 13.10.2 | [Npm Address](https://www.npmjs.com/package/@react-native-ohos/react-native-webview)|
|
|
26
|
-
|@react-native-oh-tpl/react-native-webview| <=13.10.4@deprecated | [Github Releases(deprecated)](https://github.com/react-native-oh-library/react-native-webview/releases) | 0.72.* | 否 | API12+ | 13.10.2 | [Npm Address](https://www.npmjs.com/package/@react-native-oh-tpl/react-native-webview) |
|
|
23
|
+
|@react-native-ohos/react-native-webview| ~13.16.1 | [Gitcode Releases](https://gitcode.com/CPF-RN/rntpc_react-native-webview/releases) | 0.82.* | 否 | API20+ | 13.16.0 | [Npm Address](https://www.npmjs.com/package/@react-native-ohos/react-native-webview)|
|
|
27
24
|
|
|
28
|
-
对于未发布到npm的旧版本,请参考[安装指南](/tgz-usage.md)安装tgz包。
|
|
25
|
+
对于未发布到npm的旧版本,请参考[安装指南](https://gitcode.com/CPF-RN/usage-docs/blob/master/zh-cn/tgz-usage.md)安装tgz包。
|
|
29
26
|
|
|
30
27
|
进入到工程目录并输入以下命令:
|
|
31
28
|
|
|
@@ -62,18 +59,14 @@ export default function WebViewDemo() {
|
|
|
62
59
|
|
|
63
60
|
## Link
|
|
64
61
|
|
|
65
|
-
| |
|
|
62
|
+
| | 是否支持 Autolink | 支持的 RN 版本 |
|
|
66
63
|
|--------------------------------------|-----------------------|----------------------|
|
|
67
|
-
| ~13.16.1 |
|
|
68
|
-
| ~13.15.1 | No | 0.77 |
|
|
69
|
-
| ~13.10.5 | Yes | 0.72 |
|
|
70
|
-
| <= 13.10.4@deprecated | No | 0.72 |
|
|
64
|
+
| ~13.16.1 | 否 | 0.82 |
|
|
71
65
|
|
|
72
|
-
使用AutoLink的工程需要根据该文档配置,Autolink框架指导文档:https://gitcode.com/
|
|
66
|
+
使用AutoLink的工程需要根据该文档配置,Autolink框架指导文档:https://gitcode.com/CPF-RN/ohos_react_native/blob/master/docs/zh-cn/Autolinking.md
|
|
73
67
|
|
|
74
68
|
如您使用的版本支持 Autolink,并且工程已接入 Autolink,可跳过ManualLink配置。
|
|
75
|
-
|
|
76
|
-
<summary>ManualLink: 此步骤为手动配置原生依赖项的指导</summary>
|
|
69
|
+
ManualLink: 此步骤为手动配置原生依赖项的指导
|
|
77
70
|
|
|
78
71
|
首先需要使用 DevEco Studio 打开项目里的 HarmonyOS 工程 `harmony`
|
|
79
72
|
|
|
@@ -120,7 +113,7 @@ ohpm install
|
|
|
120
113
|
|
|
121
114
|
方法二:直接链接源码
|
|
122
115
|
|
|
123
|
-
> [!TIP] 如需使用直接链接源码,请参考[直接链接源码说明](/link-source-code.md)
|
|
116
|
+
> [!TIP] 如需使用直接链接源码,请参考[直接链接源码说明](https://gitcode.com/CPF-RN/usage-docs/blob/master/zh-cn/link-source-code.md)
|
|
124
117
|
|
|
125
118
|
### 3.配置 CMakeLists 和引入 WebViewPackage
|
|
126
119
|
|
|
@@ -253,10 +246,75 @@ ohpm install
|
|
|
253
246
|
|
|
254
247
|
在以下版本验证通过:
|
|
255
248
|
|
|
256
|
-
1. RNOH: 0.
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
249
|
+
1. RNOH: 0.82.1; SDK: HarmonyOS 6.0.0 Release SDK; IDE: DevEco Studio 6.0.0.858; ROM: 6.0.0.112;
|
|
250
|
+
|
|
251
|
+
### 权限要求
|
|
252
|
+
|
|
253
|
+
> [!TIP] 以下权限为按需申请:若不使用相关功能,无需配置。
|
|
254
|
+
|
|
255
|
+
| 权限名 | 触发场景 |
|
|
256
|
+
| --- | --- |
|
|
257
|
+
| `ohos.permission.APPROXIMATELY_LOCATION` | 设置 `geolocationEnabled={true}`,网页请求定位时。 |
|
|
258
|
+
| `ohos.permission.CAMERA` | 网页通过 `mediaCapturePermissionGrantType` 请求摄像头(`TYPE_VIDEO_CAPTURE`)时。 |
|
|
259
|
+
| `ohos.permission.MICROPHONE` | 网页通过 `mediaCapturePermissionGrantType` 请求麦克风(`TYPE_AUDIO_CAPTURE`)时。 |
|
|
260
|
+
|
|
261
|
+
在 `entry` 目录下的 `module.json5` 中添加权限
|
|
262
|
+
|
|
263
|
+
```
|
|
264
|
+
"requestPermissions": [
|
|
265
|
+
+ {
|
|
266
|
+
+ "name": "ohos.permission.APPROXIMATELY_LOCATION", // 定位权限名称
|
|
267
|
+
+ "reason": "$string:webview_location_reason",
|
|
268
|
+
+ "usedScene": {
|
|
269
|
+
+ "abilities": [
|
|
270
|
+
+ "EntryAbility"
|
|
271
|
+
+ ],
|
|
272
|
+
+ "when":"inuse"
|
|
273
|
+
+ }
|
|
274
|
+
+ },
|
|
275
|
+
+ {
|
|
276
|
+
+ "name": "ohos.permission.CAMERA", // 相机权限名称
|
|
277
|
+
+ "reason": "$string:webview_camera_reason",
|
|
278
|
+
+ "usedScene": {
|
|
279
|
+
+ "abilities": [
|
|
280
|
+
+ "EntryAbility"
|
|
281
|
+
+ ],
|
|
282
|
+
+ "when":"inuse"
|
|
283
|
+
+ }
|
|
284
|
+
+ },
|
|
285
|
+
+ {
|
|
286
|
+
+ "name": "ohos.permission.MICROPHONE", // 麦克风权限名称
|
|
287
|
+
+ "reason": "$string:webview_microphone_reason",
|
|
288
|
+
+ "usedScene": {
|
|
289
|
+
+ "abilities": [
|
|
290
|
+
+ "EntryAbility"
|
|
291
|
+
+ ],
|
|
292
|
+
+ "when":"inuse"
|
|
293
|
+
+ }
|
|
294
|
+
+ },
|
|
295
|
+
]
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
在 entry 目录下添加申请以上权限的原因
|
|
299
|
+
打开 `entry/src/main/resources/base/element/string.json`,添加:
|
|
300
|
+
```
|
|
301
|
+
{
|
|
302
|
+
"string": [
|
|
303
|
+
+ {
|
|
304
|
+
+ "name": "webview_location_reason",
|
|
305
|
+
+ "value": "用于网页获取地理位置"
|
|
306
|
+
+ },
|
|
307
|
+
+ {
|
|
308
|
+
+ "name": "webview_camera_reason",
|
|
309
|
+
+ "value": "用于网页访问摄像头"
|
|
310
|
+
+ },
|
|
311
|
+
+ {
|
|
312
|
+
+ "name": "webview_microphone_reason",
|
|
313
|
+
+ "value": "用于网页访问麦克风"
|
|
314
|
+
+ },
|
|
315
|
+
]
|
|
316
|
+
}
|
|
317
|
+
```
|
|
260
318
|
|
|
261
319
|
## 属性
|
|
262
320
|
> [!WARNING]ignoreSilentHardwareSwitch需要设置true网页播放才有声音
|
|
@@ -267,76 +325,79 @@ ohpm install
|
|
|
267
325
|
|
|
268
326
|
详情请查看[webview 官方文档](https://github.com/react-native-webview/react-native-webview/blob/master/docs/Reference.md)
|
|
269
327
|
|
|
270
|
-
|
|
|
328
|
+
| 名称 | 描述 | 类型 | 必填 | 平台 | 鸿蒙支持 |
|
|
271
329
|
|----------------------------------------------------------| ------------------------------------------------------------ | -------- |----------|---------------------|------------------------------------------------------------------------------------|
|
|
272
|
-
| `source` |
|
|
273
|
-
| `ref` |
|
|
274
|
-
| `injectedJavaScript?` |
|
|
275
|
-
| `originWhitelist?` |
|
|
276
|
-
| `scalesPageToFit?` |
|
|
277
|
-
| `startInLoadingState?` |
|
|
278
|
-
| `style?` |
|
|
279
|
-
| `domStorageEnabled?` |
|
|
280
|
-
| `javaScriptEnabled?` |
|
|
281
|
-
| `showsHorizontalScrollIndicator?` |
|
|
282
|
-
| `showsVerticalScrollIndicator` |
|
|
283
|
-
| `
|
|
284
|
-
| `
|
|
285
|
-
| `
|
|
286
|
-
| `
|
|
287
|
-
| `
|
|
288
|
-
| `
|
|
289
|
-
| `
|
|
290
|
-
| `
|
|
291
|
-
| `
|
|
292
|
-
| `
|
|
293
|
-
| `
|
|
294
|
-
| `
|
|
295
|
-
| `
|
|
296
|
-
| `
|
|
297
|
-
| `
|
|
298
|
-
| `
|
|
299
|
-
| `
|
|
300
|
-
| `
|
|
301
|
-
| `
|
|
302
|
-
| `
|
|
303
|
-
| `
|
|
304
|
-
| `
|
|
305
|
-
| `
|
|
306
|
-
| `
|
|
307
|
-
| `
|
|
308
|
-
| `
|
|
309
|
-
| `
|
|
310
|
-
| `
|
|
311
|
-
| `
|
|
312
|
-
| `
|
|
313
|
-
| `
|
|
314
|
-
| `
|
|
315
|
-
| `
|
|
316
|
-
| `
|
|
317
|
-
| `
|
|
318
|
-
| `
|
|
319
|
-
| `
|
|
320
|
-
| `
|
|
321
|
-
| `
|
|
322
|
-
| `
|
|
323
|
-
| `
|
|
324
|
-
| `
|
|
325
|
-
| `
|
|
326
|
-
| `
|
|
327
|
-
| `
|
|
328
|
-
| `
|
|
329
|
-
| `
|
|
330
|
-
| `
|
|
331
|
-
| `
|
|
332
|
-
| `
|
|
333
|
-
| `
|
|
334
|
-
| `
|
|
335
|
-
| `
|
|
336
|
-
| `
|
|
337
|
-
| `
|
|
338
|
-
| `
|
|
339
|
-
| `
|
|
330
|
+
| `source` | 在 WebView 中加载静态 HTML 或 URI(可选附带 headers) | object | 是 | All | 部分支持(仅支持:**加载 URI:** uri headers **静态 HTML:** html baseUrl) |
|
|
331
|
+
| `ref` | 用于获取组件实例的引用 | object | 是 | All | 是 |
|
|
332
|
+
| `injectedJavaScript?` | 设置在页面文档加载完成后注入到网页中的 JavaScript 代码 | string | 否 | All | 是 |
|
|
333
|
+
| `originWhitelist?` | 允许导航到的来源字符串列表。 | string[] | 否 | iOS,Android,macOS | 否 |
|
|
334
|
+
| `scalesPageToFit?` | 布尔值,控制网页内容是否缩放以适应视图,并允许用户改变缩放比例。 | boolean | 否 | Android | 是 |
|
|
335
|
+
| `startInLoadingState?` | 布尔值,强制 WebView 在首次加载时显示加载视图。 | boolean | 否 | iOS,Android,macOS | 否 |
|
|
336
|
+
| `style?` | 样式对象,用于自定义 WebView 的样式。 | Style | 否 | ALL | 是 |
|
|
337
|
+
| `domStorageEnabled?` | 布尔值,控制是否启用 DOM Storage。仅在 Android 和鸿蒙上使用。Harmony 中的默认值为 `false` | boolean | 否 | Android | 是 |
|
|
338
|
+
| `javaScriptEnabled?` | 布尔值,控制是否在 WebView 中启用 JavaScript。 | boolean | 否 | All | 是 |
|
|
339
|
+
| `showsHorizontalScrollIndicator?` | 布尔值,控制是否在 WebView 中显示水平滚动指示器。 | boolean | 否 | iOS,Android,macOS | 是 |
|
|
340
|
+
| `showsVerticalScrollIndicator` | 布尔值,控制是否在 WebView 中显示垂直滚动指示器。 | boolean | 否 | iOS,Android,macOS | 是 |
|
|
341
|
+
| `overScrollMode?` | 覆盖过滚动模式 | string | 否 | Android | 否 |
|
|
342
|
+
| `bounces?` | 布尔值,控制 WebView 内容滚动到边界时是否产生弹性回弹效果。默认值为 `true`。在未显式设置 `overScrollMode` 时生效,作为回弹开关的兜底。 | boolean | 否 | iOS | 是 |
|
|
343
|
+
| `ignoreSilentHardwareSwitch` | 布尔值,设置为 true 时将忽略硬件静音开关。 | boolean | 否 | iOS | 是 |
|
|
344
|
+
| `cacheEnabled?` | 设置 WebView 是否使用浏览器缓存。 | boolean | 否 | iOS,Android,macOS | 是 |
|
|
345
|
+
| `cacheMode?` | 覆盖缓存的使用方式。 | string | 否 | Android | 是 |
|
|
346
|
+
| `textZoom?` | 如果用户在 Android 和鸿蒙系统中设置了自定义字体大小,WebView 中的网页界面会发生不必要的缩放。 | number | 否 | Android | 是 |
|
|
347
|
+
| `incognito?` | 在 WebView 的生命周期内不存储任何数据。 | boolean | 否 | All | 是 |
|
|
348
|
+
| `mediaPlaybackRequiresUserAction?` | 布尔值,决定 HTML5 音视频是否需要用户点击后才能开始播放。默认值为 `true`。(Android API 最低版本 17)。 | boolean | 否 | iOS,Android,macOS | 是 |
|
|
349
|
+
| `geolocationEnabled?` | 设置是否在 `WebView` 中启用地理位置功能。默认值为 `false`。仅在 Android 上使用。 | boolean | 否 | Android | 是 |
|
|
350
|
+
| `fraudulentWebsiteWarningEnabled?` | 布尔值,指示 Web 视图是否对可疑欺诈内容(如恶意软件或钓鱼攻击)显示警告。默认值为 `true`。(iOS 13+) | boolean | 否 | iOS | 是(该接口不生效,调用不会产生任何实际效果,非法和欺诈网站是强制启用的,鸿蒙 OS 当前实现如此。) |
|
|
351
|
+
| `userAgent?` | 为 `WebView` 设置 User-Agent。 | string | 否 | iOS,Android,macOS | 是 |
|
|
352
|
+
| `minimumFontSize?` | Android 根据此值强制设置最小字体大小。取值为 1 到 72 之间的非负整数。超出范围的值将被限定。默认值为 8。如果使用较小的字体大小且无法将整个窗口适配到一屏,尝试将此值设为更小的值。 | number | 否 | Android | 是 |
|
|
353
|
+
| `forceDarkOn?` | 配置深色主题 | boolean | 否 | Android | 是(依赖系统开启深色模式) |
|
|
354
|
+
| `injectedJavaScriptBeforeContentLoaded?` | 设置在文档元素创建后、其他子资源完成加载前注入到网页中的 JavaScript 代码。 | string | 否 | iOS,Android,macOS | 是 |
|
|
355
|
+
| `automaticallyAdjustContentInsets?` | 控制是否为放置在导航栏、标签栏或工具栏后面的 Web 视图调整内容间距。默认值为 `true` | boolean | 否 | iOS | 否 |
|
|
356
|
+
| `automaticallyAdjustsScrollIndicatorInsets?` | 控制是否为放置在导航栏、标签栏或工具栏后面的 Web 视图调整滚动指示器间距。默认值为 `false`。(iOS 13+) | boolean | 否 | iOS | 否 |
|
|
357
|
+
| `injectedJavaScriptBeforeContentLoadedForMainFrameOnly?` | 如果为 `true`(默认值;Android 下为必填),仅在主框架中加载 `injectedJavaScriptBeforeContentLoaded`。 | boolean | 否 | iOS | 否 |
|
|
358
|
+
| `nativeConfig?` | 覆盖用于渲染 WebView 的原生组件。允许使用与原 WebView 相同 JavaScript 的自定义原生 WebView。 | object | 否 | iOS, Android, macOS | 否 |
|
|
359
|
+
| `decelerationRate?` | 浮点数,决定用户抬起手指后滚动视图减速的速度。也可使用字符串快捷方式 `"normal"` 和 `"fast"`,对应 iOS 底层实现。 | number | 否 | iOS | 否 |
|
|
360
|
+
| `javaScriptCanOpenWindowsAutomatically?` | 布尔值,指示 JavaScript 是否可以在没有用户交互的情况下打开窗口。默认值为 `false`。 | boolean | 否 | iOS, Android, macOS | 否 |
|
|
361
|
+
| `AndroidLayerType?` | 指定图层类型。 | string | 否 | Android | 否 |
|
|
362
|
+
| `mixedContentMode?` |指定混合内容模式。即 WebView 是否允许安全来源加载来自任何其他来源的内容。 | string | 否 | Android | 否 |
|
|
363
|
+
| `allowsFullscreenVideo?` | 布尔值,决定是否允许视频全屏播放。默认值为 false。 | boolean | 否 | Android | 是 |
|
|
364
|
+
| `allowsInlineMediaPlayback?` | 布尔值,决定 HTML5 视频是内联播放还是使用原生全屏控制器。默认值为 `false`。 | boolean | 否 | iOS | 否 |
|
|
365
|
+
| `allowsAirPlayForMediaPlayback?` | 布尔值,指示是否允许 AirPlay。默认值为 `false`。 | boolean | 否 | iOS and macOS | 否 |
|
|
366
|
+
| `contentInset?` | Web 视图内容与滚动视图边缘的间距量。默认为 {top: 0, left: 0, bottom: 0, right: 0}。 | object | 否 | iOS | 否 |
|
|
367
|
+
| `contentInsetAdjustmentBehavior?` | 此属性指定如何使用安全区域间距来修改滚动视图的内容区域。此属性的默认值为 "never"。iOS 11 及以上可用。默认为 `never`。 | string | 否 | iOS | 否 |
|
|
368
|
+
| `contentMode?` | 控制加载的内容类型。iOS 13 及以上可用。默认为 `recommended`,即在 iPhone 和 iPad Mini 上加载移动端内容,在更大的 iPad 上加载桌面端内容。 | string | 否 | iOS | 否 |
|
|
369
|
+
| `dataDetectorTypes?` | 决定 Web 视图内容中哪些类型的数据被转换为可点击的 URL。默认仅检测电话号码。 | string, or array | 否 | ios | 否 |
|
|
370
|
+
| `setBuiltInZoomControls?` | 设置 WebView 是否使用其内置缩放机制。默认值为 `true`。设置为 `false` 将阻止使用捏合手势控制缩放。 | boolean | 否 | Android | 否 |
|
|
371
|
+
| `setDisplayZoomControls?` | 设置使用内置缩放机制时 WebView 是否显示屏幕缩放控件(参见 `setBuiltInZoomControls`)。默认值为 `false`。 | boolean | 否 | Android | 否 |
|
|
372
|
+
| `directionalLockEnabled?` | 布尔值,决定是否在特定方向上禁用滚动。默认值为 `true`。 | boolean | 否 | iOS | 否 |
|
|
373
|
+
| `allowFileAccessFromFileURLs?` | 布尔值,设置在 file 协议 URL 上下文中运行的 JavaScript 是否允许访问其他 file 协议 URL 的内容。默认值为 `false`。 | boolean | 否 | iOS, Android, macOS | 否 |
|
|
374
|
+
| `allowUniversalAccessFromFileURLs?` | boolean | 否 | 否 | iOS, Android, macOS | 否 |
|
|
375
|
+
| `allowingReadAccessToURL` | 字符串值,指示 WebView 的文件可以在脚本、AJAX 请求和 CSS 导入中引用哪些 URL。仅适用于通过 `source.uri` 设置为 `'file://'` URL 加载的 WebView。如未提供,默认仅允许对 `source.uri` 中提供的 URL 进行读取访问。 | string | 否 | iOS and macOS | 否 |
|
|
376
|
+
| `keyboardDisplayRequiresUserAction?` | 如果为 `false`,网页内容可以通过编程方式显示键盘。默认值为 `true`。 | boolean | 否 | iOS and macOS | 否 |
|
|
377
|
+
| `hideKeyboardAccessoryView?` | 如果为 `true`,将隐藏键盘附件视图(< > 和 Done)。 | boolean | 否 | iOS | 否 |
|
|
378
|
+
| `allowsBackForwardNavigationGestures?` | 如果为 `true`,将支持水平滑动手势。默认值为 `false`。 | boolean | 否 | iOS | 否 |
|
|
379
|
+
| `allowFileAccess?` | 如果为 `true`,将允许通过 `file://` URI 访问文件系统。默认值为 `false`。 | boolean | 否 | Android | 否 |
|
|
380
|
+
| `saveFormDataDisabled?` | 设置 WebView 是否禁用保存表单数据。默认值为 `false`。从 Android API 26 级开始此功能不再有效,因为有自动填充功能来存储表单数据。 | boolean | 否 | Android | 否 |
|
|
381
|
+
| `pagingEnabled?` | 如果此属性值为 `true`,滚动视图在用户滚动时会停在滚动视图边界的倍数位置。默认值为 `false`。 | boolean | 否 | iOS | 否 |
|
|
382
|
+
| `allowsLinkPreview?` | 布尔值,决定点击链接时是否显示链接目标的预览。在 iOS 中,此属性在支持 3D Touch 的设备上可用。iOS 10 及以上默认值为 `true`;之前默认值为 `false`。 | boolean | 否 | iOS and macOS | 否 |
|
|
383
|
+
| `sharedCookiesEnabled?` | 如果为 `true`,每次 WebView 加载请求时将使用 `[NSHTTPCookieStorage sharedHTTPCookieStorage]` 中的共享 Cookie。默认值为 `false`。更多关于 Cookie 的信息,请阅读 [指南](https://github.com/react-native-webview/react-native-webview/blob/master/docs/Guide.md#Managing-Cookies) | boolean | 否 | iOS and macOS | 否 |
|
|
384
|
+
| `limitsNavigationsToAppBoundDomains?` | 如果为 `true`,向 WebKit 表明 WKWebView 将仅在应用绑定的域中导航。仅适用于 iOS 14 或更高版本。 | boolean | 否 | iOS | 否 |
|
|
385
|
+
| `textInteractionEnabled?` | 如果为 false,向 WebKit 表明 WKWebView 不会与文本交互,因此不显示文本选择循环。仅适用于 iOS 14.5 或更高版本。 | boolean | 否 | iOS | 否 |
|
|
386
|
+
| `suppressMenuItems?` | 允许从默认上下文菜单中隐藏菜单项。 | array of strings | 否 | iOS | 否 |
|
|
387
|
+
| `mediaCapturePermissionGrantType?` | 此属性指定如何处理媒体捕获权限请求。默认为 `prompt`,即反复提示用户。iOS 15 及以上可用。 | string | 否 | iOS | 是 |
|
|
388
|
+
| `autoManageStatusBarEnabled?` | 如果设置为 `true`,WebView 将自动隐藏/显示状态栏,特别是在观看全屏视频时。如果为 `false`,WebView 将完全不管理状态栏。默认值为 `true`。 | boolean | 否 | iOS | 否 |
|
|
389
|
+
| `basicAuthCredential`? | 对象,指定用于基本身份验证的用户凭据。 | object | 否 | iOS, Android | 否 |
|
|
390
|
+
| `useWebView2?` | 使用 WinUI WebView2 控件代替 WebView 控件作为原生 Web 视图。WebView2 控件是使用 Microsoft Edge (Chromium) 渲染引擎渲染网页内容的 WinUI 控件。可在运行时切换并支持 Fast Refresh。 | boolean | 否 | Windows | 否 |
|
|
391
|
+
| `applicationNameForUserAgent?` | 追加到现有的 User-Agent。设置 `userAgent` 将覆盖此项。 | string | 否 | All | 是 |
|
|
392
|
+
| `thirdPartyCookiesEnabled?` | 布尔值,在 `WebView` 中启用第三方 Cookie。仅在 Android Lollipop 及以上使用,因为 Android Kitkat 及以下和 iOS 上默认启用第三方 Cookie。默认值为 `true`。 | boolean | 否 | All | 是 |
|
|
393
|
+
| `menuItems?` | 自定义菜单项对象数组,在选择文本时显示。空数组将隐藏菜单 | array of objects | 否 | iOS,Android | 是 |
|
|
394
|
+
| `paymentRequestEnabled` | 是否为 WebView 启用 Payment Request API。默认值为 `false`。 | boolean | 否 | Android | 否 |
|
|
395
|
+
| `webviewDebuggingEnabled?` | 布尔值,控制是否允许通过远程调试工具(如 DevTools)调试 WebView 中加载的网页。默认值为 `false`。建议仅在开发环境开启,生产环境关闭以避免安全风险。 | boolean | 否 | Android | 是 |
|
|
396
|
+
| `allowsPictureInPictureMediaPlayback` | 布尔值,指示 HTML5 视频是否可以画中画播放。默认值为 `false`。 | boolean | 否 | Android | 否 |
|
|
397
|
+
| `refreshControlLightMode` | (仅 iOS)布尔值,决定刷新控件颜色是否为白色。默认值为 `false`。 | boolean | 否 | iOS | 否 |
|
|
398
|
+
| `indicatorStyle ` | 滚动指示器的颜色样式。 | string | 否 | iOS, Android | 否 |
|
|
399
|
+
| `renderMode` | 此属性用于控制 Web 组件的渲染模式,是 OpenHarmony 特有属性。枚举值:`SYNC_RENDER`(默认)、`ASYNC_RENDER` | string | 否 | - | 是 |
|
|
400
|
+
| `scrollEnabled` | 布尔值,决定 WebView 中是否启用滚动。默认值为 true。设置为 false 将阻止键盘出现在输入框上方时 webview 移动文档正文。默认值为 `false`。 | boolean | 否 | iOS and macOS | 是 |
|
|
340
401
|
|
|
341
402
|
|
|
342
403
|
## 事件回调
|
|
@@ -345,47 +406,59 @@ ohpm install
|
|
|
345
406
|
|
|
346
407
|
> [!TIP] "HarmonyOS Support"列为 yes 表示 HarmonyOS 平台支持该属性;no 则表示不支持;partially 表示部分支持。使用方法跨平台一致,效果对标 iOS 或 Android 的效果。
|
|
347
408
|
|
|
348
|
-
|
|
|
409
|
+
| 名称 | 描述 | 类型 | 必填 | 平台 | 鸿蒙支持 |
|
|
349
410
|
|---------------------------------------------------------------| ------------------------------------------------------------ | -------- | -------- | ----------------------- |-------------------|
|
|
350
|
-
| `onScroll?: (event) => void` |
|
|
351
|
-
| `onHttpError?: (event) => void` |
|
|
352
|
-
| `onLoadStart?: (event) => void` |
|
|
353
|
-
| `onLoad?: (event) => void` |
|
|
354
|
-
| `onOpenWindow?` |
|
|
355
|
-
| `onLoadEnd?: (event) => void` |
|
|
356
|
-
| `onLoadProgress?: (event) => void` |
|
|
357
|
-
| `onMessage?: (event) => void` |
|
|
358
|
-
| `onShouldStartLoadWithRequest?: (event) => void` |
|
|
359
|
-
| `onContentProcessDidTerminate: (event) => void` |
|
|
360
|
-
| `
|
|
361
|
-
| `
|
|
362
|
-
| `
|
|
363
|
-
| `
|
|
364
|
-
| `
|
|
365
|
-
|
|
411
|
+
| `onScroll?: (event) => void` | 当 `WebView` 中触发滚动事件时调用的函数。 | function | 否 | iOS and macOS | 是 |
|
|
412
|
+
| `onHttpError?: (event) => void` | 当 `WebView` 收到 HTTP 错误时调用的函数。 | function | 否 | 是 | 是 |
|
|
413
|
+
| `onLoadStart?: (event) => void` | 当 `WebView` 开始加载时调用的函数。 | function | 否 | All | 是 |
|
|
414
|
+
| `onLoad?: (event) => void` | 当 `WebView` 完成加载时调用的函数。 | function | 否 | All | 是 |
|
|
415
|
+
| `onOpenWindow?` | 当 `WebView` 需要打开新窗口时调用的函数。 | function | 否 | iOS, Android, macOS | 否 |
|
|
416
|
+
| `onLoadEnd?: (event) => void` | 当 WebView 加载成功或失败时调用的函数。 | function | 否 | All | 是 |
|
|
417
|
+
| `onLoadProgress?: (event) => void` | 当 WebView 正在加载时调用的函数。 | function | 否 | All | 是 |
|
|
418
|
+
| `onMessage?: (event) => void` | 当 webview 调用 window.ReactNativeWebView.postMessage 时调用的函数。 | function | 否 | iOS,Android,macOS | 是 |
|
|
419
|
+
| `onShouldStartLoadWithRequest?: (event) => void` | 允许自定义处理任何 Web 视图请求的函数。此功能需要与 worker 线程结合使用,相关配置可参考 [worker 线程](https://gitcode.com/CPF-RN/ohos_react_native/blob/master/docs/zh-cn/TurboModule.md#%E8%AE%BE%E7%BD%AE%E8%87%AA%E5%AE%9A%E4%B9%89turbomodule%E8%BF%90%E8%A1%8C%E5%9C%A8worker%E7%BA%BF%E7%A8%8B)的第三步。| function | 否 | iOS,Android,macOS | 是 |
|
|
420
|
+
| `onContentProcessDidTerminate: (event) => void` | 当 `WebView` 内容进程终止时调用的函数。 | function | 否 | iOS and macOS WKWebView | 否 |
|
|
421
|
+
| `onRenderProcessGone?: (event) => void` | 当 WebView 的渲染进程崩溃或被系统回收时调用的函数。可用于感知页面渲染异常并做恢复处理(如 `reload`)。 | function | 否 | Android | 否 |
|
|
422
|
+
| `renderLoading?` | 返回加载指示器的函数。必须将 `startInLoadingState` 属性设置为 `true` 才能使用此属性。 | function | 否 | iOS, Android, macOS | 否 |
|
|
423
|
+
| `onCustomMenuSelection?` | 当选择自定义菜单项时调用的函数。接收一个 Native 事件,包含三个自定义键:`label`、`key` 和 `selectedText`。 | function | 否 | iOS, Android | 是 |
|
|
424
|
+
| `onNavigationStateChange?: (event) => void` | 当 WebView 开始或结束加载时调用的函数。 | function | 否 | iOS, Android | 是 |
|
|
425
|
+
| `onError: (event) => void` | 处理加载错误的回调函数。 | function | 否 | iOS,Android | 是 |
|
|
426
|
+
| `onLoadSubResourceError: (event) => void ` | 子资源 SSL 错误处理的函数。 | function | 否 | Android | 是 |
|
|
427
|
+
## 函数
|
|
366
428
|
|
|
367
429
|
> [!TIP] "Platform"列表示该属性在原三方库上支持的平台。
|
|
368
430
|
|
|
369
431
|
> [!TIP] "HarmonyOS Support"列为 yes 表示 HarmonyOS 平台支持该属性;no 则表示不支持;partially 表示部分支持。使用方法跨平台一致,效果对标 iOS 或 Android 的效果。
|
|
370
432
|
|
|
371
|
-
|
|
433
|
+
> [!NOTE] 以下方法均为实例方法,需通过组件 `ref` 调用,例如:`ref.current?.goBack()`。
|
|
434
|
+
|
|
435
|
+
| 名称 | 描述 | 类型 | 必填 | 平台 | 鸿蒙支持 |
|
|
436
|
+
| ---------------------------------- | ------------------------------------------------------------ | -------- | -------- | -------- | ----------------- |
|
|
437
|
+
| `goForward()` | 在 Web 视图的历史记录中前进一页。 | function | 否 | All | 是 |
|
|
438
|
+
| `goBack()` | 在 Web 视图的历史记录中后退一页。 | function | 否 | All | 是 |
|
|
439
|
+
| `reload()` | 重新加载当前页面。 | function | 否 | All | 是 |
|
|
440
|
+
| `stopLoading()` | 停止加载当前页面。 | function | 否 | All | 是 |
|
|
441
|
+
| `injectJavaScript(script: string)` | 向 WebView 注入 JavaScript 代码。重要提示:此函数必须在调用 onRestoreUserInterfaceForPictureInPictureStop 之后调用。 | function | 否 | All | 是 |
|
|
442
|
+
| `requestFocus()` | 请求 WebView 获取焦点。(开发 TV 应用的用户可能需要关注此项!) | function | 否 | All | 是 |
|
|
443
|
+
| `postMessage(data:string)` | 向 WebView 发送消息,由 `onMessage` 处理。 | function | 否 | All | 是 |
|
|
444
|
+
| `clearFormData()` | 移除当前焦点表单字段上的自动填充弹窗(如果存在)。 | function | 否 | Android | 否 |
|
|
445
|
+
| `clearCache(status:boolean)` | 清除资源缓存。注意缓存是应用级别的,因此会清除所有使用的 WebView 的缓存。 | function | 否 | All | 是 |
|
|
446
|
+
| `clearHistory()` | 通知此 WebView 清除其内部的前进/后退列表。 | function | 否 | Android | 是 |
|
|
447
|
+
| `loadUrl(url: string)` | 加载URL。 | function | 否 | Android | 是 |
|
|
448
|
+
|
|
449
|
+
## 静态方法
|
|
450
|
+
|
|
451
|
+
> [!NOTE] 静态方法无需 `ref`,直接通过 `WebView` 调用,例如:`WebView.isFileUploadSupported()`。
|
|
452
|
+
|
|
453
|
+
| 名称 | 描述 | 类型 | 必填 | 平台 | 鸿蒙支持 |
|
|
372
454
|
| ---------------------------------- | ------------------------------------------------------------ | -------- | -------- | -------- | ----------------- |
|
|
373
|
-
| `
|
|
374
|
-
| `goBack()` | Go back one page in the web view's history. | function | No | All | yes |
|
|
375
|
-
| `reload()` | Reloads the current page. | function | No | All | yes |
|
|
376
|
-
| `stopLoading()` | Stop loading the current page. | function | No | All | yes |
|
|
377
|
-
| `injectJavaScript(script: string)` | This function corresponds to the completion handler in Apple's recovery user interface ForPictureInPictureStop. IMPORTANT: This function must be called after calling onRestoreUserInterfaceForPictureInPictureStop. | function | No | All | yes |
|
|
378
|
-
| `requestFocus()` | Request the webView to ask for focus. (People working on TV apps might want having a look at this!) | function | No | All | yes |
|
|
379
|
-
| `postMessage(data:string)` | Post a message to WebView, handled by `onMessage`. | function | No | All | yes |
|
|
380
|
-
| `clearFormData()` | Removes the autocomplete popup from the currently focused form field, if present. | function | No | Android | No |
|
|
381
|
-
| `clearCache(status:boolean)` | Clears the resource cache. Note that the cache is per-application, so this will clear the cache for all WebViews used. | function | No | All | yes |
|
|
382
|
-
| `clearHistory()` | Tells this WebView to clear its internal back/forward list. | function | No | Android | yes |
|
|
455
|
+
| `isFileUploadSupported()` | 检查设备是否支持文件上传,返回 `Promise<boolean>`。 | function | 否 | All | 是 |
|
|
383
456
|
|
|
384
457
|
## 遗留问题
|
|
385
458
|
|
|
386
|
-
- [ ] webview 部分属性未实现 HarmonyOS 化[issue#17](https://gitcode.com/
|
|
459
|
+
- [ ] webview 部分属性未实现 HarmonyOS 化[issue#17](https://gitcode.com/CPF-RN/rntpc_react-native-webview/issues/17)
|
|
387
460
|
- [ ] webview 部分属性未实现 HarmonyOS 化[issue#200](https://github.com/react-native-oh-library/react-native-webview/issues/200)
|
|
388
|
-
- [ ] V13.15.1 新增属性未实现 HarmonyOS 化[issue#2](https://gitcode.com/
|
|
461
|
+
- [ ] V13.15.1 新增属性未实现 HarmonyOS 化[issue#2](https://gitcode.com/CPF-RN/rntpc_react-native-webview/issues/2)
|
|
389
462
|
- [X] 中文乱码[issue#18](https://github.com/react-native-oh-library/react-native-webview/issues/18)
|
|
390
463
|
|
|
391
464
|
## 其他
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Use these variables when you tailor your ArkTS code. They must be of the const type.
|
|
3
3
|
*/
|
|
4
|
-
export const HAR_VERSION = '13.16.2
|
|
4
|
+
export const HAR_VERSION = '13.16.2';
|
|
5
5
|
export const BUILD_MODE_NAME = 'debug';
|
|
6
6
|
export const DEBUG = true;
|
|
7
7
|
export const TARGET_NAME = 'default';
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
"name": "@react-native-ohos/react-native-webview",
|
|
7
7
|
"description": "main cpai architecture",
|
|
8
8
|
"main": "index.ets",
|
|
9
|
-
"version": "13.16.2
|
|
9
|
+
"version": "13.16.2",
|
|
10
10
|
"dependencies": {
|
|
11
11
|
"@rnoh/react-native-openharmony": "../react_native_openharmony.har"
|
|
12
12
|
}
|
|
@@ -66,7 +66,9 @@ export interface WebViewProps extends ViewRawProps {
|
|
|
66
66
|
pullToRefreshEnabled: boolean
|
|
67
67
|
mediaCapturePermissionGrantType?: 'prompt' | 'grant' | 'deny' | 'grantIfSameHostElsePrompt' | 'grantIfSameHostElseDeny'
|
|
68
68
|
menuItems?: Array<MenuItem> | undefined;
|
|
69
|
+
allowsFullscreenVideo?: boolean;
|
|
69
70
|
renderMode?: 'SYNC_RENDER' | 'ASYNC_RENDER';
|
|
71
|
+
allowFileAccess?: boolean;
|
|
70
72
|
}
|
|
71
73
|
|
|
72
74
|
export interface MenuItem {
|
|
@@ -33,6 +33,7 @@ import { abilityAccessCtrl, bundleManager, Permissions } from '@kit.AbilityKit';
|
|
|
33
33
|
import { WebViewTurboModule, ShouldStartParams, ShouldOverrideCallbackState } from './WebViewTurboModule';
|
|
34
34
|
import { AnyThreadRNInstance, WorkerTaskRunnable } from '@rnoh/react-native-openharmony/src/main/ets/RNOH';
|
|
35
35
|
import buffer from '@ohos.buffer';
|
|
36
|
+
import { window } from '@kit.ArkUI';
|
|
36
37
|
|
|
37
38
|
export const TAG = "WebView"
|
|
38
39
|
|
|
@@ -66,7 +67,6 @@ export struct RNCWebView {
|
|
|
66
67
|
controller: webview.WebviewController = new webview.WebviewController();
|
|
67
68
|
javaScriptEnable: boolean = true;
|
|
68
69
|
allowFileAccess: boolean = true;
|
|
69
|
-
forceDark: boolean = true;
|
|
70
70
|
minFontSize: number = EIGHT;
|
|
71
71
|
overScrollMode: OverScrollMode = OverScrollMode.NEVER;
|
|
72
72
|
progress: number = ZERO;
|
|
@@ -87,23 +87,29 @@ export struct RNCWebView {
|
|
|
87
87
|
@State webviewWidth: number = ZERO
|
|
88
88
|
@State webviewHeight: number = ZERO
|
|
89
89
|
@State isRefreshing: boolean = false
|
|
90
|
-
@State
|
|
90
|
+
@State isFullScreen: boolean = false
|
|
91
|
+
@State mode: MixedMode = MixedMode.None;
|
|
91
92
|
private unregisterDescriptorChangesListener?: () => void = undefined
|
|
92
93
|
private cleanupCommandCallback?: () => void = undefined
|
|
93
94
|
private eventEmitter: RNC.RNCWebView.EventEmitter | undefined = undefined
|
|
94
|
-
private cleanUpCallbacks: (() => void)[] = []
|
|
95
95
|
private descriptorWrapper: WebViewDescriptor = Object() as WebViewDescriptor
|
|
96
96
|
private webViewBaseOperate: BaseOperate | null = null
|
|
97
|
-
private shouldInterceptLoad: boolean = true
|
|
98
|
-
private callLoadTimer: number = -1
|
|
99
97
|
static readonly SHOULD_OVERRIDE_URL_LOADING_TIMEOUT: number = 250
|
|
100
98
|
private debounceTimer: number = -1
|
|
101
99
|
static readonly DEBOUNCE_TIME: number = 100
|
|
102
100
|
private isFirstDebounce: boolean = true
|
|
103
|
-
|
|
104
|
-
|
|
101
|
+
private initialOrientation: window.Orientation = window.Orientation.PORTRAIT
|
|
102
|
+
private isOrientationSaved: boolean = false
|
|
103
|
+
private cachedWindow: window.Window | null = null
|
|
104
|
+
private allowsFullscreenVideo: boolean = false
|
|
105
|
+
private isProgrammaticLoad = false
|
|
106
|
+
private isComponentAlive: boolean = true
|
|
107
|
+
|
|
108
|
+
async aboutToAppear() {
|
|
109
|
+
this.isComponentAlive = true
|
|
105
110
|
try {
|
|
106
111
|
this.initVariable()
|
|
112
|
+
await this.saveInitialOrientation()
|
|
107
113
|
this.getBundleName()
|
|
108
114
|
this.url = this.source.uri as string;
|
|
109
115
|
this.onDescriptorWrapperChange(this.descriptorWrapper)
|
|
@@ -118,13 +124,6 @@ export struct RNCWebView {
|
|
|
118
124
|
if (this.hasIncognito()) {
|
|
119
125
|
this.cacheMode = CacheMode.Online;
|
|
120
126
|
}
|
|
121
|
-
if (this.source.headers) {
|
|
122
|
-
this.source.headers.forEach(item => {
|
|
123
|
-
if (item.name && item.value) {
|
|
124
|
-
this.headers.push({ headerKey: item.name, headerValue: item.value })
|
|
125
|
-
}
|
|
126
|
-
})
|
|
127
|
-
}
|
|
128
127
|
if (this.descriptorWrapper.rawProps.geolocationEnabled) {
|
|
129
128
|
atManager.requestPermissionsFromUser(this.ctx.uiAbilityContext, ["ohos.permission.APPROXIMATELY_LOCATION"]).then((data) => {
|
|
130
129
|
}).catch((error: BusinessError) => {
|
|
@@ -146,27 +145,58 @@ export struct RNCWebView {
|
|
|
146
145
|
}
|
|
147
146
|
|
|
148
147
|
aboutToDisappear() {
|
|
149
|
-
this.
|
|
150
|
-
this.cleanupCommandCallback?.()
|
|
148
|
+
this.isComponentAlive = false
|
|
151
149
|
this.unregisterDescriptorChangesListener?.()
|
|
152
|
-
this.
|
|
150
|
+
this.cleanupCommandCallback?.()
|
|
151
|
+
if (this.debounceTimer !== -1) {
|
|
152
|
+
clearTimeout(this.debounceTimer)
|
|
153
|
+
this.debounceTimer = -1
|
|
154
|
+
}
|
|
155
|
+
// 恢复初始屏幕方向和沉浸式状态,防止全屏状态下组件销毁后状态残留
|
|
156
|
+
// 无论是否在全屏状态,都尝试恢复窗口状态(handleFullScreenEnter 异步操作可能在组件销毁后才完成)
|
|
157
|
+
if (this.cachedWindow) {
|
|
158
|
+
try {
|
|
159
|
+
this.cachedWindow.setPreferredOrientation(this.initialOrientation);
|
|
160
|
+
this.cachedWindow.setWindowLayoutFullScreen(false);
|
|
161
|
+
this.cachedWindow.setWindowSystemBarEnable(['status', 'navigation']);
|
|
162
|
+
Logger.debug(TAG, '[WebViewFullScreen] Restored window state in aboutToDisappear');
|
|
163
|
+
} catch (error) {
|
|
164
|
+
Logger.error(TAG, `[WebViewFullScreen] Failed to restore in aboutToDisappear: ${error.code}`);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
this.eventEmitter = undefined
|
|
168
|
+
this.headers = []
|
|
169
|
+
this.isFullScreen = false;
|
|
170
|
+
this.cachedWindow = null;
|
|
171
|
+
this.getUIContext().getFocusController().clearFocus()
|
|
172
|
+
|
|
153
173
|
try {
|
|
154
174
|
if (this.hasIncognito()) {
|
|
155
175
|
this.webViewBaseOperate?.setIncognito()
|
|
156
176
|
}
|
|
157
|
-
this.controller.deleteJavaScriptRegister(JAVASCRIPT_INTERFACE)
|
|
158
|
-
this.controller.refresh()
|
|
159
|
-
this.hasRegisterJavaScriptProxy = false
|
|
160
|
-
this.webViewBaseOperate = null
|
|
161
177
|
} catch (error) {
|
|
162
178
|
Logger.error(TAG, `[RNOH]Errorcode: ${error.code}, Message: ${error.message}`);
|
|
179
|
+
} finally {
|
|
180
|
+
try {
|
|
181
|
+
this.controller.deleteJavaScriptRegister(JAVASCRIPT_INTERFACE)
|
|
182
|
+
this.controller.refresh()
|
|
183
|
+
} catch (e) {
|
|
184
|
+
Logger.error(TAG, `[RNOH] deleteJavaScriptRegister Errorcode: ${e.code}, Message: ${e.message}`);
|
|
185
|
+
}
|
|
186
|
+
this.hasRegisterJavaScriptProxy = false
|
|
187
|
+
this.webViewBaseOperate = null
|
|
163
188
|
}
|
|
164
189
|
}
|
|
165
190
|
|
|
166
191
|
registerCommandCallback() {
|
|
167
192
|
this.cleanupCommandCallback = this.ctx.componentCommandReceiver.registerCommandCallback(
|
|
168
193
|
this.tag,
|
|
169
|
-
(command:
|
|
194
|
+
(command: string, args: string[]) => {
|
|
195
|
+
if (command === COMMAND_NAME.LOADURL) {
|
|
196
|
+
this.isProgrammaticLoad = true
|
|
197
|
+
}
|
|
198
|
+
this.webViewBaseOperate?.registerCommandCallback(command as COMMAND_NAME, args)
|
|
199
|
+
});
|
|
170
200
|
}
|
|
171
201
|
|
|
172
202
|
onLoadingStart() {
|
|
@@ -333,6 +363,7 @@ export struct RNCWebView {
|
|
|
333
363
|
Logger.error(TAG,
|
|
334
364
|
`[RNOH] getBundleInfoForSelf failed ErrorCode: ${error.code}, Message: ${error.message}`);
|
|
335
365
|
} else {
|
|
366
|
+
if (!this.isComponentAlive) return
|
|
336
367
|
this.bundleName = JSON.stringify(data.name)
|
|
337
368
|
}
|
|
338
369
|
});
|
|
@@ -397,7 +428,6 @@ export struct RNCWebView {
|
|
|
397
428
|
Logger.debug('params.lockState res:' + params.lockState + `, wait time is ${Date.now() - startTime}`);
|
|
398
429
|
return params.lockState === ShouldOverrideCallbackState.SHOULD_OVERRIDE;
|
|
399
430
|
}
|
|
400
|
-
|
|
401
431
|
onOverrideUrlLoading(event: WebResourceRequest) {
|
|
402
432
|
this.webViewBaseOperate?.emitShouldStartLoadWithRequestOverrideUrlLoading(event)
|
|
403
433
|
return false
|
|
@@ -480,7 +510,152 @@ onPermissionRequestAlert(event: OnPermissionRequestEvent){
|
|
|
480
510
|
|
|
481
511
|
await atManager.requestPermissionsFromUser(this.ctx.uiAbilityContext, permissionList);
|
|
482
512
|
}
|
|
483
|
-
|
|
513
|
+
|
|
514
|
+
private async getWindow(): Promise<window.Window | null> {
|
|
515
|
+
try {
|
|
516
|
+
const win = await window.getLastWindow(getContext(this));
|
|
517
|
+
if (win) {
|
|
518
|
+
this.cachedWindow = win;
|
|
519
|
+
}
|
|
520
|
+
return win;
|
|
521
|
+
} catch (error) {
|
|
522
|
+
console.error(TAG, `[WebViewFullScreenTest] getWindow Errorcode: ${error.code}`);
|
|
523
|
+
return null;
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
private async saveInitialOrientation() {
|
|
528
|
+
const win = await this.getWindow();
|
|
529
|
+
if (win) {
|
|
530
|
+
try {
|
|
531
|
+
const orientation = win.getPreferredOrientation();
|
|
532
|
+
this.initialOrientation = orientation;
|
|
533
|
+
this.isOrientationSaved = true;
|
|
534
|
+
console.debug(TAG, `[WebViewFullScreenTest] Saved initial orientation: ${orientation}`);
|
|
535
|
+
} catch (error) {
|
|
536
|
+
console.error(TAG, `[WebViewFullScreenTest] saveInitialOrientation Errorcode: ${error.code}`);
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
private async setOrientation(orientation: window.Orientation): Promise<boolean> {
|
|
542
|
+
const win = await this.getWindow();
|
|
543
|
+
if (win) {
|
|
544
|
+
try {
|
|
545
|
+
await win.setPreferredOrientation(orientation);
|
|
546
|
+
console.debug(TAG, `[WebViewFullScreenTest] Set orientation to: ${orientation}`);
|
|
547
|
+
return true;
|
|
548
|
+
} catch (error) {
|
|
549
|
+
console.error(TAG, `[WebViewFullScreenTest] setOrientation Errorcode: ${error.code}`);
|
|
550
|
+
return false;
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
return false;
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
// 处理全屏进入(带状态保护和异步串行)
|
|
557
|
+
private async handleFullScreenEnter() {
|
|
558
|
+
if (!this.isComponentAlive || this.isFullScreen) {
|
|
559
|
+
Logger.debug(TAG, '[WebViewFullScreen] Already in full screen, skipping');
|
|
560
|
+
return;
|
|
561
|
+
}
|
|
562
|
+
if (!this.isOrientationSaved) {
|
|
563
|
+
Logger.warn(TAG, '[WebViewFullScreen] Initial orientation not saved yet, skipping full screen enter');
|
|
564
|
+
return;
|
|
565
|
+
}
|
|
566
|
+
try {
|
|
567
|
+
// 阶段1:设置方向
|
|
568
|
+
const orientationResult = await this.setOrientation(window.Orientation.AUTO_ROTATION);
|
|
569
|
+
if (!orientationResult) {
|
|
570
|
+
Logger.error(TAG, '[WebViewFullScreen] Failed to set orientation, aborting full screen enter');
|
|
571
|
+
return;
|
|
572
|
+
}
|
|
573
|
+
// 阶段2:设置沉浸式模式
|
|
574
|
+
const immersiveResult = await this.enterImmersiveMode();
|
|
575
|
+
if (!immersiveResult) {
|
|
576
|
+
Logger.error(TAG, '[WebViewFullScreen] Failed to enter immersive mode, rolling back');
|
|
577
|
+
// 回滚沉浸式模式(即使部分失败也要尝试恢复)
|
|
578
|
+
await this.exitImmersiveMode();
|
|
579
|
+
// 回滚方向设置
|
|
580
|
+
await this.setOrientation(this.initialOrientation);
|
|
581
|
+
return;
|
|
582
|
+
}
|
|
583
|
+
// 阶段3:所有操作成功,设置状态
|
|
584
|
+
this.isFullScreen = true;
|
|
585
|
+
} catch (error) {
|
|
586
|
+
Logger.error(TAG, `[WebViewFullScreen] Enter full screen failed: ${error}`);
|
|
587
|
+
// 异常时回滚所有操作
|
|
588
|
+
await this.exitImmersiveMode();
|
|
589
|
+
await this.setOrientation(this.initialOrientation);
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
// 处理全屏退出(带状态保护和异步串行)
|
|
594
|
+
private async handleFullScreenExit() {
|
|
595
|
+
if (!this.isComponentAlive ||!this.isFullScreen) {
|
|
596
|
+
Logger.debug(TAG, '[WebViewFullScreen] Not in full screen, skipping');
|
|
597
|
+
return;
|
|
598
|
+
}
|
|
599
|
+
try {
|
|
600
|
+
// 阶段1:恢复方向
|
|
601
|
+
const orientationResult = await this.setOrientation(this.initialOrientation);
|
|
602
|
+
if (!orientationResult) {
|
|
603
|
+
Logger.error(TAG, '[WebViewFullScreen] Failed to restore orientation, keeping full screen state');
|
|
604
|
+
return;
|
|
605
|
+
}
|
|
606
|
+
// 方向已恢复,清除 isFullScreen 让 UI 恢复原始布局
|
|
607
|
+
this.isFullScreen = false;
|
|
608
|
+
// 阶段2:退出沉浸式模式
|
|
609
|
+
const immersiveResult = await this.exitImmersiveMode();
|
|
610
|
+
if (!immersiveResult) {
|
|
611
|
+
Logger.error(TAG, '[WebViewFullScreen] Failed to exit immersive mode after restoring orientation');
|
|
612
|
+
// 沉浸式模式退出失败,但方向已恢复,isFullScreen 已清除,避免重复触发循环
|
|
613
|
+
}
|
|
614
|
+
} catch (error) {
|
|
615
|
+
Logger.error(TAG, `[WebViewFullScreen] Exit full screen failed: ${error}`);
|
|
616
|
+
// 异常时也应清除状态,避免卡死
|
|
617
|
+
this.isFullScreen = false;
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
// 进入沉浸式全屏模式(隐藏系统栏)
|
|
622
|
+
private async enterImmersiveMode(): Promise<boolean> {
|
|
623
|
+
const win = await this.getWindow();
|
|
624
|
+
if (win) {
|
|
625
|
+
try {
|
|
626
|
+
// 设置窗口为全屏布局模式,内容延伸到系统栏下方
|
|
627
|
+
await win.setWindowLayoutFullScreen(true);
|
|
628
|
+
// 隐藏系统导航栏和状态栏
|
|
629
|
+
await win.setWindowSystemBarEnable([]);
|
|
630
|
+
Logger.debug(TAG, '[WebViewFullScreen] Entered immersive mode');
|
|
631
|
+
return true;
|
|
632
|
+
} catch (error) {
|
|
633
|
+
console.error(TAG, `[WebViewFullScreen] enterImmersiveMode Errorcode: ${error.code}`);
|
|
634
|
+
return false;
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
return false;
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
// 退出沉浸式全屏模式(恢复系统栏)
|
|
641
|
+
private async exitImmersiveMode(): Promise<boolean> {
|
|
642
|
+
const win = await this.getWindow();
|
|
643
|
+
if (win) {
|
|
644
|
+
try {
|
|
645
|
+
// 关闭全屏布局模式
|
|
646
|
+
await win.setWindowLayoutFullScreen(false);
|
|
647
|
+
// 恢复显示系统导航栏和状态栏(默认显示所有系统栏)
|
|
648
|
+
await win.setWindowSystemBarEnable(['status', 'navigation']);
|
|
649
|
+
Logger.debug(TAG, '[WebViewFullScreen] Exited immersive mode');
|
|
650
|
+
return true;
|
|
651
|
+
} catch (error) {
|
|
652
|
+
console.error(TAG, `[WebViewFullScreen] exitImmersiveMode Errorcode: ${error.code}`);
|
|
653
|
+
return false;
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
return false;
|
|
657
|
+
}
|
|
658
|
+
|
|
484
659
|
build() {
|
|
485
660
|
Stack() {
|
|
486
661
|
if ( deviceInfo.sdkApiVersion >= 20) {
|
|
@@ -533,8 +708,8 @@ onPermissionRequestAlert(event: OnPermissionRequestEvent){
|
|
|
533
708
|
}
|
|
534
709
|
}
|
|
535
710
|
})
|
|
536
|
-
.width(this.webviewWidth)
|
|
537
|
-
.height(this.webviewHeight)
|
|
711
|
+
.width(this.isFullScreen ? "100%" : this.webviewWidth)
|
|
712
|
+
.height(this.isFullScreen ? "100%" : this.webviewHeight)
|
|
538
713
|
.fileAccess(this.allowFileAccess)
|
|
539
714
|
.constraintSize({ minHeight: MINHEIGHT })
|
|
540
715
|
.overScrollMode(this.overScrollMode)
|
|
@@ -545,9 +720,9 @@ onPermissionRequestAlert(event: OnPermissionRequestEvent){
|
|
|
545
720
|
.overviewModeAccess(this.descriptorWrapper.rawProps.scalesPageToFit)
|
|
546
721
|
.textZoomRatio(this.descriptorWrapper.rawProps.textZoom)
|
|
547
722
|
.backgroundColor(BaseOperate.getColorMode(this.ctx.uiAbilityContext,
|
|
548
|
-
this.descriptorWrapper.rawProps.forceDarkOn) === WebDarkMode.On ? Color.
|
|
723
|
+
this.descriptorWrapper.rawProps.forceDarkOn) === WebDarkMode.On ? Color.Black : Color.Transparent)
|
|
549
724
|
.darkMode(BaseOperate.getColorMode(this.ctx.uiAbilityContext, this.descriptorWrapper.rawProps.forceDarkOn))
|
|
550
|
-
.forceDarkAccess(this.
|
|
725
|
+
.forceDarkAccess(this.descriptorWrapper.rawProps.forceDarkOn)
|
|
551
726
|
.cacheMode(this.cacheMode)
|
|
552
727
|
.minFontSize(this.minFontSize)
|
|
553
728
|
.domStorageAccess(this.descriptorWrapper.rawProps.domStorageEnabled)
|
|
@@ -579,6 +754,18 @@ onPermissionRequestAlert(event: OnPermissionRequestEvent){
|
|
|
579
754
|
.onLoadIntercept((event: OnLoadInterceptEvent) => this.onLoadIntercept(event))
|
|
580
755
|
.onTitleReceive((event: OnTitleReceiveEvent) => this.webViewBaseOperate?.onTitleReceive(event))
|
|
581
756
|
.onSslErrorEvent((event: SslErrorEvent) => this.onSslErrorEventCallback(event))
|
|
757
|
+
.onFullScreenEnter(async () => {
|
|
758
|
+
Logger.debug(TAG, '[WebViewFullScreen] onFullScreenEnter called');
|
|
759
|
+
if (this.allowsFullscreenVideo) {
|
|
760
|
+
await this.handleFullScreenEnter();
|
|
761
|
+
} else {
|
|
762
|
+
Logger.debug(TAG, '[WebViewFullScreen] Fullscreen video disabled by allowsFullscreenVideo');
|
|
763
|
+
}
|
|
764
|
+
})
|
|
765
|
+
.onFullScreenExit(async () => {
|
|
766
|
+
Logger.debug(TAG, '[WebViewFullScreen] onFullScreenExit called');
|
|
767
|
+
await this.handleFullScreenExit();
|
|
768
|
+
})
|
|
582
769
|
.editMenuOptions({
|
|
583
770
|
onCreateMenu: this.onCreateMenu.bind(this),
|
|
584
771
|
onMenuItemClick: this.onMenuItemClick.bind(this),
|
|
@@ -634,8 +821,8 @@ onPermissionRequestAlert(event: OnPermissionRequestEvent){
|
|
|
634
821
|
}
|
|
635
822
|
})
|
|
636
823
|
|
|
637
|
-
.width(this.webviewWidth)
|
|
638
|
-
.height(this.webviewHeight)
|
|
824
|
+
.width(this.isFullScreen ? "100%" : this.webviewWidth)
|
|
825
|
+
.height(this.isFullScreen ? "100%" : this.webviewHeight)
|
|
639
826
|
.fileAccess(this.allowFileAccess)
|
|
640
827
|
.constraintSize({ minHeight: MINHEIGHT })
|
|
641
828
|
.overScrollMode(this.overScrollMode)
|
|
@@ -646,9 +833,9 @@ onPermissionRequestAlert(event: OnPermissionRequestEvent){
|
|
|
646
833
|
.overviewModeAccess(this.descriptorWrapper.rawProps.scalesPageToFit)
|
|
647
834
|
.textZoomRatio(this.descriptorWrapper.rawProps.textZoom)
|
|
648
835
|
.backgroundColor(BaseOperate.getColorMode(this.ctx.uiAbilityContext,
|
|
649
|
-
this.descriptorWrapper.rawProps.forceDarkOn) === WebDarkMode.On ? Color.
|
|
836
|
+
this.descriptorWrapper.rawProps.forceDarkOn) === WebDarkMode.On ? Color.Black : Color.Transparent)
|
|
650
837
|
.darkMode(BaseOperate.getColorMode(this.ctx.uiAbilityContext, this.descriptorWrapper.rawProps.forceDarkOn))
|
|
651
|
-
.forceDarkAccess(this.
|
|
838
|
+
.forceDarkAccess(this.descriptorWrapper.rawProps.forceDarkOn)
|
|
652
839
|
.cacheMode(this.cacheMode)
|
|
653
840
|
.minFontSize(this.minFontSize)
|
|
654
841
|
.domStorageAccess(this.descriptorWrapper.rawProps.domStorageEnabled)
|
|
@@ -679,15 +866,27 @@ onPermissionRequestAlert(event: OnPermissionRequestEvent){
|
|
|
679
866
|
.onLoadIntercept((event: OnLoadInterceptEvent) => this.onLoadIntercept(event))
|
|
680
867
|
.onTitleReceive((event: OnTitleReceiveEvent) => this.webViewBaseOperate?.onTitleReceive(event))
|
|
681
868
|
.onSslErrorEvent((event: SslErrorEvent) => this.onSslErrorEventCallback(event))
|
|
869
|
+
.onFullScreenEnter(async () => {
|
|
870
|
+
Logger.debug(TAG, '[WebViewFullScreen] onFullScreenEnter called');
|
|
871
|
+
if (this.allowsFullscreenVideo) {
|
|
872
|
+
await this.handleFullScreenEnter();
|
|
873
|
+
} else {
|
|
874
|
+
Logger.debug(TAG, '[WebViewFullScreen] Fullscreen video disabled by allowsFullscreenVideo');
|
|
875
|
+
}
|
|
876
|
+
})
|
|
877
|
+
.onFullScreenExit(async () => {
|
|
878
|
+
Logger.debug(TAG, '[WebViewFullScreen] onFullScreenExit called');
|
|
879
|
+
await this.handleFullScreenExit();
|
|
880
|
+
})
|
|
682
881
|
.editMenuOptions({
|
|
683
882
|
onCreateMenu: this.onCreateMenu.bind(this),
|
|
684
883
|
onMenuItemClick: this.onMenuItemClick.bind(this),
|
|
685
884
|
})
|
|
686
885
|
}
|
|
687
886
|
}
|
|
688
|
-
.width(this.webviewWidth)
|
|
689
|
-
.height(this.webviewHeight)
|
|
690
|
-
.position({
|
|
887
|
+
.width(this.isFullScreen ? "100%" : this.webviewWidth)
|
|
888
|
+
.height(this.isFullScreen ? "100%" : this.webviewHeight)
|
|
889
|
+
.position(this.isFullScreen ? undefined : {
|
|
691
890
|
x: this.descriptorWrapper.layoutMetrics.frame.origin.x,
|
|
692
891
|
y: this.descriptorWrapper.layoutMetrics.frame.origin.y
|
|
693
892
|
})
|
|
@@ -778,12 +977,6 @@ onPermissionRequestAlert(event: OnPermissionRequestEvent){
|
|
|
778
977
|
this.source.uri = $rawfile(this.source.uri.toString().replace("asset://", this.ctx.rnInstance.getAssetsDest()));
|
|
779
978
|
}
|
|
780
979
|
|
|
781
|
-
if (this.descriptorWrapper.rawProps.overScrollMode === WebViewOverScrollMode.ALWAYS) {
|
|
782
|
-
this.overScrollMode = OverScrollMode.ALWAYS
|
|
783
|
-
} else if (this.descriptorWrapper.rawProps.overScrollMode === WebViewOverScrollMode.NEVER) {
|
|
784
|
-
this.overScrollMode = OverScrollMode.NEVER
|
|
785
|
-
}
|
|
786
|
-
|
|
787
980
|
this.overScrollMode = this.descriptorWrapper.rawProps.bounces ? OverScrollMode.ALWAYS : OverScrollMode.NEVER;
|
|
788
981
|
|
|
789
982
|
if (this.descriptorWrapper.rawProps.injectedJavaScriptBeforeContentLoaded) {
|
|
@@ -794,7 +987,8 @@ onPermissionRequestAlert(event: OnPermissionRequestEvent){
|
|
|
794
987
|
|
|
795
988
|
const renderModeStr = this.descriptorWrapper.rawProps.renderMode || "SYNC_RENDER"
|
|
796
989
|
this.renderMode = (renderModeStr === "ASYNC_RENDER") ? RenderMode.ASYNC_RENDER : RenderMode.SYNC_RENDER
|
|
797
|
-
|
|
990
|
+
this.allowsFullscreenVideo = this.descriptorWrapper.rawProps.allowsFullscreenVideo ?? false;
|
|
991
|
+
this.allowFileAccess = this.descriptorWrapper.rawProps.allowFileAccess ?? true;
|
|
798
992
|
}
|
|
799
993
|
|
|
800
994
|
private registerPostMessage() {
|
|
@@ -803,15 +997,16 @@ onPermissionRequestAlert(event: OnPermissionRequestEvent){
|
|
|
803
997
|
}
|
|
804
998
|
this.messagingEnabled = this.descriptorWrapper.rawProps.messagingEnabled;
|
|
805
999
|
if (this.messagingEnabled) {
|
|
1000
|
+
const self = this;
|
|
806
1001
|
let bridge: RNCWebViewBridge = {
|
|
807
1002
|
postMessage: (data: string) => {
|
|
808
1003
|
Logger.debug(TAG, `[RNOH] bridge postMessage, ${JSON.stringify(data)}`);
|
|
809
|
-
if (
|
|
810
|
-
let result: WebViewEventParams =
|
|
1004
|
+
if (self.controller != null) {
|
|
1005
|
+
let result: WebViewEventParams = self.createWebViewEvent("onMessage")
|
|
811
1006
|
if (result) {
|
|
812
1007
|
result.data = data.toString()
|
|
813
|
-
result.lockIdentifier =
|
|
814
|
-
|
|
1008
|
+
result.lockIdentifier = self.webViewBaseOperate?.getLockIdentifier()
|
|
1009
|
+
self.eventEmitter!.emit("message", result as ResultType);
|
|
815
1010
|
}
|
|
816
1011
|
}
|
|
817
1012
|
}
|
|
@@ -21,7 +21,7 @@ interface CreateWebViewEventInterface {
|
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
export class BaseOperate {
|
|
24
|
-
private static LOCK_IDENTIFIER = 0
|
|
24
|
+
private static LOCK_IDENTIFIER = new Int32Array([0])
|
|
25
25
|
private eventEmitter: RNC.RNCWebView.EventEmitter
|
|
26
26
|
private controller: webview.WebviewController
|
|
27
27
|
private lockIdentifier: number = 0
|
|
@@ -51,8 +51,8 @@ export class BaseOperate {
|
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
static generateLockIdentifier(): number {
|
|
54
|
-
|
|
55
|
-
return
|
|
54
|
+
const old = Atomics.add(BaseOperate.LOCK_IDENTIFIER, 0, 1);
|
|
55
|
+
return old + 1;
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
getLockIdentifier():number {
|
|
@@ -323,6 +323,9 @@ export class BaseOperate {
|
|
|
323
323
|
}
|
|
324
324
|
|
|
325
325
|
injectJavaScript(args: string[]) {
|
|
326
|
+
if (!args || args.length == 0) {
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
326
329
|
try {
|
|
327
330
|
this.controller.runJavaScript(args[0])
|
|
328
331
|
} catch (error) {
|
|
@@ -331,6 +334,9 @@ export class BaseOperate {
|
|
|
331
334
|
}
|
|
332
335
|
|
|
333
336
|
postMessage(args: string[]) {
|
|
337
|
+
if (!args || args.length == 0) {
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
334
340
|
let data = JSON.stringify({ data: args[0] })
|
|
335
341
|
let result: string = "(function () {" +
|
|
336
342
|
"var event;" +
|
|
@@ -383,6 +389,9 @@ export class BaseOperate {
|
|
|
383
389
|
}
|
|
384
390
|
|
|
385
391
|
clearCache(args: string[]) {
|
|
392
|
+
if (!args || args.length == 0) {
|
|
393
|
+
return;
|
|
394
|
+
}
|
|
386
395
|
try {
|
|
387
396
|
const removeFlag = !!args[0] === true;
|
|
388
397
|
this.controller.removeCache(removeFlag);
|
|
@@ -408,6 +417,9 @@ export class BaseOperate {
|
|
|
408
417
|
}
|
|
409
418
|
|
|
410
419
|
loadUrl(args: string[]) {
|
|
420
|
+
if (!args || args.length == 0) {
|
|
421
|
+
return;
|
|
422
|
+
}
|
|
411
423
|
try {
|
|
412
424
|
this.controller.loadUrl(args[0]);
|
|
413
425
|
} catch (error) {
|
|
@@ -434,8 +446,10 @@ export class BaseOperate {
|
|
|
434
446
|
break
|
|
435
447
|
case COMMAND_NAME.REQUESTFOCUS:
|
|
436
448
|
this.requestFocus()
|
|
449
|
+
break
|
|
437
450
|
case COMMAND_NAME.CLEARCACHE:
|
|
438
451
|
this.clearCache(args)
|
|
452
|
+
break
|
|
439
453
|
case COMMAND_NAME.CLEARHISTORY:
|
|
440
454
|
this.clearHistory()
|
|
441
455
|
break
|
|
@@ -22,8 +22,8 @@ export class WebViewTurboModule extends AnyThreadTurboModule implements TM.RNCWe
|
|
|
22
22
|
if (shouldStartParams) {
|
|
23
23
|
shouldStartParams.shouldStart = shouldStart
|
|
24
24
|
shouldStartParams.lockState = shouldStart ? ShouldOverrideCallbackState.ALLOW_LOADING : ShouldOverrideCallbackState.SHOULD_OVERRIDE;
|
|
25
|
+
this.shouldStartParamsMap.delete(lockIdentifier)
|
|
25
26
|
}
|
|
26
|
-
this.shouldStartParamsMap.set(lockIdentifier,shouldStartParams || new ShouldStartParams())
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
|
|
@@ -31,6 +31,10 @@ export class WebViewTurboModule extends AnyThreadTurboModule implements TM.RNCWe
|
|
|
31
31
|
Logger.debug("setShouldStartParams:" + JSON.stringify(params))
|
|
32
32
|
this.shouldStartParamsMap.set(params.lockIdentifier,params)
|
|
33
33
|
}
|
|
34
|
+
|
|
35
|
+
__onDestroy__(): void {
|
|
36
|
+
this.shouldStartParamsMap.clear()
|
|
37
|
+
}
|
|
34
38
|
}
|
|
35
39
|
|
|
36
40
|
// 锁状态
|
|
@@ -60,4 +64,4 @@ export class ShouldStartParams {
|
|
|
60
64
|
lockIdentifier: number = -1
|
|
61
65
|
// 对应ShouldOverrideCallbackState
|
|
62
66
|
lockState: number = ShouldOverrideCallbackState.DEFAULT
|
|
63
|
-
}
|
|
67
|
+
}
|
package/harmony/rn_webview.har
CHANGED
|
Binary file
|
package/package.json
CHANGED
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
"Thibault Malbranche <malbranche.thibault@gmail.com>"
|
|
10
10
|
],
|
|
11
11
|
"license": "MIT",
|
|
12
|
-
"version": "13.16.2
|
|
13
|
-
"homepage": "https://gitcode.com/openharmony-sig/rntpc_react-native-webview/tree/br_rnoh0.
|
|
12
|
+
"version": "13.16.2",
|
|
13
|
+
"homepage": "https://gitcode.com/openharmony-sig/rntpc_react-native-webview/tree/br_rnoh0.82#readme",
|
|
14
14
|
"scripts": {
|
|
15
15
|
"pack": "tsc --noEmit false --emitDeclarationOnly --declaration --rootDir src --outDir lib && babel --extensions \".ts,.tsx\" --out-dir lib src && npm pack --ignore-scripts",
|
|
16
16
|
"macos": "react-native run-macos --scheme WebviewExample --project-path example/macos",
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
// Copyright (c) 2025 Huawei Device Co., Ltd. All rights reserved
|
|
2
|
-
// Use of this source code is governed by a Apache-2.0 license that can be
|
|
3
|
-
// found in the LICENSE file.
|
|
4
|
-
|
|
5
|
-
export class CustomReference {
|
|
6
|
-
private atomicValue: number;
|
|
7
|
-
private callBack!: Function;
|
|
8
|
-
constructor(init: number) {
|
|
9
|
-
this.atomicValue = init
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
getValue() {
|
|
13
|
-
return this.atomicValue
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
setCallBack(callBack: Function) {
|
|
17
|
-
this.callBack = callBack
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
getCallBack() {
|
|
21
|
-
return this.callBack
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
setValue(newValue: number) {
|
|
25
|
-
this.atomicValue = newValue
|
|
26
|
-
if (this.callBack) {
|
|
27
|
-
this.callBack()
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
}
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
// Copyright (c) 2025 Huawei Device Co., Ltd. All rights reserved
|
|
2
|
-
// Use of this source code is governed by a Apache-2.0 license that can be
|
|
3
|
-
// found in the LICENSE file.
|
|
4
|
-
|
|
5
|
-
import { CustomReference } from './CutomReference';
|
|
6
|
-
import HashMap from '@ohos.util.HashMap';
|
|
7
|
-
|
|
8
|
-
export enum CallbackState {
|
|
9
|
-
UNDECIDED,
|
|
10
|
-
SHOULD_OVERRIDE,
|
|
11
|
-
DO_NOT_OVERRIDE,
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export class ShouldRequestUrl {
|
|
15
|
-
private constructor() {
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
static nextLockIdentifier: number = 1;
|
|
19
|
-
static ShouldRequestUrlLocks: HashMap<string, CustomReference> = new HashMap();
|
|
20
|
-
static callBack: Function;
|
|
21
|
-
|
|
22
|
-
static setCallBack(lockIdentifier: string, callBack: Function): void {
|
|
23
|
-
let data: CustomReference = ShouldRequestUrl.ShouldRequestUrlLocks.get(lockIdentifier);
|
|
24
|
-
data.setCallBack(callBack)
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
public static getNewData(): string {
|
|
28
|
-
let lockIdentifier = ShouldRequestUrl.nextLockIdentifier++ + ''
|
|
29
|
-
let custom = new CustomReference(CallbackState.UNDECIDED)
|
|
30
|
-
ShouldRequestUrl.ShouldRequestUrlLocks.set(lockIdentifier, custom)
|
|
31
|
-
return lockIdentifier
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
public static setValue(lockIdentifier: number, stateParam: CallbackState): void {
|
|
35
|
-
let lock: string = lockIdentifier + '';
|
|
36
|
-
if (ShouldRequestUrl.ShouldRequestUrlLocks.hasKey(lock)) {
|
|
37
|
-
let data: CustomReference = ShouldRequestUrl.ShouldRequestUrlLocks.get(lock)
|
|
38
|
-
data.setValue(stateParam)
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
public static getValue(lockIdentifier: string): CallbackState {
|
|
43
|
-
return ShouldRequestUrl.ShouldRequestUrlLocks.get(lockIdentifier).getValue()
|
|
44
|
-
}
|
|
45
|
-
public static removeData(lockIdentifier: string): void {
|
|
46
|
-
ShouldRequestUrl.ShouldRequestUrlLocks.remove(lockIdentifier)
|
|
47
|
-
}
|
|
48
|
-
}
|