Native 开发 和 H5 谁优谁劣,不在这边展开讨论。目前的开发过程中经常会遇到 原生应用 和web 交互的 需求。接下来我们就聊聊吧。
需求点
首页 运营一个活动,一个大转盘,转呀转呀,送 各种礼品呐。一个人一天可以转三次,分享到社交软件增加一次抽奖机会。
开始
iOS 应用 和web 页面交互 有以下 几种方法:
1、挺有名的第三方框架 WebViewJavaScriptBridge
2、iOS7 之后自带的 JavaScriptCore
3、据说还可以 拦截协议
第一种 和 第三种方法 这里就不详细介绍了(其实是我不会!!!)
方法一 作为 一个 知名的第三方框架,肯定会有 其他同行小伙伴介绍的,
传送门 :http://kittenyang.com/webview-javascript-bridge/
反正我也写不过他!
我选择方法二!
因为简单...
JavaScriptCore框架
JSContext:给JavaScript提供运行的上下文环境
JSValue:JavaScript和Objective-C数据和方法的桥梁
JSManagedValue:管理数据和方法的类
JSVirtualMachine:处理线程相关
JSExport:一个协议,接下来会介绍到
直接看代码
@interfaceTWWebViewController() <UIWebViewDelegate>
@property(nonatomic,strong)UIWebView*webView;
@property(nonatomic,strong)JSContext*jContext;
@property(nonatomic,strong)TWWebCallBackFunctionHelper*helper;
@end
考虑到 需求经常变化,我用 TWWebCallBackFunctionHelper 统一处理 OC 和 JS 制定的 方法。
- (void)viewDidLoad
{
[superviewDidLoad];
self.helper= [[TWWebCallBackFunctionHelperalloc]init];[self.viewaddSubview:self.webView];[self.webViewloadRequest:[NSURLRequestrequestWithURL:[NSURLURLWithString:self.webUrl]]];
}
加载 webView 和生成 TWWebCallBackFunctionHelper 对象。
#pragma mark - UIWebViewDelegate
- (BOOL)webView:(UIWebView*)webView
shouldStartLoadWithRequest:(NSURLRequest*)request
navigationType:(UIWebViewNavigationType)navigationType
{
returnYES;
}
- (void)webViewDidStartLoad:(UIWebView*)webView
{
if(!_jContext) {
self.jContext=
[webViewvalueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
self.jContext[@"toApp"] =_helper;
}
}
- (void)webViewDidFinishLoad:(UIWebView*)webView
{
if(!self.webTitle.length) {
//获取当前页面的title
NSString*webTitle = [webViewstringByEvaluatingJavaScriptFromString:@"document.title"];
self.title= webTitle;
}
}
- (void)webView:(UIWebView*)webView didFailLoadWithError:(NSError*)error
{
NSLog(@"didFailLoadWithError = %@", error);
}
在 webView 开始加载的时候 获取 JavaScript 上下文,和前端的小伙伴约定 toApp 为回调对象名(也有一些叫法 桥梁对象 ),helper 为实现协议对象。
接下来实现 TWWebCallBackFunctionHelper
#import <JavaScriptCore/JavaScriptCore.h>
@protocol webViewJsDelegate<JSExport>
JSExportAs(sharered, -(void)sharered
: (NSString *)url shareContent
: (NSString *)content linkUrl
: (NSString *)lUrl);
@end
JSExport 是 一个 协议, 自定义的 webViewJsDelegate 协议 需要遵守此协议。
我们来看下 JSExportAs 宏定义
PropertyName 类似 一个 key,和 对应的 例子里是 sharered,其 对应 要实现的方法是
-(void)sharered:shareContent:linkUrl;其中 'key' 对应的 sharered 需要和 web 约定一致。
//遵守 webViewJsDelegate 协议
@interfaceTWWebCallBackFunctionHelper() <webViewJsDelegate>
@end
@implementationTWWebCallBackFunctionHelper
- (void)sharered:(NSString*)url shareContent:(NSString*)content linkUrl:(NSString*)lUrl
{
//TODO:
//实现业务逻辑,调起 分享 功能
}
@end
好了,差不多就这样了,在运行过程中,偶现一个bug,点击分享 按钮没有 丝毫 反应,也就是 分享UI组件 没有 调用起来。这是什么鬼呀!
好吧,直接断点 调试,-(void)sharered:shareContent:linkUrl 方法是跑到了,也就是 调用 UI 时没有 反应。考虑是不是线程问题,看了JavaStript 相关定义,果然,“avaScript引擎是单线程运行的”,“JavaStript调用本地方法是在子线程中执行的” ,so...
- (void)sharered:(NSString*)url shareContent:(NSString*)content linkUrl:(NSString*)lUrl
{
//TODO:
//实现业务逻辑,调起 分享 功能
//主线程中去 刷新 UI 等功能
dispatch_async(dispatch_get_main_queue(), ^{
}
});
}
结论
这边只是简单的介绍 JavaScriptCore 最基础的 用法,很轻量。更多的 JavaScriptCore API 可以去查 苹果官方文档。另外在网上搜了下,发现一篇 类似 介绍 OC WebView 与JavaScript 交互 文章,除了 介绍JavaScriptCore 还介绍了 iOS8之后的WKWebView 和 第三点 拦截协议,介绍的都 比我 的详细,贴出来 给大家参考:http://www.jianshu.com/p/f896d73c670a?utm_campaign=hugo&utm_medium=reader_share&utm_content=note&utm_source=weibo