CM's Blog


  • 首页

  • 关于

  • 标签

  • 归档

WebView与JS的交互手记

发表于 2017-07-10

手机APP的开发越来越敏捷,很多地方如果可以用webView的形式代替原生开发,成为了不少团队的技术选择。webView虽然灵活,但是在操作体验和用户交互上还存在不少的缺陷。但因为webView应用的场景越来越多,原生WebView与JS的交互变得非常重要。本文主要记录了WebView与JS交互的几种主要方式,并且补充了自己使用过程中踩过的坑和心得。


方式1: WebViewJavascriptBridge

Issues

  • WKWebViewJavascriptBridge 在Xcode9上导致crash的解决方法:
  • 官方给出的issue

  • 解决方式一:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
    if (webView != _webView) { return; }
    NSURL *url = navigationAction.request.URL;
    __strong typeof(_webViewDelegate) strongDelegate = _webViewDelegate;
    if ([_base isWebViewJavascriptBridgeURL:url]) {
    if ([_base isBridgeLoadedURL:url]) {
    [_base injectJavascriptFile];
    } else if ([_base isQueueMessageURL:url]) {
    [self WKFlushMessageQueue];
    } else {
    [_base logUnkownMessage:url];
    }
    decisionHandler(WKNavigationActionPolicyCancel);
    } else {
    /// 在这新添加了else
    if (strongDelegate && [strongDelegate respondsToSelector:@selector(webView:decidePolicyForNavigationAction:decisionHandler:)]) {
    [_webViewDelegate webView:webView decidePolicyForNavigationAction:navigationAction decisionHandler:decisionHandler];
    } else {
    decisionHandler(WKNavigationActionPolicyAllow);
    }
    }
    }

  • 解决方式二:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
    if (webView != _webView) { return; }
    NSURL *url = navigationAction.request.URL;
    __strong typeof(_webViewDelegate) strongDelegate = _webViewDelegate;
    if ([_base isWebViewJavascriptBridgeURL:url]) {
    if ([_base isBridgeLoadedURL:url]) {
    [_base injectJavascriptFile];
    } else if ([_base isQueueMessageURL:url]) {
    [self WKFlushMessageQueue];
    } else {
    [_base logUnkownMessage:url];
    }
    decisionHandler(WKNavigationActionPolicyCancel);
    /// 在这新添加了return
    return;
    }
    if (strongDelegate && [strongDelegate respondsToSelector:@selector(webView:decidePolicyForNavigationAction:decisionHandler:)]) {
    [_webViewDelegate webView:webView decidePolicyForNavigationAction:navigationAction decisionHandler:decisionHandler];
    } else {
    decisionHandler(WKNavigationActionPolicyAllow);
    }
    }

方式2: JavascriptCore

前情提要

JavaScriptCore 是 Objective-C 的API,作用于链接JS语言和OC语言。通过较少的代码,开发者可以从OC运行JS或者从JS调用OC。

JavaScriptCore具有如下优势:

    1. 让你能够在UIWebView之外使用JS,运行简单的JS脚本无需依赖于web view.
    1. 可以使用现代OC的特性比如blocks和collection subscripting.
    1. 可以很方便的在两种语言之间进行值传递或者对象传递。
    1. 可以创建混合对象:OC的对象能够拥有JS的值甚至函数作为属性。(比如一个原生的按钮在点击的时候触发JS的函数)

合适的使用场景:

    1. 用在业务和原型经常会变化的地方。例如游戏。
    1. 用在不同的团队协作开发的时候。比如iOS程序员和前端程序员共同做一个项目。
    1. 用在需要能立刻看到变化的地方。JS语言是解释型的,所以更改JS代码我们可以看到app的实时变化。

原则上苹果不允许使用的场景:

    1. 从远程服务器下载并运行JS代码。(即使是开发者自己的服务器用内购的方式也不行)
    1. 用户在app内编写JS代码并运行。

JavaScriptCore 概览

主要的类和协议

    1. JSValue: 用来代表JS实体的OC对象。
    1. JSManagedValue: 本质上还是JSValue对象,但是引入了内存管理的特性用来协调OC的引用计数和JS的GC。
    1. JSContext:代表JS运行环境的对象。所有的JSValue对象都要依赖于JSContext。
    1. JSExport:协议。可以用这个协议把原生对象转化成JS对象,把原生的属性和方法转化成JS的属性和方法。
    1. JSVirtualMachine: 代表对象空间,拥有自己的heap和garbage collector.

记一次版本上线总结

发表于 2016-10-14

刚刚上线app新版本, 记得临上线前 leader 一再强调关键时刻不要出错,千万不要出错,可是一再小心,上线后还是出现了几个备受关注的问题。做为开发人员,我想每个人都不想出现这样的结果。

这算作是墨菲定律事件吧,越是不想发生错误,错误越是不可避免。

就我个人而言,总结了几点经验和建议,希望能有所用处。总结如下:

  1. 总结以前线上出现过的问题、产生原因、避免再犯方法,列出文档,督促小组内成员经常看一看,避免同一个问题多人身上多次出现。
  2. 单元测试,自己开发的内容,不能完全依赖测试人员把关,要把自己的主要逻辑业务的边边角角使用测试用例模拟测试起来,不能偷懒。
  3. 有人的地方,不可避免总要出现错误,觉得单元测试完全之后可以交叉测试下。比如两个关系好的,可以你测我开发的,我测你开发的,测试时候认真点,奖罚措施自己协商。
  4. 上线前配置文档多人排查,不要仅仅一人把关,有排查注意事项文档,让几个人都认真校验一下,避免出现低级错误。
  5. iOS 数组越界、字典塞空等不容易测试到但又极易导致crash 的地方要多留心,遇到数组和字典取值塞值的时候,强制做下数据校验排查,防患未然。
  6. 时刻保持学习积极性,多了解时下热门技术,多学习,多总结。对知识进行收集整理,好记性不如烂笔头,时间长了,自己的知识库会是一个宝藏。
  7. 小组内是否可以开一个集体的博客或者论坛,将自己踩过的坑,以及自己认为好的东西分享出来,方便他人,同时也方便以后的自己。
  8. 经常组织技术分享,讨论,头脑风暴,将大家的智慧组织起来,将好的方法和点子运用起来。
  9. 想办法提高工作效率(如:使用适合自己的合理的工作法)和工作积极性(如:多研究感兴趣的方向,做出运用,提高成就感)。
  10. 团队协作,文档共享,是否可以考虑更有效率的云平台,像 svn 文件、office 文档,经常性的更新,极易让人搞混,感觉有更好的办法可以取代的。
CodeMozart

CodeMozart

即使在编程,也要听莫扎特

2 日志
© 2018 CodeMozart
由 Hexo 强力驱动
|
主题 — NexT.Mist v5.1.3