? ? ? ? 這套協議在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.lxweimin.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.lxweimin.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上先寫再復制過來的,各位勉強看吧