Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: implement onShouldStartLoadWithRequest and webView turboModule #250

Merged
merged 2 commits into from
Nov 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 55 additions & 4 deletions harmony/rn_webview/src/main/ets/RNCWebView.ets
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
import { RNComponentContext } from '@rnoh/react-native-openharmony';
import webview from '@ohos.web.webview';
import { url as OSUrl } from '@kit.ArkTS';
import { RNC } from '@rnoh/react-native-openharmony/generated';
import { RNC, TM } from '@rnoh/react-native-openharmony/generated';
import Logger from './Logger';
import { BaseOperate } from './WebViewBaseOperate';
import {
Expand All @@ -45,6 +45,7 @@ import {
REFRESH_OFFSET,
MINHEIGHT,
} from './Magic';
import { WebViewTurboModule } from './WebViewTurboModule';
import { bundleManager } from '@kit.AbilityKit';

export const TAG = "WebView"
Expand Down Expand Up @@ -73,7 +74,6 @@ export struct RNCWebView {
overScrollMode: OverScrollMode = OverScrollMode.NEVER;
progress: number = ZERO;
cacheMode: number = CacheMode.Default;
lockIdentifier: string = "";
requestUrl: string = "";
bundleName: string = "";
messagingEnabled: boolean = false;
Expand All @@ -97,6 +97,9 @@ export struct RNCWebView {
private cleanUpCallbacks: (() => void)[] = []
private descriptorWrapper: WebViewDescriptor = Object() as WebViewDescriptor
private webViewBaseOperate: BaseOperate | null = null
private shouldInterceptLoad: boolean = true
private callLoadTimer: number = -1
static readonly SHOULD_OVERRIDE_URL_LOADING_TIMEOUT: number = 250

aboutToAppear() {
try {
Expand Down Expand Up @@ -269,6 +272,7 @@ export struct RNCWebView {
let uri = this.source.uri
if (this.source.html != undefined && this.source.html != "") {
try {
this.resetIntercept()
this.controller.loadData(
this.source.html,
"text/html",
Expand All @@ -280,8 +284,10 @@ export struct RNCWebView {
Logger.error(TAG, "error:" + error)
}
} else if (uri != undefined && uri != "") {
this.resetIntercept()
this.controller.loadUrl(uri, this.headers);
} else {
this.resetIntercept()
this.controller.loadUrl(uri, this.headers);
}
if (!this.hasRegisterJavaScriptProxy) {
Expand Down Expand Up @@ -352,15 +358,57 @@ export struct RNCWebView {
}

onLoadIntercept(event: OnLoadInterceptEvent): boolean {
Logger.debug(TAG, `onLoadIntercept request url:${event.data.getRequestUrl()} ,shouldInterceptLoad:${this.shouldInterceptLoad}`)
if (!this.shouldInterceptLoad) {
return false
}

let lockIdentifier = this.webViewBaseOperate?.getLockIdentifier()
let webViewTurboModule = this.ctx.rnInstance.getUITurboModule<WebViewTurboModule>(TM.RNCWebViewModule.NAME)
this.callLoadTimer = setTimeout(()=>{
Logger.debug(TAG, "call setTimeout")
webViewTurboModule.callLoadFunction(lockIdentifier)
}, RNCWebView.SHOULD_OVERRIDE_URL_LOADING_TIMEOUT)

webViewTurboModule.setLoadCallback(lockIdentifier, ()=>{
Logger.debug(TAG, "call setLoadCallback")
clearTimeout(this.callLoadTimer)
this.shouldInterceptLoad = false
if (this.html != "") {
try {
this.controller.loadData(
this.source.html,
"text/html",
"UTF-8",
this.source.baseUrl,
" "
);
} catch (error) {
Logger.error(TAG, "error: " + error)
}
} else if (this.source.uri != "") {
Logger.debug(TAG, `uri: ` + this.source.uri);
this.controller.loadUrl(this.descriptorWrapper.rawProps.newSource.uri, this.headers)
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

都为空的时候是否需要添加判断

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

进入加载拦截的回调中都是有url 或者data的,前面加载前已经做了判断处理

Copy link

@ninjarz ninjarz Nov 27, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this.descriptorWrapper.rawProps.newSource.uri 导致 asset:// 转换失效了
@425765923

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

如果没有onShouldStartLoadWithRequest使用需求,建议0.2.33版本webview。当前版本onShouldStartLoadWithRequest实现的适用场景比较有限,完整实现需要依赖后续rnoh接口。若目前对该接口有简单需求,也可修改arkts实现代码,将rn拦截逻辑放置与原生端做规避。

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👌

})
this.webViewBaseOperate?.emitShouldStartLoadWithRequest(event)
return false
return true
}

onOverrideUrlLoading(event: WebResourceRequest) {
this.webViewBaseOperate?.emitShouldStartLoadWithRequestOverrideUrlLoading(event)
return false
}

resetIntercept() {
Logger.debug(TAG,"resetIntercept")
this.ctx.rnInstance.getUITurboModule<WebViewTurboModule>(TM.RNCWebViewModule.NAME)
.clearLoadFunction(this.webViewBaseOperate?.getLockIdentifier())
clearTimeout(this.callLoadTimer)
this.shouldInterceptLoad = true
this.webViewBaseOperate?.setLockIdentifier(BaseOperate.generateLockIdentifier())
}

build() {
Stack() {
Web({ src: "", controller: this.controller, renderMode: this.renderMode })
Expand Down Expand Up @@ -444,6 +492,7 @@ export struct RNCWebView {
this.html = this.source.html
if (this.controllerAttached) {
try {
this.resetIntercept()
this.controller.loadData(
this.source.html,
"text/html",
Expand All @@ -459,6 +508,7 @@ export struct RNCWebView {
Logger.debug(TAG, `[RNOH] newDescriptor props update uri: ` + this.source.uri);
this.url = this.source.uri as string;
if (this.controllerAttached) {
this.resetIntercept()
this.controller.loadUrl(this.descriptorWrapper.rawProps.newSource.uri, this.headers)
}
}
Expand Down Expand Up @@ -529,13 +579,14 @@ export struct RNCWebView {
let result: WebViewEventParams = this.createWebViewEvent("onMessage")
if (result) {
result.data = data.toString()
result.lockIdentifier = ZERO
result.lockIdentifier = this.webViewBaseOperate?.getLockIdentifier()
this.eventEmitter!.emit("message", result as ResultType);
}
}
}
};
this.controller.registerJavaScriptProxy(bridge, JAVASCRIPT_INTERFACE, ["postMessage"])
this.resetIntercept()
this.source.uri ?
this.controller.loadUrl(this.source.uri, this.headers) : this.controller.refresh()
this.hasRegisterJavaScriptProxy = true
Expand Down
23 changes: 21 additions & 2 deletions harmony/rn_webview/src/main/ets/RNCWebViewPackage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,32 @@ import type {
DescriptorWrapperFactoryByDescriptorType,
DescriptorWrapperFactoryByDescriptorTypeCtx,
} from '@rnoh/react-native-openharmony/ts';
import { RNPackage } from '@rnoh/react-native-openharmony/ts';
import { RNC } from '@rnoh/react-native-openharmony/generated/ts';
import { RNPackage, UITurboModuleFactory, UITurboModule } from '@rnoh/react-native-openharmony/ts';
import { RNC, TM } from '@rnoh/react-native-openharmony/generated/ts';
import { WebViewTurboModule } from './WebViewTurboModule'
import { UITurboModuleContext } from '@rnoh/react-native-openharmony/src/main/ets/RNOH/RNOHContext';

export class RNCWebViewPackage extends RNPackage {
createDescriptorWrapperFactoryByDescriptorType(ctx: DescriptorWrapperFactoryByDescriptorTypeCtx): DescriptorWrapperFactoryByDescriptorType {
return {
[RNC.RNCWebView.NAME]: (ctx) => new RNC.RNCWebView.DescriptorWrapper(ctx.descriptor)
}
}

createUITurboModuleFactory(ctx: UITurboModuleContext): UITurboModuleFactory {
return new WebViewTurboModulesFactory(ctx);
}
}

class WebViewTurboModulesFactory extends UITurboModuleFactory {
createTurboModule(name: string): UITurboModule | null {
if (name === TM.RNCWebViewModule.NAME) {
return new WebViewTurboModule(this.ctx);
}
return null;
}

hasTurboModule(name: string): boolean {
return name === TM.RNCWebViewModule.NAME;
}
}
31 changes: 23 additions & 8 deletions harmony/rn_webview/src/main/ets/WebViewBaseOperate.ets
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,15 @@ interface CreateWebViewEventInterface {
}

export class BaseOperate {
private static LOCK_IDENTIFIER = 0
private eventEmitter: RNC.RNCWebView.EventEmitter
private controller: webview.WebviewController
private title: string = ''
private lockIdentifier: number = 0

constructor(eventEmitter: RNC.RNCWebView.EventEmitter, controller: webview.WebviewController) {
this.eventEmitter = eventEmitter
this.controller = controller
this.lockIdentifier = BaseOperate.generateLockIdentifier()
}

static setThirdPartyCookiesEnabled(status: boolean) {
Expand All @@ -44,6 +46,19 @@ export class BaseOperate {
}
}

static generateLockIdentifier(): number {
BaseOperate.LOCK_IDENTIFIER = BaseOperate.LOCK_IDENTIFIER + 1
return BaseOperate.LOCK_IDENTIFIER
}

getLockIdentifier():number {
return this.lockIdentifier
}

setLockIdentifier(lockIdentifier: number) {
this.lockIdentifier = lockIdentifier
}

emitProgressChange(params: ProgressInterface) {
try {
this.eventEmitter!.emit('loadingProgress', {
Expand All @@ -52,7 +67,7 @@ export class BaseOperate {
title: this.controller.getTitle(),
canGoBack: this.controller.accessBackward(),
canGoForward: this.controller.accessForward(),
lockIdentifier: 0,
lockIdentifier: this.lockIdentifier,
progress: params.progress / ONE_HUNDRED
})
} catch (error) {
Expand All @@ -68,7 +83,7 @@ export class BaseOperate {
title: this.controller.getTitle(),
canGoBack: this.controller.accessBackward(),
canGoForward: this.controller.accessForward(),
lockIdentifier: 0,
lockIdentifier: this.lockIdentifier,
navigationType: "other",
mainDocumentURL: ""
})
Expand All @@ -85,7 +100,7 @@ export class BaseOperate {
title: this.controller.getTitle(),
canGoBack: this.controller.accessBackward(),
canGoForward: this.controller.accessForward(),
lockIdentifier: 0,
lockIdentifier: this.lockIdentifier,
navigationType: "other",
mainDocumentURL: ""
})
Expand All @@ -106,7 +121,7 @@ export class BaseOperate {
title: this.controller.getTitle(),
canGoBack: this.controller.accessBackward(),
canGoForward: this.controller.accessForward(),
lockIdentifier: 0,
lockIdentifier: this.lockIdentifier,
domain: "",
code: event.error.getErrorCode(),
description: event.error.getErrorInfo()
Expand All @@ -124,7 +139,7 @@ export class BaseOperate {
title: this.controller.getTitle(),
canGoBack: this.controller.accessBackward(),
canGoForward: this.controller.accessForward(),
lockIdentifier: 0,
lockIdentifier: this.lockIdentifier,
description: event.response.getResponseData(),
statusCode: event.response.getResponseCode()
})
Expand Down Expand Up @@ -159,7 +174,7 @@ export class BaseOperate {
title: this.controller.getTitle(),
canGoBack: this.controller.accessBackward(),
canGoForward: this.controller.accessForward(),
lockIdentifier: 0,
lockIdentifier: this.lockIdentifier,
navigationType: "other",
mainDocumentURL: "",
isTopFrame: false
Expand All @@ -177,7 +192,7 @@ export class BaseOperate {
title: this.controller.getTitle(),
canGoBack: this.controller.accessBackward(),
canGoForward: this.controller.accessForward(),
lockIdentifier: 0,
lockIdentifier: this.lockIdentifier,
navigationType: "other",
mainDocumentURL: "",
isTopFrame: false
Expand Down
37 changes: 37 additions & 0 deletions harmony/rn_webview/src/main/ets/WebViewTurboModule.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { UITurboModule } from '@rnoh/react-native-openharmony/ts';
import { TM } from '@rnoh/react-native-openharmony/generated/ts';
import Logger from './Logger';

const TAG = "WebViewTurboModule"

export class WebViewTurboModule extends UITurboModule implements TM.RNCWebViewModule.Spec {
private loadCallbackMap : Map<number,()=> void> = new Map();

isFileUploadSupported(): Promise<boolean> {
return Promise.resolve(true)
}

shouldStartLoadWithLockIdentifier(shouldStart: boolean, lockIdentifier: number): void {
Logger.debug(TAG,`shouldStartLoadWithLockIdentifier shouldStart:${shouldStart},lockIdentifier:${lockIdentifier}`)
if (shouldStart) {
this.callLoadFunction(lockIdentifier)
}else {
this.clearLoadFunction(lockIdentifier)
}
}

setLoadCallback(lockIdentifier:number, cb: ()=> void) {
this.loadCallbackMap.set(lockIdentifier,cb)
}

callLoadFunction(lockIdentifier:number){
Logger.debug(TAG,`callLoadFunction function:${JSON.stringify(this.loadCallbackMap.get(lockIdentifier))}`)
this.loadCallbackMap.get(lockIdentifier)?.()
this.clearLoadFunction(lockIdentifier)
}

clearLoadFunction(lockIdentifier:number){
Logger.debug(TAG,`clearLoadFunction lockIdentifier:${lockIdentifier} `)
this.loadCallbackMap.delete(lockIdentifier)
}
}
13 changes: 13 additions & 0 deletions src/NativeRNCWebViewModule.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import type { TurboModule } from 'react-native';
import { TurboModuleRegistry } from 'react-native';
import { Double } from 'react-native/Libraries/Types/CodegenTypes';

export interface Spec extends TurboModule {
isFileUploadSupported(): Promise<boolean>;
shouldStartLoadWithLockIdentifier(
shouldStart: boolean,
lockIdentifier: Double
): void;
}

export default TurboModuleRegistry.getEnforcing<Spec>('RNCWebViewModule');
11 changes: 3 additions & 8 deletions src/WebView.harmony.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ import React, {
useRef
} from 'react';
import { Image, View, ImageSourcePropType, HostComponent } from 'react-native';
import { Double } from 'react-native/Libraries/Types/CodegenTypes';
import invariant from 'invariant';

import RNCWebView, { Commands, NativeProps } from './RNCWebViewNativeComponent';
import RNCWebViewModule from './NativeRNCWebViewModule';

import {
defaultOriginWhitelist,
Expand Down Expand Up @@ -46,11 +46,6 @@ const useWarnIfChanges = <T extends unknown>(value: T, name: string) => {
}
};

const shouldStartLoadWithLockIdentifier: (
shouldStart: boolean,
lockIdentifier: Double
) => void = () => { }

const WebViewComponent = forwardRef<{}, IOSWebViewProps & { scalesPageToFit: boolean, minimumFontSize: number, thirdPartyCookiesEnabled: boolean, geolocationEnabled: boolean }>(
(
{
Expand Down Expand Up @@ -113,7 +108,7 @@ const WebViewComponent = forwardRef<{}, IOSWebViewProps & { scalesPageToFit: boo

const onShouldStartLoadWithRequestCallback = useCallback(
(shouldStart: boolean, _url: string, lockIdentifier = 0) => {
shouldStartLoadWithLockIdentifier(
RNCWebViewModule.shouldStartLoadWithLockIdentifier(
shouldStart,
lockIdentifier
);
Expand Down Expand Up @@ -328,4 +323,4 @@ const isFileUploadSupported: () => Promise<boolean> = async () => true;

const WebView = Object.assign(WebViewComponent, { isFileUploadSupported });

export default WebView;
export default WebView;