WKWebView和UIWebView加载本地html和JS交互各种坑解决办法
来源:互联网 发布:查看mysql启动状态 编辑:程序博客网 时间:2024/06/05 02:25
因为苹果的文件机制,所有的资源文件都相当于放在bundle的路径里,里面不分任何文件夹路径,所以我们在加载(js, css, png)等等的资源文件的时候,不应该加上任何文件名,所以最好是把所有有关html的文件都放在同一平级的文件夹
UIWebView
1.OC调JS
/** * ocCalls:js的函数名 */ JSValue *value = self.jsContext[@"ocCalls"]; /** * @[@"参数"]:传给js端的参数 */ [value callWithArguments:@[@"参数"]];
2.JS调OC
JS调OC有好几种方法,这里我就只列举一种我个人常用的方法,这个可以写在加载之前就行
// 获取js上下文 self.jsContext = [self.webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"]; // 获取js对象,这样会强持有。。没释放对象,目前没解决(个人觉得用单例,这样起码不会一直创建对象,有哪个大神这个可以指教一下嘛0.0) self.jsContext[@"obj"] = self.uihd;
// 个人觉得这两个协议还是分开好,虽然写在一次方便,看起来少,但我觉得逻辑上是比较混乱的// 这是传出去的协议@protocol UIHDelegate <NSObject>- (void)hdOne;- (void)hdTwo:(NSString *)name;- (void)hdThree:(NSString *)name age:(NSString *)age;@end// 这是遵守JS里方法的协议,必须得遵守JSExport协议@protocol JSDelegate <JSExport>// 这里的方法名称和html的函数名称必须相同,同时这个方法的返回值,html里面也能取的到,也相当于另一种传值- (NSString *)one;- (void)two:(NSString *)name;// 多参数写法一:注意,js那边的函数必须驼峰命名- (void)three:(NSString *)name age:(NSString *)age;// 多参数写法二:直接完全和js一样,但后面参数面前不能加名字//- (void)threeAge:(NSString *)name :(NSString *)age;@end// 遵守刚刚写的js协议,然后在.m实现,再通过另一个协议传出去@interface UIHD : NSObject <JSDelegate>@property (nonatomic, weak) id <UIHDelegate> delegate;
self.uihd .m文件
#pragma mark -- JSDelegate- (NSString *)one { // 代理 if ([self.delegate respondsToSelector:@selector(hdOne)]) { [self.delegate hdOne]; } NSLog(@"one"); return @"one";}- (void)two:(NSString *)name { if ([self.delegate respondsToSelector:@selector(hdTwo:)]) { [self.delegate hdTwo:name]; } NSLog(@"two %@", name);}- (void)three:(NSString *)name age:(NSString *)age { if ([self.delegate respondsToSelector:@selector(hdThree:age:)]) { [self.delegate hdThree:name age:age]; } NSLog(@"three %@, %@", name, age);}
html代码
// html代码 创建对象,让UIWebView在外面监听 var obj; // 调用OC方法,并且获取方法返回值 var returnValue = obj.threeAge("老王", "18");
WKWebView
说到WKWebView就一把心酸泪了,最近公司突然说搞h5界面,并且得用性能比较好的,而且还是保持用原生,不用第三方的情况下。就这样,默默的跳进了这个坑里,特别我这边的前端当时还写错html代码,然后我一直以为是我的错~.~,好吧,吐槽到此为止,直接上代码
OC调用JS
/** !!必须在加载完之后才能调用 * 调用的函数,传参数则自己拼接到 () 里面 */ NSString *js = @"tapBtnThree()"; [self.webView evaluateJavaScript:js completionHandler:^(id _Nullable object, NSError * _Nullable error) { if (error) { NSLog(@"error = %@", error); }else { NSLog(@"object = %@", object); } }];
// configuration:WKWebViewConfiguration类,自己查这个是什么鬼 /** !!!注意,这个方法不要填self,连weakSelf都不行,不然会一直强持有,所以这里得重新建一个控制器,当然你也可以想一下其他办法 * @prama Handler:回调人 * @prama name:js方法名称 */ WKMD *delegate = [[WKMD alloc] init]; delegate.delegate = self; /** * @prama Handler:代理 * @prama name:JS发送消息的名字 JS发送消息格式: window.webkit.messageHandlers.hehe.postMessage(message) */ [configuration.userContentController addScriptMessageHandler:delegate name:@"one"];
@protocol WKMDDelegate <NSObject> // 通过代理传js发送的消息出去- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message;@end@interface WKMD : NSObject <WKScriptMessageHandler>@property (nonatomic, weak) id <WKMDDelegate> delegate;@end
WKMD .m文件
#pragma mark -- WKScriptMessageHandler- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message { NSLog(@"WKMD调用代理"); if ([self.delegate respondsToSelector:@selector(userContentController:didReceiveScriptMessage:)]) { [self.delegate userContentController:userContentController didReceiveScriptMessage:message]; }}
html代码
// 这是html里面的代码 // 消息 var message = { 'method' : 'hello', 'param1' : 'liuyanwei', }; // 发送消息 window.webkit.messageHandlers.约定好的消息名.postMessage(消息) window.webkit.messageHandlers.three.postMessage(message);
WKWebView9.0版本以下加载本地html问题
- (void)loadWeb { // 原理就是9.0以下,把文件移到临时文件夹 // 9.0以上 if ([[UIDevice currentDevice].systemVersion floatValue] >= 9.0) { // 取本地html文件路径 NSString *path = [[NSBundle mainBundle] pathForResource:@"index" ofType:@"html"]; if (path) { // 获取本地html的url和资源的url(就是bundle的url) [self.webView loadFileURL:[NSURL fileURLWithPath:path] allowingReadAccessToURL:[NSBundle mainBundle].resourceURL]; } }else { // 9.0以下 // 获取本地文件夹的路径(必须得是蓝色文件夹 Create folder references) NSString *path = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"devyellow_8.0"]; if(path) { NSURL *fileUrl = [NSURL fileURLWithPath:path]; // 把文件夹转到tmp目录 fileUrl = [self fileURLForBuggyWKWebView:fileUrl]; NSURL *realUrl = [NSURL fileURLWithPath:[fileUrl.path stringByAppendingString:@"/index.html"]]; NSURLRequest *request = [NSURLRequest requestWithURL:realUrl]; [self.webView loadRequest:request]; } }}// 9.0以下将文件夹copy到tmp目录- (NSURL *)fileURLForBuggyWKWebView:(NSURL *)fileURL { NSError *error = nil; if (!fileURL.fileURL || ![fileURL checkResourceIsReachableAndReturnError:&error]) { return nil; } NSFileManager *fileManager = [NSFileManager defaultManager]; NSURL *temDirURL = [NSURL fileURLWithPath:NSTemporaryDirectory()]; [fileManager createDirectoryAtURL:temDirURL withIntermediateDirectories:YES attributes:nil error:&error]; NSURL *dstURL = [temDirURL URLByAppendingPathComponent:fileURL.lastPathComponent]; [fileManager removeItemAtURL:dstURL error:&error]; [fileManager copyItemAtURL:fileURL toURL:dstURL error:&error]; return dstURL;}
WKWebView这里还有个坑,当时还有个需求,就是本地的html加载的时候要从我这边获取值才能加载,WKWebView它又不能在加载的时候从我这边获取值,不像UIWebView能直接用一个对象调用OC方法,然后传一个返回值给html。经过各种姿势的查资料,终于想出了一个解决办法,就是加载之前,把要传的值,放到webView的缓存里,然后前端自己从缓存里取值加载!~不废话,直接上代码
/** 其实这个格式和字典一样 * key: 和前端约定好的key * value: 需要传的值 */ NSString *sipNum = [NSString stringWithFormat:@"localStorage.setItem(\"key\", '%@');", @"value"]; /** 添加脚本 * param injectionTime:WKUserScriptInjectionTimeAtDocumentStart在加载之前注入 * param forMainFrameOnly:是否主窗口(其实我也不清楚这个是啥) */ WKUserScript *script = [[WKUserScript alloc] initWithSource:sipNum injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:NO]; [configuration.userContentController addUserScript:script];
阅读全文
0 0
- WKWebView和UIWebView加载本地html和JS交互各种坑解决办法
- UIWebview和WKWebview加载本地html
- UIWebview和WKWebview的使用 js交互 本地加载 网络加载
- UIWebView和WKWebView的使用及js交互
- UIWebView和WKWebView的使用及js交互
- UIWebView和WKWebView的使用及js交互
- WKWebView和UIWebView及其四种交互
- WKWebView详解&WKWebVieW和JS交互
- android webview & ios uiwebview和wkwebview的交互以及本地缓存
- UIWebView和js交互
- UIWebView和Js交互
- WKWebView OC和JS交互
- iOS 加载HTML的相关问题(与JS的互相调用和WKWebView加载本地网页)
- WKWebView 和本地代码交互方式
- UIWebView和WKWebView
- Swift UIWebView 和 WKWebView
- WKWebView和UIWebView
- WKWebView 和UIWebView
- Android线程管理(二)
- instanceof关键字
- 主题模型-LDA浅析
- vs20XX版本 当没有mvc的时候怎么办
- OpenGL ES学习笔记(二)
- WKWebView和UIWebView加载本地html和JS交互各种坑解决办法
- java基础问题
- HDU 1051 Wooden Sticks
- mysql数据库有哪些存储引擎
- Java对象池技术的原理及其实现
- POJ2385-Apple Catching
- URAL
- 《深入理解java虚拟机》学习笔记3——垃圾回收算法
- git安装使用