diff --git a/flutter_inappwebview_ohos/ohos/src/main/ets/components/plugin/types/SafeBrowsingResponse.ets b/flutter_inappwebview_ohos/ohos/src/main/ets/components/plugin/types/SafeBrowsingResponse.ets new file mode 100644 index 0000000000000000000000000000000000000000..2ce576831a57c8144fbf3791a95dbf3887b5559a --- /dev/null +++ b/flutter_inappwebview_ohos/ohos/src/main/ets/components/plugin/types/SafeBrowsingResponse.ets @@ -0,0 +1,44 @@ +/* +* Copyright (c) 2024 Hunan OpenValley Digital Industry Development Co., Ltd. +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + + +import { Any } from '@ohos/flutter_ohos' + +export default class SafeBrowsingResponse { + private action: number; + private report: boolean; + + constructor(report: boolean, action: number) { + this.action = action + this.report = report; + } + + getAction(): number { + return this.action; + } + + isReport(): boolean { + return this.report; + } + + public static fromMap(map: Map): SafeBrowsingResponse | null { + if (map == null) { + return null; + } + let action: number = map.get("action") as number; + let report: boolean = map.get("report") as boolean; + return new SafeBrowsingResponse(report, action); + } +} \ No newline at end of file diff --git a/flutter_inappwebview_ohos/ohos/src/main/ets/components/plugin/webview/WebViewChannelDelegate.ets b/flutter_inappwebview_ohos/ohos/src/main/ets/components/plugin/webview/WebViewChannelDelegate.ets index 87967a1591e8f5e2ae52be2b39115e7bc7fe56b7..41d0c710b5d285f8c1d6886adf0ffa05f9df11b8 100644 --- a/flutter_inappwebview_ohos/ohos/src/main/ets/components/plugin/webview/WebViewChannelDelegate.ets +++ b/flutter_inappwebview_ohos/ohos/src/main/ets/components/plugin/webview/WebViewChannelDelegate.ets @@ -54,6 +54,7 @@ import ServerTrustAuthResponse from '../types/ServerTrustAuthResponse'; import ServerTrustChallenge from '../types/ServerTrustChallenge'; import ClientCertResponse from '../types/ClientCertResponse'; import ClientCertChallenge from '../types/ClientCertChallenge'; +import SafeBrowsingResponse from '../types/SafeBrowsingResponse'; const LOG_TAG = "WebViewChannelDelegate"; @@ -998,15 +999,13 @@ export default class WebViewChannelDelegate extends ChannelDelegateImpl { return callback.result; } - async shouldOverrideUrlLoading(navigationAction: NavigationAction) { + shouldOverrideUrlLoading(navigationAction: NavigationAction, callback: ShouldOverrideUrlLoadingCallback) { let channel = this.getChannel(); if (channel == null) { - return NavigationActionPolicy.ALLOW; + callback.defaultBehaviour(null); + return; } - let callback = new SyncShouldOverrideUrlLoadingCallback(); channel.invokeMethod("shouldOverrideUrlLoading", navigationAction.toMap(), callback); - await callback.waitResponse() - return callback.result; } onCallJsHandler(handlerName: string, args: string, callback: CallJsHandlerCallback) { @@ -1066,6 +1065,18 @@ export default class WebViewChannelDelegate extends ChannelDelegateImpl { obj.set("url", url); channel.invokeMethod("onFormResubmission", obj, callback); } + + onSafeBrowsingHit(url: string, threatType: ThreatType, callback: SafeBrowsingHitCallback) { + let channel = this.getChannel(); + if (channel == null) { + callback.defaultBehaviour(null); + return; + } + let obj: Map = new Map(); + obj.set("url", url); + obj.set("threatType", threatType); + channel.invokeMethod("onSafeBrowsingHit", obj, callback); + } } export class JsAlertCallback extends BaseCallbackResultImpl { @@ -1140,7 +1151,7 @@ class SyncLoadResourceWithCustomSchemeCallback extends SyncBaseCallbackResultImp } } -export class SyncShouldOverrideUrlLoadingCallback extends SyncBaseCallbackResultImpl { +export class ShouldOverrideUrlLoadingCallback extends BaseCallbackResultImpl { public decodeResult(obj: Any): NavigationActionPolicy { if (!(typeof obj == 'number')) { return NavigationActionPolicy.CANCEL; @@ -1177,4 +1188,10 @@ export class FormResubmissionCallback extends BaseCallbackResultImpl { decodeResult(obj: Any): number | null { return typeof obj == 'number' ? obj as number : null; } +} + +export class SafeBrowsingHitCallback extends BaseCallbackResultImpl { + public decodeResult(obj: Any): SafeBrowsingResponse | null { + return SafeBrowsingResponse.fromMap(obj); + } } \ No newline at end of file diff --git a/flutter_inappwebview_ohos/ohos/src/main/ets/components/plugin/webview/in_app_webview/InAppWebViewChromeClient.ets b/flutter_inappwebview_ohos/ohos/src/main/ets/components/plugin/webview/in_app_webview/InAppWebViewChromeClient.ets index 907faaf17b50833bfd59eedc0c5babd381380044..bf8d04b2163d171e4729b263f1d93c805d460a59 100644 --- a/flutter_inappwebview_ohos/ohos/src/main/ets/components/plugin/webview/in_app_webview/InAppWebViewChromeClient.ets +++ b/flutter_inappwebview_ohos/ohos/src/main/ets/components/plugin/webview/in_app_webview/InAppWebViewChromeClient.ets @@ -45,7 +45,9 @@ import { ReceivedServerTrustAuthRequestCallback, ReceivedClientCertRequestCallback, CreateWindowCallback, - FormResubmissionCallback + FormResubmissionCallback, + ShouldOverrideUrlLoadingCallback, + SafeBrowsingHitCallback } from '../WebViewChannelDelegate'; import JsAlertResponse from '../../types/JsAlertResponse'; import JsConfirmResponse from '../../types/JsConfirmResponse'; @@ -67,6 +69,7 @@ import ServerTrustChallenge from '../../types/ServerTrustChallenge'; import ClientCertChallenge from '../../types/ClientCertChallenge'; import ClientCertResponse from '../../types/ClientCertResponse'; import CreateWindowAction from '../../types/CreateWindowAction'; +import SafeBrowsingResponse from '../../types/SafeBrowsingResponse'; import { cert } from '@kit.DeviceCertificateKit' import { List } from '@kit.ArkTS'; import { common } from '@kit.AbilityKit'; @@ -619,21 +622,38 @@ export default class InAppWebViewChromeClient { Log.d(TAG, "onFirstContentfulPaint=" + JSON.stringify(event)) // TODO } - onLoadIntercept = (event: Any) => { //对应安卓 shouldOverrideUrlLoading OHOS不知道异步 不知道如何适配了 - // TODO + onLoadIntercept = (event: Any) : boolean => { Log.d(TAG, "onLoadIntercept=" + event.data.getRequestUrl()) - // if (this.inAppWebView.customSettings.useShouldOverrideUrlLoading) { - // let request = WebResourceRequestExt.fromWebResourceRequest(event.data); - // return await this.onShouldOverrideUrlLoading( - // this.inAppWebView, - // request.getUrl(), - // request.getMethod(), - // request.getHeaders(), - // request.getForMainFrame(), - // request.isHasGesture(), - // request.getRedirect()); - // } - Log.d(TAG, "onLoadInterceptEnd=" + event.data.getRequestUrl()) + // TODO + return false; + } + onOverrideUrlLoading = (request: WebResourceRequest) : boolean => { + Log.d(TAG, "onOverrideUrlLoading=" + request.getRequestUrl()) + if (this.inAppWebView.customSettings.useShouldOverrideUrlLoading) { + let headers = new Map() + request.getRequestHeader().forEach(header => headers.set(header.headerKey, header.headerValue)); + + this.onShouldOverrideUrlLoading( + this.inAppWebView, + request.getRequestUrl(), + request.getRequestMethod(), + headers, + request.isMainFrame(), + request.isRequestGesture(), + request.isRedirect()); + + if (this.inAppWebView.regexToCancelSubFramesLoadingCompiled != null) { + if (request.isMainFrame()) + return true + else { + return this.inAppWebView.regexToCancelSubFramesLoadingCompiled!.test(request.getRequestUrl()); + } + } else { + // There isn't any way to load an URL for a frame that is not the main frame, + // so if the request is not for the main frame, the navigation is allowed. + return request.isMainFrame(); + } + } return false; } onRequestSelected = () => { @@ -663,9 +683,15 @@ export default class InAppWebViewChromeClient { Log.d(TAG, "onNavigationEntryCommitted=") // TODO } - onSafeBrowsingCheckResult = () => { + onSafeBrowsingCheckResult = (threatType: ThreatType) => { Log.d(TAG, "onSafeBrowsingCheckResult=") - // TODO + let resultCallback = new InnerSafeBrowsingHitCallback(); + if (this.inAppWebView.channelDelegate != null) { + let url = this.inAppWebView!.controller!.getUrl(); + this.inAppWebView.channelDelegate.onSafeBrowsingHit(url, threatType, resultCallback); + } else { + resultCallback.defaultBehaviour(null); + } } onNativeEmbedLifecycleChange = (callback: NativeEmbedDataInfo) => { Log.d(TAG, "onNativeEmbedLifecycleChange=") @@ -676,20 +702,18 @@ export default class InAppWebViewChromeClient { // TODO } - private async onShouldOverrideUrlLoading(webView: InAppWebView, url: string, method: string, + private onShouldOverrideUrlLoading(webView: InAppWebView, url: string, method: string, headers: Map, isForMainFrame: boolean, hasGesture: boolean, isRedirect: boolean) { let request = new URLRequest(url, method, null, headers); let navigationAction = new NavigationAction(request, isForMainFrame, hasGesture, isRedirect); - let result: NavigationActionPolicy | null = NavigationActionPolicy.ALLOW - if (webView.channelDelegate != null) { - result = await webView.channelDelegate.shouldOverrideUrlLoading(navigationAction); + let callback = new InnerShouldOverrideUrlLoadingCallback(this.inAppWebView, url, headers, isForMainFrame) + if (this.inAppWebView.channelDelegate != null) { + this.inAppWebView.channelDelegate.shouldOverrideUrlLoading(navigationAction, callback); } else { - result = NavigationActionPolicy.ALLOW + callback.defaultBehaviour(null); } - Log.d(TAG, "onLoadInterceptEnd=" + url) - return result == NavigationActionPolicy.CANCEL } private async onReceivedHttpAuthRequest(handler: HttpAuthHandler, host: string, realm: string) { @@ -1431,4 +1455,81 @@ class InnerFormResubmissionCallback extends FormResubmissionCallback { Log.e(TAG, errorCode + ", " + ((errorMessage != null) ? errorMessage : "")); this.defaultBehaviour(null); } -}; \ No newline at end of file +}; + +class InnerShouldOverrideUrlLoadingCallback extends ShouldOverrideUrlLoadingCallback { + + private inAppWebView: InAppWebView; + private url: string; + private headers: Map; + private isForMainFrame: boolean; + + constructor(inAppWebView: InAppWebView, url: string, headers: Map, isForMainFrame: boolean) { + super(); + this.inAppWebView = inAppWebView; + this.url = url; + this.headers = headers; + this.isForMainFrame = isForMainFrame; + } + + nonNullSuccess(result: NavigationActionPolicy) : boolean { + switch (result) { + case NavigationActionPolicy.ALLOW: + this.allowShouldOverrideUrlLoading(this.inAppWebView, this.url, this.headers, this.isForMainFrame); + break; + case NavigationActionPolicy.CANCEL: + default: + break; + } + return false; + } + + defaultBehaviour(result: NavigationActionPolicy | null) { + this.allowShouldOverrideUrlLoading(this.inAppWebView, this.url, this.headers, this.isForMainFrame); + } + + error(errorCode: string, errorMessage: string, errorDetails: Any): void { + Log.e(TAG, errorCode + ", " + ((errorMessage != null) ? errorMessage : "")); + this.defaultBehaviour(null); + } + + allowShouldOverrideUrlLoading(inAppWebView: InAppWebView, url: string, headers: Map, + isForMainFrame: boolean) { + if (isForMainFrame) { + this.inAppWebView.controller.loadUrl(url, this.inAppWebView.toWebHeaders(headers)); + } + } +}; + +class InnerSafeBrowsingHitCallback extends SafeBrowsingHitCallback { + public nonNullSuccess(response: SafeBrowsingResponse): boolean { + let action = response.getAction(); + if (action != null) { + let report = response.isReport(); + switch (action) { + case 0: // TODO android backToSafety + return true; + break; + case 1: // TODO android proceed + return true; + break; + case 2: + default: //TODO android showInterstitial + return true; + } + return false; + } + return true; + } + + defaultBehaviour(result: SafeBrowsingResponse | null) { + if (result != null) { + this.nonNullSuccess(result) + } + } + + error(errorCode: string, errorMessage: string, errorDetails: Any): void { + Log.e(TAG, errorCode + ", " + ((errorMessage != null) ? errorMessage : "")); + this.defaultBehaviour(null); + } +} \ No newline at end of file diff --git a/flutter_inappwebview_ohos/ohos/src/main/ets/components/plugin/webview/in_app_webview/OhosWebView.ets b/flutter_inappwebview_ohos/ohos/src/main/ets/components/plugin/webview/in_app_webview/OhosWebView.ets index 32639a5f954004fb33ca9b52cec325a5ac726b59..89e1ee55c88862db0fd9f7af884644d631a1a6ef 100644 --- a/flutter_inappwebview_ohos/ohos/src/main/ets/components/plugin/webview/in_app_webview/OhosWebView.ets +++ b/flutter_inappwebview_ohos/ohos/src/main/ets/components/plugin/webview/in_app_webview/OhosWebView.ets @@ -119,9 +119,8 @@ export struct OhosWebView { .onFaviconReceived(this.inAppWebView!.inAppWebViewChromeClient?.onFaviconReceived) .onAudioStateChanged(this.inAppWebView!.inAppWebViewChromeClient?.onAudioStateChanged) .onFirstContentfulPaint(this.inAppWebView!.inAppWebViewChromeClient?.onFirstContentfulPaint) - .onLoadIntercept((event) => { - return this.inAppWebView!.inAppWebViewChromeClient?.onLoadIntercept(event) - }) + .onLoadIntercept(this.inAppWebView!.inAppWebViewChromeClient?.onLoadIntercept) + .onOverrideUrlLoading(this.inAppWebView!.inAppWebViewChromeClient?.onOverrideUrlLoading) .onRequestSelected(this.inAppWebView!.inAppWebViewChromeClient?.onRequestSelected) .onScreenCaptureRequest(this.inAppWebView!.inAppWebViewChromeClient?.onScreenCaptureRequest) .onOverScroll(this.inAppWebView!.inAppWebViewChromeClient?.onOverScroll)