1- //
2- // WKJavaScriptController.swift
3- // Ridibooks
4- //
5- // Created by Da Vin Ahn on 2017. 1. 12..
6- // Copyright © 2017년 Ridibooks. All rights reserved.
7- //
8-
91import WebKit
102
113private var javaScriptControllerKey : UInt8 = 0
@@ -26,8 +18,10 @@ public extension WKWebView {
2618 // return super.loadHTMLString(string, baseURL: baseURL)
2719 // }
2820 public func prepareForJavaScriptController( ) {
29- if let controller = javaScriptController, controller. needsInject && configuration. preferences. javaScriptEnabled {
30- controller. injectTo ( configuration. userContentController)
21+ if let controller = javaScriptController,
22+ controller. needsInject,
23+ configuration. preferences. javaScriptEnabled {
24+ controller. injectTo ( configuration. userContentController)
3125 }
3226 }
3327}
@@ -58,8 +52,10 @@ open class JSFloat: JSValueType {
5852 }
5953}
6054
61- public let WKJavaScriptControllerIgnoredMethodInvocationNotification = NSNotification . Name ( rawValue: " WKJavaScriptControllerIgnoredMethodInvocationNotification " )
62- public let WKJavaScriptControllerWillMethodInvocationNotification = NSNotification . Name ( rawValue: " WKJavaScriptControllerWillMethodInvocationNotification " )
55+ public extension Notification . Name {
56+ static let WKJavaScriptControllerIgnoredMethodInvocation = Notification . Name ( " WKJavaScriptControllerIgnoredMethodInvocationNotification " )
57+ static let WKJavaScriptControllerWillMethodInvocation = Notification . Name ( " WKJavaScriptControllerWillMethodInvocationNotification " )
58+ }
6359
6460open class WKJavaScriptController : NSObject {
6561 // If true, do not allow NSNull(If passed undefined in JavaScript) for method arguments.
@@ -69,12 +65,12 @@ open class WKJavaScriptController: NSObject {
6965 // If true, converts to dictionary when json string is received as an argument.
7066 open var shouldConvertJSONString = true
7167
72- fileprivate let name : String
68+ private let bridgeProtocol : Protocol
69+ private let name : String
7370 fileprivate weak var target : AnyObject ?
74- fileprivate let bridgeProtocol : Protocol
7571
7672 // User script that will use the bridge.
77- fileprivate var userScripts = [ WKUserScript] ( )
73+ private var userScripts = [ WKUserScript] ( )
7874
7975 fileprivate var bridgeList = [ MethodBridge] ( )
8076
@@ -126,86 +122,88 @@ open class WKJavaScriptController: NSObject {
126122 parseBridgeProtocol ( )
127123 }
128124
129- fileprivate func protocolsAdoptedBy( `protocol`: Protocol ) -> [ Protocol ] {
125+ private func protocolsAdoptedBy( `protocol`: Protocol ) -> [ Protocol ] {
130126 var protocols = [ `protocol`]
131127 let protocolList = protocol_copyProtocolList ( `protocol`, nil )
132- if protocolList != nil , let list = Optional ( protocolList) {
133- if let adoptedProtocol = list? . pointee {
134- protocols += protocolsAdoptedBy ( protocol: adoptedProtocol)
135- }
128+ if protocolList != nil ,
129+ let list = Optional ( protocolList) {
130+ if let adoptedProtocol = list? . pointee {
131+ protocols += protocolsAdoptedBy ( protocol: adoptedProtocol)
132+ }
136133 }
137134 return protocols
138135 }
139136
140- fileprivate func parseBridgeProtocol( ) {
137+ private func parseBridgeProtocol( ) {
141138 for `protocol` in protocolsAdoptedBy ( protocol: bridgeProtocol. self) . reversed ( ) {
142139 log ( " Protocol: \( String ( format: " %s " , protocol_getName ( `protocol`) ) ) " )
143140
144141 // Class methods are not supported.
145142 for (isRequired, isInstance) in [ ( true , true ) , ( false , true ) ] {
146143 let methodList = protocol_copyMethodDescriptionList ( `protocol`, isRequired, isInstance, nil )
147- if methodList != nil , var list = Optional ( methodList) {
148- let limit = argumentLengthLimit
149- while list? . pointee. name != nil {
150- defer { list = list? . successor ( ) }
151-
152- guard let selector = list? . pointee. name,
153- let types = list? . pointee. types,
154- let signature = String ( cString: types, encoding: String . Encoding. utf8) else {
155- log ( " Method signature not found, so it was excluded. (selector: \( list? . pointee. name ?? Selector ( ( " nil " ) ) ) ) " )
144+ if methodList != nil ,
145+ var list = Optional ( methodList) {
146+ let limit = argumentLengthLimit
147+ while list? . pointee. name != nil {
148+ defer { list = list? . successor ( ) }
149+
150+ guard let selector = list? . pointee. name,
151+ let types = list? . pointee. types,
152+ let signature = String ( cString: types, encoding: . utf8) else {
153+ log ( " Method signature not found, so it was excluded. (selector: \( list? . pointee. name ?? Selector ( ( " nil " ) ) ) ) " )
154+ continue
155+ }
156+
157+ // Ref: http://nshipster.com/type-encodings/
158+ // c: A char v: A void
159+ // C: An unsigned char B: A C++ bool or C99 _bool
160+ // i: An int @: An object (whether statically typed or typed id)
161+ // I: An unsigned int #: A class object
162+ // s: A short :: A method selector (SEL)
163+ // S: An unsigned short [array type]: An array
164+ // l: A long {name=type...}: A structure
165+ // L: An unsigned long (name=type...): A union
166+ // q: A long long bnum: A bit field of num bits
167+ // Q: An unsigned long long ^type: A pointer to type
168+ // f: A float ?: An unknown type (among other things, this code is used for function pointers)
169+ // d: A double
170+ if !signature. hasPrefix ( " v " ) {
171+ log ( " Can not receive native return in JavaScript, so it was excluded. (selector: \( selector) ) " )
156172 continue
173+ }
174+
175+ if signature. range ( of: " [cC# \\ [ \\ { \\ (b \\ ^ \\ ?] " , options: . regularExpression) != nil {
176+ log ( " It has an unsupported reference type as arguments, so it was excluded. (selector: \( selector) ) " )
177+ log ( " Allowed reference types are NSNumber, NSString, NSDate, NSArray, NSDictionary, and NSNull. " )
178+ continue
179+ }
180+
181+ // Value types of Swift can't be used. because method call is based on ObjC.
182+ if signature. range ( of: " [iIsSlLqQfdB] " , options: . regularExpression) != nil {
183+ log ( " It has an unsupported value type as arguments, so it was excluded. (selector: \( selector) ) " )
184+ log ( " Allowed value types are JSBool, JSInt and JSFloat. " )
185+ continue
186+ }
187+
188+ let bridge = MethodBridge ( nativeSelector: selector)
189+ if bridge. argumentLength > limit {
190+ log ( " Argument length is longer than \( limit) , so it was excluded. (selector: \( bridge. nativeSelector) ) " )
191+ continue
192+ }
193+
194+ // Using ObjC style naming if have a method with the same name.
195+ let list = bridgeList. filter { $0. jsSelector == bridge. jsSelector }
196+ if !list. isEmpty {
197+ bridge. extendJsSelector = true
198+ }
199+ for bridge in list {
200+ bridge. extendJsSelector = true
201+ }
202+
203+ bridgeList. append ( bridge)
204+ log ( " Parsed: \( isRequired ? " " : " Optional " ) \( bridge. nativeSelector) -> \( bridge. jsSelector) " )
157205 }
158-
159- // Ref: http://nshipster.com/type-encodings/
160- // c: A char v: A void
161- // C: An unsigned char B: A C++ bool or C99 _bool
162- // i: An int @: An object (whether statically typed or typed id)
163- // I: An unsigned int #: A class object
164- // s: A short :: A method selector (SEL)
165- // S: An unsigned short [array type]: An array
166- // l: A long {name=type...}: A structure
167- // L: An unsigned long (name=type...): A union
168- // q: A long long bnum: A bit field of num bits
169- // Q: An unsigned long long ^type: A pointer to type
170- // f: A float ?: An unknown type (among other things, this code is used for function pointers)
171- // d: A double
172- if !signature. hasPrefix ( " v " ) {
173- log ( " Can not receive native return in JavaScript, so it was excluded. (selector: \( selector) ) " )
174- continue
175- }
176-
177- if signature. range ( of: " [cC# \\ [ \\ { \\ (b \\ ^ \\ ?] " , options: [ . regularExpression] ) != nil {
178- log ( " It has an unsupported reference type as arguments, so it was excluded. (selector: \( selector) ) " )
179- log ( " Allowed reference types are NSNumber, NSString, NSDate, NSArray, NSDictionary, and NSNull. " )
180- continue
181- }
182-
183- // Value types of Swift can't be used. because method call is based on ObjC.
184- if signature. range ( of: " [iIsSlLqQfdB] " , options: [ . regularExpression] ) != nil {
185- log ( " It has an unsupported value type as arguments, so it was excluded. (selector: \( selector) ) " )
186- log ( " Allowed value types are JSBool, JSInt and JSFloat. " )
187- continue
188- }
189-
190- let bridge = MethodBridge ( nativeSelector: selector)
191- if bridge. argumentLength > limit {
192- log ( " Argument length is longer than \( limit) , so it was excluded. (selector: \( bridge. nativeSelector) ) " )
193- continue
194- }
195-
196- // Using ObjC style naming if have a method with the same name.
197- let list = bridgeList. filter ( { $0. jsSelector == bridge. jsSelector } )
198- if !list. isEmpty {
199- bridge. extendJsSelector = true
200- }
201- for bridge in list {
202- bridge. extendJsSelector = true
203- }
204-
205- bridgeList. append ( bridge)
206- log ( " Parsed: \( isRequired ? " " : " Optional " ) \( bridge. nativeSelector) -> \( bridge. jsSelector) " )
207- }
208- free ( methodList)
206+ free ( methodList)
209207 }
210208 }
211209 }
@@ -226,7 +224,7 @@ open class WKJavaScriptController: NSObject {
226224 needsInject = false
227225 }
228226
229- fileprivate func bridgeScript( _ forMainFrameOnly: Bool ) -> WKUserScript {
227+ private func bridgeScript( _ forMainFrameOnly: Bool ) -> WKUserScript {
230228 var source = " window. \( name) = { "
231229 for bridge in bridgeList {
232230 source += " \( bridge. jsSelector) : function() { window.webkit.messageHandlers. \( ( bridge. jsSelector) ) .postMessage(Array.prototype.slice.call(arguments)); }, "
@@ -294,7 +292,7 @@ extension WKJavaScriptController: WKScriptMessageHandler {
294292
295293 func cast( _ arg: Arg ) -> Arg {
296294 if let number = arg as? NSNumber ,
297- let type = String ( cString: number. objCType, encoding: String . Encoding . utf8) {
295+ let type = String ( cString: number. objCType, encoding: . utf8) {
298296 switch type {
299297 case " c " , " C " , " B " :
300298 return JSBool ( value: number)
@@ -309,18 +307,19 @@ extension WKJavaScriptController: WKScriptMessageHandler {
309307 } else if shouldConvertJSONString,
310308 let string = arg as? String ,
311309 let data = string. data ( using: . utf8) ,
312- let json = try ? JSONSerialization . jsonObject ( with: data, options: [ . allowFragments] ) {
310+ let json = try ? JSONSerialization . jsonObject ( with: data, options: . allowFragments) {
313311 return json as Arg
314312 }
315313 return arg
316314 }
317315
316+ let notificationCenter = NotificationCenter . default
318317 let userInfo = [
319318 " nativeSelector " : bridge. nativeSelector,
320319 " jsSelector " : bridge. jsSelector,
321320 " args " : args
322321 ] as [ String : Any ]
323- NotificationCenter . default . post ( name: WKJavaScriptControllerWillMethodInvocationNotification , object: nil , userInfo: userInfo)
322+ notificationCenter . post ( name: . WKJavaScriptControllerWillMethodInvocation , object: nil , userInfo: userInfo)
324323
325324 if shouldSafeMethodCall {
326325 for arg in args {
@@ -331,7 +330,7 @@ extension WKJavaScriptController: WKScriptMessageHandler {
331330 " args " : args,
332331 " reason " : " Arguments has NSNull(=undefined). "
333332 ] as [ String : Any ]
334- NotificationCenter . default . post ( name: WKJavaScriptControllerIgnoredMethodInvocationNotification , object: nil , userInfo: userInfo)
333+ notificationCenter . post ( name: . WKJavaScriptControllerIgnoredMethodInvocation , object: nil , userInfo: userInfo)
335334 return
336335 }
337336 }
0 commit comments