最近项目里面有有个商品活动界面,要与web端传值,将用户在网页点击的商品id 传给客户端,也就是js交互,其实再说明白一点就是方法的互相调用而已。
本文叙述下如何进行原生的JavaScript交互
本文包括JS调用OC方法并传值,OC调用JS方法并传值
本来想把html放进服务器里面,然后访问,但是觉得如果html在本地加载更有助于理解,特把html放进项目里
HTML代码
<span style="font-family: Arial;"></span><pre class="hljs xml" name="code" style="white-space: pre-wrap; word-wrap: break-word; padding: 0.5em; background-color: rgb(255, 255, 255); font-size: 14px;"><code class="xml"><span class="hljs-doctype" style="color: rgb(102, 0, 102);"><!DOCTYPE html></span> <span class="hljs-tag" style="color: rgb(0, 102, 102);"><<span class="hljs-title" style="color: rgb(0, 0, 136);">html</span>></span> <span class="hljs-tag" style="color: rgb(0, 102, 102);"><<span class="hljs-title" style="color: rgb(0, 0, 136);">head</span>></span> <span class="hljs-tag" style="color: rgb(0, 102, 102);"><<span class="hljs-title" style="color: rgb(0, 0, 136);">meta</span> <span class="hljs-attribute" style="color: rgb(102, 0, 102);">charset</span>=<span class="hljs-value" style="color: rgb(0, 136, 0);">"UTF-8"</span>></span> <span class="hljs-tag" style="color: rgb(0, 102, 102);"></<span class="hljs-title" style="color: rgb(0, 0, 136);">head</span>></span> <span class="hljs-tag" style="color: rgb(0, 102, 102);"><<span class="hljs-title" style="color: rgb(0, 0, 136);">body</span>></span> <span class="hljs-tag" style="color: rgb(0, 102, 102);"><<span class="hljs-title" style="color: rgb(0, 0, 136);">div</span> <span class="hljs-attribute" style="color: rgb(102, 0, 102);">style</span>=<span class="hljs-value" style="color: rgb(0, 136, 0);">"margin-top: 20px"</span>></span> <span class="hljs-tag" style="color: rgb(0, 102, 102);"><<span class="hljs-title" style="color: rgb(0, 0, 136);">h2</span>></span>JS与OC交互<span class="hljs-tag" style="color: rgb(0, 102, 102);"></<span class="hljs-title" style="color: rgb(0, 0, 136);">h2</span>></span> <span class="hljs-tag" style="color: rgb(0, 102, 102);"><<span class="hljs-title" style="color: rgb(0, 0, 136);">input</span> <span class="hljs-attribute" style="color: rgb(102, 0, 102);">type</span>=<span class="hljs-value" style="color: rgb(0, 136, 0);">"button"</span> <span class="hljs-attribute" style="color: rgb(102, 0, 102);">value</span>=<span class="hljs-value" style="color: rgb(0, 136, 0);">"唤起本地方法(call)"</span> <span class="hljs-attribute" style="color: rgb(102, 0, 102);">onclick</span>=<span class="hljs-value" style="color: rgb(0, 136, 0);">"tianbai.call()"</span>></span> <span class="hljs-tag" style="color: rgb(0, 102, 102);"></<span class="hljs-title" style="color: rgb(0, 0, 136);">div</span>></span> <span class="hljs-tag" style="color: rgb(0, 102, 102);"><<span class="hljs-title" style="color: rgb(0, 0, 136);">div</span>></span> <span class="hljs-tag" style="color: rgb(0, 102, 102);"><<span class="hljs-title" style="color: rgb(0, 0, 136);">input</span> <span class="hljs-attribute" style="color: rgb(102, 0, 102);">type</span>=<span class="hljs-value" style="color: rgb(0, 136, 0);">"button"</span> <span class="hljs-attribute" style="color: rgb(102, 0, 102);">value</span>=<span class="hljs-value" style="color: rgb(0, 136, 0);">"唤起getCall:(NSString *)callString传值"</span> <span class="hljs-attribute" style="color: rgb(102, 0, 102);">onclick</span>=<span class="hljs-value" style="color: rgb(0, 136, 0);">"call()"</span>></span> <span class="hljs-tag" style="color: rgb(0, 102, 102);"></<span class="hljs-title" style="color: rgb(0, 0, 136);">div</span>></span> <span class="hljs-tag" style="color: rgb(0, 102, 102);"><<span class="hljs-title" style="color: rgb(0, 0, 136);">script</span>></span></code>
<code class="xml"><span class="hljs-tag" style="color: rgb(0, 102, 102);"></span></code><pre class="hljs xml" name="code" style="white-space: pre-wrap; word-wrap: break-word; padding: 0.5em; background-color: rgb(255, 255, 255); font-size: 14px;"><code class="xml"><span class="javascript"><span class="hljs-keyword" style="color: rgb(0, 0, 136);">var</span> call = <span class="hljs-function"><span class="hljs-keyword" style="color: rgb(0, 0, 136);">function</span>(<span class="hljs-params" style="color: rgb(102, 0, 102);"></span>) </span>{ <span class="hljs-keyword" style="color: rgb(0, 0, 136);">var</span> callInfo = <span class="hljs-built_in" style="color: rgb(102, 0, 102);">JSON</span>.stringify({<span class="hljs-string" style="color: rgb(0, 136, 0);">"jianshu"</span>: <span class="hljs-string" style="color: rgb(0, 136, 0);">"http://www.jianshu.com/users/55c8fdc3c6e7/latest_articles"</span>}); tianbai.getCall(callInfo); } <span class="hljs-keyword" style="color: rgb(0, 0, 136);">var</span> Callback = <span class="hljs-function"><span class="hljs-keyword" style="color: rgb(0, 0, 136);">function</span>(<span class="hljs-params" style="color: rgb(102, 0, 102);">str</span>) </span>{ alert(str); } <span class="hljs-keyword" style="color: rgb(0, 0, 136);">var</span> alerCallback = <span class="hljs-function"><span class="hljs-keyword" style="color: rgb(0, 0, 136);">function</span>(<span class="hljs-params" style="color: rgb(102, 0, 102);"></span>) </span>{ alert(<span class="hljs-string" style="color: rgb(0, 136, 0);">'成功'</span>); } </span><span class="hljs-tag" style="color: rgb(0, 102, 102);"></<span class="hljs-title" style="color: rgb(0, 0, 136);">script</span>></span> <span class="hljs-tag" style="color: rgb(0, 102, 102);"></<span class="hljs-title" style="color: rgb(0, 0, 136);">body</span>></span> <span class="hljs-tag" style="color: rgb(0, 102, 102);"></<span class="hljs-title" style="color: rgb(0, 0, 136);">html</span>></span></code>
上面html的代码:建立了两个button
第一个button绑定了 tianbai.call()
方法,这里 tianbai
是一个对象,这个对象的作用下面OC代码中会说明,tianbai.call()
代表 tianbai
对象调用 call()
方法
第二个button绑定了 call()
的方法,调用的是下面JavaScript中的 call()
方法,在 JavaScript 的 call()
里面,定义一个 callInfo
参数,方法中 tianbai.getCall(callInfo)
代表 tianbai
对象调用 getCall
方法并传参数 callInfo
,下面两个方法是OC调用JavaScript方法,其中Callback传回str,alerCallback为OC仅调用JavaScript方法!
OC代码
demo采用原生的JavaScriptCore类
引入三个名词:
- JSContext:给JavaScript提供运行的上下文环境
- JSValue:JavaScript和Objective-C数据和方法的桥梁
- JSExport:这是一个协议,如果采用协议的方法交互,自己定义的协议必须遵守此协议
ViewController.h中的代码(代码过长,方法说明都在注释里)
<pre class="hljs objectivec" name="code" style="white-space: pre-wrap; word-wrap: break-word; padding: 0.5em; background-color: rgb(255, 255, 255); font-size: 14px;"><code class="objectivec"><span class="hljs-preprocessor" style="color: rgb(68, 68, 68);">#import <span class="hljs-title"><UIKit/UIKit.h></span></span> <span class="hljs-comment" style="color: rgb(136, 0, 0);">//导入头文件</span> <span class="hljs-preprocessor" style="color: rgb(68, 68, 68);">#import <span class="hljs-title"><JavaScriptCore/JavaScriptCore.h></span></span> <span class="hljs-class"><span class="hljs-keyword" style="color: rgb(0, 0, 136);">@protocol</span> <span class="hljs-title" style="color: rgb(102, 0, 102);">JSObjcDelegate</span> <<span class="hljs-title" style="color: rgb(102, 0, 102);">JSExport</span>></span> <span class="hljs-comment" style="color: rgb(136, 0, 0);">//tianbai对象调用的JavaScript方法,必须声明!!!</span> - (<span class="hljs-keyword" style="color: rgb(0, 0, 136);">void</span>)call; - (<span class="hljs-keyword" style="color: rgb(0, 0, 136);">void</span>)getCall:(<span class="hljs-built_in" style="color: rgb(102, 0, 102);">NSString</span> *)callString; <span class="hljs-keyword" style="color: rgb(0, 0, 136);">@end</span> <span class="hljs-class"><span class="hljs-keyword" style="color: rgb(0, 0, 136);">@interface</span> <span class="hljs-title" style="color: rgb(102, 0, 102);">ViewController</span> : <span class="hljs-title" style="color: rgb(102, 0, 102);">UIViewController</span><<span class="hljs-title" style="color: rgb(102, 0, 102);">UIWebViewDelegate</span>,<span class="hljs-title" style="color: rgb(102, 0, 102);">JSObjcDelegate</span>></span> <span class="hljs-keyword" style="color: rgb(0, 0, 136);">@property</span> (<span class="hljs-keyword" style="color: rgb(0, 0, 136);">nonatomic</span>, <span class="hljs-keyword" style="color: rgb(0, 0, 136);">strong</span>) JSContext *jsContext; <span class="hljs-keyword" style="color: rgb(0, 0, 136);">@property</span> (<span class="hljs-keyword" style="color: rgb(0, 0, 136);">strong</span>, <span class="hljs-keyword" style="color: rgb(0, 0, 136);">nonatomic</span>) <span class="hljs-built_in" style="color: rgb(102, 0, 102);">UIWebView</span> *webView; <span class="hljs-keyword" style="color: rgb(0, 0, 136);">@end</span></code>
ViewController.m中的代码(代码过长,方法说明都在注释里)
JavaScriptCore中web页面调用原生应用的方法可以用Delegate或Block两种方法,此文以按Delegate讲解。
设置webView
<pre class="hljs objectivec" name="code" style="white-space: pre-wrap; word-wrap: break-word; padding: 0.5em; background-color: rgb(255, 255, 255); font-size: 14px;"><code class="objectivec"><span class="hljs-keyword" style="color: rgb(0, 0, 136);">self</span><span class="hljs-variable" style="color: rgb(102, 0, 102);">.webView</span> = [[<span class="hljs-built_in" style="color: rgb(102, 0, 102);">UIWebView</span> alloc]initWithFrame:<span class="hljs-built_in" style="color: rgb(102, 0, 102);">CGRectMake</span>(<span class="hljs-number" style="color: rgb(0, 102, 102);">0</span>, <span class="hljs-number" style="color: rgb(0, 102, 102);">20</span>, [<span class="hljs-built_in" style="color: rgb(102, 0, 102);">UIScreen</span> mainScreen]<span class="hljs-variable" style="color: rgb(102, 0, 102);">.bounds</span><span class="hljs-variable" style="color: rgb(102, 0, 102);">.size</span><span class="hljs-variable" style="color: rgb(102, 0, 102);">.width</span>, [<span class="hljs-built_in" style="color: rgb(102, 0, 102);">UIScreen</span> mainScreen]<span class="hljs-variable" style="color: rgb(102, 0, 102);">.bounds</span><span class="hljs-variable" style="color: rgb(102, 0, 102);">.size</span><span class="hljs-variable" style="color: rgb(102, 0, 102);">.height</span>)]; <span class="hljs-keyword" style="color: rgb(0, 0, 136);">self</span><span class="hljs-variable" style="color: rgb(102, 0, 102);">.webView</span><span class="hljs-variable" style="color: rgb(102, 0, 102);">.delegate</span> = <span class="hljs-keyword" style="color: rgb(0, 0, 136);">self</span>; <span class="hljs-comment" style="color: rgb(136, 0, 0);">//从本地加载html文件</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102);">NSString</span>* path = [[<span class="hljs-built_in" style="color: rgb(102, 0, 102);">NSBundle</span> mainBundle] pathForResource:<span class="hljs-string" style="color: rgb(0, 136, 0);">@"index"</span> ofType:<span class="hljs-string" style="color: rgb(0, 136, 0);">@"html"</span>]; <span class="hljs-built_in" style="color: rgb(102, 0, 102);">NSURL</span>* url = [<span class="hljs-built_in" style="color: rgb(102, 0, 102);">NSURL</span> fileURLWithPath:path]; <span class="hljs-built_in" style="color: rgb(102, 0, 102);">NSURLRequest</span>* request = [<span class="hljs-built_in" style="color: rgb(102, 0, 102);">NSURLRequest</span> requestWithURL:url] ; [<span class="hljs-keyword" style="color: rgb(0, 0, 136);">self</span><span class="hljs-variable" style="color: rgb(102, 0, 102);">.webView</span> loadRequest:request]; [<span class="hljs-keyword" style="color: rgb(0, 0, 136);">self</span><span class="hljs-variable" style="color: rgb(102, 0, 102);">.view</span> addSubview:<span class="hljs-keyword" style="color: rgb(0, 0, 136);">self</span><span class="hljs-variable" style="color: rgb(102, 0, 102);">.webView</span>];</code>
JavaScript的tianbai是一个对象,充当原生应用和web页面之间的一个桥梁。用来调用方法
webview加载完成调用代理
<pre class="hljs objectivec" name="code" style="white-space: pre-wrap; word-wrap: break-word; padding: 0.5em; background-color: rgb(255, 255, 255); font-size: 14px;"><code class="objectivec">- (<span class="hljs-keyword" style="color: rgb(0, 0, 136);">void</span>)webViewDidFinishLoad:(<span class="hljs-built_in" style="color: rgb(102, 0, 102);">UIWebView</span> *)webView { <span class="hljs-comment" style="color: rgb(136, 0, 0);">// 设置javaScriptContext上下文</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136);">self</span><span class="hljs-variable" style="color: rgb(102, 0, 102);">.jsContext</span> = [webView valueForKeyPath:<span class="hljs-string" style="color: rgb(0, 136, 0);">@"documentView.webView.mainFrame.javaScriptContext"</span>]; <span class="hljs-comment" style="color: rgb(136, 0, 0);">//将tianbai对象指向自身</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136);">self</span><span class="hljs-variable" style="color: rgb(102, 0, 102);">.jsContext</span>[<span class="hljs-string" style="color: rgb(0, 136, 0);">@"tianbai"</span>] = <span class="hljs-keyword" style="color: rgb(0, 0, 136);">self</span>; <span class="hljs-keyword" style="color: rgb(0, 0, 136);">self</span><span class="hljs-variable" style="color: rgb(102, 0, 102);">.jsContext</span><span class="hljs-variable" style="color: rgb(102, 0, 102);">.exceptionHandler</span> = ^(JSContext *context, JSValue *exceptionValue) { context<span class="hljs-variable" style="color: rgb(102, 0, 102);">.exception</span> = exceptionValue; <span class="hljs-built_in" style="color: rgb(102, 0, 102);">NSLog</span>(<span class="hljs-string" style="color: rgb(0, 136, 0);">@"异常信息:%@"</span>, exceptionValue); }; }</code>
将对象指向自身后,如果调用 tianbai.call()
会响应下面的方法,OC方法中调用js中的Callback方法,并传值
<pre class="hljs objectivec" name="code" style="white-space: pre-wrap; word-wrap: break-word; padding: 0.5em; background-color: rgb(255, 255, 255); font-size: 14px;"><code class="objectivec">- (<span class="hljs-keyword" style="color: rgb(0, 0, 136);">void</span>)call{ <span class="hljs-built_in" style="color: rgb(102, 0, 102);">NSLog</span>(<span class="hljs-string" style="color: rgb(0, 136, 0);">@"call"</span>); <span class="hljs-comment" style="color: rgb(136, 0, 0);">// 之后在回调JavaScript的方法Callback把内容传出去</span> JSValue *Callback = <span class="hljs-keyword" style="color: rgb(0, 0, 136);">self</span><span class="hljs-variable" style="color: rgb(102, 0, 102);">.jsContext</span>[<span class="hljs-string" style="color: rgb(0, 136, 0);">@"Callback"</span>]; <span class="hljs-comment" style="color: rgb(136, 0, 0);">//传值给web端</span> [Callback callWithArguments:@[<span class="hljs-string" style="color: rgb(0, 136, 0);">@"唤起本地OC回调完成"</span>]]; }</code>
将对象指向自身后,如果调用 tianbai.getCall(callInfo)
会响应下面的方法,OC方法中仅调用JavaScript中的alerCallback方法
<pre class="hljs objectivec" name="code" style="white-space: pre-wrap; word-wrap: break-word; padding: 0.5em; background-color: rgb(255, 255, 255); font-size: 14px;"><code class="objectivec">- (<span class="hljs-keyword" style="color: rgb(0, 0, 136);">void</span>)getCall:(<span class="hljs-built_in" style="color: rgb(102, 0, 102);">NSString</span> *)callString{ <span class="hljs-built_in" style="color: rgb(102, 0, 102);">NSLog</span>(<span class="hljs-string" style="color: rgb(0, 136, 0);">@"Get:%@"</span>, callString); <span class="hljs-comment" style="color: rgb(136, 0, 0);">// 成功回调JavaScript的方法Callback</span> JSValue *Callback = <span class="hljs-keyword" style="color: rgb(0, 0, 136);">self</span><span class="hljs-variable" style="color: rgb(102, 0, 102);">.jsContext</span>[<span class="hljs-string" style="color: rgb(0, 136, 0);">@"alerCallback"</span>]; [Callback callWithArguments:<span class="hljs-literal" style="color: rgb(0, 102, 102);">nil</span>]; }</code>
将对象指向自身后,还可以向html注入js
<pre class="hljs objectivec" name="code" style="white-space: pre-wrap; word-wrap: break-word; padding: 0.5em; background-color: rgb(255, 255, 255); font-size: 14px;"><code class="objectivec">- (<span class="hljs-keyword" style="color: rgb(0, 0, 136);">void</span>)alert{ <span class="hljs-comment" style="color: rgb(136, 0, 0);">// 直接添加提示框</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102);">NSString</span> *str = <span class="hljs-string" style="color: rgb(0, 136, 0);">@"alert('OC添加JS提示成功')"</span>; [<span class="hljs-keyword" style="color: rgb(0, 0, 136);">self</span><span class="hljs-variable" style="color: rgb(102, 0, 102);">.jsContext</span> evaluateScript:str]; }</code>
Demo地址:点击下载
原文链接:http://www.jianshu.com/p/fd378c6d70c0
著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。