参考资料: Swift和Javascript的神奇魔法
JavaScriptCore初探
NSHipster -- Java​Script​Core

Demo:

  • PADemo
    • KSUIWebViewController类中有在UIWebView下使用JavaScriptCore实现native和JavaScript交互的示例
    • KSWKWebViewController类提供了WKWebView与JavaScript的交互示例
  • Swift-JavascriptDemo
    • BasicsViewController中提供了不依赖于WebView进行native和JS交互的代码示例

JavaScript于原生App交互的几种方式

iOS7之前

拦截/重定向的方式实现交互,必须依赖于WebView才能实现。 通过note-on-iOS-work-with-JavaScript中的一个简单的代码片段可以说明UIWebView中怎样进行拦截实现JS与UIWebView的交互:

extension ViewController: UIWebViewDelegate {
  func webView(_ webView: UIWebView,
             shouldStartLoadWith request: URLRequest,
             navigationType: UIWebViewNavigationType) -> Bool {

    // 1 拦截名为 hello 协议;拦截之后根据具体的参数做具体的操作,从而实现了JS对原生的调用
    if request.url?.scheme == "hello" {

     // 2 获取协议后的 path,也就是lien;
     let path = request.url?.absoluteString as String!

      // 3 将 path 的 string 作为 window.alert() 方法的参数,
      // 通过 webview.stringByEvaluatingJavaScript() 方法执行该 JavaScript 函数;
      let msg = String(format: "alert('intercept scheme: %@')", path!)
      //func stringByEvaluatingJavaScript(_:String) -> String 这是UIWebView中实现对JS调用的函
      webview.stringByEvaluatingJavaScript(from: msg)

      // 4 因为拦截到了对应的hello 协议,在 delegate method 最终返回 false,
      // 阻止 UIWebView 继续执行该请求(跳转了也是个 404)。
      return false
    }

    return true
 }
}

拦截重定向的方式进行交互看似简单,但只能在WebView中使用成了其主要的限制。

iOS7之后 JavaScriptCore

JavaScriptCore可以实现native不依赖于webView直接和JavaScript进行交互,也提供了UIWebView与JavaScript进行交互的方式。注意:WKWebView与JavaScript的交互不使用JavaScriptCore。

通过几个重要类型了解JavaScriptCore

  • JSContext 运行JavaScript代码的环境。

    // 官方API对JSContext的描述
    A JSContext is a JavaScript execution environment. All
    JavaScript execution takes place within a context, and all JavaScript values
    are tied to a context.
    
  • 任何出自JSContext的值都被包裹成JSValue类型,再从JSValue类型转换成需要的类型;也可以说任何JSValue值都来源于JSContext,同时JSValue强引用JSContext,所以在使用时要特别注意内存问题。

    // 官方API对JSValue的描述
    A JSValue is a reference to a JavaScript value. Every JSValue
    originates from a JSContext and holds a strong reference to it.
    When a JSValue instance method creates a new JSValue, the new value
    originates from the same JSContext.
    
  • JSExport协议可以将OC/Swift类型的属性、实例方法、类方法、析构函数(初始化方法)转换成JavaScript。从而实现JS对OC/Swift的调用。

    // 官方API对JSExport的描述
    JSExport provides a declarative way to export Objective-C objects and
    classes -- including properties, instance methods, class methods, and
    initializers -- to JavaScript.
    
JavaScriptCore中原生调用JS的简单示例:
let context = JSContext()
context.evaluateScript("var num = 5 + 5")
context.evaluateScript("var names = ['Grace', 'Ada', 'Margaret']")
context.evaluateScript("var triple = function(value) { return value * 3 }")
let tripleNum: JSValue = context.evaluateScript("triple(num)")
// JS代码片段
 function sumValue (a, b) {
     return a + b;
 }
// Swift代码片段
let context = JSContext()
let sumFunc = context.objectForKeyedSubscript(sumValue)
let sumResult = sumFunc?.call(withArguments: [1, 2])
print("1 + 2 = \(sumResult.toInt32())")
JavaScriptCore-JS调用原生
let nativeLog: @convention(block) (String) -> Void = { str in
    print("str = \(str)")
}
// unsafeBitCast用来强制类型转换 使用的时候需要明确的知道要转换的类型
let nativeLogObject = unsafeBitCast(nativeLog, to: AnyObject.self)
// setObject(:, forKeyedSubscript:) 为JS添加方法或属性
context.setObject(nativeLogObject, forKeyedSubscript: "nslog" as NSCopying &
NSObjectProtocol)
// 通过上面的代码,JS里面就有了一个nslog函数可以直接使用了。

注意:webview获取JSContext使用下面的代码片段属于私有API,最好不用以免被拒,所以要找到一个替换方案。

if let aContext = webView.value(forKeyPath: "documentView.webView.mainFrame.javaScriptContext") as? JSContext {
    self.context = aContext
 }

WKWebView

WkWebView中获取不到JSContext,不使用JavaScriptCore与JavaScript进行交互。在下一片介绍WKWebView的文章中会详细说明WKWebView与JavaScript的交互方式。

Copyright © shuoliu.com 2018 all right reserved,powered by Gitbook该文件修订时间: 2018-09-03 03:46:41

results matching ""

    No results matching ""