├── JavaScriptInterfaceDemo.xcodeproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ │ └── Kem.xcuserdatad │ │ └── UserInterfaceState.xcuserstate ├── xcuserdata │ └── Kem.xcuserdatad │ │ └── xcschemes │ │ ├── xcschememanagement.plist │ │ └── JavaScriptInterfaceDemo.xcscheme └── project.pbxproj ├── JavaScriptInterfaceDemo ├── index.html ├── JSInterface.swift ├── Assets.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json ├── Info.plist ├── ViewController.swift ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── AppDelegate.swift └── UIWebViewExt.swift ├── .gitignore └── README.md /JavaScriptInterfaceDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /JavaScriptInterfaceDemo.xcodeproj/project.xcworkspace/xcuserdata/Kem.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suale-dev/JavaScriptInterface/HEAD/JavaScriptInterfaceDemo.xcodeproj/project.xcworkspace/xcuserdata/Kem.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /JavaScriptInterfaceDemo.xcodeproj/xcuserdata/Kem.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | JavaScriptInterfaceDemo.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | BAE3D6891BA53660002F9581 16 | 17 | primary 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /JavaScriptInterfaceDemo/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |

Demo App

6 | 7 |

Click the button to call native function.

8 | 9 | 10 | 11 |
12 | 13 | 14 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /JavaScriptInterfaceDemo/JSInterface.swift: -------------------------------------------------------------------------------- 1 | // 2 | // JSInterface.swift 3 | // JSInterface 4 | // 5 | // Created by Kem on 9/12/15. 6 | // Copyright © 2015 Kem. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import JavaScriptCore 11 | import UIKit 12 | 13 | @objc protocol MyExport : JSExport 14 | { 15 | func check(_ message : String) 16 | func sayGreeting(_ message: String, _ name: String) 17 | func anotherSayGreeting(_ message: String, name: String) 18 | func showDialog(_ title: String, _ message : String) 19 | } 20 | 21 | 22 | class JSInterface : NSObject, MyExport 23 | { 24 | func check(_ message: String) { 25 | print("JS Interface works!") 26 | } 27 | 28 | func sayGreeting(_ message: String, _ name: String) 29 | { 30 | print("sayGreeting: \(message): \(name)") 31 | } 32 | 33 | func anotherSayGreeting(_ message: String, name: String) 34 | { 35 | print("anotherSayGreeting: \(message): \(name)") 36 | } 37 | 38 | func showDialog(_ title: String, _ message : String) 39 | { 40 | DispatchQueue.main.async(execute: { 41 | UIAlertView(title: title, message: message, delegate: nil, cancelButtonTitle: "OK").show() 42 | }) 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /JavaScriptInterfaceDemo/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 | "idiom" : "ipad", 35 | "size" : "29x29", 36 | "scale" : "1x" 37 | }, 38 | { 39 | "idiom" : "ipad", 40 | "size" : "29x29", 41 | "scale" : "2x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "40x40", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "40x40", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "76x76", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "76x76", 61 | "scale" : "2x" 62 | } 63 | ], 64 | "info" : { 65 | "version" : 1, 66 | "author" : "xcode" 67 | } 68 | } -------------------------------------------------------------------------------- /JavaScriptInterfaceDemo/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 | UISupportedInterfaceOrientations~ipad 40 | 41 | UIInterfaceOrientationPortrait 42 | UIInterfaceOrientationPortraitUpsideDown 43 | UIInterfaceOrientationLandscapeLeft 44 | UIInterfaceOrientationLandscapeRight 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData/ 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata/ 19 | 20 | ## Other 21 | *.moved-aside 22 | *.xccheckout 23 | *.xcscmblueprint 24 | 25 | ## Obj-C/Swift specific 26 | *.hmap 27 | *.ipa 28 | *.dSYM.zip 29 | *.dSYM 30 | 31 | ## Playgrounds 32 | timeline.xctimeline 33 | playground.xcworkspace 34 | 35 | # Swift Package Manager 36 | # 37 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 38 | # Packages/ 39 | # Package.pins 40 | .build/ 41 | 42 | # CocoaPods 43 | # 44 | # We recommend against adding the Pods directory to your .gitignore. However 45 | # you should judge for yourself, the pros and cons are mentioned at: 46 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 47 | # 48 | # Pods/ 49 | 50 | # Carthage 51 | # 52 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 53 | # Carthage/Checkouts 54 | 55 | Carthage/Build 56 | 57 | # fastlane 58 | # 59 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 60 | # screenshots whenever they are needed. 61 | # For more information about the recommended setup visit: 62 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 63 | 64 | fastlane/report.xml 65 | fastlane/Preview.html 66 | fastlane/screenshots 67 | fastlane/test_output 68 | -------------------------------------------------------------------------------- /JavaScriptInterfaceDemo/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // JSInterface 4 | // 5 | // Created by Kem on 9/11/15. 6 | // Copyright © 2015 Kem. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class ViewController: UIViewController { 12 | 13 | @IBOutlet weak var webView : UIWebView! 14 | 15 | override func viewDidLoad() { 16 | super.viewDidLoad() 17 | let indexPath = Bundle.main.path(forResource: "index", ofType: "html", inDirectory: "/") 18 | if let indexPath = indexPath 19 | { 20 | do 21 | { 22 | let htmlContent = try String(contentsOfFile: indexPath, encoding: String.Encoding.utf8) 23 | 24 | let base = Bundle.main.resourceURL 25 | 26 | self.webView.addJavascriptInterface(JSInterface(), forKey: "Native"); 27 | 28 | self.webView.loadHTMLString(htmlContent, baseURL: base) 29 | 30 | } 31 | catch let err as NSError 32 | { 33 | print(err.debugDescription) 34 | } 35 | } 36 | // Do any additional setup after loading the view, typically from a nib. 37 | } 38 | 39 | @IBAction func showAlert(){ 40 | let result = self.webView.callJSMethod(name: "showAlert", agruments: "Sua", "80.51") 41 | 42 | print("result: \(result ?? "no return value")") 43 | } 44 | 45 | deinit { 46 | self.webView.removeJavascriptInterfaces() 47 | } 48 | 49 | override func didReceiveMemoryWarning() { 50 | super.didReceiveMemoryWarning() 51 | // Dispose of any resources that can be recreated. 52 | } 53 | 54 | 55 | } 56 | 57 | -------------------------------------------------------------------------------- /JavaScriptInterfaceDemo/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 | -------------------------------------------------------------------------------- /JavaScriptInterfaceDemo/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // JavaScriptInterfaceDemo 4 | // 5 | // Created by Kem on 9/13/15. 6 | // Copyright © 2015 Kem. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | 17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { 18 | // Override point for customization after application launch. 19 | return true 20 | } 21 | 22 | func applicationWillResignActive(_ application: UIApplication) { 23 | // 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. 24 | // 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. 25 | } 26 | 27 | func applicationDidEnterBackground(_ application: UIApplication) { 28 | // 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. 29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 30 | } 31 | 32 | func applicationWillEnterForeground(_ application: UIApplication) { 33 | // 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. 34 | } 35 | 36 | func applicationDidBecomeActive(_ application: UIApplication) { 37 | // 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. 38 | } 39 | 40 | func applicationWillTerminate(_ application: UIApplication) { 41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 42 | } 43 | 44 | 45 | } 46 | 47 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # JavaScriptInterface 2 | UIWebview extension help you to call native code from Javascript in the iOS application. And call Javascript function from iOS Application. 3 | 4 | Support Swift 4.0. It's similar WebView.addJavascriptInterface in the Android application. 5 | 6 | ## Setting your project 7 | 8 | Step 1: 9 | Expand the Link Binary With Libraries section and add the following item: 10 | JavaScriptCore.framework 11 | 12 | Step 2: 13 | - Define a protocol, inherit from JSExport protocol, which contains these native functions as you want to work with JavaScript. 14 | For example: 15 | 16 | ```swift 17 | @objc protocol MyExport : JSExport 18 | { 19 | func check(_ message : String) 20 | func sayGreeting(_ message: String, _ name: String) 21 | func anotherSayGreeting(_ message: String, name: String) 22 | func showDialog(_ title: String, _ message : String) 23 | } 24 | ``` 25 | 26 | Step 3: 27 | Define a class to implement native functions above. 28 | ```swift 29 | class JSInterface : NSObject, MyExport 30 | { 31 | func check(_ message: String) { 32 | print("JS Interface works!") 33 | } 34 | 35 | func sayGreeting(_ message: String, _ name: String) 36 | { 37 | print("sayGreeting: \(message): \(name)") 38 | } 39 | 40 | func anotherSayGreeting(_ message: String, name: String) 41 | { 42 | print("anotherSayGreeting: \(message): \(name)") 43 | } 44 | 45 | func showDialog(_ title: String, _ message : String) 46 | { 47 | dispatch_async(dispatch_get_main_queue(), { 48 | UIAlertView(title: title, message: message, delegate: nil, cancelButtonTitle: "OK").show() 49 | }) 50 | } 51 | } 52 | ``` 53 | 54 | Step 4: 55 | Create an outlet to the webview in your view controller 56 | ```swift 57 | @IBOutlet weak var webView : UIWebView! 58 | ``` 59 | 60 | Step 5: 61 | Add java script interface as below at viewDidLoad: 62 | ```swift 63 | self.webView.addJavascriptInterface(JSInterface(), forKey: "Native"); 64 | ``` 65 | # Usage 66 | 67 | ## Now to call those native functions above from JavaScipt is loaded your webview, just call: 68 | 69 | ```swift 70 | Native.check() 71 | 72 | Native.sayGreeting('Hello', 'JavaScript Interface') 73 | 74 | ``` 75 | 76 | ## Define a function showAlert in Javascript 77 | ```javascript 78 | 84 | ``` 85 | 86 | ## Now you can call Javascript function from iOS Application, from ViewController 87 | ```swift 88 | let result = self.webView.callJSMethod(name: "showAlert", agruments: "Sua", "80.51") 89 | 90 | print("result: \(result ?? "no return value")") 91 | ``` 92 | 93 | # Avoid memmory leak, at deinit of ViewController: 94 | ```swift 95 | deinit { 96 | self.webView.removeJavascriptInterfaces() 97 | } 98 | 99 | ``` 100 | 101 | 102 | 103 | 104 | -------------------------------------------------------------------------------- /JavaScriptInterfaceDemo.xcodeproj/xcuserdata/Kem.xcuserdatad/xcschemes/JavaScriptInterfaceDemo.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 33 | 34 | 40 | 41 | 42 | 43 | 44 | 45 | 56 | 58 | 64 | 65 | 66 | 67 | 68 | 69 | 75 | 77 | 83 | 84 | 85 | 86 | 88 | 89 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /JavaScriptInterfaceDemo/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 | 25 | 26 | 27 | 28 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /JavaScriptInterfaceDemo/UIWebViewExt.swift: -------------------------------------------------------------------------------- 1 | // 2 | // KWebView.swift 3 | // JSInterface 4 | // 5 | // Created by Kem on 9/12/15. 6 | // Copyright © 2015 Kem. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | import JavaScriptCore 12 | 13 | 14 | extension UIWebView { 15 | func addJavascriptInterface(_ object: T, forKey key: String){ 16 | if let existed = __jsExportDatas.first(where: { (exportData) -> Bool in 17 | return exportData.webView === self && exportData.key == key 18 | }) 19 | { 20 | existed.export = object 21 | } 22 | else { 23 | let exportData = JSExportData(webView: self, export: object, key: key) 24 | __jsExportDatas.append(exportData) 25 | } 26 | } 27 | 28 | func removeJavascriptInterfaces(){ 29 | 30 | let exportDatas = __jsExportDatas.filter({ (exportData) -> Bool in 31 | exportData.webView === self 32 | }) 33 | 34 | for exportData in exportDatas { 35 | let context = exportData.context 36 | context?.setObject(nil, forKeyedSubscript: exportData.key as (NSCopying & NSObjectProtocol)?) 37 | } 38 | 39 | __jsExportDatas = __jsExportDatas.filter({ (exportData) -> Bool in 40 | exportData.webView !== self 41 | }) 42 | print("count: \(__jsExportDatas.count)") 43 | 44 | } 45 | 46 | @discardableResult 47 | func callJSMethod(name: String, agruments: StringConvertable...) -> String?{ 48 | var agrumentString = "" 49 | for agrument in agruments { 50 | if agrumentString.count > 0 { 51 | agrumentString = "\(agrumentString)," 52 | } 53 | if agrument is String { 54 | agrumentString = "\(agrumentString)'\(agrument)'" 55 | } else if agrument is NSNumber { 56 | agrumentString = "\(agrumentString)\(agrument)" 57 | } else if let agrument = agrument as? [String: Any] { 58 | if let json = try? JSONSerialization.data(withJSONObject: agrument, options: []), let jsonString = String(data: json, encoding: .utf8) { 59 | agrumentString = "\(agrumentString)\(jsonString)" 60 | } else { 61 | fatalError("Only support [String: String] or [String: Numberic] !!") 62 | } 63 | } else { 64 | fatalError("Only support string or number or dictionary !!") 65 | } 66 | } 67 | let js = "\(name)(\(agrumentString))" 68 | print("call: \(js)") 69 | return self.stringByEvaluatingJavaScript(from: js) 70 | } 71 | } 72 | 73 | protocol StringConvertable {} 74 | extension Int: StringConvertable {} 75 | extension Float: StringConvertable {} 76 | extension Double: StringConvertable {} 77 | extension CGFloat: StringConvertable {} 78 | extension String: StringConvertable {} 79 | extension Dictionary: StringConvertable {} 80 | //TODO: update callJSMethod to support Array 81 | //extension Array: StringConvertable {} 82 | 83 | extension NSObject 84 | { 85 | @objc func webView(_ webView: AnyObject!, didCreateJavaScriptContext context: JSContext!, forFrame frame: AnyObject!) 86 | { 87 | let notifyDidCreateJavaScriptContext = {() -> Void in 88 | for exportData in __jsExportDatas 89 | { 90 | if exportData.export == nil{ 91 | continue 92 | } 93 | let webView = exportData.webView! 94 | let checksum = "__KKKWebView\(webView.hash)" 95 | webView.stringByEvaluatingJavaScript(from: "var \(checksum) = '\(checksum)'") 96 | if context.objectForKeyedSubscript(checksum).toString() == checksum 97 | { 98 | context.setObject(exportData.export!, forKeyedSubscript: exportData.key as (NSCopying & NSObjectProtocol)?) 99 | exportData.context = context 100 | } 101 | } 102 | } 103 | 104 | if (Thread.isMainThread) 105 | { 106 | notifyDidCreateJavaScriptContext() 107 | } 108 | else 109 | { 110 | DispatchQueue.main.async(execute: notifyDidCreateJavaScriptContext) 111 | } 112 | } 113 | } 114 | 115 | class JSExportData{ 116 | weak var webView: UIWebView? 117 | var export : JSExport? 118 | var key: String = "Native" 119 | var context: JSContext? 120 | 121 | init(webView: UIWebView, export: JSExport, key: String = "Native") { 122 | self.webView = webView 123 | self.export = export 124 | self.key = key 125 | } 126 | } 127 | var __jsExportDatas : [JSExportData] = [] 128 | -------------------------------------------------------------------------------- /JavaScriptInterfaceDemo.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | BAE3D68E1BA53660002F9581 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = BAE3D68D1BA53660002F9581 /* AppDelegate.swift */; }; 11 | BAE3D6901BA53660002F9581 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BAE3D68F1BA53660002F9581 /* ViewController.swift */; }; 12 | BAE3D6931BA53660002F9581 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = BAE3D6911BA53660002F9581 /* Main.storyboard */; }; 13 | BAE3D6951BA53660002F9581 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = BAE3D6941BA53660002F9581 /* Assets.xcassets */; }; 14 | BAE3D6981BA53660002F9581 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = BAE3D6961BA53660002F9581 /* LaunchScreen.storyboard */; }; 15 | BAE3D6A11BA536A4002F9581 /* JSInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = BAE3D69F1BA536A4002F9581 /* JSInterface.swift */; }; 16 | BAE3D6A21BA536A4002F9581 /* UIWebViewExt.swift in Sources */ = {isa = PBXBuildFile; fileRef = BAE3D6A01BA536A4002F9581 /* UIWebViewExt.swift */; }; 17 | BAE3D6A41BA5373D002F9581 /* index.html in Resources */ = {isa = PBXBuildFile; fileRef = BAE3D6A31BA5373D002F9581 /* index.html */; }; 18 | BAE3D6A61BA538FC002F9581 /* JavaScriptCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BAE3D6A51BA538FC002F9581 /* JavaScriptCore.framework */; }; 19 | /* End PBXBuildFile section */ 20 | 21 | /* Begin PBXFileReference section */ 22 | BAE3D68A1BA53660002F9581 /* JavaScriptInterfaceDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = JavaScriptInterfaceDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; 23 | BAE3D68D1BA53660002F9581 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 24 | BAE3D68F1BA53660002F9581 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 25 | BAE3D6921BA53660002F9581 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 26 | BAE3D6941BA53660002F9581 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 27 | BAE3D6971BA53660002F9581 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 28 | BAE3D6991BA53660002F9581 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 29 | BAE3D69F1BA536A4002F9581 /* JSInterface.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JSInterface.swift; sourceTree = ""; }; 30 | BAE3D6A01BA536A4002F9581 /* UIWebViewExt.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIWebViewExt.swift; sourceTree = ""; }; 31 | BAE3D6A31BA5373D002F9581 /* index.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = index.html; sourceTree = ""; }; 32 | BAE3D6A51BA538FC002F9581 /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; }; 33 | /* End PBXFileReference section */ 34 | 35 | /* Begin PBXFrameworksBuildPhase section */ 36 | BAE3D6871BA53660002F9581 /* Frameworks */ = { 37 | isa = PBXFrameworksBuildPhase; 38 | buildActionMask = 2147483647; 39 | files = ( 40 | BAE3D6A61BA538FC002F9581 /* JavaScriptCore.framework in Frameworks */, 41 | ); 42 | runOnlyForDeploymentPostprocessing = 0; 43 | }; 44 | /* End PBXFrameworksBuildPhase section */ 45 | 46 | /* Begin PBXGroup section */ 47 | BAE3D6811BA53660002F9581 = { 48 | isa = PBXGroup; 49 | children = ( 50 | BAE3D6A51BA538FC002F9581 /* JavaScriptCore.framework */, 51 | BAE3D68C1BA53660002F9581 /* JavaScriptInterfaceDemo */, 52 | BAE3D68B1BA53660002F9581 /* Products */, 53 | ); 54 | sourceTree = ""; 55 | }; 56 | BAE3D68B1BA53660002F9581 /* Products */ = { 57 | isa = PBXGroup; 58 | children = ( 59 | BAE3D68A1BA53660002F9581 /* JavaScriptInterfaceDemo.app */, 60 | ); 61 | name = Products; 62 | sourceTree = ""; 63 | }; 64 | BAE3D68C1BA53660002F9581 /* JavaScriptInterfaceDemo */ = { 65 | isa = PBXGroup; 66 | children = ( 67 | BAE3D6A31BA5373D002F9581 /* index.html */, 68 | BAE3D69F1BA536A4002F9581 /* JSInterface.swift */, 69 | BAE3D6A01BA536A4002F9581 /* UIWebViewExt.swift */, 70 | BAE3D68D1BA53660002F9581 /* AppDelegate.swift */, 71 | BAE3D68F1BA53660002F9581 /* ViewController.swift */, 72 | BAE3D6911BA53660002F9581 /* Main.storyboard */, 73 | BAE3D6941BA53660002F9581 /* Assets.xcassets */, 74 | BAE3D6961BA53660002F9581 /* LaunchScreen.storyboard */, 75 | BAE3D6991BA53660002F9581 /* Info.plist */, 76 | ); 77 | path = JavaScriptInterfaceDemo; 78 | sourceTree = ""; 79 | }; 80 | /* End PBXGroup section */ 81 | 82 | /* Begin PBXNativeTarget section */ 83 | BAE3D6891BA53660002F9581 /* JavaScriptInterfaceDemo */ = { 84 | isa = PBXNativeTarget; 85 | buildConfigurationList = BAE3D69C1BA53660002F9581 /* Build configuration list for PBXNativeTarget "JavaScriptInterfaceDemo" */; 86 | buildPhases = ( 87 | BAE3D6861BA53660002F9581 /* Sources */, 88 | BAE3D6871BA53660002F9581 /* Frameworks */, 89 | BAE3D6881BA53660002F9581 /* Resources */, 90 | ); 91 | buildRules = ( 92 | ); 93 | dependencies = ( 94 | ); 95 | name = JavaScriptInterfaceDemo; 96 | productName = JavaScriptInterfaceDemo; 97 | productReference = BAE3D68A1BA53660002F9581 /* JavaScriptInterfaceDemo.app */; 98 | productType = "com.apple.product-type.application"; 99 | }; 100 | /* End PBXNativeTarget section */ 101 | 102 | /* Begin PBXProject section */ 103 | BAE3D6821BA53660002F9581 /* Project object */ = { 104 | isa = PBXProject; 105 | attributes = { 106 | LastUpgradeCheck = 0920; 107 | ORGANIZATIONNAME = Kem; 108 | TargetAttributes = { 109 | BAE3D6891BA53660002F9581 = { 110 | CreatedOnToolsVersion = 7.0; 111 | DevelopmentTeam = MQDSDQ68ZR; 112 | LastSwiftMigration = 0920; 113 | }; 114 | }; 115 | }; 116 | buildConfigurationList = BAE3D6851BA53660002F9581 /* Build configuration list for PBXProject "JavaScriptInterfaceDemo" */; 117 | compatibilityVersion = "Xcode 3.2"; 118 | developmentRegion = English; 119 | hasScannedForEncodings = 0; 120 | knownRegions = ( 121 | en, 122 | Base, 123 | ); 124 | mainGroup = BAE3D6811BA53660002F9581; 125 | productRefGroup = BAE3D68B1BA53660002F9581 /* Products */; 126 | projectDirPath = ""; 127 | projectRoot = ""; 128 | targets = ( 129 | BAE3D6891BA53660002F9581 /* JavaScriptInterfaceDemo */, 130 | ); 131 | }; 132 | /* End PBXProject section */ 133 | 134 | /* Begin PBXResourcesBuildPhase section */ 135 | BAE3D6881BA53660002F9581 /* Resources */ = { 136 | isa = PBXResourcesBuildPhase; 137 | buildActionMask = 2147483647; 138 | files = ( 139 | BAE3D6981BA53660002F9581 /* LaunchScreen.storyboard in Resources */, 140 | BAE3D6A41BA5373D002F9581 /* index.html in Resources */, 141 | BAE3D6951BA53660002F9581 /* Assets.xcassets in Resources */, 142 | BAE3D6931BA53660002F9581 /* Main.storyboard in Resources */, 143 | ); 144 | runOnlyForDeploymentPostprocessing = 0; 145 | }; 146 | /* End PBXResourcesBuildPhase section */ 147 | 148 | /* Begin PBXSourcesBuildPhase section */ 149 | BAE3D6861BA53660002F9581 /* Sources */ = { 150 | isa = PBXSourcesBuildPhase; 151 | buildActionMask = 2147483647; 152 | files = ( 153 | BAE3D6901BA53660002F9581 /* ViewController.swift in Sources */, 154 | BAE3D6A21BA536A4002F9581 /* UIWebViewExt.swift in Sources */, 155 | BAE3D6A11BA536A4002F9581 /* JSInterface.swift in Sources */, 156 | BAE3D68E1BA53660002F9581 /* AppDelegate.swift in Sources */, 157 | ); 158 | runOnlyForDeploymentPostprocessing = 0; 159 | }; 160 | /* End PBXSourcesBuildPhase section */ 161 | 162 | /* Begin PBXVariantGroup section */ 163 | BAE3D6911BA53660002F9581 /* Main.storyboard */ = { 164 | isa = PBXVariantGroup; 165 | children = ( 166 | BAE3D6921BA53660002F9581 /* Base */, 167 | ); 168 | name = Main.storyboard; 169 | sourceTree = ""; 170 | }; 171 | BAE3D6961BA53660002F9581 /* LaunchScreen.storyboard */ = { 172 | isa = PBXVariantGroup; 173 | children = ( 174 | BAE3D6971BA53660002F9581 /* Base */, 175 | ); 176 | name = LaunchScreen.storyboard; 177 | sourceTree = ""; 178 | }; 179 | /* End PBXVariantGroup section */ 180 | 181 | /* Begin XCBuildConfiguration section */ 182 | BAE3D69A1BA53660002F9581 /* Debug */ = { 183 | isa = XCBuildConfiguration; 184 | buildSettings = { 185 | ALWAYS_SEARCH_USER_PATHS = NO; 186 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 187 | CLANG_CXX_LIBRARY = "libc++"; 188 | CLANG_ENABLE_MODULES = YES; 189 | CLANG_ENABLE_OBJC_ARC = YES; 190 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 191 | CLANG_WARN_BOOL_CONVERSION = YES; 192 | CLANG_WARN_COMMA = YES; 193 | CLANG_WARN_CONSTANT_CONVERSION = YES; 194 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 195 | CLANG_WARN_EMPTY_BODY = YES; 196 | CLANG_WARN_ENUM_CONVERSION = YES; 197 | CLANG_WARN_INFINITE_RECURSION = YES; 198 | CLANG_WARN_INT_CONVERSION = YES; 199 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 200 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 201 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 202 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 203 | CLANG_WARN_STRICT_PROTOTYPES = YES; 204 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 205 | CLANG_WARN_UNREACHABLE_CODE = YES; 206 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 207 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 208 | COPY_PHASE_STRIP = NO; 209 | DEBUG_INFORMATION_FORMAT = dwarf; 210 | ENABLE_STRICT_OBJC_MSGSEND = YES; 211 | ENABLE_TESTABILITY = YES; 212 | GCC_C_LANGUAGE_STANDARD = gnu99; 213 | GCC_DYNAMIC_NO_PIC = NO; 214 | GCC_NO_COMMON_BLOCKS = YES; 215 | GCC_OPTIMIZATION_LEVEL = 0; 216 | GCC_PREPROCESSOR_DEFINITIONS = ( 217 | "DEBUG=1", 218 | "$(inherited)", 219 | ); 220 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 221 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 222 | GCC_WARN_UNDECLARED_SELECTOR = YES; 223 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 224 | GCC_WARN_UNUSED_FUNCTION = YES; 225 | GCC_WARN_UNUSED_VARIABLE = YES; 226 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 227 | MTL_ENABLE_DEBUG_INFO = YES; 228 | ONLY_ACTIVE_ARCH = YES; 229 | SDKROOT = iphoneos; 230 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 231 | TARGETED_DEVICE_FAMILY = "1,2"; 232 | }; 233 | name = Debug; 234 | }; 235 | BAE3D69B1BA53660002F9581 /* Release */ = { 236 | isa = XCBuildConfiguration; 237 | buildSettings = { 238 | ALWAYS_SEARCH_USER_PATHS = NO; 239 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 240 | CLANG_CXX_LIBRARY = "libc++"; 241 | CLANG_ENABLE_MODULES = YES; 242 | CLANG_ENABLE_OBJC_ARC = YES; 243 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 244 | CLANG_WARN_BOOL_CONVERSION = YES; 245 | CLANG_WARN_COMMA = YES; 246 | CLANG_WARN_CONSTANT_CONVERSION = YES; 247 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 248 | CLANG_WARN_EMPTY_BODY = YES; 249 | CLANG_WARN_ENUM_CONVERSION = YES; 250 | CLANG_WARN_INFINITE_RECURSION = YES; 251 | CLANG_WARN_INT_CONVERSION = YES; 252 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 253 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 254 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 255 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 256 | CLANG_WARN_STRICT_PROTOTYPES = YES; 257 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 258 | CLANG_WARN_UNREACHABLE_CODE = YES; 259 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 260 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 261 | COPY_PHASE_STRIP = NO; 262 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 263 | ENABLE_NS_ASSERTIONS = NO; 264 | ENABLE_STRICT_OBJC_MSGSEND = YES; 265 | GCC_C_LANGUAGE_STANDARD = gnu99; 266 | GCC_NO_COMMON_BLOCKS = YES; 267 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 268 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 269 | GCC_WARN_UNDECLARED_SELECTOR = YES; 270 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 271 | GCC_WARN_UNUSED_FUNCTION = YES; 272 | GCC_WARN_UNUSED_VARIABLE = YES; 273 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 274 | MTL_ENABLE_DEBUG_INFO = NO; 275 | SDKROOT = iphoneos; 276 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 277 | TARGETED_DEVICE_FAMILY = "1,2"; 278 | VALIDATE_PRODUCT = YES; 279 | }; 280 | name = Release; 281 | }; 282 | BAE3D69D1BA53660002F9581 /* Debug */ = { 283 | isa = XCBuildConfiguration; 284 | buildSettings = { 285 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 286 | DEVELOPMENT_TEAM = MQDSDQ68ZR; 287 | INFOPLIST_FILE = JavaScriptInterfaceDemo/Info.plist; 288 | IPHONEOS_DEPLOYMENT_TARGET = 8.4; 289 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 290 | PRODUCT_BUNDLE_IDENTIFIER = com.kesustudio.JavaScriptInterfaceDemo; 291 | PRODUCT_NAME = "$(TARGET_NAME)"; 292 | SWIFT_SWIFT3_OBJC_INFERENCE = Default; 293 | SWIFT_VERSION = 4.0; 294 | }; 295 | name = Debug; 296 | }; 297 | BAE3D69E1BA53660002F9581 /* Release */ = { 298 | isa = XCBuildConfiguration; 299 | buildSettings = { 300 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 301 | DEVELOPMENT_TEAM = MQDSDQ68ZR; 302 | INFOPLIST_FILE = JavaScriptInterfaceDemo/Info.plist; 303 | IPHONEOS_DEPLOYMENT_TARGET = 8.4; 304 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 305 | PRODUCT_BUNDLE_IDENTIFIER = com.kesustudio.JavaScriptInterfaceDemo; 306 | PRODUCT_NAME = "$(TARGET_NAME)"; 307 | SWIFT_SWIFT3_OBJC_INFERENCE = Default; 308 | SWIFT_VERSION = 4.0; 309 | }; 310 | name = Release; 311 | }; 312 | /* End XCBuildConfiguration section */ 313 | 314 | /* Begin XCConfigurationList section */ 315 | BAE3D6851BA53660002F9581 /* Build configuration list for PBXProject "JavaScriptInterfaceDemo" */ = { 316 | isa = XCConfigurationList; 317 | buildConfigurations = ( 318 | BAE3D69A1BA53660002F9581 /* Debug */, 319 | BAE3D69B1BA53660002F9581 /* Release */, 320 | ); 321 | defaultConfigurationIsVisible = 0; 322 | defaultConfigurationName = Release; 323 | }; 324 | BAE3D69C1BA53660002F9581 /* Build configuration list for PBXNativeTarget "JavaScriptInterfaceDemo" */ = { 325 | isa = XCConfigurationList; 326 | buildConfigurations = ( 327 | BAE3D69D1BA53660002F9581 /* Debug */, 328 | BAE3D69E1BA53660002F9581 /* Release */, 329 | ); 330 | defaultConfigurationIsVisible = 0; 331 | defaultConfigurationName = Release; 332 | }; 333 | /* End XCConfigurationList section */ 334 | }; 335 | rootObject = BAE3D6821BA53660002F9581 /* Project object */; 336 | } 337 | --------------------------------------------------------------------------------