@react-native-ohos/react-native-webview 13.16.1-rc.1 → 13.16.2-beta.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/README.md +2 -2
- package/harmony/rn_webview/oh-package.json5 +1 -1
- package/harmony/rn_webview/src/main/ets/Magic.ets +14 -0
- package/harmony/rn_webview/src/main/ets/RNCWebView.ets +169 -39
- package/harmony/rn_webview/src/main/ets/WebViewBaseOperate.ets +13 -0
- package/harmony/rn_webview.har +0 -0
- package/package.json +4 -2
- 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/CPF-RN/usage-docs/blob/master/zh-cn/react-native-webview.md)
|
|
8
8
|
|
|
9
|
-
- [English](https://
|
|
9
|
+
- [English](https://gitcode.com/CPF-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.16.
|
|
9
|
+
"version": "13.16.2-beta.2",
|
|
10
10
|
"dependencies": {
|
|
11
11
|
"@rnoh/react-native-openharmony": "../react_native_openharmony.har"
|
|
12
12
|
}
|
|
@@ -64,8 +64,22 @@ export interface WebViewProps extends ViewRawProps {
|
|
|
64
64
|
geolocationEnabled: boolean
|
|
65
65
|
applicationNameForUserAgent: string
|
|
66
66
|
pullToRefreshEnabled: boolean
|
|
67
|
+
mediaCapturePermissionGrantType?: 'prompt' | 'grant' | 'deny' | 'grantIfSameHostElsePrompt' | 'grantIfSameHostElseDeny'
|
|
68
|
+
menuItems?: Array<MenuItem> | undefined;
|
|
67
69
|
}
|
|
68
70
|
|
|
71
|
+
export interface MenuItem {
|
|
72
|
+
label: string,
|
|
73
|
+
key: string
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export enum WebMediaCapturePermissionGrantType {
|
|
77
|
+
GRANT_IF_SAME_HOST_ELSE_PROMPT = "grantIfSameHostElsePrompt",
|
|
78
|
+
GRANT_IF_SAME_HOST_ELSE_DENY = "grantIfSameHostElseDeny",
|
|
79
|
+
DENY = "deny",
|
|
80
|
+
GRANT = "grant",
|
|
81
|
+
PROMPT = "prompt",
|
|
82
|
+
}
|
|
69
83
|
|
|
70
84
|
export class RNCWebViewBridge {
|
|
71
85
|
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';
|
|
@@ -404,34 +406,131 @@ export struct RNCWebView {
|
|
|
404
406
|
onSslErrorEventCallback(event: SslErrorEvent){
|
|
405
407
|
this.webViewBaseOperate?.emitOnSslErrorEventCallback(event);
|
|
406
408
|
}
|
|
409
|
+
|
|
410
|
+
onCreateMenu = (menuItems: Array<TextMenuItem>) => {
|
|
411
|
+
let customMenuItems = this.descriptorWrapper.rawProps.menuItems
|
|
412
|
+
if (customMenuItems == undefined) {
|
|
413
|
+
return menuItems;
|
|
414
|
+
} else if (customMenuItems.length == 0) {
|
|
415
|
+
return [];
|
|
416
|
+
} else {
|
|
417
|
+
let menuItemsArray: Array<TextMenuItem> = [];
|
|
418
|
+
for (let index = 0; index < customMenuItems.length; index++) {
|
|
419
|
+
let element: MenuItem = customMenuItems[index];
|
|
420
|
+
let customItem: TextMenuItem = {
|
|
421
|
+
content: element.label,
|
|
422
|
+
id: TextMenuItemId.of(element.key)
|
|
423
|
+
};
|
|
424
|
+
menuItemsArray.push(customItem)
|
|
425
|
+
}
|
|
426
|
+
return menuItemsArray;
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
onMenuItemClick(menuItem: TextMenuItem): boolean {
|
|
431
|
+
if (this.descriptorWrapper.rawProps.menuItems != undefined) {
|
|
432
|
+
this.controller.runJavaScript("(function(){return {selection: window.getSelection().toString()} })()")
|
|
433
|
+
.then((result: string) => {
|
|
434
|
+
this.webViewBaseOperate?.customMenuSelection(menuItem, result)
|
|
435
|
+
})
|
|
436
|
+
.catch((error: string | Error) => {
|
|
437
|
+
Logger.info('[RNOH] function onMenuItemClick error: ' + error);
|
|
438
|
+
})
|
|
439
|
+
// 禁用系统默认行为
|
|
440
|
+
return true;
|
|
441
|
+
}
|
|
442
|
+
return false;
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
onPermissionRequestAlert(event: OnPermissionRequestEvent){
|
|
446
|
+
AlertDialog.show({
|
|
447
|
+
title: this.resourceToString($r('app.string.on_confirm')) + event.request.getOrigin(),
|
|
448
|
+
message: this.getPermissionDialogMessage(event),
|
|
449
|
+
alignment: DialogAlignment.Center,
|
|
450
|
+
primaryButton: {
|
|
451
|
+
value: $r('app.string.deny'),
|
|
452
|
+
action: () => {
|
|
453
|
+
event.request.deny();
|
|
454
|
+
}
|
|
455
|
+
},
|
|
456
|
+
secondaryButton: {
|
|
457
|
+
value: $r('app.string.on_confirm'),
|
|
458
|
+
action: () => {
|
|
459
|
+
event.request.grant(event.request.getAccessibleResource());
|
|
460
|
+
}
|
|
461
|
+
},
|
|
462
|
+
cancel: () => {
|
|
463
|
+
event.request.deny();
|
|
464
|
+
}
|
|
465
|
+
})
|
|
466
|
+
}
|
|
407
467
|
|
|
468
|
+
async handleMediaCapturePermissionGrantType(resources: string[], domain: string) {
|
|
469
|
+
let permissionList: Array<Permissions> = [];
|
|
470
|
+
resources.forEach(resource => {
|
|
471
|
+
switch (resource.toString()) {
|
|
472
|
+
case 'TYPE_VIDEO_CAPTURE':
|
|
473
|
+
permissionList.push('ohos.permission.CAMERA');
|
|
474
|
+
break;
|
|
475
|
+
case 'TYPE_AUDIO_CAPTURE':
|
|
476
|
+
permissionList.push('ohos.permission.MICROPHONE');
|
|
477
|
+
break;
|
|
478
|
+
}
|
|
479
|
+
});
|
|
480
|
+
|
|
481
|
+
await atManager.requestPermissionsFromUser(this.ctx.uiAbilityContext, permissionList);
|
|
482
|
+
}
|
|
483
|
+
|
|
408
484
|
build() {
|
|
409
485
|
Stack() {
|
|
410
486
|
if ( deviceInfo.sdkApiVersion >= 20) {
|
|
411
487
|
Web({ src: "", controller: this.controller, renderMode: this.renderMode })
|
|
412
488
|
.mixedMode(this.mode)
|
|
413
|
-
.onPermissionRequest((event: OnPermissionRequestEvent) => {
|
|
489
|
+
.onPermissionRequest(async (event: OnPermissionRequestEvent) => {
|
|
414
490
|
if (event && (this.getPermissionDialogMessage(event) != "TYPE_SENSOR")) {
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
491
|
+
const resources: string[] = event.request.getAccessibleResource();
|
|
492
|
+
if (resources.indexOf('TYPE_AUDIO_CAPTURE') >= 0 || resources.indexOf('TYPE_VIDEO_CAPTURE') >= 0 ) {
|
|
493
|
+
const originUrl = this.webViewBaseOperate?.verifyURLFormat(event.request.getOrigin(), this.source.html,
|
|
494
|
+
this.source.baseUrl);
|
|
495
|
+
const currentUrl = this.webViewBaseOperate?.verifyURLFormat(this.controller.getUrl(), this.source.html,
|
|
496
|
+
this.source.baseUrl);
|
|
497
|
+
const originDomain: string = OSUrl.URL.parseURL(originUrl).hostname;
|
|
498
|
+
const currentDomain: string = OSUrl.URL.parseURL(currentUrl).hostname;
|
|
499
|
+
let mediaCapturePermissionGrantType: string = WebMediaCapturePermissionGrantType.PROMPT
|
|
500
|
+
if (this.descriptorWrapper.rawProps.mediaCapturePermissionGrantType != undefined) {
|
|
501
|
+
mediaCapturePermissionGrantType = this.descriptorWrapper.rawProps.mediaCapturePermissionGrantType;
|
|
502
|
+
}
|
|
503
|
+
if (mediaCapturePermissionGrantType != WebMediaCapturePermissionGrantType.DENY) {
|
|
504
|
+
await this.handleMediaCapturePermissionGrantType(resources, originDomain)
|
|
505
|
+
}
|
|
506
|
+
switch (mediaCapturePermissionGrantType) {
|
|
507
|
+
case WebMediaCapturePermissionGrantType.GRANT_IF_SAME_HOST_ELSE_PROMPT:
|
|
508
|
+
if (originDomain != currentDomain) {
|
|
509
|
+
this.onPermissionRequestAlert(event)
|
|
510
|
+
} else {
|
|
511
|
+
event.request.grant(resources);
|
|
512
|
+
}
|
|
513
|
+
break;
|
|
514
|
+
case WebMediaCapturePermissionGrantType.GRANT_IF_SAME_HOST_ELSE_DENY:
|
|
515
|
+
if (originDomain != currentDomain) {
|
|
516
|
+
event.request.deny();
|
|
517
|
+
} else {
|
|
518
|
+
event.request.grant(resources);
|
|
519
|
+
}
|
|
520
|
+
break;
|
|
521
|
+
case WebMediaCapturePermissionGrantType.DENY:
|
|
422
522
|
event.request.deny();
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
},
|
|
431
|
-
cancel: () => {
|
|
432
|
-
event.request.deny();
|
|
523
|
+
break;
|
|
524
|
+
case WebMediaCapturePermissionGrantType.GRANT:
|
|
525
|
+
event.request.grant(resources);
|
|
526
|
+
break;
|
|
527
|
+
case WebMediaCapturePermissionGrantType.PROMPT:
|
|
528
|
+
this.onPermissionRequestAlert(event)
|
|
529
|
+
break;
|
|
433
530
|
}
|
|
434
|
-
}
|
|
531
|
+
} else {
|
|
532
|
+
this.onPermissionRequestAlert(event)
|
|
533
|
+
}
|
|
435
534
|
}
|
|
436
535
|
})
|
|
437
536
|
.width(this.webviewWidth)
|
|
@@ -480,31 +579,58 @@ export struct RNCWebView {
|
|
|
480
579
|
.onLoadIntercept((event: OnLoadInterceptEvent) => this.onLoadIntercept(event))
|
|
481
580
|
.onTitleReceive((event: OnTitleReceiveEvent) => this.webViewBaseOperate?.onTitleReceive(event))
|
|
482
581
|
.onSslErrorEvent((event: SslErrorEvent) => this.onSslErrorEventCallback(event))
|
|
582
|
+
.editMenuOptions({
|
|
583
|
+
onCreateMenu: this.onCreateMenu.bind(this),
|
|
584
|
+
onMenuItemClick: this.onMenuItemClick.bind(this),
|
|
585
|
+
})
|
|
483
586
|
} else {
|
|
484
587
|
Web({ src: "", controller: this.controller, renderMode: this.renderMode })
|
|
485
588
|
.mixedMode(this.mode)
|
|
486
|
-
.onPermissionRequest((event: OnPermissionRequestEvent) => {
|
|
589
|
+
.onPermissionRequest(async (event: OnPermissionRequestEvent) => {
|
|
487
590
|
if (event && (this.getPermissionDialogMessage(event) != "TYPE_SENSOR")) {
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
591
|
+
const resources: string[] = event.request.getAccessibleResource();
|
|
592
|
+
if (resources.indexOf('TYPE_AUDIO_CAPTURE') >= 0 || resources.indexOf('TYPE_VIDEO_CAPTURE') >= 0 ) {
|
|
593
|
+
const originUrl = this.webViewBaseOperate?.verifyURLFormat(event.request.getOrigin(), this.source.html,
|
|
594
|
+
this.source.baseUrl);
|
|
595
|
+
const currentUrl = this.webViewBaseOperate?.verifyURLFormat(this.controller.getUrl(), this.source.html,
|
|
596
|
+
this.source.baseUrl);
|
|
597
|
+
const originDomain: string = OSUrl.URL.parseURL(originUrl).hostname;
|
|
598
|
+
const currentDomain: string = OSUrl.URL.parseURL(currentUrl).hostname;
|
|
599
|
+
let mediaCapturePermissionGrantType: string = WebMediaCapturePermissionGrantType.PROMPT
|
|
600
|
+
if (this.descriptorWrapper.rawProps.mediaCapturePermissionGrantType != undefined) {
|
|
601
|
+
mediaCapturePermissionGrantType = this.descriptorWrapper.rawProps.mediaCapturePermissionGrantType;
|
|
602
|
+
}
|
|
603
|
+
if (mediaCapturePermissionGrantType != WebMediaCapturePermissionGrantType.DENY) {
|
|
604
|
+
await this.handleMediaCapturePermissionGrantType(resources, originDomain)
|
|
605
|
+
}
|
|
606
|
+
switch (mediaCapturePermissionGrantType) {
|
|
607
|
+
case WebMediaCapturePermissionGrantType.GRANT_IF_SAME_HOST_ELSE_PROMPT:
|
|
608
|
+
if (originDomain != currentDomain) {
|
|
609
|
+
this.onPermissionRequestAlert(event)
|
|
610
|
+
} else {
|
|
611
|
+
event.request.grant(resources);
|
|
612
|
+
}
|
|
613
|
+
break;
|
|
614
|
+
case WebMediaCapturePermissionGrantType.GRANT_IF_SAME_HOST_ELSE_DENY:
|
|
615
|
+
if (originDomain != currentDomain) {
|
|
616
|
+
event.request.deny();
|
|
617
|
+
} else {
|
|
618
|
+
event.request.grant(resources);
|
|
619
|
+
}
|
|
620
|
+
break;
|
|
621
|
+
case WebMediaCapturePermissionGrantType.DENY:
|
|
495
622
|
event.request.deny();
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
},
|
|
504
|
-
cancel: () => {
|
|
505
|
-
event.request.deny();
|
|
623
|
+
break;
|
|
624
|
+
case WebMediaCapturePermissionGrantType.GRANT:
|
|
625
|
+
event.request.grant(resources);
|
|
626
|
+
break;
|
|
627
|
+
case WebMediaCapturePermissionGrantType.PROMPT:
|
|
628
|
+
this.onPermissionRequestAlert(event)
|
|
629
|
+
break;
|
|
506
630
|
}
|
|
507
|
-
}
|
|
631
|
+
} else {
|
|
632
|
+
this.onPermissionRequestAlert(event)
|
|
633
|
+
}
|
|
508
634
|
}
|
|
509
635
|
})
|
|
510
636
|
|
|
@@ -553,6 +679,10 @@ export struct RNCWebView {
|
|
|
553
679
|
.onLoadIntercept((event: OnLoadInterceptEvent) => this.onLoadIntercept(event))
|
|
554
680
|
.onTitleReceive((event: OnTitleReceiveEvent) => this.webViewBaseOperate?.onTitleReceive(event))
|
|
555
681
|
.onSslErrorEvent((event: SslErrorEvent) => this.onSslErrorEventCallback(event))
|
|
682
|
+
.editMenuOptions({
|
|
683
|
+
onCreateMenu: this.onCreateMenu.bind(this),
|
|
684
|
+
onMenuItemClick: this.onMenuItemClick.bind(this),
|
|
685
|
+
})
|
|
556
686
|
}
|
|
557
687
|
}
|
|
558
688
|
.width(this.webviewWidth)
|
|
@@ -498,4 +498,17 @@ export class BaseOperate {
|
|
|
498
498
|
Logger.error(TAG, `[RNOH] onTitleReceive Errorcode: ${error.code}`);
|
|
499
499
|
}
|
|
500
500
|
}
|
|
501
|
+
|
|
502
|
+
customMenuSelection(menuItem: TextMenuItem, selectionText: string) {
|
|
503
|
+
try {
|
|
504
|
+
selectionText = JSON.parse(selectionText).selection;
|
|
505
|
+
this.eventEmitter!.emit('customMenuSelection', {
|
|
506
|
+
label: menuItem.content.toString(),
|
|
507
|
+
key: JSON.parse(JSON.stringify(menuItem.id)).id_,
|
|
508
|
+
selectedText: selectionText
|
|
509
|
+
})
|
|
510
|
+
} catch (error) {
|
|
511
|
+
Logger.error(TAG, `[RNOH] customMenuSelection Errorcode: ${error.code}`);
|
|
512
|
+
}
|
|
513
|
+
}
|
|
501
514
|
}
|
package/harmony/rn_webview.har
CHANGED
|
Binary file
|
package/package.json
CHANGED
|
@@ -9,9 +9,10 @@
|
|
|
9
9
|
"Thibault Malbranche <malbranche.thibault@gmail.com>"
|
|
10
10
|
],
|
|
11
11
|
"license": "MIT",
|
|
12
|
-
"version": "13.16.
|
|
12
|
+
"version": "13.16.2-beta.2",
|
|
13
13
|
"homepage": "https://gitcode.com/openharmony-sig/rntpc_react-native-webview/tree/br_rnoh0.77#readme",
|
|
14
14
|
"scripts": {
|
|
15
|
+
"pack": "tsc --noEmit false --emitDeclarationOnly --declaration --rootDir src --outDir lib && babel --extensions \".ts,.tsx\" --out-dir lib src && npm pack --ignore-scripts",
|
|
15
16
|
"macos": "react-native run-macos --scheme WebviewExample --project-path example/macos",
|
|
16
17
|
"start": "react-native start",
|
|
17
18
|
"windows": "install-windows-test-app --project-directory example/windows && react-native run-windows --root example --arch x64",
|
|
@@ -48,7 +49,7 @@
|
|
|
48
49
|
"@react-native/eslint-config": "0.73.2",
|
|
49
50
|
"@react-native/metro-config": "0.73.5",
|
|
50
51
|
"@react-native/typescript-config": "0.73.1",
|
|
51
|
-
"@react-native-oh/react-native-harmony-cli": "
|
|
52
|
+
"@react-native-oh/react-native-harmony-cli": "npm:@react-native-oh/react-native-harmony-cli@0.82.30",
|
|
52
53
|
"@rnx-kit/metro-config": "1.3.15",
|
|
53
54
|
"@semantic-release/git": "7.0.16",
|
|
54
55
|
"@types/invariant": "^2.2.30",
|
|
@@ -78,6 +79,7 @@
|
|
|
78
79
|
},
|
|
79
80
|
"files": [
|
|
80
81
|
"src",
|
|
82
|
+
"lib",
|
|
81
83
|
"harmony",
|
|
82
84
|
"react-native-webview.podspec",
|
|
83
85
|
"!**/__tests__",
|
package/src/WebView.harmony.tsx
CHANGED
|
@@ -67,7 +67,7 @@ const WebViewComponent = forwardRef<{}, IOSWebViewProps & {onLoadSubResourceErro
|
|
|
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,
|