这套协议在OC的Webview里面主要采用delegate的写法,一般与前端交互不使用第三方框架的情况下,JS给OC传值基本存在三种交互协议,但是每种协议都是需要和前端人员确认好方法名,两边要保持一致。
JS给OC传值,并调用OC方法
1.使用delegate的方式交互,此种方法在iOS7之后提出,通过JavaScriptCore这个框架进行交互,具体的代码在文后给出或者看代码。此种方法有一些需要注意的点,例如
-(NSString *)appVersion:(JSValue *)version{
return"someThing";
}
在网上的一些文章中基本没有提到可以设置返回值,在这个方法里面可以直接return返回值,为同步回调。前端回传的参数类型为JSValue类型,如要解析,需要使用JSValue的toString方法,然后再转为NSDictionary即可。如果不定义接收参数其实使用delegate这种方式也是可以接收的,代码如下
NSArray *arg = [JSContext currentArguments];
JSValue *resouce = arg.firstObject;
此种情况适用于前端需要回传多个参数,但是写法又不能和安卓的冲突的时候。在delegate里面需要注意的还有这些代理方法都是出于子线程的,Xcode9增加了自动检测线程,注意线程问题。
2.使用Block进行交互,此种方法比较方便简洁, OC核心代码:
- (void)webViewDidFinishLoad:(UIWebView *)webView{
JSContext *context = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
context[@"passValue"] = ^{
NSArray *arg = [JSContext currentArguments];
for (id obj in arg) {
NSLog(@"%@", obj);
} };
}
JS核心代码是
function testClick() {
var str1=document.getElementById("text1").value;
var str2=document.getElementById("text2").value;
passValue(str1,str2);
}
注意:此代码需要放在webViewDidFinishLoad里面,这种方法应该是不可以设置前缀的
3.使用拦截协议,两方定好协议头,如果传过来的协议头符合就做相应的处理,多用于页面按钮的一些跳转事件,比如点击客户咨询,跳转到原生的客户咨询界面。
JS代码:
function testClick() {
var str1=document.getElementById("text1").value;
var str2=document.getElementById("text2").value;
// "objc://"为自定义协议头; // str1&str2为要传给OC的值,以":/"作为分隔 window.location.href="objc://"+":/"+str1+":/"+str2;
}
在需要给OC传值的函数里(例如:testClick())写如上格式的代码
OC代码:
//遵守UIWebViewDelegate代理协议。
-(BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType{
//拿到网页的实时url NSString *requestStr = [[request.URL absoluteString] stringByRemovingPercentEncoding]; /
/在url中寻找自定义协议头"objc://"
// 格式 objc://loadUrl/blog.csdn.net 协议/方法/网址
//判断链接中的协议头,如果是objc://, 则进行相关操作
if ([requestStr hasPrefix:@"objc://"]) {
//拿到除去协议头的后部 NSString *urlContent = [urlStr substringFromIndex:[@"objc://" length]]; NSLog(@"%@", urlContent); //用/来拆分字符串
NSArray *urls = [urlContent componentsSeparatedByString:@"/"];
NSLog(@"拆分的结果为:%@", urls);
//怕重复可以多定义一个头aaa,也可省略
if ([@"aaa.toChat" isEqualToString:urls[0]]){
[self pushChatView];
}
return NO;
}
return YES;
}
-(void)pushChatView{
//具体业务代码
}
OC调用JC方法并传值:
[_webView stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:@"window.sendOCData&&window.sendOCData('%@')",parameter]];
parameter是需要传递的值,建议为JSON字符串,注意%@外面是一个单引号,另外传递给JSON的字符串不要使用自动换行方法encode,先把NSDictionary转为NSData再转为NSString,代码如下
NSData *paramsJsonData = [NSJSONSerialization dataWithJSONObject:params options:0 error:nil]; //NSJSONWritingPrettyPrinted不要使用这些加了自动换行的,不然 前端无法接收
NSString * paramsStr = [[NSString alloc] initWithData:paramsJsonData encoding:NSUTF8StringEncoding];
还有如果项目中即用了delegate又使用拦截协议,而且定义的协议头一样,那么会首先执行delegate的,拦截协议无法生效,所以如果需要使用两种,那么请定义不同的协议头。
参考网址:
http://blog.csdn.net/leaderqiu/article/details/51955956 http://www.cnblogs.com/yueyuanyueyuan/p/5651266.html
http://www.cocoachina.com/cms/wap.php?action=article&id=15105 http://blog.csdn.net/u012963325/article/details/51134574
http://www.jianshu.com/p/063d748e072d
delegate的主要代码 OC代码:
#import "ViewController.h"
#import JavaScriptCore/JavaScriptCore.h 尖括号
@protocol JSObjcDelegate
- (void)callCamera;
- (void)share:(NSString *)shareString;
@end
@interface ViewController () UIWebViewDelegate,JSExport 尖括号
@property (nonatomic, strong) JSContext *jsContext;
@property (strong, nonatomic) UIWebView *webView;
@end@implementation ViewController
#pragma mark - Life Circle
- (void)viewDidLoad {
[super viewDidLoad];
self.webView = [[UIWebView alloc]initWithFrame:self.view.bounds];
[self.view addSubview:self.webView];
self.webView.userInteractionEnabled = YES;
NSURL *url = [[NSBundle mainBundle] URLForResource:@"test" withExtension:@"html"]; self.webView.delegate = self; [self.webView loadRequest:[[NSURLRequest alloc] initWithURL:url]];
}
#pragma mark - UIWebViewDelegate
- (void)webViewDidFinishLoad:(UIWebView *)webView {
__weak typeof(self) weakSelf = self; self.jsContext = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
self.jsContext[@"Toyun"] = self;
self.jsContext.exceptionHandler = ^(JSContext *context, JSValue *exceptionValue) {
context.exception = exceptionValue;
NSLog(@"异常信息:%@", exceptionValue
);
};
}
#pragma mark - JSObjcDelegate
- (void)callCamera {
NSLog(@"callCamera"); // 获取到照片之后在回调js的方法picCallback把图片传出去 JSValue *picCallback = self.jsContext[@"picCallback"];
[picCallback callWithArguments:@[@"photos"]];
}
- (void)share:(NSString *)shareString {
NSLog(@"share:%@", shareString); // 分享成功回调js的方法shareCallback JSValue *shareCallback = self.jsContext[@"shareCallback"];
[shareCallback callWithArguments:nil];
}
@end
JS代码:
Objective-C和JavaScript交互的那些事
var callShare = function() {
var shareInfo = JSON.stringify({"title": "标题", "desc": "内容", "shareUrl": "http://www.jianshu.com/p/f896d73c670a",
"shareIco":"http://upload-images.jianshu.io/upload_images/1192353-fd26211d54aea8a9.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240"});
Toyun.share(shareInfo);
}
var picCallback = function(photos) {
alert(photos);
}
var shareCallback = function(){
alert('success');
}
能力有限有错误的话请指出,谢谢,排版是直接先在公司的worktile上先写再复制过来的,各位勉强看吧