@react-native-ohos/react-native-webview 13.15.2-rc.1 → 13.15.3-1
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/README.md +2 -2
- package/harmony/rn_webview/oh-package.json5 +1 -1
- package/harmony/rn_webview/src/main/ets/Magic.ets +15 -1
- package/harmony/rn_webview/src/main/ets/RNCWebView.ets +169 -40
- package/harmony/rn_webview/src/main/ets/WebViewBaseOperate.ets +13 -0
- package/harmony/rn_webview.har +0 -0
- package/package.json +2 -1
- package/src/WebView.harmony.tsx +1 -1
package/README.md
CHANGED
|
@@ -4,9 +4,9 @@ This project is based on [react-native-webview@13.15.0](https://github.com/react
|
|
|
4
4
|
|
|
5
5
|
## Documentation
|
|
6
6
|
|
|
7
|
-
- [中文](https://
|
|
7
|
+
- [中文](https://gitcode.com/OpenHarmony-RN/usage-docs/blob/master/zh-cn/react-native-webview.md)
|
|
8
8
|
|
|
9
|
-
- [English](https://
|
|
9
|
+
- [English](https://gitcode.com/OpenHarmony-RN/usage-docs/blob/master/en/react-native-webview.md)
|
|
10
10
|
|
|
11
11
|
## License
|
|
12
12
|
|
|
@@ -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.15.
|
|
9
|
+
"version": "13.15.3-1",
|
|
10
10
|
"dependencies": {
|
|
11
11
|
"@rnoh/react-native-openharmony": "../react_native_openharmony.har"
|
|
12
12
|
}
|
|
@@ -45,7 +45,7 @@ export interface WebViewProps extends ViewRawProps {
|
|
|
45
45
|
cacheMode: CACHE_MODE
|
|
46
46
|
domStorageEnabled: boolean
|
|
47
47
|
scalesPageToFit: boolean
|
|
48
|
-
|
|
48
|
+
hasOnShouldStartLoadWithRequestEvent?: boolean
|
|
49
49
|
messagingModuleName: string
|
|
50
50
|
webviewDebuggingEnabled: boolean
|
|
51
51
|
scrollEnabled: boolean
|
|
@@ -65,8 +65,22 @@ export interface WebViewProps extends ViewRawProps {
|
|
|
65
65
|
geolocationEnabled: boolean
|
|
66
66
|
applicationNameForUserAgent: string
|
|
67
67
|
pullToRefreshEnabled: boolean
|
|
68
|
+
mediaCapturePermissionGrantType?: 'prompt' | 'grant' | 'deny' | 'grantIfSameHostElsePrompt' | 'grantIfSameHostElseDeny'
|
|
69
|
+
menuItems?: Array<MenuItem> | undefined;
|
|
68
70
|
}
|
|
69
71
|
|
|
72
|
+
export interface MenuItem {
|
|
73
|
+
label: string,
|
|
74
|
+
key: string
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export enum WebMediaCapturePermissionGrantType {
|
|
78
|
+
GRANT_IF_SAME_HOST_ELSE_PROMPT = "grantIfSameHostElsePrompt",
|
|
79
|
+
GRANT_IF_SAME_HOST_ELSE_DENY = "grantIfSameHostElseDeny",
|
|
80
|
+
DENY = "deny",
|
|
81
|
+
GRANT = "grant",
|
|
82
|
+
PROMPT = "prompt",
|
|
83
|
+
}
|
|
70
84
|
|
|
71
85
|
export class RNCWebViewBridge {
|
|
72
86
|
postMessage!: (data: string) => void;
|
|
@@ -25,9 +25,11 @@ import {
|
|
|
25
25
|
WebViewDescriptor,
|
|
26
26
|
REFRESH_OFFSET,
|
|
27
27
|
MINHEIGHT,
|
|
28
|
+
WebMediaCapturePermissionGrantType,
|
|
29
|
+
MenuItem
|
|
28
30
|
} from './Magic';
|
|
29
31
|
|
|
30
|
-
import { abilityAccessCtrl, bundleManager } from '@kit.AbilityKit';
|
|
32
|
+
import { abilityAccessCtrl, bundleManager, Permissions } from '@kit.AbilityKit';
|
|
31
33
|
import { WebViewTurboModule, ShouldStartParams, ShouldOverrideCallbackState } from './WebViewTurboModule';
|
|
32
34
|
import { AnyThreadRNInstance, WorkerTaskRunnable } from '@rnoh/react-native-openharmony/src/main/ets/RNOH';
|
|
33
35
|
import buffer from '@ohos.buffer';
|
|
@@ -425,33 +427,130 @@ export struct RNCWebView {
|
|
|
425
427
|
return false
|
|
426
428
|
}
|
|
427
429
|
|
|
430
|
+
onCreateMenu = (menuItems: Array<TextMenuItem>) => {
|
|
431
|
+
let customMenuItems = this.descriptorWrapper.rawProps.menuItems
|
|
432
|
+
if (customMenuItems == undefined) {
|
|
433
|
+
return menuItems;
|
|
434
|
+
} else if (customMenuItems.length == 0) {
|
|
435
|
+
return [];
|
|
436
|
+
} else {
|
|
437
|
+
let menuItemsArray: Array<TextMenuItem> = [];
|
|
438
|
+
for (let index = 0; index < customMenuItems.length; index++) {
|
|
439
|
+
let element: MenuItem = customMenuItems[index];
|
|
440
|
+
let customItem: TextMenuItem = {
|
|
441
|
+
content: element.label,
|
|
442
|
+
id: TextMenuItemId.of(element.key)
|
|
443
|
+
};
|
|
444
|
+
menuItemsArray.push(customItem)
|
|
445
|
+
}
|
|
446
|
+
return menuItemsArray;
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
onMenuItemClick(menuItem: TextMenuItem): boolean {
|
|
451
|
+
if (this.descriptorWrapper.rawProps.menuItems != undefined) {
|
|
452
|
+
this.controller.runJavaScript("(function(){return {selection: window.getSelection().toString()} })()")
|
|
453
|
+
.then((result: string) => {
|
|
454
|
+
this.webViewBaseOperate?.customMenuSelection(menuItem, result)
|
|
455
|
+
})
|
|
456
|
+
.catch((error: string | Error) => {
|
|
457
|
+
Logger.info('[RNOH] function onMenuItemClick error: ' + error);
|
|
458
|
+
})
|
|
459
|
+
// 禁用系统默认行为
|
|
460
|
+
return true;
|
|
461
|
+
}
|
|
462
|
+
return false;
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
onPermissionRequestAlert(event: OnPermissionRequestEvent){
|
|
466
|
+
AlertDialog.show({
|
|
467
|
+
title: this.resourceToString($r('app.string.on_confirm')) + event.request.getOrigin(),
|
|
468
|
+
message: this.getPermissionDialogMessage(event),
|
|
469
|
+
alignment: DialogAlignment.Center,
|
|
470
|
+
primaryButton: {
|
|
471
|
+
value: $r('app.string.deny'),
|
|
472
|
+
action: () => {
|
|
473
|
+
event.request.deny();
|
|
474
|
+
}
|
|
475
|
+
},
|
|
476
|
+
secondaryButton: {
|
|
477
|
+
value: $r('app.string.on_confirm'),
|
|
478
|
+
action: () => {
|
|
479
|
+
event.request.grant(event.request.getAccessibleResource());
|
|
480
|
+
}
|
|
481
|
+
},
|
|
482
|
+
cancel: () => {
|
|
483
|
+
event.request.deny();
|
|
484
|
+
}
|
|
485
|
+
})
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
async handleMediaCapturePermissionGrantType(resources: string[], domain: string) {
|
|
489
|
+
let permissionList: Array<Permissions> = [];
|
|
490
|
+
resources.forEach(resource => {
|
|
491
|
+
switch (resource.toString()) {
|
|
492
|
+
case 'TYPE_VIDEO_CAPTURE':
|
|
493
|
+
permissionList.push('ohos.permission.CAMERA');
|
|
494
|
+
break;
|
|
495
|
+
case 'TYPE_AUDIO_CAPTURE':
|
|
496
|
+
permissionList.push('ohos.permission.MICROPHONE');
|
|
497
|
+
break;
|
|
498
|
+
}
|
|
499
|
+
});
|
|
500
|
+
|
|
501
|
+
await atManager.requestPermissionsFromUser(this.ctx.uiAbilityContext, permissionList);
|
|
502
|
+
}
|
|
503
|
+
|
|
428
504
|
build() {
|
|
429
505
|
Stack() {
|
|
430
506
|
if ( deviceInfo.sdkApiVersion >= 20) {
|
|
431
507
|
Web({ src: "", controller: this.controller, renderMode: this.renderMode })
|
|
432
508
|
.mixedMode(this.mode)
|
|
433
|
-
.onPermissionRequest((event: OnPermissionRequestEvent) => {
|
|
509
|
+
.onPermissionRequest(async (event: OnPermissionRequestEvent) => {
|
|
434
510
|
if (event && (this.getPermissionDialogMessage(event) != "TYPE_SENSOR")) {
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
511
|
+
const resources: string[] = event.request.getAccessibleResource();
|
|
512
|
+
if (resources.indexOf('TYPE_AUDIO_CAPTURE') >= 0 || resources.indexOf('TYPE_VIDEO_CAPTURE') >= 0 ) {
|
|
513
|
+
const originUrl = this.webViewBaseOperate?.verifyURLFormat(event.request.getOrigin(), this.source.html,
|
|
514
|
+
this.source.baseUrl);
|
|
515
|
+
const currentUrl = this.webViewBaseOperate?.verifyURLFormat(this.controller.getUrl(), this.source.html,
|
|
516
|
+
this.source.baseUrl);
|
|
517
|
+
const originDomain: string = OSUrl.URL.parseURL(originUrl).hostname;
|
|
518
|
+
const currentDomain: string = OSUrl.URL.parseURL(currentUrl).hostname;
|
|
519
|
+
let mediaCapturePermissionGrantType: string = WebMediaCapturePermissionGrantType.PROMPT
|
|
520
|
+
if (this.descriptorWrapper.rawProps.mediaCapturePermissionGrantType != undefined) {
|
|
521
|
+
mediaCapturePermissionGrantType = this.descriptorWrapper.rawProps.mediaCapturePermissionGrantType;
|
|
522
|
+
}
|
|
523
|
+
if (mediaCapturePermissionGrantType != WebMediaCapturePermissionGrantType.DENY) {
|
|
524
|
+
await this.handleMediaCapturePermissionGrantType(resources, originDomain)
|
|
525
|
+
}
|
|
526
|
+
switch (mediaCapturePermissionGrantType) {
|
|
527
|
+
case WebMediaCapturePermissionGrantType.GRANT_IF_SAME_HOST_ELSE_PROMPT:
|
|
528
|
+
if (originDomain != currentDomain) {
|
|
529
|
+
this.onPermissionRequestAlert(event)
|
|
530
|
+
} else {
|
|
531
|
+
event.request.grant(resources);
|
|
532
|
+
}
|
|
533
|
+
break;
|
|
534
|
+
case WebMediaCapturePermissionGrantType.GRANT_IF_SAME_HOST_ELSE_DENY:
|
|
535
|
+
if (originDomain != currentDomain) {
|
|
536
|
+
event.request.deny();
|
|
537
|
+
} else {
|
|
538
|
+
event.request.grant(resources);
|
|
539
|
+
}
|
|
540
|
+
break;
|
|
541
|
+
case WebMediaCapturePermissionGrantType.DENY:
|
|
442
542
|
event.request.deny();
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
},
|
|
451
|
-
cancel: () => {
|
|
452
|
-
event.request.deny();
|
|
543
|
+
break;
|
|
544
|
+
case WebMediaCapturePermissionGrantType.GRANT:
|
|
545
|
+
event.request.grant(resources);
|
|
546
|
+
break;
|
|
547
|
+
case WebMediaCapturePermissionGrantType.PROMPT:
|
|
548
|
+
this.onPermissionRequestAlert(event)
|
|
549
|
+
break;
|
|
453
550
|
}
|
|
454
|
-
}
|
|
551
|
+
} else {
|
|
552
|
+
this.onPermissionRequestAlert(event)
|
|
553
|
+
}
|
|
455
554
|
}
|
|
456
555
|
})
|
|
457
556
|
.width(this.webviewWidth)
|
|
@@ -499,31 +598,58 @@ export struct RNCWebView {
|
|
|
499
598
|
.onRenderExited((event: OnRenderExitedEvent) => this.webViewBaseOperate?.onRenderExited(event))
|
|
500
599
|
.onLoadIntercept((event: OnLoadInterceptEvent) => this.onLoadIntercept(event))
|
|
501
600
|
.onTitleReceive((event: OnTitleReceiveEvent) => this.webViewBaseOperate?.onTitleReceive(event))
|
|
601
|
+
.editMenuOptions({
|
|
602
|
+
onCreateMenu: this.onCreateMenu.bind(this),
|
|
603
|
+
onMenuItemClick: this.onMenuItemClick.bind(this),
|
|
604
|
+
})
|
|
502
605
|
} else {
|
|
503
606
|
Web({ src: "", controller: this.controller, renderMode: this.renderMode })
|
|
504
607
|
.mixedMode(this.mode)
|
|
505
|
-
.onPermissionRequest((event: OnPermissionRequestEvent) => {
|
|
608
|
+
.onPermissionRequest(async (event: OnPermissionRequestEvent) => {
|
|
506
609
|
if (event && (this.getPermissionDialogMessage(event) != "TYPE_SENSOR")) {
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
610
|
+
const resources: string[] = event.request.getAccessibleResource();
|
|
611
|
+
if (resources.indexOf('TYPE_AUDIO_CAPTURE') >= 0 || resources.indexOf('TYPE_VIDEO_CAPTURE') >= 0 ) {
|
|
612
|
+
const originUrl = this.webViewBaseOperate?.verifyURLFormat(event.request.getOrigin(), this.source.html,
|
|
613
|
+
this.source.baseUrl);
|
|
614
|
+
const currentUrl = this.webViewBaseOperate?.verifyURLFormat(this.controller.getUrl(), this.source.html,
|
|
615
|
+
this.source.baseUrl);
|
|
616
|
+
const originDomain: string = OSUrl.URL.parseURL(originUrl).hostname;
|
|
617
|
+
const currentDomain: string = OSUrl.URL.parseURL(currentUrl).hostname;
|
|
618
|
+
let mediaCapturePermissionGrantType: string = WebMediaCapturePermissionGrantType.PROMPT
|
|
619
|
+
if (this.descriptorWrapper.rawProps.mediaCapturePermissionGrantType != undefined) {
|
|
620
|
+
mediaCapturePermissionGrantType = this.descriptorWrapper.rawProps.mediaCapturePermissionGrantType;
|
|
621
|
+
}
|
|
622
|
+
if (mediaCapturePermissionGrantType != WebMediaCapturePermissionGrantType.DENY) {
|
|
623
|
+
await this.handleMediaCapturePermissionGrantType(resources, originDomain)
|
|
624
|
+
}
|
|
625
|
+
switch (mediaCapturePermissionGrantType) {
|
|
626
|
+
case WebMediaCapturePermissionGrantType.GRANT_IF_SAME_HOST_ELSE_PROMPT:
|
|
627
|
+
if (originDomain != currentDomain) {
|
|
628
|
+
this.onPermissionRequestAlert(event)
|
|
629
|
+
} else {
|
|
630
|
+
event.request.grant(resources);
|
|
631
|
+
}
|
|
632
|
+
break;
|
|
633
|
+
case WebMediaCapturePermissionGrantType.GRANT_IF_SAME_HOST_ELSE_DENY:
|
|
634
|
+
if (originDomain != currentDomain) {
|
|
635
|
+
event.request.deny();
|
|
636
|
+
} else {
|
|
637
|
+
event.request.grant(resources);
|
|
638
|
+
}
|
|
639
|
+
break;
|
|
640
|
+
case WebMediaCapturePermissionGrantType.DENY:
|
|
514
641
|
event.request.deny();
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
},
|
|
523
|
-
cancel: () => {
|
|
524
|
-
event.request.deny();
|
|
642
|
+
break;
|
|
643
|
+
case WebMediaCapturePermissionGrantType.GRANT:
|
|
644
|
+
event.request.grant(resources);
|
|
645
|
+
break;
|
|
646
|
+
case WebMediaCapturePermissionGrantType.PROMPT:
|
|
647
|
+
this.onPermissionRequestAlert(event)
|
|
648
|
+
break;
|
|
525
649
|
}
|
|
526
|
-
}
|
|
650
|
+
} else {
|
|
651
|
+
this.onPermissionRequestAlert(event)
|
|
652
|
+
}
|
|
527
653
|
}
|
|
528
654
|
})
|
|
529
655
|
|
|
@@ -571,7 +697,10 @@ export struct RNCWebView {
|
|
|
571
697
|
.onRenderExited((event: OnRenderExitedEvent) => this.webViewBaseOperate?.onRenderExited(event))
|
|
572
698
|
.onLoadIntercept((event: OnLoadInterceptEvent) => this.onLoadIntercept(event))
|
|
573
699
|
.onTitleReceive((event: OnTitleReceiveEvent) => this.webViewBaseOperate?.onTitleReceive(event))
|
|
574
|
-
|
|
700
|
+
.editMenuOptions({
|
|
701
|
+
onCreateMenu: this.onCreateMenu.bind(this),
|
|
702
|
+
onMenuItemClick: this.onMenuItemClick.bind(this),
|
|
703
|
+
})
|
|
575
704
|
}
|
|
576
705
|
}
|
|
577
706
|
.width(this.webviewWidth)
|
|
@@ -454,4 +454,17 @@ export class BaseOperate {
|
|
|
454
454
|
Logger.error(TAG, `[RNOH] onTitleReceive Errorcode: ${error.code}`);
|
|
455
455
|
}
|
|
456
456
|
}
|
|
457
|
+
|
|
458
|
+
customMenuSelection(menuItem: TextMenuItem, selectionText: string) {
|
|
459
|
+
try {
|
|
460
|
+
selectionText = JSON.parse(selectionText).selection;
|
|
461
|
+
this.eventEmitter!.emit('customMenuSelection', {
|
|
462
|
+
label: menuItem.content.toString(),
|
|
463
|
+
key: JSON.parse(JSON.stringify(menuItem.id)).id_,
|
|
464
|
+
selectedText: selectionText
|
|
465
|
+
})
|
|
466
|
+
} catch (error) {
|
|
467
|
+
Logger.error(TAG, `[RNOH] customMenuSelection Errorcode: ${error.code}`);
|
|
468
|
+
}
|
|
469
|
+
}
|
|
457
470
|
}
|
package/harmony/rn_webview.har
CHANGED
|
Binary file
|
package/package.json
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"Thibault Malbranche <malbranche.thibault@gmail.com>"
|
|
10
10
|
],
|
|
11
11
|
"license": "MIT",
|
|
12
|
-
"version": "13.15.
|
|
12
|
+
"version": "13.15.3-1",
|
|
13
13
|
"homepage": "https://gitcode.com/openharmony-sig/rntpc_react-native-webview/tree/br_rnoh0.77#readme",
|
|
14
14
|
"scripts": {
|
|
15
15
|
"macos": "react-native run-macos --scheme WebviewExample --project-path example/macos",
|
|
@@ -48,6 +48,7 @@
|
|
|
48
48
|
"@react-native/eslint-config": "0.73.2",
|
|
49
49
|
"@react-native/metro-config": "0.73.5",
|
|
50
50
|
"@react-native/typescript-config": "0.73.1",
|
|
51
|
+
"@react-native-oh/react-native-harmony-cli": "npm:@react-native-oh/react-native-harmony-cli@0.77.18-1",
|
|
51
52
|
"@rnx-kit/metro-config": "1.3.15",
|
|
52
53
|
"@semantic-release/git": "7.0.16",
|
|
53
54
|
"@types/invariant": "^2.2.30",
|
package/src/WebView.harmony.tsx
CHANGED
|
@@ -67,7 +67,7 @@ const WebViewComponent = forwardRef<{}, IOSWebViewProps & { scalesPageToFit: boo
|
|
|
67
67
|
injectedJavaScript,
|
|
68
68
|
injectedJavaScriptBeforeContentLoaded,
|
|
69
69
|
injectedJavaScriptObject,
|
|
70
|
-
menuItems
|
|
70
|
+
menuItems,
|
|
71
71
|
injectedJavaScriptForMainFrameOnly = true,
|
|
72
72
|
injectedJavaScriptBeforeContentLoadedForMainFrameOnly = true,
|
|
73
73
|
thirdPartyCookiesEnabled = false,
|