论 iOS 开发中 JS 与 Native 的交互方式.docx
- 文档编号:4574298
- 上传时间:2022-12-06
- 格式:DOCX
- 页数:8
- 大小:18.44KB
论 iOS 开发中 JS 与 Native 的交互方式.docx
《论 iOS 开发中 JS 与 Native 的交互方式.docx》由会员分享,可在线阅读,更多相关《论 iOS 开发中 JS 与 Native 的交互方式.docx(8页珍藏版)》请在冰豆网上搜索。
论iOS开发中JS与Native的交互方式
论iOS开发中JS与Native的交互方式
作者
CoCodeDZ
2016.03.0817:
01*
写了16521字,被14人关注,获得了19个喜欢
论iOS开发中JS与Native的交互方式
字数2020
阅读500
评论0
喜欢4
前言
在iOS开发中,JS与Native的交互分为两种,第一种是Native调JS,即通过在Native代码中执行JS达到在webkit控件中展现相应JS代码的效果;另一种就是JS调用Native,通过web前段JS的执行来调用Native本地的方法,用以实现例如开启照相机、数据持久化等等只能通过Native代码实现的效果。
目前进行JS和Native交互主要有两种方式,下面进行一一介绍:
一、WebView方法/代理方法
通常来说,iOS中实现加载web页面主要有两种控件,UIWebView和WKWebview,两种控件对应具体的实现方法不同,我们在这里分开进行介绍:
UIWebView控件
Native调用JS:
在Native中执行JS语句非常简单,JS作为脚本语言它的执行需要解释器的存在,即浏览器,所以UIWebView作为浏览器控件,提供了native调用JS的对象方法:
//script是要执行的JS语句
//返回值为JS执行结果,如果JS执行失败则返回nil,如果JS执行没有返回值,则返回值为空字符串
-(nullableNSString*)stringByEvaluatingJavaScriptFromString:
(NSString*)script;
这里编写了一个demo仅供参考:
-(void)webViewDidFinishLoad:
(UIWebView*)webView
{
NSString*str=[self.webViewstringByEvaluatingJavaScriptFromString:
@"pageDidLoad()"];
NSLog(@"%@",str);
}
当WebView加载完毕的时候调用JS中的pageDidLoad方法,并在控制台打印JS的执行结果。
JS调用Native:
使用WebView方法/代理方法完成JS调用Native要稍微复杂一点,需要Native前端和web前端的良好配合,主要原理是通过UIWebVIew的代理方法截取web前端的跳转请求,通过识别与web前端约定好的自定义协议头来判断本次请求是否为JS调用Native的请求,来调用对应的Native方法。
其中涉及到的UIWebView代理方法为:
-(BOOL)webView:
(UIWebView*)webViewshouldStartLoadWithRequest:
(NSURLRequest*)requestnavigationType:
(UIWebViewNavigationType)navigationType;
下面通过例子来进行演示:
JavaScript代码:
functionbtnOnClickBaidu(){
varurl="";
alert("马上跳转的页面是:
"+url);
window.location.href=url;
}
functionbtnOnClickNative(){
varurl="DZBridge:
//printSomeWords";
alert("马上跳转的页面是:
"+url);
window.location.href=url;
}
functionbtnOnClickNativeWithConfig(){
varurl="DZBridge:
//printSomeWords?
{\"string\":
\"HelloWorld\"}";
alert("马上跳转的页面是:
"+url);
window.location.href=url;
}
functionpageDidLoad(){
alert("页面加载完毕!
");
return11;
}
OC代码:
-(BOOL)webView:
(UIWebView*)webViewshouldStartLoadWithRequest:
(NSURLRequest*)requestnavigationType:
(UIWebViewNavigationType)navigationType
{
//dzbridge为约定好的协议头,如果是,则页面不进行跳转
if([request.URL.schemeisEqualToString:
@"dzbridge"]){
//截取字符串来判断是否存在参数
NSArray<NSString*>*arr=[request.URL.absoluteStringcomponentsSeparatedByString:
@"?
"];
if(arr.count>1){
NSString*str=[arr[1]stringByRemovingPercentEncoding];
NSDictionary*dict=[NSJSONSerializationJSONObjectWithData:
[strdataUsingEncoding:
NSUTF8StringEncoding]options:
0error:
NULL];
NSLog(@"%@",dict[@"string"]);
}
else{
NSLog(@"没有参数的打印");
}
returnNO;
}
//不是自定义协议头,跳转页面
returnYES;
}
WKWebView控件
iOS8以后,苹果推出了新框架WKWebKit,其中提供了可以替换UIWebView的组件WKWebView。
原来UIWebView的各种问题得到了改善,速度更快了,占用内存少了(模拟器加载XX与开源中国网站时,WKWebView占用23M,而UIWebView占用85M),目前来看,WKWebView是App内部加载网页更佳的选择!
WKWebView相对UIWebView做了较大幅度的重构,将UIWebViewDelegate与UIWebView重构成了14类与3个协议,因此,在WKWebView中进行JS与Native的交互与UIWebView相比也有较大的不同。
Native调用JS:
在WKWebView中Native调用JS的方式与UIWebview中比较相似,也是通过自己本身的一个对象方法:
//javaScriptString为待执行的JS语句
//completionHandler为执行JS完毕后的回调,block的第一个参数为执行结果,第二个参数为错误
-(void)evaluateJavaScript:
(NSString*)javaScriptStringcompletionHandler:
(void(^__nullable)(__nullableid,NSError*__nullableerror))completionHandler;
看下面一个小例子:
#pragmamark-----WKNavigationDelegate-----
-(void)webView:
(WKWebView*)webViewdidFinishNavigation:
(WKNavigation*)navigation
{
[self.webViewevaluateJavaScript:
@"pageDidLoad()"completionHandler:
^(id_Nullablevalue,NSError*_Nullableerror){
NSLog(@"%@",value);
}];
}
JS调用Native:
WKWebView中JS调用Native与UIWebView有着比较大的不同,首先需要介绍几个类(/协议/属性):
WKWebViewConfiguration:
是WKWebView初始化时的配置类,里面存放着初始化WK的一系列属性;
WKUserContentController:
为JS提供了一个发送消息的通道并且可以向页面注入JS的类;
WKScriptMessageHandler:
一个协议,协议中只有一个方法,这个方法是页面执行特定JS的一个回调,这个特定的JS格式为:
window.webkit.messageHandlers.<name>.postMessage(<messageBody>);
WKWebViewConfiguration作为WK的配置类,其中有一个属性为
@property(nonatomic,strong)WKUserContentController*userContentController;
是WKUserContentController的一个实例,WKUserContentController有一个对象方法为:
/*!
@abstractAddsascriptmessagehandler.
@paramscriptMessageHandlerThemessagehandlertoadd.
@paramnameThenameofthemessagehandler.
@discussionAddingascriptMessageHandleraddsafunction
window.webkit.messageHandlers.<name>.postMessage(<messageBody>)forall
frames.
*/
-(void)addScriptMessageHandler:
(id<WKScriptMessageHandler>)scriptMessageHandlername:
(NSString*)name;
从苹果给出的注释来看,通过该方法能够添加一个脚本消息的处理器,即(id<WKScriptMessageHandler>)scriptMessageHandler,另外还能发现,添加脚本处理器后,需要在JS中添加window.webkit.messageHandlers.<name>.postMessage(<messageBody>)才能起作用。
demo:
//创建并配置WKWebView的相关参数
WKWebViewConfiguration*config=[[WKWebViewConfigurationalloc]init];
WKUserContentController*userContent=[[WKUserContentControlleralloc]init];
//self指代的对象需要遵守WKScriptMessageHandler协议
[userContentaddScriptMessageHandler:
selfname:
@"test"];
config.userContentController=userContent;
在页面上的JS执行window.webkit.messageHandlers.<name>.postMessage(<messageBody>)时,被添加的ScriptMessageHandler就会执行实现的WKScriptMessageHandler协议的方法,例如:
#pragmamark-----WKScriptMessageHandler-----
/**
*JS调用OC时webview会调用此方法
*
*@paramuserContentControllerwebview中配置的userContentController信息
*@parammessagejs执行传递的消息
*/
-(void)userContentController:
(WKUserContentController*)userContentControllerdidReceiveScriptMessage:
(WKScriptMessage*)message
{
NSLog(@"%@",message);
}
在代理方法中实现相应的Native代码,即完成了JS调用Native的过程。
二、JavaScriptCore
OSXMavericks和iOS7引入了JavaScriptCore库,把WebKit的JavaScript引擎用Objective-C封装,提供了简单,快速以及安全的方式接入JavaScript。
JavaScriptCore中类及协议
JSContext:
JavaScript运行的上下文环境JSValue:
JavaScript和Objective-C数据和方法的桥梁JSExport:
这是一个协议,如果采用协议的方法交互,自己定义的协议必须遵守此协议JSManagedValue:
管理数据和方法的类JSVirtualMachine:
处理线程相关,使用较少
JavaScript调用Native
使用JavaScriptCore进行JS和Native的交互,无论想要实现什么样的效果都需要获得一个有效的JSContext实例,即一个有效的JS运行的上下文(这一步骤以下不再重复提及)。
获得当前的JSContext:
可以在页面加载完毕后,采用KVC的方式从webView中获得,如下:
JSContext*jsContext=[webViewvalueForKeyPath:
@"documentView.webView.mainFrame.javaScriptContext"];
将想要被暴露给JS的方法抽象成为一个协议(protocol),该协议需要遵守JSExport协议:
@protocolJSObjcDelegate<JSExport>
-(void)callCamera;
-(NSString*)share:
(NSString*)shareString;
@end
将要暴露给JS的对象的类需要遵守自定义的协议,如上:
JSObjcDelegate;将OC对象桥接到JS环境中,并设置异常处理
//将本对象与JS中的DZBridge对象桥接在一起,在JS中DZBridge代表本对象
[self.jsContextsetObject:
selfforKeyedSubscript:
@"DZBridge"];
self.jsContext.exceptionHandler=^(JSContext*context,JSValue*exceptionValue){
context.exception=exceptionValue;
NSLog(@"异常信息:
%@",exceptionValue);
};
在JS中通过DZBridge调用本对象暴露出的方法:
varcallShare=function(){
varshareInfo=JSON.stringify({"title":
"标题","desc":
"内容","shareUrl":
""});
varstr=DZBridge.share(shareInfo);
alert(str);
}
Native调用JavaScript
第一种方式同UIWebView中类似,都是直接执行JS字符串,通过JSContext执行JS代码:
[self.jsContextevaluateScript:
@"alert(\"执行JS\")"];
另一种方式适用于执行web页面上已有的方法,通过JSValue来调用JS中的方法,JSValue是JavaScript中值得一个引用,他可能包装着一个JavaScript的方法,通过callWithArguments:
方法进行调用,例如:
JSValue*picCallback=self.jsContext[@"picCallback"];
[picCallbackcallWithArguments:
@[@"photos"]];推荐拓展阅读著作权归作者所有如果觉得我的文章对您有用,请随意打赏。
您的支持将鼓励我继续创作!
¥打赏支持喜欢
4
分享到微博
分享到微信
更多分享
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- iOS 开发中 JS Native 的交互方式 开发 交互 方式