• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Web开发常见问题
2
3
4## H5页面如何与ArkTS交互(API 10)
5
6**问题现象**
7
8目前javaScriptProxy仅支持同步调用,异步调用无法获取执行结果。
9
10**解决措施**
11
12对javaScriptProxy和runJavaScript封装,实现JSBridge通信方案。适用于H5调用原生侧函数。使用Web组件javaScriptProxy将原生侧接口注入到H5的window对象上,通过runJavaScript接口执行JS脚本到H5中,并在回调中获取脚本执行结果。具体调用流程如下图所示:
13
14![image5](figures/image5.png)
15
16- 首先通过Web组件的javaScriptProxy属性,将JSBridgeHandle对象注册到H5的window上,作为H5调用原生的通道。当H5开始加载时,在onPageBegin生命周期中调用initJSBridge()方法初始化JSBridge。
17  ```
18  // javaScriptProxy对象
19  public get javaScriptProxy() {
20      return {
21          object: {
22              call: this.call
23          },
24          name: "JSBridgeHandle",
25          methodList: ['call'],
26          controller: this.controller,
27      }
28  }
29  ```
30
31  ```
32  // 使用Web组件加载H5页面
33  @Component
34  struct JsProxy {
35    private controller: WebviewController = new WebView.WebviewController()
36    private jsBridge: JSBridge = new JSBridge(this.controller)
37    build() {
38      Column(){
39        Web({ src: $rawfile('index.html'), controller: this.controller })
40          .javaScriptProxy(this.jsBridge.javaScriptProxy)
41          .onPageBegin(() => {
42            this.jsBridge.initJSBridge()
43          })
44      }
45    }
46  }
47  ```
48
49- 在initJSBridge方法中,通过webviewControll.runJavaScript()将JSBridge初始化脚本注入H5执行。当H5调用时,生成window.callID标识回调函数,将callID与调用参数使用JSBridgeHandle.call传到原生侧。通过JSBridgeCallback接收原生侧执行的结果,根据callID找到对应callback执行并且释放内存。
50  ```
51  // bridgeKey与bridgeMethod动态生成H5侧调用的入口
52  bridgeKey: string = 'JSBridge'
53  bridgeMethod: string = 'call'
54  // 初始化脚本注入H5侧
55  public initJSBridge() {
56      try {
57          this.controller.runJavaScript(`
58              // 接收原生侧结果,执行callback
59              function JSBridgeCallback(id, params){
60                  window.JSBridgeMap[id](params)
61              };
62              // 声明调用入口
63              window.${this.bridgeKey} = {
64                  ${this.bridgeMethod}(method, params, callback){
65                      window.JSBridgeMap[id] = callback || (() => {});
66                      JSBridgeHandle.call(method, JSON.stringify(paramsObj));
67                  },
68              }`)
69      }
70  }
71  ```
72
73- JSBridgeHandle.call()是H5调用原生接口的统一入口,在该方法中根据H5调用的方法名,匹配到对应接口去调用。调用结束后通过this.callback()方法将调用结果返回H5。callback方法中使用webviewControll.runJavaScript()调用H5的JSBridgeCallback回传callID和调用结果。
74  ```
75  // call方法调用原生侧方法,接收结果
76  private call = (fun, params) => {
77      try {
78          const paramsObj = JSON.parse(params)
79          const events = this.exposeManage.methodMap.get(fun)
80          const results = []
81          events.forEach(callFun => {
82              results.push(callFun(paramsObj.data))
83          })
84          Promise.all(results.filter(i => !!i)).then(res => {
85              // 依赖于results中包含非undefined或null的元素。
86              this.callback(paramsObj.callID, res.length > 1 ? res : res[0])
87          })
88      }
89  }
90
91  // 通过runJavaScript调用JSBridgeCallback执行回调
92  private callback(id, data) {
93      this.controller.runJavaScript(`__JSBridgeCallback__("${id}", ${JSON.stringify(data)})`);
94  }
95  ```
96
97
98## Web组件的onUrlLoadIntercept返回结果是否影响onInterceptRequest(API 9)
99
100**解决措施**
101
102Web组件的onUrlLoadIntercept的不同返回结果对应不同的操作:
103
104- onUrlLoadIntercept返回true则直接拦截URL请求。
105
106- onUrlLoadIntercept返回false走onInterceptRequest回调。
107
108**参考链接**
109
110[onUrlloadIntercept](../reference/apis-arkweb/arkts-basic-components-web-events.md#onurlloadinterceptdeprecated)
111
112
113## 为什么Web组件的onKeyEvent键盘事件不生效(API 9)
114
115**问题现象**
116
117Web组件设置onKeyEvent监听键盘事件,键盘按下或抬起该事件不触发。
118
119**解决措施**
120
121onKeyEvent为通用事件,当前Web组件不支持通用事件。Web组件监听键盘事件可以使用onInterceptKeyEvent回调函数。
122
123**参考链接**
124
125[onInterceptKeyEvent](../reference/apis-arkweb/arkts-basic-components-web-events.md#oninterceptkeyevent9)
126
127
128## onInterceptRequest拦截URL并自定义HTML文件,页面加载失败(API 9)
129
130**问题现象**
131
132onInterceptRequest拦截页面Web的src的链接后返回自定义HTML,但是自定义HTML文件里面的script标签里的内容没有加载。
133
134**解决措施**
135
136设置拦截器时,如果只设置setResponseData,内核将无法识别到这是个HTML文件,需要同时设置setResponseEncoding、setResponseMimeType、setResponseHeader等参数。
137
138**代码示例**
139
140```
141Web({ src: 'www.example.com', controller: this.controller })
142  .onInterceptRequest((event) => {
143    console.log('url:' + event.request.getRequestUrl())
144    this.responseweb = new WebResourceResponse();
145    var head1:Header = {
146      headerKey:"Connection",
147      headerValue:"keep-alive"
148    }
149    var length = this.heads.push(head1)
150    this.responseweb.setResponseHeader(this.heads)
151    this.responseweb.setResponseData(this.webdata)
152    this.responseweb.setResponseEncoding('utf-8')
153    this.responseweb.setResponseMimeType('text/html')
154    this.responseweb.setResponseCode(200)
155    this.responseweb.setReasonMessage('OK')
156    return this.responseweb
157})
158```
159
160**参考链接**
161
162[WebResourceResponse](../reference/apis-arkweb/arkts-basic-components-web-WebResourceResponse.md)
163
164
165## 如何在ArkTS代码中执行HTML内的JS函数(API 9)
166
167**解决措施**
168
169通过WebviewController中runJavaScript方法异步执行JavaScript脚本,并通过回调方式获取执行结果。
170
171> **说明:**
172> runJavaScript需要在loadUrl完成后,比如onPageEnd中调用。
173
174**参考链接**
175
176[runJavaScript](../reference/apis-arkweb/arkts-apis-webview-WebviewController.md#runjavascript)
177
178
179## 使用Web组件加载本地网页时,如何在本地网页中调用ArkTS中的函数(API 9)
180
181**解决措施**
182
1831. 准备一个html文件,例如:
184
185   ```
186   <!DOCTYPE html>
187   <html lang="en">
188   <head>
189       <meta charset="UTF-8">
190       <meta http-equiv="X-UA-Compatible" content="IE=edge">
191       <meta name="viewport" content="width=device-width, initial-scale=1.0">
192       <title>Document</title>
193   </head>
194   <body>
195       <h1>标题</h1>
196       <h5 id="h5"></h5>
197       <h5 id="h6"></h5>
198       <button onclick="handleFromH5">调用Arkts的方法</button>
199       <script type="text/javascript">
200           function handleFromH5(){
201               let result = window.objName.test();
202               document.getElementById('h6').innerHTML = result;
203           }
204       </script>
205   </body>
206   </html>
207   ```
208
2092. 在ArkTs中使用JavaScriptProxy方法将ArkTs里的对象注册到H5的window对象中,然后在h5中使用window对象调用该方法。比如下面例子,在ArkTs中将testObj这个对象以别名objName注册到h5的window对象上,在上面的h5中就可以使用window.objName去访问这个对象。
210
211   ```
212   // xxx.ets
213   import web_webview from '@ohos.web.webview'
214   @Entry
215   @Component
216   struct Index {
217     @State message: string = 'Hello World'
218     controller: web_webview.WebviewController = new web_webview.WebviewController()
219     testObj = {
220       test: (data1, data2, data3) => {
221         console.log("data1:" + data1);
222         console.log("data2:" + data2);
223         console.log("data3:" + data3);
224         return "AceString";
225       },
226       toString: () => {
227         console.log('toString' + "interface instead.");
228       }
229     }
230     build() {
231       Row() {
232         Column() {
233           Web({ src:$rawfile('index.html'), controller:this.controller })
234             .javaScriptAccess(true)
235             .javaScriptProxy({
236               object: this.testObj,
237               name: "objName",
238               methodList: ["test", "toString"],
239               controller: this.controller,
240            })
241         }
242         .width('100%')
243       }
244       .height('100%')
245     }
246   }
247   ```
248
249**参考链接**
250
251[javaScriptProxy](../reference/apis-arkweb/arkts-basic-components-web-i.md#javascriptproxy12)
252
253
254## Web组件domStorageAccess属性设置(API 9)
255
256**解决措施**
257
258设置是否开启文档对象模型存储接口(DOM Storage API)权限,默认未开启,控制web网页中localStorage的使用,对sessionStorage未做控制
259
260**参考链接**
261
262[domStorageAccess](../reference/apis-arkweb/arkts-basic-components-web-attributes.md#domstorageaccess)
263
264
265## 如何解决Web组件加载的HTML页面内检测网络状态失败(API 9)
266
267**问题现象**
268
269在HTML页面内通过window.navigator.onLine获取网络状态,联网和断网情况下均为false。
270
271**解决措施**
272
273配置应用获取网络信息权限: ohos.permission.GET_NETWORK_INFO
274
275**参考链接**
276
277[GET\_NETWORK\_INFO](../security/AccessToken/permissions-for-all.md#ohospermissionget_network_info)
278
279
280## 如何自定义拼接设置User-Agent参数(API 9)
281
282**解决措施**
283
284默认User-Agent需要通过WebviewController获取。WebviewController对象必须在Web组件绑定后,才能调用WebviewController上的方法getUserAgent获取默认User-Agent。因此在页面加载前通过自定义字符串拼接修改User-Agent,可采用此方式:
285
2861. 使用\@State定义初始User-Agent,绑定到Web组件;
287
2882. 在Web组件的onUrlLoadIntercept回调中,通过WebviewController.getUserAgent()获取默认User-Agent,并修改Web组件绑定的User-Agent
289
290**代码示例**
291
292```
293import web_webview from '@ohos.web.webview'
294@Entry
295@Component
296struct Index {
297  private controller: web_webview.WebviewController = new web_webview.WebviewController()
298  @State userAgentPa: string = ''
299  build() {
300    Row() {
301      Column() {
302        Web({ src: 'http://www.example.com', controller: this.controller }) //需要手动替换为真实网站
303          .width('100%')
304          .userAgent(this.userAgentPa)
305          .onUrlLoadIntercept((event) => {
306            let userAgent = this.controller.getUserAgent();
307            this.userAgentPa = userAgent + ' 111111111'
308            return false;
309          })
310      }
311      .width('100%')
312    }
313    .height('100%')
314  }
315}
316```
317
318**参考链接**
319
320[userAgent](../reference/apis-arkweb/arkts-basic-components-web-attributes.md#useragentdeprecated)、[getUserAgent](../reference/apis-arkweb/arkts-apis-webview-WebviewController.md#getuseragent)
321## WebView支持同层渲染吗(API 10)
322
323**解决措施**
324
3251. 支持Video、Map、Camera、Canvas、WebGL、WebView组件同层渲染。
3262. 支持将Web embed标签的id、type、src、width、height、url属性传递给原生组件。
327
328
329## WebView有哪些调试工具,调试工具的用法是什么(API 10)
330
331**解决措施**
332
333setWebDebuggingAccess()接口开启Web组件前端页面调试能力,利用DevTools工具可以在2in1上调试移动设备上的前端网页,设备需为4.1.0及以上版本。
334
335**参考链接**
336
337[使用Devtools工具调试前端页面(开发指南)](../web/web-debugging-with-devtools.md)
338
339
340## WebView如何实现网络请求拦截功能(API 10)
341
342**解决措施**
343
344可以通过onInterceptRequest()接口实现自定义资源请求响应,该能力可用于自定义Web页面响应、自定义文件资源响应等场景。当Web网页发起资源加载请求时,应用层会收到该请求消息并构造本地资源响应消息发送给Web内核,Web内核根据应用层响应信息进行页面资源加载。
345
346**参考链接**
347
348[自定义页面请求响应(开发指南)](../web/web-resource-interception-request-mgmt.md)
349
350
351## WebView和原生进行通信的方式有哪些,如何实现(API 10)
352
353**解决措施**
354
3551. Native->H5使用runJavaScript接口注入JS进行通信,H5->Native使用registerJavaScriptProy接口。先将Native方法注册至H5侧,H5再通过调用前端方法实现与Native侧的通信。
3562. runJavaScript、registerJavaScriptProy接口同时在NDK侧C API暴露。
3573. 使用onInterceptrequest接口拦截H5侧请求,同时将Native侧数据作为Response返回至H5,实现Native与H5的通信。
358
359**参考链接**
360
361[runJavaScript](../reference/apis-arkweb/arkts-apis-webview-WebviewController.md#runjavascriptext10)、[registerJavaScriptProxy](../reference/apis-arkweb/arkts-apis-webview-WebviewController.md#registerjavascriptproxy)、[javaScriptProxy](../reference/apis-arkweb/arkts-basic-components-web-attributes.md#javascriptproxy)、[onInterceptRequest](../reference/apis-arkweb/arkts-basic-components-web-events.md#oninterceptrequest9)
362
363
364## WebView进程模型和渲染机制是什么(API 11)
365
366**解决措施**
367
3681. 进程模型:1个主进程、多个render进程。
3692. 渲染机制:web自渲染。
370
371
372## 系统目前是否支持Webrtc的功能?规格是什么?
373
374**解决措施**
375
3761. WebView支持Webrtc的P-P功能以及音视频流功能。
3772. 非WebView场景,系统不直接提供Webrtc,但会提供技术支持,比如支持三方gn+ninja交叉编译方式适配Webrtc(RR-30030985),包含以下两点:
378   * sdk支持gn+ninja交叉编译方式
379   * 提供编译样例指导
380
381
382## Webview如何设置mixcontent策略,用以解决http与https混合加载的问题?
383
384**解决措施**
385
386Webview提供mixedMode(mixedMode: MixedMode)接口,设置是否允许加载超文本传输协议(HTTP)和超文本传输安全协议(HTTPS)混合内容,默认不允许加载HTTP和HTTPS混合内容。
387
388**参考链接**
389
390[mixedmode](../reference/apis-arkweb/arkts-basic-components-web-e.md#mixedmode)
391
392
393## WebView除了设置缓存,还有什么方式可以提升渲染速度吗?
394
395**解决措施**
396
397使用prepareForPageLoad接口开启预解析。
398
399**参考链接**
400
401[prepareforpageload](../reference/apis-arkweb/arkts-apis-webview-WebviewController.md#prepareforpageload10)
402
403
404## 如何预创建Web组件?如何回收web组件复用?
405
406**解决措施**
407
408通过ArkUI提供的组件动态上下树能力,实现Web组件预创建、回收复用,使用指南见参考链接。
409
410**参考链接**
411
412[动态创建Web组件](../web/web-page-loading-with-web-components.md)
413
414
415## 目前OpenHarmony是否有提供类似其他系统的JavaScript引擎能力?
416
417**解决措施**
418
419目前已支持,详情请见参考链接。
420
421**参考链接**
422
423[JSVM](../reference/common/capi-jsvm.md)