├── JavascriptCoreDemo.zip ├── README.md └── WKWebViewDemo ├── OC与JS交互之WKWebView.xcodeproj └── project.pbxproj ├── OC与JS交互之WKWebView ├── AppDelegate.h ├── AppDelegate.m ├── Assets.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── IJSTestController.h ├── IJSTestController.m ├── IJSTestController.xib ├── IJSTestObjc.h ├── IJSTestObjc.m ├── Info.plist ├── SMSDK.js ├── TouchController.h ├── TouchController.m ├── TouchController.xib ├── ViewController.h ├── ViewController.m ├── index.html └── main.m └── README.md /JavascriptCoreDemo.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangjinshan/JSCDemo/93ba1e8c17335dbffca5e8cee3e6ca61827845dd/JavascriptCoreDemo.zip -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # JSCDemo 2 | ios与js交互demo 3 | ### 认识JavaScriptCore.framework 4 | 简书地址:http://www.jianshu.com/p/c7a7c2211be7 5 | #### 项目演示 6 | 7 | ![11.gif](http://upload-images.jianshu.io/upload_images/2845360-ac2e6d5ac71ece40.gif?imageMogr2/auto-orient/strip) 8 | ![94E8E789-02BE-4C1B-80A0-B5272F19BA47.png](http://upload-images.jianshu.io/upload_images/2845360-fecc50801af55aa2.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 9 | 10 | ![107BFC2C-26E3-4395-BE81-8EFD558D3F52.png](http://upload-images.jianshu.io/upload_images/2845360-95351fbd2ddb914d.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 11 | #### 正文 12 | JavaScriptCore.framework 是苹果在ios7之后新增的框架,是对 UIWebView的一次封装,方便开发者使用,使用JavaScriptCore.framework可以轻松实现 ios与js的交互 13 | ##### JavaScriptCore的组成 14 | JavaScriptCore中主要的类 15 | ![java.png](http://upload-images.jianshu.io/upload_images/2845360-8a05a212578bf2db.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 16 | 详细介绍 17 | 1, JSContext --- 在OC中创建JavaScript运行的上下文环境 18 | 19 | ``` 20 | // 创建JSContext对象,获得JavaScript运行的上下文环 21 | - (instancetype)init; 22 | // 在特定的对象空间上创建JSContext对象,获得JavaScript运行的上下文环境 23 | - (instancetype)initWithVirtualMachine:(JSVirtualMachine *)virtualMachine; 24 | // 运行一段js代码,输出结果为JSValue类型 25 | - (JSValue *)evaluateScript:(NSString *)script; 26 | // iOS 8.0以后可以调用此方法 27 | - (JSValue *)evaluateScript:(NSString *)script withSourceURL:(NSURL *)sourceURL NS_AVAILABLE(10_10, 8_0); 28 | // 获取当前正在运行的JavaScript上下文环境 29 | + (JSContext *)currentContext; 30 | // 返回结果当前执行的js函数 function () { [native code] } ,iOS 8.0以后可以调用此方法 31 | + (JSValue *)currentCallee NS_AVAILABLE(10_10, 8_0); 32 | // 返回结果当前方法的调用者[object Window] 33 | + (JSValue *)currentThis; 34 | // 返回结果为当前被调用方法的参数 35 | + (NSArray *)currentArguments; 36 | // js的全局变量 [object Window] 37 | @property (readonly, strong) JSValue *globalObject; 38 | // 返回js 调用时候的异常信息 39 | @property (copy) void(^exceptionHandler)(JSContext *context, JSValue *exception); 40 | // 异常捕获中错误值处理 41 | @property (strong) JSValue *exception; 42 | // 上下文的名字 43 | @property (copy) NSString *name NS_AVAILABLE(10_10, 8_0); 44 | ``` 45 | JSValue --- JavaScript中的变量和方法,可以转成OC数据类型,每个JSValue都和JSContext相关联并且强引用context 46 | OC 和 js 数据对照表 47 | 48 | | Objective-C type |  JavaScript type | 49 | | --- | --- | 50 | | nil  | undefined | 51 | | NSNull  |  null | 52 | | NSString | string | 53 | | NSNumber  | number, boolean | 54 | | NSDictionary | Object object | 55 | | NSArray |  Array object | 56 | | NSDate |  Date object | 57 | | NSBlock (1)  | Function object (1) | 58 | | id (2)  | Wrapper object (2) | 59 | |  Class (3)  | Constructor object (3) | 60 | 61 | ``` 62 | // 在context创建BOOL的JS变量 63 | + (JSValue *)valueWithBool:(BOOL)value inContext:(JSContext *)context; 64 | // 修改JS对象的属性的值 65 | - (void)setValue:(id)value forProperty:(NSString *)property; 66 | // 调用者JSValue对象为JS中的方法名称,arguments为参数,调用JS中Window直接调用的方法 67 | - (JSValue *)callWithArguments:(NSArray *)arguments; 68 | // 调用者JSValue对象为JS中的全局对象名称,method为全局对象的方法名称,arguments为参数 69 | - (JSValue *)invokeMethod:(NSString *)method withArguments:(NSArray *)arguments; 70 | // JS中的结构体类型转换为OC 71 | + (JSValue *)valueWithPoint:(CGPoint)point inContext:(JSContext *)context; 72 | // 将JS变量转换成OC中的BOOL类型/提供了其他方法的转换 73 | - (BOOL)toBool; 74 | // JS中是否有这个对象 75 | // @property (readonly) BOOL isUndefined; 76 | // 比较两个JS对象是否相等 77 | - (BOOL)isEqualToObject:(id)value; 78 | ``` 79 | 3, JSExport --- JS调用OC中的方法和属性写在继承自JSExport的协议当中,OC对象实现自定义的协议 80 | 81 | ``` 82 | 官方给的例子 83 | //@textblock 84 | @protocol MyClassJavaScriptMethods 85 | - (void)foo; 86 | @end 87 | // 方法实现 88 | @interface MyClass : NSObject 89 | - (void)foo; 90 | - (void)bar; 91 | @end 92 | //@/textblock 93 | ``` 94 | 4, JSManagedValue --- JS和OC对象的内存管理辅助对象,主要用来保存JSValue对象,解决OC对象中存储js的值,导致的循环引用问题 95 | 96 | ``` 97 | // 初始化 98 | - (instancetype)initWithValue:(JSValue *)value; 99 | + (JSManagedValue *)managedValueWithValue:(JSValue *)value; 100 | + (JSManagedValue *)managedValueWithValue:(JSValue *)value andOwner:(id)owner NS_AVAILABLE(10_10, 8_0); 101 | ``` 102 | **JSManagedValue本身只弱引用js值,需要调用JSVirtualMachine的addManagedReference:withOwner:把它添加到JSVirtualMachine中,这样如果JavaScript能够找到该JSValue的Objective-C owner,该JSValue的引用就不会被释放**。 103 | 104 | 5, JSVirtualMachine --- JS运行的虚拟机,有独立的堆空间和垃圾回收机制,运行在不同虚拟机环境的JSContext可以通过此类通信。 105 | 106 | ``` 107 | // 初始化 108 | - (instancetype)init; 109 | // 添加 110 | - (void)addManagedReference:(id)object withOwner:(id)owner; 111 | // 移除 112 | - (void)removeManagedReference:(id)object withOwner:(id)owner; 113 | ``` 114 | 到此 JavaScriptCore.framework 能够使用的基本api已经介绍完毕 115 |
116 | 下面我们以简单集成SMSDK为 实际例子进行讲解 117 | 首先创建必要的三个文件 SMSDK.html/ SMSDK.cc SMSDK.js 在viewDidLoad中创建webview进行加载SDMSDK.html 118 | #### iOS调用 js 119 | 120 | ![jsios.png](http://upload-images.jianshu.io/upload_images/2845360-3ad5a055a460bc13.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 121 | js中方法的实现 122 | 123 | ``` 124 | 在 SMSDK.js中 创建 ios需要的初始化对象 并保留一个 对象接口 方便在 html中 调用这个方法 125 | SMSDK.js 126 | function SMSDK() 127 | { 128 | // 不能添加 alert() 等外部的方法 129 | // alert(--qq--); 130 | var name = "金山"; 131 | this.initSDK = function (hello) 132 | { 133 | var initData ={}; 134 | var appkey = 135 | { 136 | "appkey":"f3fc6baa9ac4" 137 | } 138 | var appSecrect= 139 | { 140 | "appSecrect":"7f3dedcb36d92deebcb373af921d635a" 141 | } 142 | initData["appkey"] = appkey; 143 | initData["appSecrect"] = appSecrect; 144 | return initData; 145 | }; 146 | // 必须使用this 关键字 147 | } 148 | var $smsdk = new SMSDK(); 149 | 在 SMSDK.html中进行引用并 创建js 方法 150 | 156 | 这里的 initSDK(); 方法就是留给ios 调用的方法 157 | ``` 158 | 我们同样选择在网页加载完成的方法中进行方法调用 159 | 160 | ``` 161 | -(void) webViewDidFinishLoad:(UIWebView *)webView 162 | { 163 | [self initSMSDK]; 164 | } 165 | 实现 方法 166 | -(void) initSMSDK 167 | { 168 | // 创建上下文 169 | // 1.这种方式需要传入一个JSVirtualMachine对象,如果传nil,会导致应用崩溃的。 170 | JSVirtualMachine *JSVM = [[JSVirtualMachine alloc] init]; 171 | JSContext *jscontext = [[JSContext alloc] initWithVirtualMachine:JSVM]; 172 | 2.这种方式,内部会自动创建一个JSVirtualMachine对象,可以通过JSCtx.virtualMachine 173 | // 看其是否创建了一个JSVirtualMachine对象。 174 | JSContext *jscontext = [[JSContext alloc] init]; 175 | /**********以上的方法经过测试都不好使*************/ 176 | 正确的姿势 177 | 1, 创建上下文,意思就是让oc和js 同处于一个环境,方便进行方法调用 178 | JSContext *jscontext = [self.mywebview valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"]; 179 | 2 参数接受 注意一定输传递方法的名字,不要加()// 和webview的调用方法的区别 180 | JSValue *jsvalue = jscontext[@"initSDK"]; // 返回的是方法的名字和内容 181 | 3 调用函数/传递参数 182 | JSValue *initData = [jsvalue callWithArguments:@[@"从oc中传递第一个参数进去"]]; 183 | 接收到的字典对象进行解析,并调用SMSDK的初始化方法 184 | NSDictionary *dic = [initData toDictionary]; 185 | NSString *appkey = dic[@"appkey"][@"appkey"]; 186 | NSString *appSecrect = dic[@"appSecrect"][@"appSecrect"]; 187 | [SMSSDK registerApp:appkey withSecret:appSecrect]; 188 | } 189 | ``` 190 | 我们通过打印上面的 appkey 等参数就知道 实现了ios调用 js的方法 191 | 192 | #### js调用 ios 193 | 194 | 可以通过两种方式在JavaScript中调用Objective-C: 195 | Blocks: 对应JS函数 196 | JSExport协议: 对应JS对象 197 | 我们先实现 block的方法 198 | 199 | Block的方法 200 | 首先在html中 写一个button的点击方法 201 | 202 | ``` 203 | 204 | ``` 205 | getCode()方法就是将来 ios 中需要注册的方法体, 里面是对js返回参数方法的调用 相当于 getCode('返回给js的参数,在参数列表中调用就可以'); 206 | 207 | ``` 208 | 过程和上面一样 209 | // 1,获取上下文 // 下文weakSelf.jsContext 中已经在属性中保存jscontext 210 | JSContext *_jsContext = [self.mywebview valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"]; 211 | // 2 异常捕获机制 212 | _jsContext.exceptionHandler = ^(JSContext *context, JSValue *exception) { 213 | context.exception = exception; 214 | //别忘了给exception赋值,否则JSContext的异常信息为空 215 | NSLog(@"---错误数据的处理----%@",exception); 216 | }; 217 | __weak typeof (self) weakSelf = self; // 防止循环引用就加上 __weak 218 | _jsContext[@"getCode"] = ^ (){ 219 | 220 | NSArray *arr =[JSContext currentArguments]; // 获取当前的上下文,然后加载 js返回的参数列表 221 | for (id objc in arr) { 222 | weakSelf.phoneNumber = objc; 223 | [SMSSDK getVerificationCodeByMethod:SMSGetCodeMethodSMS phoneNumber:objc zone:@"86" customIdentifier:nil result:^(NSError *error) { 224 | JSContext *jscontext = weakSelf.jsContext; 225 | if (!error) 226 | { 227 | // ios回调 js的代码 并传递参数给 js 228 | JSValue *jsvalue = jscontext[@"getCodeCallBack"]; // 注入方法 229 | [jsvalue callWithArguments:@[@"获取短信验证码成功"]]; // 调用方法 230 | } 231 | else 232 | { 233 | JSValue *jsvalue = jscontext[@"getCodeCallBack"]; // 注入方法 234 | [jsvalue callWithArguments:@[@"获取验证码失败"]]; 235 | } 236 | }]; 237 | } 238 | }; 239 | ``` 240 | 通过上面的方法我们知道, block 方法 ios 给 js传递的是方法 ,如果传递 对象则需要用到 协议的方法 241 | 首先我们来看一个最简单的例子 : 242 | 在 js 上写一个 点击事件,然后调用 ios 的方法 243 | 在 js中 244 | 245 | ``` 246 | 在 SMDK.html中添加 247 |
248 | 249 |
250 | 说明: 这里的 objc 对象就是将来我们需要在 ios中注册的对象, takePicture() ,就是在协议中的方法 251 | ``` 252 | 在viewController.m中,定义协议 253 | 254 | ``` 255 | /** 256 | * 实现js代理,js调用ios的入口就在这里 257 | */ 258 | @protocol JSDelegate 259 | 260 | - (void)getImage:(id)parameter;// 这个方法就是window.document.iosDelegate.getImage(JSON.stringify(parameter)); 中的 getImage()方法 261 | 262 | @end 263 | ``` 264 | 签订协议: 注意这里的协议不需要实现,在外部也不需要设置代理,直接实现就可以 265 | 266 | ``` 267 | @interface ViewController () 268 | ``` 269 | 在网页加载完成的代理中实现, 上下文 270 | 271 | ``` 272 | self.jsContext = [self.myWebView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"]; 273 | // 测试处理 274 | self.jsContext[@"objc"] = self;//挂上代理 iosDelegate是window.document.iosDelegate.getImage(JSON.stringify(parameter)); 中的 iosDelegate 275 | self.jsContext.exceptionHandler = ^(JSContext *context, JSValue *exception){ 276 | context.exception = exception; 277 | NSLog(@"js方法写错了 错误的信息都会在此处输出:%@",exception); 278 | }; 279 | ``` 280 | 最后一步就是实现 在 js中声明的协议方法 281 | 282 | ``` 283 | // 协议实现 284 | - (void)getImage:(id)parameter 285 | { 286 | NSArray *arr =[JSContext currentArguments]; 287 | for (id objc in arr) 288 | { 289 | NSLog(@"=-----%@",[objc toDictionary]); 290 | } 291 | [self beginOpenPhoto]; // 相机的处理, 292 | } 293 | ``` 294 | 实现相机的方法,很简单, 里面的数据传递和上文中说到的一个样子,这里将不再赘述. 295 | 到此, 利用协议实现 js 调用 ios的方法基本完成 296 | 297 | 关于内存泄漏,循环引用的问题 注意不要在 block中直接 引用外部 强引用的对象就可以 298 | 299 | ``` 300 | __weak typeof (self) weakSelf = self; // 防止循环引用就加上 __weak 301 | _jsContext[@"getCode"] = ^ (id oc){ 302 | NSArray *arr =[JSContext currentArguments]; // 获取当前的上下文 303 | for (id objc in arr) { 304 | weakSelf.phoneNumber = objc; 305 | 这个 weakSelf 的处理就ok 306 | ``` 307 | 308 | 简书地址:http://www.jianshu.com/p/c7a7c2211be7 309 |
310 | -------------------------------------------------------------------------------- /WKWebViewDemo/OC与JS交互之WKWebView.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 74222BAC20D00D990049ACF2 /* IJSTestObjc.m in Sources */ = {isa = PBXBuildFile; fileRef = 74222BAB20D00D990049ACF2 /* IJSTestObjc.m */; }; 11 | 74222BB220D0AB860049ACF2 /* IJSTestController.m in Sources */ = {isa = PBXBuildFile; fileRef = 74222BB020D0AB860049ACF2 /* IJSTestController.m */; }; 12 | 74222BB320D0AB860049ACF2 /* IJSTestController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 74222BB120D0AB860049ACF2 /* IJSTestController.xib */; }; 13 | 74301AF720D10E13008EF5C3 /* TouchController.m in Sources */ = {isa = PBXBuildFile; fileRef = 74301AF520D10E13008EF5C3 /* TouchController.m */; }; 14 | 74301AF820D10E13008EF5C3 /* TouchController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 74301AF620D10E13008EF5C3 /* TouchController.xib */; }; 15 | 7443556D20CE7FFB00D8B45A /* SMSDK.js in Resources */ = {isa = PBXBuildFile; fileRef = 7443556C20CE7FFA00D8B45A /* SMSDK.js */; }; 16 | CE9947121D65C79800F38608 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = CE9947111D65C79800F38608 /* main.m */; }; 17 | CE9947151D65C79800F38608 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = CE9947141D65C79800F38608 /* AppDelegate.m */; }; 18 | CE9947181D65C79800F38608 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = CE9947171D65C79800F38608 /* ViewController.m */; }; 19 | CE99471B1D65C79800F38608 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = CE9947191D65C79800F38608 /* Main.storyboard */; }; 20 | CE99471D1D65C79800F38608 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = CE99471C1D65C79800F38608 /* Assets.xcassets */; }; 21 | CE9947201D65C79800F38608 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = CE99471E1D65C79800F38608 /* LaunchScreen.storyboard */; }; 22 | CE9947281D66B5FF00F38608 /* index.html in Resources */ = {isa = PBXBuildFile; fileRef = CE9947271D66B5FF00F38608 /* index.html */; }; 23 | /* End PBXBuildFile section */ 24 | 25 | /* Begin PBXFileReference section */ 26 | 74222BAA20D00D990049ACF2 /* IJSTestObjc.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IJSTestObjc.h; sourceTree = ""; }; 27 | 74222BAB20D00D990049ACF2 /* IJSTestObjc.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IJSTestObjc.m; sourceTree = ""; }; 28 | 74222BAF20D0AB860049ACF2 /* IJSTestController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IJSTestController.h; sourceTree = ""; }; 29 | 74222BB020D0AB860049ACF2 /* IJSTestController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IJSTestController.m; sourceTree = ""; }; 30 | 74222BB120D0AB860049ACF2 /* IJSTestController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = IJSTestController.xib; sourceTree = ""; }; 31 | 74301AF420D10E13008EF5C3 /* TouchController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TouchController.h; sourceTree = ""; }; 32 | 74301AF520D10E13008EF5C3 /* TouchController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TouchController.m; sourceTree = ""; }; 33 | 74301AF620D10E13008EF5C3 /* TouchController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = TouchController.xib; sourceTree = ""; }; 34 | 7443556C20CE7FFA00D8B45A /* SMSDK.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = SMSDK.js; sourceTree = ""; }; 35 | CE99470D1D65C79800F38608 /* OC与JS交互之WKWebView.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "OC与JS交互之WKWebView.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 36 | CE9947111D65C79800F38608 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 37 | CE9947131D65C79800F38608 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 38 | CE9947141D65C79800F38608 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 39 | CE9947161D65C79800F38608 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 40 | CE9947171D65C79800F38608 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 41 | CE99471A1D65C79800F38608 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 42 | CE99471C1D65C79800F38608 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 43 | CE99471F1D65C79800F38608 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 44 | CE9947211D65C79800F38608 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 45 | CE9947271D66B5FF00F38608 /* index.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = index.html; sourceTree = ""; }; 46 | /* End PBXFileReference section */ 47 | 48 | /* Begin PBXFrameworksBuildPhase section */ 49 | CE99470A1D65C79800F38608 /* Frameworks */ = { 50 | isa = PBXFrameworksBuildPhase; 51 | buildActionMask = 2147483647; 52 | files = ( 53 | ); 54 | runOnlyForDeploymentPostprocessing = 0; 55 | }; 56 | /* End PBXFrameworksBuildPhase section */ 57 | 58 | /* Begin PBXGroup section */ 59 | CE9947041D65C79800F38608 = { 60 | isa = PBXGroup; 61 | children = ( 62 | CE99470F1D65C79800F38608 /* OC与JS交互之WKWebView */, 63 | CE99470E1D65C79800F38608 /* Products */, 64 | ); 65 | sourceTree = ""; 66 | }; 67 | CE99470E1D65C79800F38608 /* Products */ = { 68 | isa = PBXGroup; 69 | children = ( 70 | CE99470D1D65C79800F38608 /* OC与JS交互之WKWebView.app */, 71 | ); 72 | name = Products; 73 | sourceTree = ""; 74 | }; 75 | CE99470F1D65C79800F38608 /* OC与JS交互之WKWebView */ = { 76 | isa = PBXGroup; 77 | children = ( 78 | CE9947271D66B5FF00F38608 /* index.html */, 79 | 7443556C20CE7FFA00D8B45A /* SMSDK.js */, 80 | CE9947131D65C79800F38608 /* AppDelegate.h */, 81 | CE9947141D65C79800F38608 /* AppDelegate.m */, 82 | CE9947161D65C79800F38608 /* ViewController.h */, 83 | CE9947171D65C79800F38608 /* ViewController.m */, 84 | 74222BAF20D0AB860049ACF2 /* IJSTestController.h */, 85 | 74222BB020D0AB860049ACF2 /* IJSTestController.m */, 86 | 74222BB120D0AB860049ACF2 /* IJSTestController.xib */, 87 | 74301AF420D10E13008EF5C3 /* TouchController.h */, 88 | 74301AF520D10E13008EF5C3 /* TouchController.m */, 89 | 74301AF620D10E13008EF5C3 /* TouchController.xib */, 90 | 74222BAA20D00D990049ACF2 /* IJSTestObjc.h */, 91 | 74222BAB20D00D990049ACF2 /* IJSTestObjc.m */, 92 | CE9947191D65C79800F38608 /* Main.storyboard */, 93 | CE99471C1D65C79800F38608 /* Assets.xcassets */, 94 | CE99471E1D65C79800F38608 /* LaunchScreen.storyboard */, 95 | CE9947211D65C79800F38608 /* Info.plist */, 96 | CE9947101D65C79800F38608 /* Supporting Files */, 97 | ); 98 | path = "OC与JS交互之WKWebView"; 99 | sourceTree = ""; 100 | }; 101 | CE9947101D65C79800F38608 /* Supporting Files */ = { 102 | isa = PBXGroup; 103 | children = ( 104 | CE9947111D65C79800F38608 /* main.m */, 105 | ); 106 | name = "Supporting Files"; 107 | sourceTree = ""; 108 | }; 109 | /* End PBXGroup section */ 110 | 111 | /* Begin PBXNativeTarget section */ 112 | CE99470C1D65C79800F38608 /* OC与JS交互之WKWebView */ = { 113 | isa = PBXNativeTarget; 114 | buildConfigurationList = CE9947241D65C79800F38608 /* Build configuration list for PBXNativeTarget "OC与JS交互之WKWebView" */; 115 | buildPhases = ( 116 | CE9947091D65C79800F38608 /* Sources */, 117 | CE99470A1D65C79800F38608 /* Frameworks */, 118 | CE99470B1D65C79800F38608 /* Resources */, 119 | ); 120 | buildRules = ( 121 | ); 122 | dependencies = ( 123 | ); 124 | name = "OC与JS交互之WKWebView"; 125 | productName = "OC与JS交互之WKWebView"; 126 | productReference = CE99470D1D65C79800F38608 /* OC与JS交互之WKWebView.app */; 127 | productType = "com.apple.product-type.application"; 128 | }; 129 | /* End PBXNativeTarget section */ 130 | 131 | /* Begin PBXProject section */ 132 | CE9947051D65C79800F38608 /* Project object */ = { 133 | isa = PBXProject; 134 | attributes = { 135 | LastUpgradeCheck = 0730; 136 | ORGANIZATIONNAME = rrcc; 137 | TargetAttributes = { 138 | CE99470C1D65C79800F38608 = { 139 | CreatedOnToolsVersion = 7.3.1; 140 | DevelopmentTeam = 7V3U9AVLEY; 141 | }; 142 | }; 143 | }; 144 | buildConfigurationList = CE9947081D65C79800F38608 /* Build configuration list for PBXProject "OC与JS交互之WKWebView" */; 145 | compatibilityVersion = "Xcode 3.2"; 146 | developmentRegion = English; 147 | hasScannedForEncodings = 0; 148 | knownRegions = ( 149 | en, 150 | Base, 151 | ); 152 | mainGroup = CE9947041D65C79800F38608; 153 | productRefGroup = CE99470E1D65C79800F38608 /* Products */; 154 | projectDirPath = ""; 155 | projectRoot = ""; 156 | targets = ( 157 | CE99470C1D65C79800F38608 /* OC与JS交互之WKWebView */, 158 | ); 159 | }; 160 | /* End PBXProject section */ 161 | 162 | /* Begin PBXResourcesBuildPhase section */ 163 | CE99470B1D65C79800F38608 /* Resources */ = { 164 | isa = PBXResourcesBuildPhase; 165 | buildActionMask = 2147483647; 166 | files = ( 167 | CE9947201D65C79800F38608 /* LaunchScreen.storyboard in Resources */, 168 | 74222BB320D0AB860049ACF2 /* IJSTestController.xib in Resources */, 169 | 7443556D20CE7FFB00D8B45A /* SMSDK.js in Resources */, 170 | CE9947281D66B5FF00F38608 /* index.html in Resources */, 171 | CE99471D1D65C79800F38608 /* Assets.xcassets in Resources */, 172 | CE99471B1D65C79800F38608 /* Main.storyboard in Resources */, 173 | 74301AF820D10E13008EF5C3 /* TouchController.xib in Resources */, 174 | ); 175 | runOnlyForDeploymentPostprocessing = 0; 176 | }; 177 | /* End PBXResourcesBuildPhase section */ 178 | 179 | /* Begin PBXSourcesBuildPhase section */ 180 | CE9947091D65C79800F38608 /* Sources */ = { 181 | isa = PBXSourcesBuildPhase; 182 | buildActionMask = 2147483647; 183 | files = ( 184 | CE9947181D65C79800F38608 /* ViewController.m in Sources */, 185 | 74301AF720D10E13008EF5C3 /* TouchController.m in Sources */, 186 | CE9947151D65C79800F38608 /* AppDelegate.m in Sources */, 187 | 74222BB220D0AB860049ACF2 /* IJSTestController.m in Sources */, 188 | 74222BAC20D00D990049ACF2 /* IJSTestObjc.m in Sources */, 189 | CE9947121D65C79800F38608 /* main.m in Sources */, 190 | ); 191 | runOnlyForDeploymentPostprocessing = 0; 192 | }; 193 | /* End PBXSourcesBuildPhase section */ 194 | 195 | /* Begin PBXVariantGroup section */ 196 | CE9947191D65C79800F38608 /* Main.storyboard */ = { 197 | isa = PBXVariantGroup; 198 | children = ( 199 | CE99471A1D65C79800F38608 /* Base */, 200 | ); 201 | name = Main.storyboard; 202 | sourceTree = ""; 203 | }; 204 | CE99471E1D65C79800F38608 /* LaunchScreen.storyboard */ = { 205 | isa = PBXVariantGroup; 206 | children = ( 207 | CE99471F1D65C79800F38608 /* Base */, 208 | ); 209 | name = LaunchScreen.storyboard; 210 | sourceTree = ""; 211 | }; 212 | /* End PBXVariantGroup section */ 213 | 214 | /* Begin XCBuildConfiguration section */ 215 | CE9947221D65C79800F38608 /* Debug */ = { 216 | isa = XCBuildConfiguration; 217 | buildSettings = { 218 | ALWAYS_SEARCH_USER_PATHS = NO; 219 | CLANG_ANALYZER_NONNULL = YES; 220 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 221 | CLANG_CXX_LIBRARY = "libc++"; 222 | CLANG_ENABLE_MODULES = YES; 223 | CLANG_ENABLE_OBJC_ARC = YES; 224 | CLANG_WARN_BOOL_CONVERSION = YES; 225 | CLANG_WARN_CONSTANT_CONVERSION = YES; 226 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 227 | CLANG_WARN_EMPTY_BODY = YES; 228 | CLANG_WARN_ENUM_CONVERSION = YES; 229 | CLANG_WARN_INT_CONVERSION = YES; 230 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 231 | CLANG_WARN_UNREACHABLE_CODE = YES; 232 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 233 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 234 | COPY_PHASE_STRIP = NO; 235 | DEBUG_INFORMATION_FORMAT = dwarf; 236 | ENABLE_STRICT_OBJC_MSGSEND = YES; 237 | ENABLE_TESTABILITY = YES; 238 | GCC_C_LANGUAGE_STANDARD = gnu99; 239 | GCC_DYNAMIC_NO_PIC = NO; 240 | GCC_NO_COMMON_BLOCKS = YES; 241 | GCC_OPTIMIZATION_LEVEL = 0; 242 | GCC_PREPROCESSOR_DEFINITIONS = ( 243 | "DEBUG=1", 244 | "$(inherited)", 245 | ); 246 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 247 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 248 | GCC_WARN_UNDECLARED_SELECTOR = YES; 249 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 250 | GCC_WARN_UNUSED_FUNCTION = YES; 251 | GCC_WARN_UNUSED_VARIABLE = YES; 252 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 253 | MTL_ENABLE_DEBUG_INFO = YES; 254 | ONLY_ACTIVE_ARCH = YES; 255 | SDKROOT = iphoneos; 256 | }; 257 | name = Debug; 258 | }; 259 | CE9947231D65C79800F38608 /* Release */ = { 260 | isa = XCBuildConfiguration; 261 | buildSettings = { 262 | ALWAYS_SEARCH_USER_PATHS = NO; 263 | CLANG_ANALYZER_NONNULL = YES; 264 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 265 | CLANG_CXX_LIBRARY = "libc++"; 266 | CLANG_ENABLE_MODULES = YES; 267 | CLANG_ENABLE_OBJC_ARC = YES; 268 | CLANG_WARN_BOOL_CONVERSION = YES; 269 | CLANG_WARN_CONSTANT_CONVERSION = YES; 270 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 271 | CLANG_WARN_EMPTY_BODY = YES; 272 | CLANG_WARN_ENUM_CONVERSION = YES; 273 | CLANG_WARN_INT_CONVERSION = YES; 274 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 275 | CLANG_WARN_UNREACHABLE_CODE = YES; 276 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 277 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 278 | COPY_PHASE_STRIP = NO; 279 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 280 | ENABLE_NS_ASSERTIONS = NO; 281 | ENABLE_STRICT_OBJC_MSGSEND = YES; 282 | GCC_C_LANGUAGE_STANDARD = gnu99; 283 | GCC_NO_COMMON_BLOCKS = YES; 284 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 285 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 286 | GCC_WARN_UNDECLARED_SELECTOR = YES; 287 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 288 | GCC_WARN_UNUSED_FUNCTION = YES; 289 | GCC_WARN_UNUSED_VARIABLE = YES; 290 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 291 | MTL_ENABLE_DEBUG_INFO = NO; 292 | SDKROOT = iphoneos; 293 | VALIDATE_PRODUCT = YES; 294 | }; 295 | name = Release; 296 | }; 297 | CE9947251D65C79800F38608 /* Debug */ = { 298 | isa = XCBuildConfiguration; 299 | buildSettings = { 300 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 301 | DEVELOPMENT_TEAM = 7V3U9AVLEY; 302 | INFOPLIST_FILE = "OC与JS交互之WKWebView/Info.plist"; 303 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 304 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 305 | PRODUCT_BUNDLE_IDENTIFIER = "com.renrencaichang.OC-JS---WKWebView"; 306 | PRODUCT_NAME = "$(TARGET_NAME)"; 307 | }; 308 | name = Debug; 309 | }; 310 | CE9947261D65C79800F38608 /* Release */ = { 311 | isa = XCBuildConfiguration; 312 | buildSettings = { 313 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 314 | DEVELOPMENT_TEAM = 7V3U9AVLEY; 315 | INFOPLIST_FILE = "OC与JS交互之WKWebView/Info.plist"; 316 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 317 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 318 | PRODUCT_BUNDLE_IDENTIFIER = "com.renrencaichang.OC-JS---WKWebView"; 319 | PRODUCT_NAME = "$(TARGET_NAME)"; 320 | }; 321 | name = Release; 322 | }; 323 | /* End XCBuildConfiguration section */ 324 | 325 | /* Begin XCConfigurationList section */ 326 | CE9947081D65C79800F38608 /* Build configuration list for PBXProject "OC与JS交互之WKWebView" */ = { 327 | isa = XCConfigurationList; 328 | buildConfigurations = ( 329 | CE9947221D65C79800F38608 /* Debug */, 330 | CE9947231D65C79800F38608 /* Release */, 331 | ); 332 | defaultConfigurationIsVisible = 0; 333 | defaultConfigurationName = Release; 334 | }; 335 | CE9947241D65C79800F38608 /* Build configuration list for PBXNativeTarget "OC与JS交互之WKWebView" */ = { 336 | isa = XCConfigurationList; 337 | buildConfigurations = ( 338 | CE9947251D65C79800F38608 /* Debug */, 339 | CE9947261D65C79800F38608 /* Release */, 340 | ); 341 | defaultConfigurationIsVisible = 0; 342 | defaultConfigurationName = Release; 343 | }; 344 | /* End XCConfigurationList section */ 345 | }; 346 | rootObject = CE9947051D65C79800F38608 /* Project object */; 347 | } 348 | -------------------------------------------------------------------------------- /WKWebViewDemo/OC与JS交互之WKWebView/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // OC与JS交互之WKWebView 4 | // 5 | // Created by user on 16/8/18. 6 | // Copyright © 2016年 rrcc. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /WKWebViewDemo/OC与JS交互之WKWebView/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // OC与JS交互之WKWebView 4 | // 5 | // Created by user on 16/8/18. 6 | // Copyright © 2016年 rrcc. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | @interface AppDelegate () 12 | 13 | @end 14 | 15 | @implementation AppDelegate 16 | 17 | 18 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 19 | { 20 | // Override point for customization after application launch. 21 | 22 | 23 | 24 | return YES; 25 | } 26 | 27 | - (void)applicationWillResignActive:(UIApplication *)application { 28 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 29 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 30 | } 31 | 32 | - (void)applicationDidEnterBackground:(UIApplication *)application { 33 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 34 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 35 | } 36 | 37 | - (void)applicationWillEnterForeground:(UIApplication *)application { 38 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 39 | } 40 | 41 | - (void)applicationDidBecomeActive:(UIApplication *)application { 42 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 43 | } 44 | 45 | - (void)applicationWillTerminate:(UIApplication *)application { 46 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 47 | } 48 | 49 | @end 50 | -------------------------------------------------------------------------------- /WKWebViewDemo/OC与JS交互之WKWebView/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | } 33 | ], 34 | "info" : { 35 | "version" : 1, 36 | "author" : "xcode" 37 | } 38 | } -------------------------------------------------------------------------------- /WKWebViewDemo/OC与JS交互之WKWebView/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /WKWebViewDemo/OC与JS交互之WKWebView/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 36 | 48 | 60 | 67 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /WKWebViewDemo/OC与JS交互之WKWebView/IJSTestController.h: -------------------------------------------------------------------------------- 1 | // 2 | // IJSTestController.h 3 | // OC与JS交互之WKWebView 4 | // 5 | // Created by 山神 on 2018/6/13. 6 | // Copyright © 2018年 rrcc. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface IJSTestController : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /WKWebViewDemo/OC与JS交互之WKWebView/IJSTestController.m: -------------------------------------------------------------------------------- 1 | 2 | 3 | // 4 | // IJSTestController.m 5 | // OC与JS交互之WKWebView 6 | // 7 | // Created by 山神 on 2018/6/13. 8 | // Copyright © 2018年 rrcc. All rights reserved. 9 | // 10 | 11 | #import "IJSTestController.h" 12 | #import 13 | #import "IJSTestObjc.h" 14 | #import "TouchController.h" 15 | 16 | @interface IJSTestController () 17 | 18 | @property (weak, nonatomic) IBOutlet UIView *backView; 19 | 20 | @property(nonatomic,strong) WKWebView *wkwebV; // 参数说明 21 | @property(nonatomic,strong) IJSTestObjc *objc; // 参数说明 22 | @property (weak, nonatomic) IBOutlet UIProgressView *wkProgressV; 23 | @property(nonatomic,strong) TouchController *touchVc; // 参数说明 24 | 25 | @end 26 | 27 | @implementation IJSTestController 28 | 29 | - (void)viewDidLoad 30 | { 31 | [super viewDidLoad]; 32 | self.view.backgroundColor =[UIColor greenColor]; 33 | [self _setupWK]; 34 | } 35 | -(void)viewWillLayoutSubviews 36 | { 37 | [super viewWillLayoutSubviews]; 38 | self.wkwebV.frame = CGRectMake(0, 0, self.backView.frame.size.width, self.backView.frame.size.height); 39 | } 40 | 41 | - (void)_setupWK 42 | { 43 | self.objc =[IJSTestObjc new]; 44 | // 进程池配置 45 | WKWebViewConfiguration * config = [[WKWebViewConfiguration alloc]init]; 46 | config.applicationNameForUserAgent = @"applicationNameForUserAgent应用名称"; 47 | config.ignoresViewportScaleLimits =YES; // 允许页面缩放 48 | config.suppressesIncrementalRendering = NO; // 是否抑制内容渲染呈现,直到它完全载入内存 49 | config.allowsInlineMediaPlayback = NO; // 不使用系统的播放器 50 | config.allowsAirPlayForMediaPlayback =YES; //是否允许AirPlay播放媒体 51 | config.allowsPictureInPictureMediaPlayback =YES; // 是否允许HTML5视屏以画中画形式播放,iPhone不支持 52 | config.mediaTypesRequiringUserActionForPlayback = WKAudiovisualMediaTypeVideo; //哪些媒体类型需要用户手势才能开始播放 53 | 54 | config.selectionGranularity = WKSelectionGranularityDynamic; //用户可以在WebView中交互式地选择内容的粒度级别,比如说,当使用WKSelectionGranularityDynamic时,而所选择的内容是单个块,这时候granularity可能会是单个字符;当所选择的web内容不限制于某个块时,granularity可能会是单个块。 55 | config.dataDetectorTypes = WKDataDetectorTypeLink; 56 | /* 57 | WKDataDetectorTypeNone //不执行检测 58 | WKDataDetectorTypePhoneNumber // 电话号码 59 | WKDataDetectorTypeLink //文本中的url 60 | WKDataDetectorTypeAddress // 地址 61 | WKDataDetectorTypeCalendarEvent //在未来的日期和时间 62 | WKDataDetectorTypeTrackingNumber // 跟踪号码/查询号/运单号 63 | WKDataDetectorTypeFlightNumber // 航班号 64 | WKDataDetectorTypeLookupSuggestion 65 | WKDataDetectorTypeAll = NSUIntegerMax, //所有 66 | */ 67 | // 暂时不知道干啥用的 68 | [config setURLSchemeHandler:self.objc forURLScheme:@"weixin"]; 69 | id urlscheme = [config urlSchemeHandlerForURLScheme:@"weixin"]; 70 | 71 | WKPreferences *preferences = [[WKPreferences alloc]init]; 72 | preferences.minimumFontSize = 10; //最小字体的尺寸 73 | preferences.javaScriptEnabled =YES; //是否启用JavaScript,设置为NO将会禁用页面加载的或执行的JavaScript,但这个配置不会影响用户的script 74 | preferences.javaScriptCanOpenWindowsAutomatically =YES;//是否可以在没有用户操作的情况下自动打开窗口 75 | config.preferences = preferences; 76 | 77 | 78 | WKProcessPool *processPool = [[WKProcessPool alloc]init]; 79 | config.processPool =processPool; 80 | 81 | WKUserContentController *userContentController =[[WKUserContentController alloc]init]; 82 | config.userContentController = userContentController; 83 | 84 | WKWebsiteDataStore *websiteDataStore = [WKWebsiteDataStore nonPersistentDataStore]; //无痕浏览 85 | config.websiteDataStore = websiteDataStore; 86 | 87 | // 属性设置 88 | self.wkwebV =[[WKWebView alloc]initWithFrame:CGRectZero configuration:config]; 89 | [self.backView insertSubview:self.wkwebV atIndex:0]; 90 | self.wkwebV.allowsBackForwardNavigationGestures = YES; // 全屏滑动 91 | self.wkwebV.allowsLinkPreview = YES; //按住预览 92 | 93 | self.wkwebV.navigationDelegate = self; 94 | self.wkwebV.UIDelegate = self; 95 | 96 | // ios11添加规则 97 | WKContentRuleListStore *rulerListStrore =[WKContentRuleListStore defaultStore]; 98 | 99 | 100 | NSString *javaScriptSource = @"function userFunc(){window.confirm('sometext');}"; //@"function userFunc(){ alert('警告')}"; 101 | WKUserScript *userScript = [[WKUserScript alloc] initWithSource:javaScriptSource injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:NO]; 102 | // forMainFrameOnly:NO(全局窗口),yes(只限主窗口) 103 | [config.userContentController addUserScript:userScript]; 104 | 105 | NSString *filePath = [[NSBundle mainBundle] pathForResource:@"index" ofType:@"html"]; 106 | NSURL *baseURL = [[NSBundle mainBundle] bundleURL]; 107 | // [self.wkwebV loadHTMLString:[NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil] baseURL:baseURL]; 108 | 109 | [self.wkwebV loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"https://v.qq.com/x/cover/7casb7nes159mrl.html?ptag=baidu.video.paymovie&frp=v.baidu.com%2Fmovie_intro%2F&vfm=bdvtx"]]]; 110 | 111 | [self.wkwebV.configuration.userContentController addScriptMessageHandler:self.objc name:@"showName"]; 112 | [config.userContentController addScriptMessageHandler:self.objc name:@"userFunc"]; 113 | 114 | [self.wkwebV addObserver:self forKeyPath:@"estimatedProgress" options:NSKeyValueObservingOptionNew context:nil]; 115 | 116 | // dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 117 | // [self.wkwebV.configuration.userContentController removeAllUserScripts]; 118 | // [self dismissViewControllerAnimated:YES completion:nil]; 119 | // }); 120 | // dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 121 | // WKSnapshotConfiguration *snap =[[WKSnapshotConfiguration alloc]init]; 122 | // snap.rect = CGRectMake(100, 100, 100, 100); 123 | // snap.snapshotWidth = @(100); 124 | // [self.wkwebV takeSnapshotWithConfiguration:snap completionHandler:^(UIImage * _Nullable snapshotImage, NSError * _Nullable error) { 125 | // UIImageView *imageV = [[UIImageView alloc]initWithFrame:CGRectMake(50, 50, 300, 300)]; 126 | // imageV.image = snapshotImage; 127 | // [self.wkwebV addSubview:imageV]; 128 | // }]; 129 | // }); 130 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 131 | [self.wkwebV evaluateJavaScript:@"userFunc()" completionHandler:^(id _Nullable resp, NSError * _Nullable error) { 132 | 133 | }]; 134 | NSURL *url = [NSURL URLWithString:@"wjs://"]; 135 | //打开url 136 | [[UIApplication sharedApplication] openURL:url]; 137 | }); 138 | [userContentController.userScripts enumerateObjectsUsingBlock:^(WKUserScript * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { 139 | NSLog(@"-------1----%@",obj.source); 140 | }]; 141 | // WKContentRuleListStore 142 | // WKWebsiteDataStore 143 | // WKContentRuleList 144 | // WKWebsiteDataRecord 145 | // WKSelectionGranularity 146 | //WKURLSchemeTask 147 | //WKURLSchemeHandler 148 | // WKBackForwardList 149 | } 150 | #pragma mark - WKNavigationDelegate 151 | // 152 | //- (void)webView:(WKWebView *)webView didCommitNavigation:(null_unspecified WKNavigation *)navigation 153 | //{ 154 | // NSLog(@"当WebView开始接收网页内容时触发"); 155 | //} 156 | //- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(null_unspecified WKNavigation *)navigation 157 | //{ 158 | // NSLog(@"当WevView的内容开始加载时触发"); 159 | //} 160 | // 161 | //- (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(null_unspecified WKNavigation *)navigation 162 | //{ 163 | // NSLog(@"主机地址重定向时触发"); 164 | //} 165 | // 166 | //- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(null_unspecified WKNavigation *)navigation withError:(NSError *)error 167 | //{ 168 | // NSLog(@"当页面加载内容过程中发生错误时触发"); 169 | //} 170 | // 171 | //- (void)webView:(WKWebView *)webView didFinishNavigation:(null_unspecified WKNavigation *)navigation 172 | //{ 173 | // NSLog(@"当前页面加载完成后触发"); 174 | //} 175 | // 176 | //- (void)webView:(WKWebView *)webView didFailNavigation:(null_unspecified WKNavigation *)navigation withError:(NSError *)error 177 | //{ 178 | // NSLog(@"页面发生错误时触发"); 179 | //} 180 | // 181 | //- (void)webView:(WKWebView *)webView didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * _Nullable credential))completionHandler 182 | //{ 183 | // NSLog(@"当WebView需要响应网页的登录请求时触发"); 184 | // completionHandler(NSURLSessionAuthChallengeUseCredential,nil); 185 | //} 186 | // 187 | //- (void)webViewWebContentProcessDidTerminate:(WKWebView *)webView 188 | //{ 189 | // NSLog(@"当WebContent进程中止时触发"); 190 | //} 191 | 192 | //- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler 193 | //{ // WKNavigationActionPolicyCancel 取消请求 WKNavigationActionPolicyAllow 允许继续 194 | // NSLog(@"决定是否允许或者取消一次页面加载请求"); 195 | // NSLog(@"----%@",navigationAction); 196 | // decisionHandler(WKNavigationActionPolicyAllow); 197 | //} 198 | // 199 | //- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler 200 | //{ // WKNavigationResponsePolicyCancel 取消加载 WKNavigationResponsePolicyAllow 允许继续 201 | // NSLog(@"在已经收到response时决定是否允许或者取消页面的加载"); 202 | // decisionHandler(WKNavigationResponsePolicyAllow); 203 | //} 204 | 205 | #pragma mark - WKUIDelegate 206 | // 这个方法相当于浏览器中的新建窗口,这个方法触发的条件是当html中点击了 A 标签需要新开窗口时候 207 | - (nullable WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures 208 | { // 这个处理方法解决的是,当某些界面点击 A 标签无响应的问题,就是存在 target='_blank' 时 209 | WKFrameInfo *frameInfo = navigationAction.targetFrame; 210 | if (![frameInfo isMainFrame]) 211 | { 212 | [webView loadRequest:navigationAction.request]; 213 | } 214 | return nil; 215 | } 216 | - (void)webViewDidClose:(WKWebView *)webView 217 | { 218 | // webview 关闭 219 | } 220 | // 显示一个JavScript 警告界面 221 | - (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler 222 | { // 对应着 alert('警告') 223 | UIAlertAction *alertAction = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) { 224 | completionHandler(); 225 | }]; 226 | // alert弹出框 227 | UIAlertController *alertController = [UIAlertController alertControllerWithTitle:message message:nil preferredStyle:UIAlertControllerStyleAlert]; 228 | [alertController addAction:alertAction]; 229 | [self presentViewController:alertController animated:YES completion:nil]; 230 | } 231 | // 带着确认取消的弹框 232 | - (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL result))completionHandler 233 | { // window.confirm('sometext'); 234 | UIAlertAction *ok = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { 235 | completionHandler(YES); 236 | }]; 237 | UIAlertAction *no = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) { 238 | completionHandler(NO); 239 | }]; 240 | // alert弹出框 241 | UIAlertController *alertController = [UIAlertController alertControllerWithTitle:message message:nil preferredStyle:UIAlertControllerStyleAlert]; 242 | [alertController addAction:ok]; 243 | [alertController addAction:no]; 244 | [self presentViewController:alertController animated:YES completion:nil]; 245 | } 246 | // 带着输入框 247 | - (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(nullable NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * _Nullable result))completionHandler 248 | { 249 | UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"输入框" message:prompt preferredStyle:UIAlertControllerStyleAlert]; 250 | [alert addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) { 251 | textField.textColor = [UIColor blackColor]; 252 | textField.placeholder = defaultText; 253 | }]; 254 | [alert addAction:[UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { 255 | completionHandler([[alert.textFields lastObject] text]); 256 | }]]; 257 | [alert addAction:[UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) { 258 | completionHandler(nil); 259 | }]]; 260 | [self presentViewController:alert animated:YES completion:NULL]; 261 | } 262 | // 决定是否要预览指定的WKPreviewElementInfo 263 | - (BOOL)webView:(WKWebView *)webView shouldPreviewElement:(WKPreviewElementInfo *)elementInfo 264 | { 265 | return YES; 266 | } 267 | // 当用户发出了预览操作(比如3D Touch按压)时调用 268 | - (nullable UIViewController *)webView:(WKWebView *)webView previewingViewControllerForElement:(WKPreviewElementInfo *)elementInfo defaultActions:(NSArray> *)previewActions 269 | { 270 | self.touchVc =[[TouchController alloc]init]; 271 | WKWebView *wk = [[WKWebView alloc]initWithFrame:CGRectMake(50, 100, 300, 300) configuration:webView.configuration]; 272 | [wk loadRequest:[NSURLRequest requestWithURL:elementInfo.linkURL]]; 273 | UILabel *label =[[UILabel alloc]initWithFrame:CGRectMake(20, 30, 100, 100)]; 274 | label.text = previewActions.firstObject.title; 275 | [wk addSubview:label]; 276 | self.touchVc.itemArr = previewActions; 277 | [self.touchVc.view addSubview:wk]; 278 | return self.touchVc; 279 | } 280 | /// 继续按压 281 | - (void)webView:(WKWebView *)webView commitPreviewingViewController:(UIViewController *)previewingViewController 282 | { 283 | [self addChildViewController:self.touchVc]; 284 | } 285 | 286 | // 长按图片保存 287 | - (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation 288 | {// 不执行前段界面弹出列表的JS代码 289 | [self.wkwebV evaluateJavaScript:@"document.documentElement.style.webkitTouchCallout='none';" completionHandler:nil]; 290 | } 291 | - (void)handleLongPress:(UILongPressGestureRecognizer *)sender 292 | { 293 | if (sender.state != UIGestureRecognizerStateBegan) 294 | { 295 | return; 296 | } 297 | CGPoint touchPoint = [sender locationInView:self.wkwebV]; 298 | // 获取长按位置对应的图片url的JS代码 299 | NSString *imgJS = [NSString stringWithFormat:@"document.elementFromPoint(%f, %f).src", touchPoint.x, touchPoint.y]; 300 | // 执行对应的JS代码 获取url 301 | [self.wkwebV evaluateJavaScript:imgJS completionHandler:^(id _Nullable imgUrl, NSError * _Nullable error) { 302 | if (imgUrl) 303 | { 304 | } 305 | }]; 306 | } 307 | -(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context 308 | { 309 | if ([keyPath isEqualToString:@"estimatedProgress"]) 310 | { 311 | self.wkProgressV.progress = self.wkwebV.estimatedProgress; 312 | // [self _logWKInfo]; 313 | // NSLog(@"--c------%@",self.wkwebV.backForwardList.currentItem.title); 314 | // NSLog(@"---b-----%@",self.wkwebV.backForwardList.backItem.title); 315 | // NSLog(@"---f-----%@",self.wkwebV.backForwardList.forwardItem.title); 316 | } 317 | } 318 | 319 | - (IBAction)backAction:(UIButton *)sender 320 | { 321 | [self.wkwebV goBack]; 322 | } 323 | - (IBAction)goForAction:(UIButton *)sender 324 | { 325 | [self.wkwebV goForward]; 326 | } 327 | 328 | - (IBAction)wuhenAction:(UIButton *)sender 329 | { 330 | 331 | } 332 | 333 | - (IBAction)stopLoadingAction:(UIButton *)sender 334 | { 335 | [self.wkwebV stopLoading]; 336 | } 337 | // 刷新返回的是上一个界面 338 | - (IBAction)reloadAction:(UIButton *)sender 339 | { 340 | [self.wkwebV reload]; 341 | } 342 | 343 | - (IBAction)listAction:(UIButton *)sender 344 | { 345 | 346 | } 347 | // 重加载 348 | - (IBAction)test1Action:(UIButton *)sender 349 | { 350 | [self.wkwebV reloadFromOrigin]; 351 | } 352 | 353 | - (IBAction)test2Action:(UIButton *)sender 354 | { 355 | 356 | } 357 | 358 | -(void)_logWKInfo 359 | { 360 | NSMutableDictionary *dic =[NSMutableDictionary dictionary]; 361 | [dic setValue:self.wkwebV.customUserAgent forKey:@"customUserAgent"]; 362 | [dic setValue:@(self.wkwebV.canGoBack) forKey:@"canGoBack"]; 363 | [dic setObject:@(self.wkwebV.canGoForward) forKey:@"canGoForward"]; 364 | // [dic setObject:self.wkwebV.serverTrust forKey:@"serverTrust"]; 365 | [dic setObject:@(self.wkwebV.hasOnlySecureContent) forKey:@"hasOnlySecureContent"]; 366 | [dic setObject:@(self.wkwebV.loading) forKey:@"loading"]; 367 | [dic setObject:self.wkwebV.title forKey:@"title"]; 368 | [dic setObject:self.wkwebV.URL forKey:@"url"]; 369 | [dic setObject:self.wkwebV.backForwardList forKey:@"backForwardList"]; 370 | NSLog(@"--------------------------start--------------------------"); 371 | NSLog(@"%@",dic); 372 | NSLog(@"--------------------------stop--------------------------"); 373 | } 374 | 375 | 376 | 377 | -(void)dealloc 378 | { 379 | NSLog(@"----------IJSTestController---------------"); 380 | // [self.wkProgressV removeObserver:self forKeyPath:@"estimatedProgress"]; 381 | } 382 | 383 | 384 | 385 | 386 | @end 387 | -------------------------------------------------------------------------------- /WKWebViewDemo/OC与JS交互之WKWebView/IJSTestController.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 37 | 46 | 55 | 64 | 74 | 84 | 94 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | -------------------------------------------------------------------------------- /WKWebViewDemo/OC与JS交互之WKWebView/IJSTestObjc.h: -------------------------------------------------------------------------------- 1 | // 2 | // IJSTestObjc.h 3 | // OC与JS交互之WKWebView 4 | // 5 | // Created by 山神 on 2018/6/12. 6 | // Copyright © 2018年 rrcc. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | 12 | 13 | @interface IJSTestObjc : NSObject 14 | 15 | 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /WKWebViewDemo/OC与JS交互之WKWebView/IJSTestObjc.m: -------------------------------------------------------------------------------- 1 | 2 | 3 | // 4 | // IJSTestObjc.m 5 | // OC与JS交互之WKWebView 6 | // 7 | // Created by 山神 on 2018/6/12. 8 | // Copyright © 2018年 rrcc. All rights reserved. 9 | // 10 | 11 | #import "IJSTestObjc.h" 12 | 13 | 14 | @interface IJSTestObjc() 15 | 16 | @end 17 | 18 | @implementation IJSTestObjc 19 | 20 | 21 | - (void)webView:(WKWebView *)webView startURLSchemeTask:(id )urlSchemeTask 22 | { 23 | 24 | } 25 | 26 | - (void)webView:(WKWebView *)webView stopURLSchemeTask:(id )urlSchemeTask 27 | { 28 | 29 | } 30 | 31 | 32 | #pragma mark - WKScriptMessageHandler 33 | 34 | - (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message 35 | { 36 | if ([message.name isEqualToString:@"showMobile"]) 37 | { 38 | [self showMsg:@"我是下面的小红 手机号是:18870707070"]; 39 | } 40 | if ([message.name isEqualToString:@"showName"]) 41 | { 42 | NSString *info = [NSString stringWithFormat:@"你好 %@, 很高兴见到你",message.body]; 43 | [self showMsg:info]; 44 | } 45 | 46 | if ([message.name isEqualToString:@"showSendMsg"]) 47 | { 48 | NSArray *array = message.body; 49 | NSString *info = [NSString stringWithFormat:@"这是我的手机号: %@, %@ !!",array.firstObject,array.lastObject]; 50 | [self showMsg:info]; 51 | } 52 | } 53 | 54 | - (void)showMsg:(NSString *)msg 55 | { 56 | [[[UIAlertView alloc] initWithTitle:nil message:msg delegate:nil cancelButtonTitle:nil otherButtonTitles:@"OK", nil] show]; 57 | } 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | @end 71 | -------------------------------------------------------------------------------- /WKWebViewDemo/OC与JS交互之WKWebView/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | NSAppTransportSecurity 40 | 41 | NSAllowsArbitraryLoads 42 | 43 | 44 | CFBundleURLTypes 45 | 46 | 47 | CFBundleURLName 48 | 49 | CFBundleURLSchemes 50 | 51 | wechat 52 | weixin 53 | wjs 54 | 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /WKWebViewDemo/OC与JS交互之WKWebView/SMSDK.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by shange on 2017/4/13. 3 | */ 4 | 5 | function SMSDK() 6 | { 7 | var name = "金山"; 8 | this.initSDK = function (hello) 9 | { 10 | var initData ={}; 11 | var appkey = 12 | { 13 | "appkey": hello 14 | } 15 | var appSecrect= 16 | { 17 | "appSecrect": hello 18 | } 19 | initData["appkey"] = appkey; 20 | initData["appSecrect"] = appSecrect;z 21 | return initData; 22 | }; 23 | 24 | this.getCode = function () 25 | { 26 | var phoneNum = document.getElementById('phoneInput').value; 27 | return phoneNum; 28 | }; 29 | this.commitCode = function () 30 | { 31 | var code = document.getElementById('codeInput').value; 32 | return code; 33 | }; 34 | this.getCodeCallBack = function(message) 35 | { 36 | var p3 = document.createElement('p'); 37 | p3.innerText = message; 38 | document.body.appendChild(p3); 39 | } 40 | this.commitCodeCallBack = function(message) 41 | { 42 | var p3 = document.createElement('p'); 43 | p3.innerText = message; 44 | document.body.appendChild(p3); 45 | } 46 | 47 | this.ocTest = function ocTest(num,msg) 48 | { 49 | document.getElementById('msg').innerHTML = '这是我的手机号:' + num + ',' + msg + '!!' 50 | var obj = new Object(); 51 | obj.name = '叫我山神' 52 | obj.qq = '1096452045' 53 | return obj 54 | } 55 | } 56 | var $smsdk = new SMSDK(); 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /WKWebViewDemo/OC与JS交互之WKWebView/TouchController.h: -------------------------------------------------------------------------------- 1 | // 2 | // TouchController.h 3 | // OC与JS交互之WKWebView 4 | // 5 | // Created by 山神 on 2018/6/13. 6 | // Copyright © 2018年 rrcc. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | 12 | @interface TouchController : UIViewController 13 | 14 | @property(nonatomic,strong ) NSArray *itemArr; // 参数说明 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /WKWebViewDemo/OC与JS交互之WKWebView/TouchController.m: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // TouchController.m 4 | // OC与JS交互之WKWebView 5 | // 6 | // Created by 山神 on 2018/6/13. 7 | // Copyright © 2018年 rrcc. All rights reserved. 8 | // 9 | 10 | #import "TouchController.h" 11 | 12 | @interface TouchController () 13 | 14 | @end 15 | 16 | @implementation TouchController 17 | 18 | - (void)viewDidLoad 19 | { 20 | [super viewDidLoad]; 21 | 22 | } 23 | 24 | - (NSArray> *)previewActionItems 25 | { 26 | return self.itemArr; 27 | UIPreviewAction *action1 = [UIPreviewAction actionWithTitle:@"测试1" style:UIPreviewActionStyleDefault handler:^(UIPreviewAction *_Nonnull action, UIViewController *_Nonnull previewViewController) { 28 | 29 | }]; 30 | 31 | UIPreviewAction *collection = [UIPreviewAction actionWithTitle:@"测试2" style:UIPreviewActionStyleDefault handler:^(UIPreviewAction *_Nonnull action, UIViewController *_Nonnull previewViewController) { 32 | 33 | }]; 34 | 35 | // UIPreviewAction *export = [UIPreviewAction actionWithTitle:[NSBundle localizedStringForKey:@"Export"] style:UIPreviewActionStyleDefault handler:^(UIPreviewAction * _Nonnull action, UIViewController * _Nonnull previewViewController) { 36 | // 37 | // if (self.model.type== JSAssetModelMediaTypeVideo) 38 | // { 39 | // 40 | // [[IJSImageManager shareManager]getVideoOutputPathWithAsset:self.model.asset completion:^(NSString *outputPath) { 41 | // [self showAlertWithTitle:@"导出成功" ]; 42 | // }]; 43 | // }else{ 44 | // [self showAlertWithTitle:@"功能未开发" ]; 45 | // } 46 | // 47 | // }]; 48 | 49 | // UIPreviewAction *Edit = [UIPreviewAction actionWithTitle:[NSBundle localizedStringForKey:@"Edit"] style:UIPreviewActionStyleDefault handler:^(UIPreviewAction * _Nonnull action, UIViewController * _Nonnull previewViewController) { 50 | // 51 | // [self showAlertWithTitle:@"功能开发" ]; 52 | // }]; 53 | 54 | NSArray *actions = @[action1, collection]; 55 | return actions; 56 | } 57 | 58 | @end 59 | -------------------------------------------------------------------------------- /WKWebViewDemo/OC与JS交互之WKWebView/TouchController.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /WKWebViewDemo/OC与JS交互之WKWebView/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // OC与JS交互之WKWebView 4 | // 5 | // Created by user on 16/8/18. 6 | // Copyright © 2016年 rrcc. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ViewController : UIViewController 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /WKWebViewDemo/OC与JS交互之WKWebView/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // OC与JS交互之WKWebView 4 | // 5 | // Created by user on 16/8/18. 6 | // Copyright © 2016年 rrcc. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | #import 11 | 12 | #import "IJSTestController.h" 13 | #import "IJSTestObjc.h" 14 | 15 | @interface ViewController () 16 | 17 | @property(nonatomic,strong) WKWebView *wkwebV; // 参数说明 18 | @property(nonatomic,strong) IJSTestObjc *objc; // 参数说明 19 | @end 20 | 21 | @implementation ViewController 22 | 23 | - (void)viewDidLoad 24 | { 25 | [super viewDidLoad]; 26 | self.objc = [IJSTestObjc new]; 27 | // 进程池配置 28 | WKWebViewConfiguration * config = [[WKWebViewConfiguration alloc]init]; 29 | // WKProcessPool类中没有暴露任何属性和方法,配置为同一个进程池的WebView会共享数据,例如Cookie、用户凭证等,开发者可以通过编写管理类来分配不同维度的WebView在不同进程池中。 30 | WKProcessPool * pool = [[WKProcessPool alloc]init]; 31 | config.processPool = pool; 32 | 33 | WKPreferences * preference = [[WKPreferences alloc]init]; //进行偏好设置 34 | preference.minimumFontSize = 5; //最小字体大小 当将javaScriptEnabled属性设置为NO时,可以看到明显的效果 35 | preference.javaScriptEnabled = YES; //设置是否支持javaScript 默认是支持的 36 | preference.javaScriptCanOpenWindowsAutomatically = YES; //设置是否允许不经过用户交互由javaScript自动打开窗口 37 | config.preferences = preference; 38 | 39 | //设置内容交互控制器 用于处理JavaScript与native交互 40 | WKUserContentController * userController = config.userContentController; 41 | //设置处理代理并且注册要被js调用的方法名称 42 | [userController addScriptMessageHandler:self.objc name:@"ijs"]; 43 | //js注入,注入一个测试方法。 44 | NSString *javaScriptSource =@"function userFunc(){alert('警告的窗口')}"; 45 | WKUserScript *userScript = [[WKUserScript alloc] initWithSource:javaScriptSource injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:NO]; 46 | // forMainFrameOnly:NO(全局窗口),yes(只限主窗口) 47 | [userController addUserScript:userScript]; 48 | config.userContentController = userController; 49 | 50 | self.wkwebV =[[WKWebView alloc]initWithFrame:CGRectMake(0, 0, self.view.frame.size.width , self.view.frame.size.height / 2) configuration:config]; 51 | 52 | [self.view addSubview:self.wkwebV]; 53 | self.wkwebV.navigationDelegate = self; 54 | self.wkwebV.UIDelegate = self; 55 | 56 | // NSString *filePath = @"http://xcqbtest.xcqb.cn/#/qa"; //[[NSBundle mainBundle] pathForResource:@"index" ofType:@"html"]; 57 | NSString *filePath = [[NSBundle mainBundle] pathForResource:@"index" ofType:@"html"]; 58 | NSURL *baseURL = [[NSBundle mainBundle] bundleURL]; 59 | // [self.wkwebV loadHTMLString:[NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil] baseURL:baseURL]; 60 | // [self.wkwebV loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:filePath]]]; 61 | // NSURLRequest *request =[NSURLRequest requestWithURL:[NSURL URLWithString:filePath]];//[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.xinhuanet.com/politics/2018-05/09/c_1122808419.htm"]]; 62 | // [self.wkwebV loadRequest:request]; 63 | 64 | // 加载本地的html 65 | NSString *html =[NSString stringWithFormat:@"%@%@",[self _getHtml],[self _getCssString]]; 66 | [self.wkwebV loadHTMLString:html baseURL:nil]; 67 | 68 | //JS调用OC 添加处理脚本 69 | [userController addScriptMessageHandler:self.objc name:@"name"]; 70 | [userController addScriptMessageHandler:self.objc name:@"showName"]; 71 | [userController addScriptMessageHandler:self.objc name:@"showSendMsg"]; 72 | [userController addScriptMessageHandler:self.objc name:@"userFunc"]; // 自己注册的方法 73 | 74 | // [self.wkwebV addObserver:self forKeyPath:@"title" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil]; 75 | 76 | // dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 77 | // IJSTestController *vc =[IJSTestController new]; 78 | // [self presentViewController:vc animated:YES completion:nil]; 79 | // }); 80 | // WKSnapshotConfiguration *snap =[[WKSnapshotConfiguration alloc]init]; 81 | // snap.rect = CGRectMake(100, 100, 100, 100); 82 | // [self.wkwebV takeSnapshotWithConfiguration:snap completionHandler:^(UIImage * _Nullable snapshotImage, NSError * _Nullable error) { 83 | // UIImageView *imageV = [[UIImageView alloc]initWithFrame:CGRectMake(50, 50, 300, 300)]; 84 | // imageV.image = snapshotImage; 85 | // [self.wkwebV addSubview:imageV]; 86 | // }]; 87 | // 88 | } 89 | 90 | - (nullable WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures 91 | { 92 | WKFrameInfo *frameInfo = navigationAction.targetFrame; 93 | if (![frameInfo isMainFrame]) 94 | { 95 | [webView loadRequest:navigationAction.request]; 96 | } 97 | return nil; 98 | } 99 | 100 | - (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler 101 | { 102 | UIAlertAction *alertAction = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) { 103 | completionHandler(); 104 | }]; 105 | // alert弹出框 106 | UIAlertController *alertController = [UIAlertController alertControllerWithTitle:message message:nil preferredStyle:UIAlertControllerStyleAlert]; 107 | [alertController addAction:alertAction]; 108 | [self presentViewController:alertController animated:YES completion:nil]; 109 | } 110 | 111 | -(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context 112 | { 113 | NSLog(@"---------------%@",self.wkwebV.title); 114 | } 115 | 116 | 117 | //网页加载完成之后调用JS代码才会执行,因为这个时候html页面已经注入到webView中并且可以响应到对应方法 118 | 119 | - (IBAction)btnClick:(UIButton *)sender 120 | { 121 | if (!self.wkwebV.loading) 122 | { 123 | if (sender.tag == 123) 124 | { 125 | [self.wkwebV evaluateJavaScript:@"alertMobile()" completionHandler:^(id _Nullable response, NSError * _Nullable error) { 126 | NSLog(@"---alertMobile----%@",response); 127 | }]; 128 | 129 | [self.wkwebV evaluateJavaScript:@"userFunc()" completionHandler:^(id _Nullable resp, NSError * _Nullable error) { 130 | 131 | 132 | }]; 133 | } 134 | 135 | if (sender.tag == 234) 136 | { 137 | [self.wkwebV evaluateJavaScript:@"alertName('小红')" completionHandler:nil]; 138 | } 139 | 140 | if (sender.tag == 345) 141 | { 142 | 143 | // $smsdk.ocTest('18870707070','只能传字符串') // @"alertSendMsg('18870707070','只能传字符串')" 144 | [self.wkwebV evaluateJavaScript:@"$smsdk.ocTest({key:111},[2000,2001])" completionHandler:^(id _Nullable resp, NSError * _Nullable error) { 145 | if (error) 146 | { 147 | NSLog(@"---error----%@",error); 148 | } 149 | else 150 | { 151 | NSLog(@"--------resp-------%@",resp); 152 | } 153 | }]; 154 | } 155 | } else { 156 | NSLog(@"the view is currently loading content"); 157 | } 158 | } 159 | 160 | 161 | - (IBAction)clear:(id)sender 162 | { 163 | [self.wkwebV evaluateJavaScript:@"clear()" completionHandler:nil]; 164 | } 165 | 166 | /* 167 | 1. WKUserContentController: 168 | 169 | 专门用来管理native与JavaScript的交互行为,addScriptMessageHandler:name:方法来注册要被js调用的方法名称,之后再JavaScript中使用window.webkit.messageHandlers.name.postMessage()方法来像native发送消息,支持OC中字典,数组,NSNumber等原生数据类型,JavaScript代码中的name要和上面注册的相同。在native代理的回调方法中,会获取到JavaScript传递进来的消息 170 | 171 | WKScriptMessage: 类是JavaScript传递的对象实例 172 | 属性 173 | //传递的消息主体 174 | @property (nonatomic, readonly, copy) id body; 175 | //传递消息的WebView 176 | @property (nullable, nonatomic, readonly, weak) WKWebView *webView; 177 | //传递消息的WebView当前页面对象 178 | @property (nonatomic, readonly, copy) WKFrameInfo *frameInfo; 179 | //消息名称 180 | @property (nonatomic, readonly, copy) NSString *name; 181 | 182 | 183 | */ 184 | 185 | -(NSString *)_getCssString 186 | { 187 | // return @""; 188 | 189 | // return @""; 190 | 191 | //return @""; 192 | 193 | return @""; 194 | 195 | } 196 | 197 | -(NSString *)_getHtml 198 | { 199 | 200 | return @"

这个是P标签的测试

这个是啥
"; 201 | 202 | return @"



"; 203 | } 204 | 205 | 206 | -(void)dealloc 207 | { 208 | NSLog(@"------------"); 209 | } 210 | 211 | @end 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | -------------------------------------------------------------------------------- /WKWebViewDemo/OC与JS交互之WKWebView/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 小黄 6 | 超链接标签 7 | 8 | 14 | 15 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 |
72 | 73 |
74 | 75 |
76 |
77 | 78 |
79 |
80 | 81 |
82 |
83 | 84 |
85 |
86 | 87 |
88 |
89 | 90 |
91 |
92 | 93 |
94 | 95 | 96 | 97 | 98 | -------------------------------------------------------------------------------- /WKWebViewDemo/OC与JS交互之WKWebView/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // OC与JS交互之WKWebView 4 | // 5 | // Created by user on 16/8/18. 6 | // Copyright © 2016年 rrcc. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /WKWebViewDemo/README.md: -------------------------------------------------------------------------------- 1 | # WebKit 认知 2 | 3 | 之前学习交互,把WK落下了,现在补上. 4 | WK中有些类,在目前的项目中没有用到,可能存在问题,本文也没加注释,后面会补上,这个文章属于WebKit的入门文档,如果有小伙伴只想知道怎么交互,前面的基础知识可以直接忽略,如果觉得文章中有错误还望指出 **QQ: 1096452045** 5 | 6 | ### 一,核心类 WKWebView 7 | 8 | #### 1,属性: 9 | 10 | ``` 11 | 1. WKWebViewConfiguration *configuration;//配置属性,下文会提及 12 | 2. id navigationDelegate;//可以自定义WebView接受、加载和完成浏览请求过程的一些行为 13 | 3. id UIDelegate; // 界面代理 14 | 4. WKBackForwardList *backForwardList;// 维护了用户访问过的网页记录.下文细讲 15 | 5. NSString *title;//当前页面的title 16 | 6. NSURL *URL; //当前的URL 17 | 7. BOOL loading; //属性来判断网页是否正在加载中 18 | 8. double estimatedProgress;//当前浏览页面加载进度的比例 0--1 支持kvo 19 | 9. BOOL hasOnlySecureContent;//是否页面内的所有资源都是通过安全链接加载的 20 | 1. SecTrustRef serverTrust //10.0+当前浏览页面的SecTrustRef对象,此对象暂时没有细究 21 | 2. BOOL canGoBack; //是否可以后退。 22 | 3. BOOL canGoForward; // 是否可以向前 23 | 4. BOOL allowsBackForwardNavigationGestures;//是否允许水平滑动手势来触发网页的前进和后退,相当于全屏返回 24 | 5. NSString *customUserAgent // 9.0+自定义User Agent 25 | 6. BOOL allowsLinkPreview// 是否允许按住链接就展示链接的预览 3DTouch支持 26 | 7. UIScrollView *scrollView; //WebView对应的ScrollView 27 | 8. BOOL allowsMagnification;//mac 是否允许放大手势来放大网页内容 28 | 9. CGFloat magnification; //mac 影响网页内容放缩的因子 默认是1 29 | 30 | ``` 31 | #### 2,方法列表: 32 | 33 | * [ ] 初始化 34 | 35 | ``` 36 | 使用 initWithFrame:configuration: 方法来创建WKWebView对象; 37 | ``` 38 | 39 | * [ ] 加载资源 40 | * 本地 41 | 42 | ``` 43 | NSString *filePath = [[NSBundle mainBundle] pathForResource:@"index" ofType:@"html"]; 44 | NSURL *baseURL = [[NSBundle mainBundle] bundleURL]; 45 | [self.wkwebV loadHTMLString:[NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil] baseURL:baseURL]; 46 | 47 | NSString *filePath = [[NSBundle mainBundle] pathForResource:@"index" ofType:@"html"]; 48 | NSURL *baseURL = [[NSBundle mainBundle] bundleURL]; 49 | [self.wkwebV loadHTMLString:[NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil] baseURL:baseURL]; 50 | ``` 51 | * 网络 52 | 53 | ``` 54 | [self.wkwebV loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"https://v.qq.com/x/cover/7casb7nes159mrl.html?ptag=baidu.video.paymovie&frp=v.baidu.com%2Fmovie_intro%2F&vfm=bdvtx"]]]; 55 | 56 | - (WKNavigation *)loadData:(NSData *)data MIMEType:(NSString *)MIMEType characterEncodingName:(NSString *)characterEncodingName baseURL:(NSURL *)baseURL; 57 | ### MIMEType是数据类型 characterEncodingName是编码名称baseURL是用于解析文档内相对URL的URL,返回一个新的WKNavigation对象 58 | ``` 59 | * [ ] 决定是否加载内容 返回WebKit是否原生地支持某一种URL Scheme ios11 60 | 61 | ``` 62 | + (BOOL)handlesURLScheme:(NSString *)urlScheme; 63 | ``` 64 | * [ ] 操作界面API 65 | 66 | ``` 67 | - (nullable WKNavigation *)goBack; //返回 68 | 69 | - (nullable WKNavigation *)goForward; //前进 70 | 71 | - (nullable WKNavigation *)reload; //重加载,刷新发现是返回上一个界面 72 | 73 | - (nullable WKNavigation *)reloadFromOrigin; //重新加载当前页面(带缓存的验证),应该用此刷新 74 | 75 | - (void)stopLoading;// 停止加载 76 | 77 | ``` 78 | ###### 缩放属性和方法在iphone 没有实践 79 | 80 | #### 3,加载JavaScript 81 | 82 | ``` 83 | [wkwebview evaluateJavaScript:js方法 completionHandler:^(id _Nullable resp, NSError * _Nullable error) { 84 | resp 是 js返回的值, 主线程中执行 85 | }]; 86 | ``` 87 | #### 4, ios11 网页截屏 88 | 89 | ``` 90 | WKSnapshotConfiguration *snap =[[WKSnapshotConfiguration alloc]init]; 91 | snap.rect = CGRectMake(100, 100, 100, 100);//截取限制 92 | snap.snapshotWidth = @(100); //控制截屏像素 93 | [self.wkwebV takeSnapshotWithConfiguration:snap completionHandler:^(UIImage * _Nullable snapshotImage, NSError * _Nullable error) { 94 | //这个方法必须在网页加载完成之后执行,否则返回的就是一个空白的image 95 | }]; 96 | ``` 97 | #### 5, 代理 98 | ##### 5.1,WKNavigationDelegate 99 | 100 | ``` 101 | - (void)webView:(WKWebView *)webView didCommitNavigation:(null_unspecified WKNavigation *)navigation 102 | { 103 | NSLog(@"当WebView开始接收网页内容时触发"); 104 | } 105 | - (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(null_unspecified WKNavigation *)navigation 106 | { 107 | NSLog(@"当WevView的内容开始加载时触发"); 108 | } 109 | 110 | - (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(null_unspecified WKNavigation *)navigation 111 | { 112 | NSLog(@"主机地址重定向时触发"); 113 | } 114 | 115 | - (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(null_unspecified WKNavigation *)navigation withError:(NSError *)error 116 | { 117 | NSLog(@"当页面加载内容过程中发生错误时触发"); 118 | } 119 | 120 | - (void)webView:(WKWebView *)webView didFinishNavigation:(null_unspecified WKNavigation *)navigation 121 | { 122 | NSLog(@"当前页面加载完成后触发"); 123 | } 124 | 125 | - (void)webView:(WKWebView *)webView didFailNavigation:(null_unspecified WKNavigation *)navigation withError:(NSError *)error 126 | { 127 | NSLog(@"页面发生错误时触发"); 128 | } 129 | 130 | - (void)webView:(WKWebView *)webView didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * _Nullable credential))completionHandler 131 | { 132 | NSLog(@"当WebView需要响应网页的登录请求时触发"); 133 | completionHandler(NSURLSessionAuthChallengeUseCredential,nil); 134 | } 135 | 136 | - (void)webViewWebContentProcessDidTerminate:(WKWebView *)webView 137 | { 138 | NSLog(@"当WebContent进程中止时触发"); 139 | } 140 | 141 | - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler 142 | { // WKNavigationActionPolicyCancel 取消请求 WKNavigationActionPolicyAllow 允许继续 143 | NSLog(@"决定是否允许或者取消一次页面加载请求"); 144 | NSLog(@"----%@",navigationAction); 145 | decisionHandler(WKNavigationActionPolicyAllow); 146 | } 147 | 148 | - (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler 149 | { // WKNavigationResponsePolicyCancel 取消加载 WKNavigationResponsePolicyAllow 允许继续 150 | NSLog(@"在已经收到response时决定是否允许或者取消页面的加载"); 151 | decisionHandler(WKNavigationResponsePolicyAllow); 152 | } 153 | ``` 154 | ##### 5.1.1 WKNavigationAction 155 | 此对象包含了可能导致一次加载的操作的信息,用于制定策略决策 156 | ###### 属性 157 | 158 | ``` 159 | WKFrameInfo *sourceFrame;//产生这次请求的frame信息 160 | NSURLRequest *request; // 加载的请求信息 161 | 162 | WKFrameInfo *targetFrame;//请求的目标frame,如果时一个新的窗口请求则是nil 163 | 164 | WKNavigationType navigationType; 触发本次浏览请求的操作类型。见WKNavigationType枚举 165 | 166 | ``` 167 | **WKNavigationType 枚举** 168 | 169 | ``` 170 | WKNavigationTypeLinkActivated 带有href属性的链接被用户激活 171 | 172 | WKNavigationTypeFormSubmitted 一个表单提交 173 | 174 | WKNavigationTypeBackForward 向前向后的导航请求 175 | 176 | WKNavigationTypeReload 网页重新加载 177 | 178 | WKNavigationTypeFormResubmitted 重新提交表单(例如后退、前进或重新加载) 179 | 180 | WKNavigationTypeOther由于其他原因 181 | ``` 182 | **WKNavigationResponse** 183 | 对象包含用于制定策略决策的浏览响应信息 184 | ###### 属性: 185 | 186 | ``` 187 | BOOL forMainFrame; //指示本次加载的frame是否是main frame 188 | 189 | NSURLResponse *response; // 如果允许了一个带有无法显示的MIME类型响应,会导致浏览加载失败 190 | 191 | BOOL canShowMIMEType; // 指示WebKit是否可以原生地支持显示这种MIME类型 192 | ``` 193 | ##### 5.2 WKUIDelegate 194 | 5.2.1 创建新窗口 195 | 196 | ``` 197 | // 这个方法相当于浏览器中的新建窗口,这个方法触发的条件是当html中点击了 A 标签需要新开窗口时候 198 | - (nullable WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures 199 | { // 这个处理方法解决的是,当某些界面点击 A 标签无响应的问题,就是存在 target='_blank' 时 200 | WKFrameInfo *frameInfo = navigationAction.targetFrame; 201 | if (![frameInfo isMainFrame]) 202 | { 203 | [webView loadRequest:navigationAction.request]; 204 | } 205 | return nil; 206 | } 207 | ``` 208 | 5.2.2 关闭 209 | 210 | ``` 211 | - (void)webViewDidClose:(WKWebView *)webView 212 | { 213 | // webview 关闭 214 | } 215 | ``` 216 | 5.2.3 网页中带着警告 217 | 218 | ``` 219 | // 显示一个JavScript 警告界面 220 | - (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler 221 | { // 对应着 alert('警告') 222 | UIAlertAction *alertAction = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) { 223 | completionHandler(); 224 | }]; 225 | // alert弹出框 226 | UIAlertController *alertController = [UIAlertController alertControllerWithTitle:message message:nil preferredStyle:UIAlertControllerStyleAlert]; 227 | [alertController addAction:alertAction]; 228 | [self presentViewController:alertController animated:YES completion:nil]; 229 | } 230 | // 带着确认取消的弹框 231 | - (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL result))completionHandler 232 | { // window.confirm('sometext'); 233 | UIAlertAction *ok = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { 234 | completionHandler(YES); 235 | }]; 236 | UIAlertAction *no = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) { 237 | completionHandler(NO); 238 | }]; 239 | // alert弹出框 240 | UIAlertController *alertController = [UIAlertController alertControllerWithTitle:message message:nil preferredStyle:UIAlertControllerStyleAlert]; 241 | [alertController addAction:ok]; 242 | [alertController addAction:no]; 243 | [self presentViewController:alertController animated:YES completion:nil]; 244 | } 245 | // 带着输入框 246 | - (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(nullable NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * _Nullable result))completionHandler 247 | { 248 | UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"输入框" message:prompt preferredStyle:UIAlertControllerStyleAlert]; 249 | [alert addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) { 250 | textField.textColor = [UIColor blackColor]; 251 | textField.placeholder = defaultText; 252 | }]; 253 | [alert addAction:[UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { 254 | completionHandler([[alert.textFields lastObject] text]); 255 | }]]; 256 | [alert addAction:[UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) { 257 | completionHandler(nil); 258 | }]]; 259 | [self presentViewController:alert animated:YES completion:NULL]; 260 | } 261 | ``` 262 | 5.3.4 3DTouch相关,按压出现列表 263 | 264 | ``` 265 | // 决定是否要预览指定的WKPreviewElementInfo 266 | - (BOOL)webView:(WKWebView *)webView shouldPreviewElement:(WKPreviewElementInfo *)elementInfo 267 | { 268 | return YES; 269 | } 270 | // 当用户发出了预览操作(比如3D Touch按压)时调用 271 | - (nullable UIViewController *)webView:(WKWebView *)webView previewingViewControllerForElement:(WKPreviewElementInfo *)elementInfo defaultActions:(NSArray> *)previewActions 272 | { 273 | self.touchVc =[[TouchController alloc]init]; 274 | WKWebView *wk = [[WKWebView alloc]initWithFrame:CGRectMake(50, 100, 300, 300) configuration:webView.configuration]; 275 | [wk loadRequest:[NSURLRequest requestWithURL:elementInfo.linkURL]]; 276 | UILabel *label =[[UILabel alloc]initWithFrame:CGRectMake(20, 30, 100, 100)]; 277 | label.text = previewActions.firstObject.identifier; 278 | [wk addSubview:label]; 279 | [self.touchVc.view addSubview:wk]; 280 | return self.touchVc; 281 | } 282 | /// 继续按压 283 | - (void)webView:(WKWebView *)webView commitPreviewingViewController:(UIViewController *)previewingViewController 284 | { 285 | [self addChildViewController:self.touchVc]; 286 | } 287 | ``` 288 | 联想: 这三个代理需要联合使用,和3DTouch案例是一样的 289 | 联想: 网页长按图片保存功能的实现 290 | 291 | ``` 292 | // 长按图片保存 293 | - (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation 294 | {// 不执行前段界面弹出列表的JS代码 295 | [self.wkwebV evaluateJavaScript:@"document.documentElement.style.webkitTouchCallout='none';" completionHandler:nil]; 296 | } 297 | - (void)handleLongPress:(UILongPressGestureRecognizer *)sender 298 | { 299 | if (sender.state != UIGestureRecognizerStateBegan) 300 | { 301 | return; 302 | } 303 | CGPoint touchPoint = [sender locationInView:self.wkwebV]; 304 | // 获取长按位置对应的图片url的JS代码 305 | NSString *imgJS = [NSString stringWithFormat:@"document.elementFromPoint(%f, %f).src", touchPoint.x, touchPoint.y]; 306 | // 执行对应的JS代码 获取url 307 | [self.wkwebV evaluateJavaScript:imgJS completionHandler:^(id _Nullable imgUrl, NSError * _Nullable error) { 308 | if (imgUrl) 309 | { 310 | } 311 | }]; 312 | } 313 | ``` 314 | 5.3.5 回调中的类 315 | 316 | **WKWindowFeatures** 新打开的窗口的可选属性 317 | 318 | 属性列表 319 | 320 | ``` 321 | NSNumber *allowsResizing;// 窗口是否可以调整尺寸(Boolean) 322 | NSNumber *height;//窗口的高度(CGFloat) 323 | NSNumber *width;//窗口的宽度(CGFloat) 324 | NSNumber *x; //窗口的x坐标(CGFloat) 325 | NSNumber *y;//窗口的y坐标(CGFloat) 326 | NSNumber *menuBarVisibility;//菜单栏是否应该可见(Boolean) 327 | NSNumber *statusBarVisibility;//状态栏是否应该可见(Boolean) 328 | NSNumber *toolbarsVisibility;//工具栏是否应该可见(Boolean) 329 | ``` 330 | **WKPreviewElementInfo** 对象包含了预览网页的信息 331 | 332 | 属性列表 333 | 334 | ``` 335 | NSURL *linkURL; //预览网页的链接 336 | ``` 337 | **WKPreviewActionItem** 协议提供预览操作的一些属性的访问方法。继承自UIPreviewActionItem 338 | 属性列表 339 | 340 | ``` 341 | NSString *identifier; //预览操作的标志符 342 | ``` 343 | **UIPreviewActionItem** 返回的就是3dTouch中的选项列表 344 | 345 | ``` 346 | NSString *title; 此字段就是touch列表中的标题 347 | ``` 348 | ### 二 配置信息类 349 | #### 1,WKWebViewConfiguration 350 | 此类: 351 | 可以决定网页的渲染时机,媒体的播放方式,用户选择项目的粒度,以及很多其他的选项. 352 | WKWebViewConfiguration只会在webview第一次初始化的时候使用,你不能用此类来改变一个已经初始化完成的webview的配置。 353 | 354 | ``` 355 | config.applicationNameForUserAgent = @"applicationNameForUserAgent应用名称"; 356 | config.ignoresViewportScaleLimits =YES; // 允许页面缩放 357 | config.suppressesIncrementalRendering = NO; // 是否抑制内容渲染呈现,直到它完全载入内存 358 | config.allowsInlineMediaPlayback = NO; // 不使用系统的播放器 359 | config.allowsAirPlayForMediaPlayback =YES; //是否允许AirPlay播放媒体 360 | config.allowsPictureInPictureMediaPlayback =YES; // 是否允许HTML5视屏以画中画形式播放,iPhone不支持 361 | config.mediaTypesRequiringUserActionForPlayback = WKAudiovisualMediaTypeVideo; //哪些媒体类型需要用户手势才能开始播放 362 | config.selectionGranularity = WKSelectionGranularityDynamic; //用户可以在WebView中交互式地选择内容的粒度级别,比如说,当使用WKSelectionGranularityDynamic时,而所选择的内容是单个块,这时候granularity可能会是单个字符;当所选择的web内容不限制于某个块时,granularity可能会是单个块。 363 | config.dataDetectorTypes = WKDataDetectorTypeLink; 364 | /* 365 | WKDataDetectorTypeNone //不执行检测 366 | WKDataDetectorTypePhoneNumber // 电话号码 367 | WKDataDetectorTypeLink //文本中的url 368 | WKDataDetectorTypeAddress // 地址 369 | WKDataDetectorTypeCalendarEvent //在未来的日期和时间 370 | WKDataDetectorTypeTrackingNumber // 跟踪号码/查询号/运单号 371 | WKDataDetectorTypeFlightNumber // 航班号 372 | WKDataDetectorTypeLookupSuggestion 373 | WKDataDetectorTypeAll = NSUIntegerMax, //所有 374 | */ 375 | // 暂时不知道干啥用的 376 | [config setURLSchemeHandler:self.objc forURLScheme:@"weixin"]; 377 | id urlscheme = [config urlSchemeHandlerForURLScheme:@"weixin"]; 378 | ``` 379 | #### 2,WKPreferences 380 | 此类封装了一个webview的偏好选项 381 | 属性: 382 | 383 | ``` 384 | preferences.minimumFontSize = 10; //最小字体的尺寸 385 | preferences.javaScriptEnabled =YES; //是否启用JavaScript,设置为NO将会禁用页面加载的或执行的JavaScript,但这个配置不会影响用户的script 386 | preferences.javaScriptCanOpenWindowsAutomatically =YES;//是否可以在没有用户操作的情况下自动打开窗口 387 | ``` 388 | #### 3,WKProcessPool 389 | 390 | 一个WKProcessPool对象代表Web Content的进程池。 391 | 与WebView的进程池关联的进程池通过其configuration来配置。每个WebView都有自己的Web Content进程,最终由一个有具体实现的进程来限制;在此之后,具有相同进程池的WebView最终共享Web Content进程. 392 | WKProcessPool对象只是一个简单的不透明token,本身没有属性或者方法 393 | #### 4,WKUserContentController 394 | 提供了一种向WebView发送JavaScript消息或者注入JavaScript脚本的方法 395 | 396 | * 属性: 397 | 398 | ``` 399 | NSArray *userScripts //用户手动添加的js代码 400 | ``` 401 | * 方法列表 402 | * [ ] 添加和删除脚本 403 | 404 | ``` 405 | - (void)addUserScript:(WKUserScript *)userScript; //添加用户自己的js代码 406 | ``` 407 | 408 | ``` 409 | - (void)removeAllUserScripts;//移除所有的WKUserScript 410 | ``` 411 | * [ ] 注册js的方法列表 412 | 413 | ``` 414 | - (void)addScriptMessageHandler:(id )scriptMessageHandler name:(NSString *)name; 415 | // 注册js的方法列表,此处的第一个参数不能是控制器self.否则内存问题 416 | 这里的名字就是 js中, name的关键字 window.webkit.messageHandlers.name.postMessage(messageBody) 417 | postMessage()有两个参数,第一个参数是需要传递的参数,第二个参数可以理解为标识,这俩参数可传可不传, 参数可以是js中的任何对象 418 | ``` 419 | 420 | ``` 421 | - (void)removeScriptMessageHandlerForName:(NSString *)name;// 移除name名字的WKScriptMessageHandler 422 | ``` 423 | * 添加或移除Content Rules 424 | 425 | ``` 426 | - (void)addContentRuleList:(WKContentRuleList *)contentRuleList; 427 | - (void)removeContentRuleList:(WKContentRuleList *)contentRuleList; 428 | - (void)removeAllContentRuleLists; 429 | ``` 430 | #### 5,WKScriptMessageHandler 处理js回调的协议,后面将交互的时候回提及 431 | #### 6,WKScriptMessage 这个是js回调过来的消息实体 432 | 属性: 433 | 434 | ``` 435 | id body;//只能是这些类型 NSNumber, NSString, NSDate, NSArray, NSDictionary, NSNull 436 | WKFrameInfo *frameInfo;//发送消息的frame 437 | NSString *name;//发送消息的WKScriptMessageHandler的名字 就是js方法名字 438 | WKWebView *webView;// 发送消息的WKWebView 439 | ``` 440 | #### 7,WKFrameInfo 441 | 包含了一个网页中的farme的相关信息。其只是一个描述瞬时状态的纯数据对象,不能用来在多次消息调用中唯一标识一个frame 442 | 属性: 443 | 444 | ``` 445 | BOOL mainFrame;//该frame是否是该网页的main frame或者子frame 446 | NSURLRequest *request;//frame对应的当前的请求 447 | WKSecurityOrigin *securityOrigin;//frame的securityOrigin 448 | WKWebView *webView;//frame对应的webView 449 | ``` 450 | #### 8,WKSecurityOrigin 451 | 一个WKSecurityOrigin对象由host,protocol和port组成。任何一个与正在加载的网页拥有相同WKSecurityOrigin的URL加载是一个First Party加载。First Party网页可以访问彼此的脚本和数据库资源。其只是一个描述瞬时状态的纯数据对象,不能用来在多次消息调用中唯一标识一个SecurityOrigin 452 | 属性: 453 | 454 | ``` 455 | NSString *host; 456 | NSInteger port; 457 | NSString *protocol; 458 | ``` 459 | #### 9,WKUserScript 460 | 代表了一个可以被注入网页中的脚本 461 | 例如 462 | 463 | ``` 464 | NSString *javaScriptSource = @"function userFunc(){window.confirm('sometext');}"; //@"function userFunc(){ alert('警告')}"; 465 | WKUserScript *userScript = [[WKUserScript alloc] initWithSource:javaScriptSource injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:NO]; 466 | // forMainFrameOnly:NO(全局窗口),yes(只限主窗口) 467 | [config.userContentController addUserScript:userScript]; 468 | * source 脚本的代码 469 | * injectionTime 脚本注入的时机,必须是这个WKUserScriptInjectionTime枚举值 470 | * forMainFrameOnly YES 只向main frame注入脚本, NO 则会向所有的frame注入脚本 471 | ``` 472 | 属性: 473 | 474 | ``` 475 | NSString *source; //脚本的代码 476 | WKUserScriptInjectionTime injectionTime;//脚本注入的时机 477 | BOOL forMainFrameOnly;//是否只注入到main frame 478 | ``` 479 | 枚举: 480 | 481 | ``` 482 | typedef NS_ENUM(NSInteger, WKUserScriptInjectionTime) { 483 | WKUserScriptInjectionTimeAtDocumentStart,//在document element创建之后,在所有其他内容加载之前 484 | WKUserScriptInjectionTimeAtDocumentEnd //在document加载完成之后,在其他子资源加载完成之前 485 | } 486 | ``` 487 | #### 10, WKContentRuleList 488 | 一个编译过的规则列表,应用到Web Content上。从WKContentExtensionStore中创建或者取得。//位置 489 | 属性 490 | 491 | ``` 492 | NSString *identifier;//标识符 493 | ``` 494 | #### 11,WKContentRuleListStore 495 | 方法列表 496 | 497 | ``` 498 | + (instancetype)defaultStore;// 返回默认的Store 499 | ``` 500 | #### 12,WKWebsiteDataStore 501 | 一个WKWebsiteDataStore对象代表了被网页使用的各种类型的数据。包括cookies,磁盘文件,内存缓存以及持久化数据如WebSQL,IndexedDB数据库,local storage 502 | #### 13, WKHTTPCookieStore 503 | 管理与特定的WKWebsiteDataStore关联的HTTP cookie的对象 504 | #### 14, WKHTTPCookieStoreObserver 505 | 506 | #### 15,WKWebsiteDataRecord 507 | 508 | #### 16,WKURLSchemeHandler 509 | 用来处理WebKit无法处理的URL Scheme类型的资源 510 | 方法: 511 | 512 | ``` 513 | //开始加载特定资源时调用 514 | - (void)webView:(WKWebView *)webView startURLSchemeTask:(id)urlSchemeTask; 515 | //handler停止处理这个任务时调用这个方法,在此此方法调用之后,你的handler不应该调用这个任务的任何方法,否则会触发异常 516 | - (void)webView:(WKWebView *)webView stopURLSchemeTask:(id)urlSchemeTask; 517 | ``` 518 | #### 17,WKURLSchemeTask 519 | 用来加载资源的任务 520 | 属性: 521 | 522 | ``` 523 | NSURLRequest *request; //加载的请求 524 | ``` 525 | 方法: 526 | 527 | ``` 528 | - (void)didReceiveResponse:(NSURLResponse *)response; 529 | 每个任务必须至少调用一次这个方法 530 | 如果你尝试在任务完成后发送一个新的response对象,会触发异常 531 | 如果在任务已经停止加载后调用,将会触发异常 532 | ``` 533 | ``` 534 | - (void)didReceiveData:(NSData *)data; 535 | 在任务接受到最终的response对象后,你应当开始发送数据 536 | 每次调用这个方法,新的数据都会append到之前的数据后 537 | 如果你尝试在发送response之前或者任务已经结束之后发送数据,将会触发异常 538 | 如果在任务已经停止加载后调用,将会触发异常 539 | ``` 540 | 541 | ``` 542 | - (void)didFinish; 543 | 如果你尝试在发送response之前或者任务已经结束之后调用该方法,将会触发异常 544 | 如果在任务已经停止加载后调用,将会触发异常 545 | ``` 546 | 547 | ``` 548 | - (void)didFailWithError:(NSError *)error; 549 | 如果在任务已经被标记为结束或失败后再调用这个方法会触发异常 550 | 如果在任务已经停止加载后调用,将会触发异常 551 | ``` 552 | #### 18,WKBackForwardList 553 | 一个WKBackForwardList对象维护了用户访问过的网页记录,用来前进后退到最近加载过的网页。WKBackForwardList对象仅仅维护的是列表数据,并不会执行任何实际的网页加载的操作,不会产生任何客户请求。如果你需要产生一次页面加载,请使用loadRequest: 这些方法 554 | 属性: 555 | 556 | ``` 557 | WKBackForwardListItem *backItem; //上一个 558 | WKBackForwardListItem *currentItem; //当前 559 | WKBackForwardListItem *forwardItem; //下一个记录 560 | NSArray *backList;//后退访问记录 561 | NSArray *forwardList;//向前 562 | ``` 563 | 方法: 564 | 565 | ``` 566 | //坐标位置的item 567 | - (nullable WKBackForwardListItem *)itemAtIndex:(NSInteger)index; 568 | ``` 569 | #### 19,WKBackForwardListItem 570 | WKBackForwardListItem对象代表了前进后退记录中的一个网页,包含了网页的一些信息(URL,标题和创建网页时的URL),前进后退记录由WKBackForwardList维护 571 | 属性: 572 | 573 | ``` 574 | NSURL *URL; //网页的URL 575 | NSURL *initialURL; //创建记录时初始化传入的URL 576 | NSString *title; // 网页的标题 577 | ``` 578 |
579 | 580 | ### 三, 基于WKWebView的ios与js交互细节 581 | 582 | 如果之前看过我写的基于 UIWebview和 JavaScriptCore ios与js的交互的话下面的内容将非常好理解 583 | 584 | #### 1, ios调用js代码 585 | ios调用js代码其实非常简单,只有一句代码 586 | 587 | ``` 588 | - (void)evaluateJavaScript:(NSString *)javaScriptString completionHandler:(void (^ _Nullable)(_Nullable id, NSError * _Nullable error))completionHandler; 589 | 第一个参数是你需要执行的js方法,参数义字符的形式拼接进去,这里面的数据转换类型和之前文档中的数据转换类型一样,请参考之前的例子 590 | ``` 591 | 实战如下: 592 | 调用js中的代码: 593 | 594 | ``` 595 | js中的代码: 596 | function alertSendMsg(num,msg) 597 | { 598 | var objc = new num(); 599 | document.getElementById('msg').innerHTML = '这是我的手机号:' + objc.key + ',' + msg + '!!' 600 | return {'ket':{'key':'wwwww'}} 601 | } 602 | 603 | function SMSDK() 604 | { 605 | this.ocTest = function ocTest(num,msg) 606 | { 607 | document.getElementById('msg').innerHTML = '这是我的手机号:' + num + ',' + msg + '!!' 608 | var obj = new Object(); 609 | obj.name = '叫我山神' 610 | obj.qq = '1096452045' 611 | return obj 612 | } 613 | } 614 | var $smsdk = new SMSDK(); 615 | 616 | ios中的调用代码 617 | 618 | $smsdk.ocTest('18870707070','只能传字符串') // @"alertSendMsg('18870707070','只能传字符串')" 619 | [self.wkwebV evaluateJavaScript:@"$smsdk.ocTest({key:111},[2000,2001])" completionHandler:^(id _Nullable resp, NSError * _Nullable error) { 620 | if (error) 621 | { 622 | NSLog(@"---error----%@",error); 623 | } 624 | else 625 | { 626 | NSLog(@"--------resp-------%@",resp); 627 | } 628 | }]; 629 | 上面的代码一目了然,第一个参数就是js的方法,主要说说参数回调 630 | resp参数是js返回来的对象,中间的数据转换和上文说的一样 631 | ``` 632 | #### 2, js调用ios 633 | 634 | 也非常简单只有一行代码 635 | 636 | ``` 637 | - (void)addScriptMessageHandler:(id )scriptMessageHandler name:(NSString *)name; 638 | 这个参数是接受回调的代理对象,这个位置不能是控制器的self,可以选自己创建的类, 639 | 第二个参数就是js中的方法名字 640 | ``` 641 | 例子: 642 | 1, 自己注入js代码(如果自己不注入js代码这一步直接忽略) 643 | 644 | ``` 645 | NSString *javaScriptSource =@"function userFunc(){alert('警告的窗口')}"; 646 | WKUserScript *userScript = [[WKUserScript alloc] initWithSource:javaScriptSource injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:NO]; 647 | [userController addUserScript:userScript]; 648 | ``` 649 | 2, 注册js中的方法名字 650 | 651 | ``` 652 | [userController addScriptMessageHandler:self.objc name:@"showSendMsg"]; 653 | [userController addScriptMessageHandler:self.objc name:@"userFunc"]; // 自己注册的方法 654 | ``` 655 | 2.1, js中的代码如下 656 | 657 | ``` 658 | function btnClick3() 659 | { 660 | window.webkit.messageHandlers.showSendMsg.postMessage(['13300001111', '{ww:我是,ee:方法无法}']) 661 | } 662 | showSendMsg 这个就是你 ios代码注册的js的方法 663 | postMessage(a,b) 这个方法接受两个参数,传递参数的规则还是之前说的, 数据类型js和ios有一个对照表,你可以参考之前的文档 664 | ``` 665 | 2.2 ,上面注册代码的时候,第一个参数传了一个遵守代理回调协议的对象,没错回调的数据就是去这个方法获取 666 | 667 | ``` 668 | - (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message 669 | { 670 | if ([message.name isEqualToString:@"showSendMsg"]) 671 | { 672 | NSArray *array = message.body; 673 | NSString *info = [NSString stringWithFormat:@"这是我的手机号: %@, %@ !!",array.firstObject,array.lastObject]; 674 | NSLog(info); 675 | } 676 | } 677 | 只有js那边调用方法,发送数据就会走这个方法,ios就可以做响应的处理 678 | ``` 679 | 680 | 实际项目的例子: 681 | 挖联网APP的js交互,我们约定html所有的需要交互的接口统一调用Call方法,唯一区别就是传递的参数是一个对象,我们在ios会解析成字典,字典中包含了 ClassName 这样的字段,我们根据这个字段动态创建一个类去处理这个js交互的数据 682 | 683 | 至此我们所有的交互就搞定了,是不是觉得非常的简单呢! 684 | 685 | 之前的文档: 686 | https://www.jianshu.com/p/c7a7c2211be7 687 | 本文档Demo 688 | https://github.com/wangjinshan/JSCDemo 689 | 690 | --------------------------------------------------------------------------------