├── .circleci
└── config.yml
├── .gitignore
├── .swiftpm
└── xcode
│ └── package.xcworkspace
│ └── contents.xcworkspacedata
├── Cartfile
├── Cartfile.private
├── Cartfile.resolved
├── Example
├── AppDelegate.swift
├── Assets.xcassets
│ └── AppIcon.appiconset
│ │ └── Contents.json
├── AuthChallengeViewController.swift
├── Base.lproj
│ └── Base.lproj
│ │ ├── LaunchScreen.storyboard
│ │ └── Main.storyboard
├── FailedRequestViewController.swift
├── Info.plist
├── InvokeJSFunctionViewController.swift
├── JavaScriptAlertPanelViewController.swift
├── JavaScriptConfirmPanelViewController.swift
├── ObservingJSEventViewController.swift
├── OtherRequestViewController.swift
├── RedirectViewController.swift
└── ViewController.swift
├── LICENSE.md
├── Package.resolved
├── Package.swift
├── README.md
├── RxWebKit.podspec
├── RxWebKit.xcodeproj
├── project.pbxproj
└── xcshareddata
│ └── xcschemes
│ ├── Example.xcscheme
│ ├── RxWebKit.xcscheme
│ ├── RxWebKitTests-iOS.xcscheme
│ └── RxWebKitTests-macOS.xcscheme
├── RxWebKit.xcworkspace
├── contents.xcworkspacedata
└── xcshareddata
│ └── IDEWorkspaceChecks.plist
├── RxWebKitTests
├── ForwardsEventsBehavior.swift
├── HasEventsBehavior.swift
├── Info.plist
└── RxWebKitTests.swift
└── Sources
├── Info.plist
├── RxWebKit.h
└── RxWebKit
├── Rx+WebKit.swift
├── RxWKNavigationDelegateProxy.swift
├── RxWKUIDelegateEvents+Rx.swift
├── RxWKUIDelegateProxy.swift
├── RxWKUserContentController.swift
└── WKNavigationDelegateEvents+Rx.swift
/.circleci/config.yml:
--------------------------------------------------------------------------------
1 | ---
2 | version: 2
3 | jobs:
4 | "RxWebKit Tests":
5 | working_directory: ~/RxSwiftCommunity/RxWebKit
6 | parallelism: 1
7 | shell: /bin/bash --login
8 | environment:
9 | XCODE_TEST_REPORTS: /tmp/xcode-test-results
10 | LANG: en_US.UTF-8
11 | macos:
12 | xcode: '11.4.1'
13 | steps:
14 | - checkout
15 | - run: mkdir -p $CIRCLE_ARTIFACTS $CIRCLE_TEST_REPORTS $XCODE_TEST_REPORTS
16 | - restore_cache:
17 | keys:
18 | - v1-dep-{{ .Branch }}-
19 | - v1-dep-master-
20 | - v1-dep-
21 | - run:
22 | name: Bootstrap Carthage
23 | command: carthage update --no-use-binaries
24 | - save_cache:
25 | key: v1-dep-{{ .Branch }}-{{ epoch }}
26 | paths:
27 | - Carthage
28 | - run:
29 | name: Build (Swift 5.0)
30 | command: >
31 | set -o pipefail && xcodebuild build SWIFT_VERSION=5.2.2
32 | -workspace RxWebKit.xcworkspace
33 | -scheme 'RxWebKit' -sdk iphonesimulator
34 | -destination "name=iPhone 11" | xcpretty -c
35 | - run:
36 | name: Run Tests (Swift 5.0)
37 | command: >
38 | set -o pipefail && xcodebuild test SWIFT_VERSION=5.2.2
39 | -workspace RxWebKit.xcworkspace
40 | -scheme 'RxWebKitTests-iOS' -sdk iphonesimulator
41 | -destination "name=iPhone 11" | xcpretty -c --test
42 | - store_artifacts:
43 | path: /tmp/xcode-test-results
44 | workflows:
45 | version: 2
46 | build:
47 | jobs:
48 | - "RxWebKit Tests":
49 | filters:
50 | tags:
51 | ignore: /[0-9]+(\.[0-9]+)*/
52 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | # Created by https://www.gitignore.io/api/swift
3 |
4 | ### Swift ###
5 | # Xcode
6 | #
7 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
8 |
9 | ## Build generated
10 | build/
11 | DerivedData
12 |
13 | ## Various settings
14 | *.pbxuser
15 | !default.pbxuser
16 | *.mode1v3
17 | !default.mode1v3
18 | *.mode2v3
19 | !default.mode2v3
20 | *.perspectivev3
21 | !default.perspectivev3
22 | xcuserdata
23 |
24 | ## Other
25 | *.xccheckout
26 | *.moved-aside
27 | *.xcuserstate
28 | *.xcscmblueprint
29 |
30 | ## Obj-C/Swift specific
31 | *.hmap
32 | *.ipa
33 |
34 | ## Playgrounds
35 | timeline.xctimeline
36 | playground.xcworkspace
37 |
38 | # Swift Package Manager
39 | #
40 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
41 | # Packages/
42 | .build/
43 |
44 | # CocoaPods
45 | #
46 | # We recommend against adding the Pods directory to your .gitignore. However
47 | # you should judge for yourself, the pros and cons are mentioned at:
48 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
49 | #
50 | Pods/
51 |
52 | # Carthage
53 | #
54 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
55 | Carthage/Checkouts
56 |
57 | Carthage/Build
58 |
59 | # fastlane
60 | #
61 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
62 | # screenshots whenever they are needed.
63 | # For more information about the recommended setup visit:
64 | # https://github.com/fastlane/fastlane/blob/master/docs/Gitignore.md
65 |
66 | fastlane/report.xml
67 | fastlane/screenshots
68 |
--------------------------------------------------------------------------------
/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Cartfile:
--------------------------------------------------------------------------------
1 | github "ReactiveX/RxSwift" ~> 6.0
2 |
--------------------------------------------------------------------------------
/Cartfile.private:
--------------------------------------------------------------------------------
1 | github "Quick/Quick"
2 | github "Quick/Nimble"
3 |
--------------------------------------------------------------------------------
/Cartfile.resolved:
--------------------------------------------------------------------------------
1 | github "Quick/Nimble" "v9.0.0"
2 | github "Quick/Quick" "v3.0.0"
3 | github "ReactiveX/RxSwift" "6.0.0"
4 |
--------------------------------------------------------------------------------
/Example/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // Example
4 | //
5 | // Created by Daichi Ichihara on 2016/02/06.
6 | // Copyright © 2016年 RxSwift Community. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @UIApplicationMain
12 | class AppDelegate: UIResponder, UIApplicationDelegate {
13 |
14 | var window: UIWindow?
15 |
16 |
17 | private func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> 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 |
--------------------------------------------------------------------------------
/Example/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 | }
--------------------------------------------------------------------------------
/Example/AuthChallengeViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AuthChallengeViewController.swift
3 | // Example
4 | //
5 | // Created by Bob Obi on 25.10.17.
6 | // Copyright © 2017 RxSwift Community. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import WebKit
11 | import RxWebKit
12 | import RxSwift
13 | import RxCocoa
14 |
15 | class AuthChallengeViewController: UIViewController {
16 |
17 | let bag = DisposeBag()
18 | let wkWebView = WKWebView()
19 |
20 | override func viewDidLoad() {
21 | super.viewDidLoad()
22 | view.addSubview(wkWebView)
23 | wkWebView.load(URLRequest(url: URL(string: "https://jigsaw.w3.org/HTTP/Basic/")!))
24 |
25 | wkWebView.rx
26 | .didReceiveChallenge
27 | .debug("didReceiveChallenge")
28 | .subscribe(onNext: {(webView, challenge, handler) in
29 | guard challenge.previousFailureCount == 0 else {
30 | handler(URLSession.AuthChallengeDisposition.performDefaultHandling, nil)
31 | return
32 | }
33 | /*
34 | The correct credentials are:
35 |
36 | user = guest
37 | password = guest
38 |
39 | You might want to start with the invalid credentials to get a sense of how this code works
40 | */
41 | let credential = URLCredential(user: "bad-user", password: "bad-password", persistence: URLCredential.Persistence.forSession)
42 | challenge.sender?.use(credential, for: challenge)
43 | handler(URLSession.AuthChallengeDisposition.useCredential, credential)
44 | })
45 | .disposed(by: bag)
46 | }
47 |
48 | override func viewDidLayoutSubviews() {
49 | super.viewDidLayoutSubviews()
50 | let originY = UIApplication.shared.statusBarFrame.maxY
51 | wkWebView.frame = CGRect(x: 0, y: originY, width: view.bounds.width, height: view.bounds.height)
52 | }
53 |
54 | }
55 |
--------------------------------------------------------------------------------
/Example/Base.lproj/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 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/Example/Base.lproj/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 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 |
277 |
278 |
279 |
280 |
281 |
282 |
283 |
284 |
285 |
286 |
287 |
288 |
289 |
290 |
291 |
292 |
293 |
294 |
295 |
296 |
297 |
298 |
299 |
300 |
301 |
302 |
303 |
304 |
305 |
306 |
307 |
308 |
309 |
310 |
311 |
312 |
313 |
314 |
315 |
316 |
317 |
318 |
319 |
320 |
321 |
322 |
323 |
324 |
325 |
326 |
327 |
328 |
329 |
330 |
331 |
332 |
333 |
334 |
335 |
336 |
337 |
338 |
339 |
340 |
341 |
342 |
343 |
344 |
345 |
346 |
347 |
348 |
349 |
350 |
351 |
352 |
353 |
354 |
355 |
356 |
357 |
358 |
359 |
360 |
361 |
362 |
363 |
364 |
365 |
366 |
367 |
368 |
369 |
370 |
371 |
372 |
373 |
374 |
375 |
376 |
377 |
378 |
379 |
380 |
381 |
382 |
383 |
384 |
385 |
386 |
387 |
388 |
389 |
390 |
391 |
392 |
393 |
394 |
395 |
396 |
397 |
398 |
399 |
400 |
401 |
402 |
403 |
404 |
405 |
406 |
407 |
408 |
409 |
410 |
411 |
412 |
413 |
414 |
415 |
416 |
417 |
418 |
419 |
420 |
--------------------------------------------------------------------------------
/Example/FailedRequestViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // FailedRequestViewController.swift
3 | // Example
4 | //
5 | // Created by Bob Godwin Obi on 10/25/17.
6 | // Copyright © 2017 RxSwift Community. All rights reserved.
7 | //
8 | import UIKit
9 | import WebKit
10 | import RxWebKit
11 | import RxSwift
12 | import RxCocoa
13 |
14 | class FailedRequestViewController: UIViewController {
15 |
16 | let bag = DisposeBag()
17 | let wkWebView = WKWebView()
18 |
19 | override func viewDidLoad() {
20 | super.viewDidLoad()
21 | view.addSubview(wkWebView)
22 | wkWebView.load(URLRequest(url: URL(string: "https://thiswebsiteisnotexisting.com")!))
23 |
24 | wkWebView.rx
25 | .didFailProvisionalNavigation
26 | .observe(on: MainScheduler.instance)
27 | .debug("didFailProvisionalNavigation")
28 | .subscribe(onNext: { [weak self] webView, navigation, error in
29 | guard let self = self else { return }
30 | let alert = UIAlertController(title: "FailProvisionalNavigation", message: error.localizedDescription, preferredStyle: .alert)
31 | alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
32 | self.present(alert, animated: true, completion: nil)
33 | })
34 | .disposed(by: bag)
35 | }
36 |
37 | override func viewDidLayoutSubviews() {
38 | super.viewDidLayoutSubviews()
39 | let originY = UIApplication.shared.statusBarFrame.maxY
40 | wkWebView.frame = CGRect(x: 0, y: originY, width: view.bounds.width, height: view.bounds.height)
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/Example/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 | 0.3
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 |
45 |
46 |
--------------------------------------------------------------------------------
/Example/InvokeJSFunctionViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // InvokeJSFunctionViewController.swift
3 | // Example
4 | //
5 | // Created by Jesse Hao on 2019/4/1.
6 | // Copyright © 2019 RxSwift Community. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import WebKit
11 | import RxWebKit
12 | import RxSwift
13 | import RxCocoa
14 |
15 | fileprivate let html = """
16 |
17 |
18 |
19 | Invoke Javascript function
20 |
21 |
22 |
23 | Invoke Javascript function
24 | Just Press 'Invoke' at top right corner.
25 | After that, pay attention to your console.
26 |
27 |
32 |
33 |
34 |
35 |
36 | """
37 |
38 | class InvokeJSFunctionViewController : UIViewController {
39 | let bag = DisposeBag()
40 | let webview = WKWebView()
41 |
42 | override func viewDidLoad() {
43 | super.viewDidLoad()
44 | view.addSubview(webview)
45 | self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Invoke", style: .plain, target: nil, action: nil)
46 | self.navigationItem.rightBarButtonItem?.rx.tap
47 | .bind { [weak self] in
48 | guard let self = self else { return }
49 | self.webview.rx.evaluateJavaScript("presentAlert()")
50 | .observe(on: MainScheduler.asyncInstance)
51 | .subscribe { event in
52 | if case .next(let body) = event, let message = body as? String {
53 | print(message)
54 | }
55 | }.disposed(by: self.bag)
56 | }
57 | .disposed(by: self.bag)
58 | webview.loadHTMLString(html, baseURL: nil)
59 | }
60 |
61 | override func viewDidLayoutSubviews() {
62 | super.viewDidLayoutSubviews()
63 | let originY = UIApplication.shared.statusBarFrame.maxY
64 | webview.frame = CGRect(x: 0, y: originY, width: view.bounds.width, height: view.bounds.height)
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/Example/JavaScriptAlertPanelViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // JavaScriptAlertPanelViewController.swift
3 | // Example
4 | //
5 | // Created by Bob Obi on 25.10.17.
6 | // Copyright © 2017 RxSwift Community. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import WebKit
11 | import RxWebKit
12 | import RxSwift
13 | import RxCocoa
14 |
15 | class JavaScriptAlertPanelViewController: UIViewController {
16 |
17 | let bag = DisposeBag()
18 | let wkWebView = WKWebView()
19 |
20 | override func viewDidLoad() {
21 | super.viewDidLoad()
22 | view.addSubview(wkWebView)
23 | wkWebView.load(URLRequest(url: URL(string: "https://www.w3schools.com/jsref/tryit.asp?filename=tryjsref_alert")!))
24 |
25 | wkWebView.rx
26 | .javaScriptAlertPanel
27 | .debug("javaScriptAlertPanel")
28 | .subscribe(onNext: { [weak self] webView, message, frame, handler in
29 | guard let self = self else { return }
30 | let alert = UIAlertController(title: "JavaScriptAlertPanel", message: message, preferredStyle: .alert)
31 | alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
32 | self.present(alert, animated: true, completion: nil)
33 | handler()
34 | })
35 | .disposed(by: bag)
36 | }
37 |
38 | override func viewDidLayoutSubviews() {
39 | super.viewDidLayoutSubviews()
40 | let originY = UIApplication.shared.statusBarFrame.maxY
41 | wkWebView.frame = CGRect(x: 0, y: originY, width: view.bounds.width, height: view.bounds.height)
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/Example/JavaScriptConfirmPanelViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // JavaScriptConfirmPanelViewController.swift
3 | // Example
4 | //
5 | // Created by Bob Obi on 25.10.17.
6 | // Copyright © 2017 RxSwift Community. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import WebKit
11 | import RxWebKit
12 | import RxSwift
13 | import RxCocoa
14 |
15 | class JavaScriptConfirmPanelViewController: UIViewController {
16 |
17 | let bag = DisposeBag()
18 | let wkWebView = WKWebView()
19 |
20 | override func viewDidLoad() {
21 | super.viewDidLoad()
22 | view.addSubview(wkWebView)
23 | wkWebView.load(URLRequest(url: URL(string: "https://www.w3schools.com/jsref/tryit.asp?filename=tryjsref_confirm2")!))
24 |
25 | wkWebView.rx
26 | .javaScriptConfirmPanel
27 | .debug("javaScriptConfirmPanel")
28 | .subscribe(onNext: { [weak self] webView, message, frame, handler in
29 | guard let self = self else { return }
30 | let alert = UIAlertController(title: "JavaScriptConfirm", message: message, preferredStyle: .alert)
31 | alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
32 | self.present(alert, animated: true, completion: nil)
33 | handler(true)
34 | })
35 | .disposed(by: bag)
36 | }
37 |
38 | override func viewDidLayoutSubviews() {
39 | super.viewDidLayoutSubviews()
40 | let originY = UIApplication.shared.statusBarFrame.maxY
41 | wkWebView.frame = CGRect(x: 0, y: originY, width: view.bounds.width, height: view.bounds.height)
42 | }
43 |
44 | }
45 |
--------------------------------------------------------------------------------
/Example/ObservingJSEventViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ObservingJSEventViewController.swift
3 | // Example
4 | //
5 | // Created by Jesse Hao on 2019/4/1.
6 | // Copyright © 2019 RxSwift Community. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import WebKit
11 | import RxWebKit
12 | import RxSwift
13 | import RxCocoa
14 |
15 | fileprivate let html = """
16 |
17 |
18 |
19 |
20 |
21 |
22 | Click the button to display a confirm box.
23 |
24 |
25 |
26 |
27 |
28 |
33 |
34 |
35 |
36 | """
37 |
38 | class ObservingJSEventViewController : UIViewController {
39 | let bag = DisposeBag()
40 | let webview = WKWebView()
41 |
42 | override func viewDidLoad() {
43 | super.viewDidLoad()
44 | view.addSubview(webview)
45 | webview.configuration.userContentController.rx.scriptMessage(forName: "RxWebKitScriptMessageHandler").bind { [weak self] scriptMessage in
46 | guard let message = scriptMessage.body as? String else { return }
47 | let alert = UIAlertController(title: "JS Event Observed", message: message, preferredStyle: .alert)
48 | alert.addAction(UIAlertAction(title: "OK", style: .cancel))
49 | self?.present(alert, animated: true)
50 | }.disposed(by: self.bag)
51 | webview.loadHTMLString(html, baseURL: nil)
52 | }
53 |
54 | override func viewDidLayoutSubviews() {
55 | super.viewDidLayoutSubviews()
56 | let originY = UIApplication.shared.statusBarFrame.maxY
57 | webview.frame = CGRect(x: 0, y: originY, width: view.bounds.width, height: view.bounds.height)
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/Example/OtherRequestViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // OtherRequestViewController.swift
3 | // Example
4 | //
5 | // Created by Bob Godwin Obi on 10/25/17.
6 | // Copyright © 2017 RxSwift Community. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import WebKit
11 | import RxWebKit
12 | import RxSwift
13 | import RxCocoa
14 |
15 | class OtherRequestViewController: UIViewController {
16 |
17 | let bag = DisposeBag()
18 | let wkWebView = WKWebView()
19 |
20 | override func viewDidLoad() {
21 | super.viewDidLoad()
22 | view.addSubview(wkWebView)
23 | wkWebView.load(URLRequest(url: URL(string: "https://github.com/ReactiveX/RxSwift")!))
24 |
25 | wkWebView.rx
26 | .didFinishNavigation
27 | .debug("didFinishNavigation")
28 | .subscribe(onNext: {_ in })
29 | .disposed(by: bag)
30 |
31 | if #available(iOS 9.0, *) {
32 | wkWebView.rx
33 | .didTerminate
34 | .debug("didTerminate")
35 | .subscribe(onNext: {_ in })
36 | .disposed(by: bag)
37 | }
38 |
39 | wkWebView.rx
40 | .didCommitNavigation
41 | .debug("didCommitNavigation")
42 | .subscribe(onNext: {_ in })
43 | .disposed(by: bag)
44 |
45 | wkWebView.rx
46 | .didStartProvisionalNavigation
47 | .debug("didStartProvisionalNavigation")
48 | .subscribe(onNext: {_ in})
49 | .disposed(by: bag)
50 |
51 | if #available(iOS 10.0, *) {
52 | wkWebView.rx
53 | .commitPreviewing
54 | .debug("commitPreviewing")
55 | .subscribe(onNext:{_ in})
56 | .disposed(by: bag)
57 | }
58 |
59 | wkWebView.rx
60 | .decidePolicyNavigationResponse
61 | .debug("decidePolicyNavigationResponse")
62 | .subscribe(onNext: {(_, _, handler) in
63 | handler(.allow)
64 | })
65 | .disposed(by: bag)
66 |
67 | wkWebView.rx
68 | .decidePolicyNavigationAction
69 | .debug("decidePolicyNavigationAction")
70 | .subscribe(onNext: {(_, _, handler) in
71 | handler(.allow)
72 | })
73 | .disposed(by: bag)
74 | }
75 |
76 | override func viewDidLayoutSubviews() {
77 | super.viewDidLayoutSubviews()
78 | let originY = UIApplication.shared.statusBarFrame.maxY
79 | wkWebView.frame = CGRect(x: 0, y: originY, width: view.bounds.width, height: view.bounds.height)
80 | }
81 | }
82 |
83 |
--------------------------------------------------------------------------------
/Example/RedirectViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RedirectViewController.swift
3 | // Example
4 | //
5 | // Created by Bob Godwin Obi on 10/25/17.
6 | // Copyright © 2017 RxSwift Community. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import WebKit
11 | import RxWebKit
12 | import RxSwift
13 | import RxCocoa
14 |
15 | class RedirectViewController: UIViewController {
16 |
17 | let bag = DisposeBag()
18 | let wkWebView = WKWebView()
19 |
20 | override func viewDidLoad() {
21 | super.viewDidLoad()
22 | view.addSubview(wkWebView)
23 | wkWebView.load(URLRequest(url: URL(string: "http://www.webconfs.com/http-header-check.php")!))
24 |
25 | wkWebView.rx
26 | .didReceiveServerRedirectForProvisionalNavigation
27 | .observe(on: MainScheduler.instance)
28 | .debug("didReceiveServerRedirectForProvisionalNavigation")
29 | .subscribe(onNext: { [weak self] webView, navigation in
30 | guard let self = self else { return }
31 | let alert = UIAlertController(title: "Redirect Navigation", message: "you have bene redirected", preferredStyle: .alert)
32 | alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
33 | self.present(alert, animated: true, completion: nil)
34 | })
35 | .disposed(by: bag)
36 | }
37 |
38 | override func viewDidLayoutSubviews() {
39 | super.viewDidLayoutSubviews()
40 | let originY = UIApplication.shared.statusBarFrame.maxY
41 | wkWebView.frame = CGRect(x: 0, y: originY, width: view.bounds.width, height: view.bounds.height)
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/Example/ViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.swift
3 | // Example
4 | //
5 | // Created by Daichi Ichihara on 2016/02/06.
6 | // Copyright © 2016年 RxSwift Community. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import WebKit
11 | import RxWebKit
12 | import RxSwift
13 | import RxCocoa
14 |
15 | class ViewController: UIViewController {
16 |
17 | @IBOutlet weak var toolBar: UIToolbar!
18 | @IBOutlet weak var backButton: UIBarButtonItem!
19 | @IBOutlet weak var forwardButton: UIBarButtonItem!
20 |
21 | var wkWebView = WKWebView()
22 | let disposeBag = DisposeBag()
23 |
24 | override func viewDidLoad() {
25 | super.viewDidLoad()
26 | self.view.addSubview(wkWebView)
27 | let request = URLRequest(url: URL(string: "https://github.com/ReactiveX/RxSwift")!)
28 | wkWebView.load(request)
29 |
30 | observeReadOnlyProperties(wkWebView: wkWebView)
31 | observeToolBarButtonItems()
32 | }
33 |
34 | override func viewDidLayoutSubviews() {
35 | super.viewDidLayoutSubviews()
36 | let originY = UIApplication.shared.statusBarFrame.maxY
37 | wkWebView.frame = CGRect(
38 | x: 0,
39 | y: originY,
40 | width: self.view.bounds.width,
41 | height: toolBar.frame.minY - originY
42 | )
43 | }
44 |
45 | private func observeReadOnlyProperties(wkWebView: WKWebView) {
46 | wkWebView.rx.title
47 | .share(replay: 1)
48 | .subscribe(onNext: {
49 | print("title: \(String(describing: $0))")
50 | })
51 | .disposed(by: disposeBag)
52 |
53 | wkWebView.rx.url
54 | .share(replay: 1)
55 | .subscribe(onNext: {
56 | print("URL: \(String(describing: $0))")
57 | })
58 | .disposed(by: disposeBag)
59 |
60 | wkWebView.rx.estimatedProgress
61 | .share(replay: 1)
62 | .subscribe(onNext: {
63 | print("estimatedProgress: \($0)")
64 | })
65 | .disposed(by: disposeBag)
66 |
67 | wkWebView.rx.loading
68 | .share(replay: 1)
69 | .subscribe(onNext: {
70 | print("loading: \($0)")
71 | })
72 | .disposed(by: disposeBag)
73 |
74 | wkWebView.rx.canGoBack
75 | .share(replay: 1)
76 | .subscribe(onNext: { [weak self] in
77 | self?.backButton.isEnabled = $0
78 | })
79 | .disposed(by: disposeBag)
80 |
81 | wkWebView.rx.canGoForward
82 | .share(replay: 1)
83 | .subscribe(onNext: { [weak self] in
84 | self?.forwardButton.isEnabled = $0
85 | })
86 | .disposed(by: disposeBag)
87 | }
88 |
89 | private func observeToolBarButtonItems() {
90 | backButton.rx.tap
91 | .share(replay: 1)
92 | .subscribe(onNext: { [weak self] in
93 | _ = self?.wkWebView.goBack()
94 | })
95 | .disposed(by: disposeBag)
96 |
97 | forwardButton.rx.tap
98 | .share(replay: 1)
99 | .subscribe(onNext: { [weak self] in
100 | _ = self?.wkWebView.goForward()
101 | })
102 | .disposed(by: disposeBag)
103 | }
104 |
105 | }
106 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | **The MIT License**
2 | **Copyright © 2016 Daichi Ichihara **
3 | **All rights reserved.**
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6 |
7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8 |
9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
10 |
--------------------------------------------------------------------------------
/Package.resolved:
--------------------------------------------------------------------------------
1 | {
2 | "object": {
3 | "pins": [
4 | {
5 | "package": "RxSwift",
6 | "repositoryURL": "https://github.com/ReactiveX/RxSwift.git",
7 | "state": {
8 | "branch": null,
9 | "revision": "b4307ba0b6425c0ba4178e138799946c3da594f8",
10 | "version": "6.5.0"
11 | }
12 | }
13 | ]
14 | },
15 | "version": 1
16 | }
17 |
--------------------------------------------------------------------------------
/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version:5.0
2 | import PackageDescription
3 |
4 | let package = Package(
5 | name: "RxWebKit",
6 | platforms: [.iOS(.v9), .macOS(.v10_13)],
7 | products: [
8 | .library(name: "RxWebKit", targets: ["RxWebKit"])
9 | ],
10 | dependencies: [
11 | .package(url: "https://github.com/ReactiveX/RxSwift.git", .upToNextMajor(from: "6.0.0"))
12 | ],
13 | targets: [
14 | .target(
15 | name: "RxWebKit",
16 | dependencies: ["RxSwift", "RxCocoa"]
17 | )
18 | ],
19 | swiftLanguageVersions: [.v5]
20 | )
21 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # RxWebKit
2 |
3 | RxWebKit is a [RxSwift](https://github.com/ReactiveX/RxSwift) wrapper for `WebKit`.
4 |
5 | [](https://github.com/Carthage/Carthage)
6 | [](http://cocoapods.org/pods/RxWebKit)
7 | [](http://cocoapods.org/pods/RxWebKit)
8 | [](http://cocoapods.org/pods/RxWebKit)
9 |
10 | ## Example Usages
11 |
12 | ```swift
13 | // MARK: Setup WKWebView
14 |
15 | let webView = WKWebView(frame: self.view.bounds)
16 | self.view.addSubview(webView)
17 |
18 |
19 | // MARK: Observing properties
20 |
21 | webView.rx.title
22 | .subscribe(onNext: {
23 | print("title: \($0)")
24 | })
25 | .disposed(by: disposeBag)
26 |
27 | webView.rx.url
28 | .subscribe(onNext: {
29 | print("URL: \($0)")
30 | })
31 | .disposed(by: disposeBag)
32 | ```
33 |
34 | ## Installation
35 |
36 | ### CocoaPods
37 |
38 | Add to `Podfile`:
39 |
40 | ```
41 | pod 'RxWebKit'
42 | ```
43 |
44 | ### Carthage
45 |
46 | Add to `Cartfile`:
47 |
48 | ```
49 | github "RxSwiftCommunity/RxWebKit"
50 | ```
51 |
52 | Run `carthage update --platform iOS`
53 |
54 | Add run script build phase `/usr/local/bin/carthage copy-frameworks` with input files being:
55 |
56 | ```
57 | $(SRCROOT)/carthage/Build/iOS/RxWebKit.framework
58 | ```
59 |
60 | ## Requirements
61 |
62 | RxWebKit requires Swift 5.2.2 and dedicated versions of RxSwift 6.0.0
63 |
64 | ## License
65 |
66 | MIT
67 |
--------------------------------------------------------------------------------
/RxWebKit.podspec:
--------------------------------------------------------------------------------
1 | Pod::Spec.new do |s|
2 | s.name = "RxWebKit"
3 | s.version = "2.0.1"
4 | s.summary = "RxWebKit is a RxSwift wrapper for WebKit."
5 | s.description = <<-DESC
6 | RxWebKit is a RxSwift wrapper for `WebKit`.
7 |
8 | ```swift
9 | // MARK: Setup WKWebView
10 |
11 | let webView = WKWebView(frame: self.view.bounds)
12 | self.view.addSubview(webView)
13 |
14 |
15 | // MARK: Observing properties
16 |
17 | webView.rx.title
18 | .subscribe(onNext: {
19 | print("title: \($0)")
20 | })
21 | .disposed(by: disposeBag)
22 |
23 | webView.rx.url
24 | .subscribe(onNext: {
25 | print("URL: \($0)")
26 | })
27 | .disposed(by: disposeBag)
28 | ```
29 | DESC
30 |
31 | s.homepage = "https://github.com/RxSwiftCommunity/RxWebKit"
32 | s.license = "MIT"
33 | s.authors = { "mokumoku" => "da1lawmoku2@gmail.com",
34 | "RxSwift Community" => "community@rxswift.org"
35 | }
36 | s.source = { :git => "https://github.com/RxSwiftCommunity/RxWebKit.git", :tag => s.version.to_s }
37 | s.source_files = "Sources/RxWebKit/**/*.{swift}"
38 | s.exclude_files = "Sources/RxWebKit/**/*.{plist}"
39 | s.ios.deployment_target = '9.0'
40 | s.osx.deployment_target = '10.13'
41 | s.swift_version = '5.0'
42 | s.dependency 'RxSwift', '~> 6.0'
43 | s.dependency 'RxCocoa', '~> 6.0'
44 | end
45 |
--------------------------------------------------------------------------------
/RxWebKit.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 42F426B61C66223E001FED46 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42F426AD1C66223E001FED46 /* AppDelegate.swift */; };
11 | 42F426B71C66223E001FED46 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 42F426AE1C66223E001FED46 /* Assets.xcassets */; };
12 | 42F426B81C66223E001FED46 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 42F426B01C66223E001FED46 /* LaunchScreen.storyboard */; };
13 | 42F426B91C66223E001FED46 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 42F426B21C66223E001FED46 /* Main.storyboard */; };
14 | 42F426BA1C66223E001FED46 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42F426B41C66223E001FED46 /* ViewController.swift */; };
15 | 42F426D11C6623C5001FED46 /* RxWebKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 42F426D01C6623C5001FED46 /* RxWebKit.h */; settings = {ATTRIBUTES = (Public, ); }; };
16 | 42F426D61C6623C5001FED46 /* RxWebKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 42F426CE1C6623C5001FED46 /* RxWebKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
17 | 42F426DC1C662CF9001FED46 /* Rx+WebKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42F426DB1C662CF9001FED46 /* Rx+WebKit.swift */; };
18 | C4135FFE22875FBE0061933C /* RxWebKitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4CB7D5322874EE700FB8D99 /* RxWebKitTests.swift */; };
19 | C4136011228764840061933C /* Nimble.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = C4D323B3228748A0004B05A5 /* Nimble.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
20 | C4136012228764840061933C /* Quick.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = C4D323B2228748A0004B05A5 /* Quick.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
21 | C4136013228764840061933C /* RxTest.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = C4D323B4228748A0004B05A5 /* RxTest.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
22 | C4136014228764840061933C /* RxSwift.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 424205831C89E9DF00214DA1 /* RxSwift.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
23 | C4136015228764840061933C /* RxCocoa.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 424205841C89E9DF00214DA1 /* RxCocoa.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
24 | C4136018228765250061933C /* RxRelay.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = C41360162287651B0061933C /* RxRelay.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
25 | C413601A2288135F0061933C /* HasEventsBehavior.swift in Sources */ = {isa = PBXBuildFile; fileRef = C41360192288135F0061933C /* HasEventsBehavior.swift */; };
26 | C413602522896CC20061933C /* RxSwift.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 424205831C89E9DF00214DA1 /* RxSwift.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
27 | C413602622896CC20061933C /* RxCocoa.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 424205841C89E9DF00214DA1 /* RxCocoa.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
28 | C413602722896CE20061933C /* RxRelay.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = C41360162287651B0061933C /* RxRelay.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
29 | C4607FD01FA0DAC9002DA12F /* RxWKUIDelegateProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4607FCF1FA0DAC9002DA12F /* RxWKUIDelegateProxy.swift */; };
30 | C4607FD61FA0DC40002DA12F /* RxWKUIDelegateEvents+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4607FD51FA0DC40002DA12F /* RxWKUIDelegateEvents+Rx.swift */; };
31 | C4607FDB1FA0E68F002DA12F /* JavaScriptAlertPanelViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4607FDA1FA0E68F002DA12F /* JavaScriptAlertPanelViewController.swift */; };
32 | C4607FDD1FA0F1D3002DA12F /* JavaScriptConfirmPanelViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4607FDC1FA0F1D3002DA12F /* JavaScriptConfirmPanelViewController.swift */; };
33 | C4607FE11FA0F549002DA12F /* AuthChallengeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4607FE01FA0F549002DA12F /* AuthChallengeViewController.swift */; };
34 | C4878CD61FA1066C00B12C60 /* FailedRequestViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4878CD51FA1066C00B12C60 /* FailedRequestViewController.swift */; };
35 | C4878CD81FA117E900B12C60 /* RedirectViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4878CD71FA117E900B12C60 /* RedirectViewController.swift */; };
36 | C4878CDA1FA11B5A00B12C60 /* OtherRequestViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4878CD91FA11B5A00B12C60 /* OtherRequestViewController.swift */; };
37 | C48E617E1F9E27A700C6A753 /* RxWKNavigationDelegateProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = C48E617D1F9E27A700C6A753 /* RxWKNavigationDelegateProxy.swift */; };
38 | C48E61841F9E336000C6A753 /* WKNavigationDelegateEvents+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = C48E61831F9E336000C6A753 /* WKNavigationDelegateEvents+Rx.swift */; };
39 | C4CA6B07228AB1680088A7A3 /* ForwardsEventsBehavior.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4CA6B06228AB1680088A7A3 /* ForwardsEventsBehavior.swift */; };
40 | EFC27F84246D7E9C0093D8B3 /* RxWebKitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4CB7D5322874EE700FB8D99 /* RxWebKitTests.swift */; };
41 | EFC27F85246D7E9C0093D8B3 /* ForwardsEventsBehavior.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4CA6B06228AB1680088A7A3 /* ForwardsEventsBehavior.swift */; };
42 | EFC27F86246D7E9C0093D8B3 /* HasEventsBehavior.swift in Sources */ = {isa = PBXBuildFile; fileRef = C41360192288135F0061933C /* HasEventsBehavior.swift */; };
43 | EFC27F96246D7F160093D8B3 /* Nimble.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = EFC27F95246D7F160093D8B3 /* Nimble.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
44 | EFC27F98246D7F1A0093D8B3 /* Quick.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = EFC27F97246D7F1A0093D8B3 /* Quick.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
45 | EFC27F9A246D7F220093D8B3 /* RxCocoa.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = EFC27F99246D7F220093D8B3 /* RxCocoa.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
46 | EFC27F9C246D7F290093D8B3 /* RxRelay.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = EFC27F9B246D7F290093D8B3 /* RxRelay.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
47 | EFC27F9E246D7F2D0093D8B3 /* RxSwift.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = EFC27F9D246D7F2D0093D8B3 /* RxSwift.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
48 | EFC27FA0246D7F310093D8B3 /* RxTest.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = EFC27F9F246D7F300093D8B3 /* RxTest.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
49 | F68CEB9E22521B1D00498607 /* InvokeJSFunctionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F68CEB9D22521B1D00498607 /* InvokeJSFunctionViewController.swift */; };
50 | F68CEBA022521B2B00498607 /* ObservingJSEventViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F68CEB9F22521B2B00498607 /* ObservingJSEventViewController.swift */; };
51 | F6D7DD0D224F62860066C90F /* RxWKUserContentController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F6D7DD0C224F62860066C90F /* RxWKUserContentController.swift */; };
52 | /* End PBXBuildFile section */
53 |
54 | /* Begin PBXContainerItemProxy section */
55 | 42F426D31C6623C5001FED46 /* PBXContainerItemProxy */ = {
56 | isa = PBXContainerItemProxy;
57 | containerPortal = 42F4268F1C66200D001FED46 /* Project object */;
58 | proxyType = 1;
59 | remoteGlobalIDString = 42F426CD1C6623C5001FED46;
60 | remoteInfo = RxWebKit;
61 | };
62 | C4CB7D4922874E5600FB8D99 /* PBXContainerItemProxy */ = {
63 | isa = PBXContainerItemProxy;
64 | containerPortal = 42F4268F1C66200D001FED46 /* Project object */;
65 | proxyType = 1;
66 | remoteGlobalIDString = 42F426CD1C6623C5001FED46;
67 | remoteInfo = RxWebKit;
68 | };
69 | EFC27F82246D7E9C0093D8B3 /* PBXContainerItemProxy */ = {
70 | isa = PBXContainerItemProxy;
71 | containerPortal = 42F4268F1C66200D001FED46 /* Project object */;
72 | proxyType = 1;
73 | remoteGlobalIDString = 42F426CD1C6623C5001FED46;
74 | remoteInfo = RxWebKit;
75 | };
76 | /* End PBXContainerItemProxy section */
77 |
78 | /* Begin PBXCopyFilesBuildPhase section */
79 | 42F426DA1C6623C5001FED46 /* Embed Frameworks */ = {
80 | isa = PBXCopyFilesBuildPhase;
81 | buildActionMask = 2147483647;
82 | dstPath = "";
83 | dstSubfolderSpec = 10;
84 | files = (
85 | 42F426D61C6623C5001FED46 /* RxWebKit.framework in Embed Frameworks */,
86 | C413602522896CC20061933C /* RxSwift.framework in Embed Frameworks */,
87 | C413602622896CC20061933C /* RxCocoa.framework in Embed Frameworks */,
88 | C413602722896CE20061933C /* RxRelay.framework in Embed Frameworks */,
89 | );
90 | name = "Embed Frameworks";
91 | runOnlyForDeploymentPostprocessing = 0;
92 | };
93 | C41360102287644B0061933C /* Embed Frameworks */ = {
94 | isa = PBXCopyFilesBuildPhase;
95 | buildActionMask = 2147483647;
96 | dstPath = "";
97 | dstSubfolderSpec = 10;
98 | files = (
99 | C4136011228764840061933C /* Nimble.framework in Embed Frameworks */,
100 | C4136012228764840061933C /* Quick.framework in Embed Frameworks */,
101 | C4136013228764840061933C /* RxTest.framework in Embed Frameworks */,
102 | C4136014228764840061933C /* RxSwift.framework in Embed Frameworks */,
103 | C4136015228764840061933C /* RxCocoa.framework in Embed Frameworks */,
104 | C4136018228765250061933C /* RxRelay.framework in Embed Frameworks */,
105 | );
106 | name = "Embed Frameworks";
107 | runOnlyForDeploymentPostprocessing = 0;
108 | };
109 | EFC27F89246D7E9C0093D8B3 /* Embed Frameworks */ = {
110 | isa = PBXCopyFilesBuildPhase;
111 | buildActionMask = 2147483647;
112 | dstPath = "";
113 | dstSubfolderSpec = 10;
114 | files = (
115 | EFC27FA0246D7F310093D8B3 /* RxTest.framework in Embed Frameworks */,
116 | EFC27F9E246D7F2D0093D8B3 /* RxSwift.framework in Embed Frameworks */,
117 | EFC27F9C246D7F290093D8B3 /* RxRelay.framework in Embed Frameworks */,
118 | EFC27F96246D7F160093D8B3 /* Nimble.framework in Embed Frameworks */,
119 | EFC27F98246D7F1A0093D8B3 /* Quick.framework in Embed Frameworks */,
120 | EFC27F9A246D7F220093D8B3 /* RxCocoa.framework in Embed Frameworks */,
121 | );
122 | name = "Embed Frameworks";
123 | runOnlyForDeploymentPostprocessing = 0;
124 | };
125 | /* End PBXCopyFilesBuildPhase section */
126 |
127 | /* Begin PBXFileReference section */
128 | 424205831C89E9DF00214DA1 /* RxSwift.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = RxSwift.framework; path = Carthage/Build/iOS/RxSwift.framework; sourceTree = ""; };
129 | 424205841C89E9DF00214DA1 /* RxCocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = RxCocoa.framework; path = Carthage/Build/iOS/RxCocoa.framework; sourceTree = ""; };
130 | 42F426971C66200D001FED46 /* Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Example.app; sourceTree = BUILT_PRODUCTS_DIR; };
131 | 42F426AC1C66223E001FED46 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
132 | 42F426AD1C66223E001FED46 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
133 | 42F426AE1C66223E001FED46 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
134 | 42F426B11C66223E001FED46 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
135 | 42F426B31C66223E001FED46 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
136 | 42F426B41C66223E001FED46 /* ViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; };
137 | 42F426CE1C6623C5001FED46 /* RxWebKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = RxWebKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
138 | 42F426D01C6623C5001FED46 /* RxWebKit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RxWebKit.h; sourceTree = ""; };
139 | 42F426D21C6623C5001FED46 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
140 | 42F426DB1C662CF9001FED46 /* Rx+WebKit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Rx+WebKit.swift"; sourceTree = ""; };
141 | C41360162287651B0061933C /* RxRelay.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = RxRelay.framework; path = Carthage/Build/iOS/RxRelay.framework; sourceTree = ""; };
142 | C41360192288135F0061933C /* HasEventsBehavior.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HasEventsBehavior.swift; sourceTree = ""; };
143 | C4607FCF1FA0DAC9002DA12F /* RxWKUIDelegateProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RxWKUIDelegateProxy.swift; sourceTree = ""; };
144 | C4607FD51FA0DC40002DA12F /* RxWKUIDelegateEvents+Rx.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "RxWKUIDelegateEvents+Rx.swift"; sourceTree = ""; };
145 | C4607FDA1FA0E68F002DA12F /* JavaScriptAlertPanelViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JavaScriptAlertPanelViewController.swift; sourceTree = ""; };
146 | C4607FDC1FA0F1D3002DA12F /* JavaScriptConfirmPanelViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JavaScriptConfirmPanelViewController.swift; sourceTree = ""; };
147 | C4607FE01FA0F549002DA12F /* AuthChallengeViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthChallengeViewController.swift; sourceTree = ""; };
148 | C4878CD51FA1066C00B12C60 /* FailedRequestViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FailedRequestViewController.swift; sourceTree = ""; };
149 | C4878CD71FA117E900B12C60 /* RedirectViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RedirectViewController.swift; sourceTree = ""; };
150 | C4878CD91FA11B5A00B12C60 /* OtherRequestViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OtherRequestViewController.swift; sourceTree = ""; };
151 | C48E617D1F9E27A700C6A753 /* RxWKNavigationDelegateProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RxWKNavigationDelegateProxy.swift; sourceTree = ""; };
152 | C48E61831F9E336000C6A753 /* WKNavigationDelegateEvents+Rx.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "WKNavigationDelegateEvents+Rx.swift"; sourceTree = ""; };
153 | C4A50F9E229AF3EF0037E608 /* config.yml */ = {isa = PBXFileReference; lastKnownFileType = text; name = config.yml; path = .circleci/config.yml; sourceTree = SOURCE_ROOT; };
154 | C4CA6B06228AB1680088A7A3 /* ForwardsEventsBehavior.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ForwardsEventsBehavior.swift; sourceTree = ""; };
155 | C4CA6B15228D752C0088A7A3 /* RxWebKit.podspec */ = {isa = PBXFileReference; lastKnownFileType = text; path = RxWebKit.podspec; sourceTree = SOURCE_ROOT; };
156 | C4CA6B16228D75410088A7A3 /* Cartfile.private */ = {isa = PBXFileReference; lastKnownFileType = text; path = Cartfile.private; sourceTree = SOURCE_ROOT; };
157 | C4CA6B17228D75420088A7A3 /* Cartfile.resolved */ = {isa = PBXFileReference; lastKnownFileType = text; path = Cartfile.resolved; sourceTree = SOURCE_ROOT; };
158 | C4CA6B18228D75420088A7A3 /* Cartfile */ = {isa = PBXFileReference; lastKnownFileType = text; path = Cartfile; sourceTree = SOURCE_ROOT; };
159 | C4CB7D4322874E5600FB8D99 /* RxWebKitTests-iOS.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "RxWebKitTests-iOS.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
160 | C4CB7D4722874E5600FB8D99 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
161 | C4CB7D5322874EE700FB8D99 /* RxWebKitTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RxWebKitTests.swift; sourceTree = ""; };
162 | C4D323B2228748A0004B05A5 /* Quick.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Quick.framework; path = Carthage/Build/iOS/Quick.framework; sourceTree = ""; };
163 | C4D323B3228748A0004B05A5 /* Nimble.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Nimble.framework; path = Carthage/Build/iOS/Nimble.framework; sourceTree = ""; };
164 | C4D323B4228748A0004B05A5 /* RxTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = RxTest.framework; path = Carthage/Build/iOS/RxTest.framework; sourceTree = ""; };
165 | EFC27F93246D7E9C0093D8B3 /* RxWebKitTests-macOS.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "RxWebKitTests-macOS.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
166 | EFC27F95246D7F160093D8B3 /* Nimble.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Nimble.framework; path = Carthage/Build/Mac/Nimble.framework; sourceTree = ""; };
167 | EFC27F97246D7F1A0093D8B3 /* Quick.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Quick.framework; path = Carthage/Build/Mac/Quick.framework; sourceTree = ""; };
168 | EFC27F99246D7F220093D8B3 /* RxCocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = RxCocoa.framework; path = Carthage/Build/Mac/RxCocoa.framework; sourceTree = ""; };
169 | EFC27F9B246D7F290093D8B3 /* RxRelay.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = RxRelay.framework; path = Carthage/Build/Mac/RxRelay.framework; sourceTree = ""; };
170 | EFC27F9D246D7F2D0093D8B3 /* RxSwift.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = RxSwift.framework; path = Carthage/Build/Mac/RxSwift.framework; sourceTree = ""; };
171 | EFC27F9F246D7F300093D8B3 /* RxTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = RxTest.framework; path = Carthage/Build/Mac/RxTest.framework; sourceTree = ""; };
172 | F68CEB9D22521B1D00498607 /* InvokeJSFunctionViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InvokeJSFunctionViewController.swift; sourceTree = ""; };
173 | F68CEB9F22521B2B00498607 /* ObservingJSEventViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ObservingJSEventViewController.swift; sourceTree = ""; };
174 | F6D7DD0C224F62860066C90F /* RxWKUserContentController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RxWKUserContentController.swift; sourceTree = ""; };
175 | /* End PBXFileReference section */
176 |
177 | /* Begin PBXFrameworksBuildPhase section */
178 | 42F426941C66200D001FED46 /* Frameworks */ = {
179 | isa = PBXFrameworksBuildPhase;
180 | buildActionMask = 2147483647;
181 | files = (
182 | );
183 | runOnlyForDeploymentPostprocessing = 0;
184 | };
185 | 42F426CA1C6623C5001FED46 /* Frameworks */ = {
186 | isa = PBXFrameworksBuildPhase;
187 | buildActionMask = 2147483647;
188 | files = (
189 | );
190 | runOnlyForDeploymentPostprocessing = 0;
191 | };
192 | C4CB7D4022874E5600FB8D99 /* Frameworks */ = {
193 | isa = PBXFrameworksBuildPhase;
194 | buildActionMask = 2147483647;
195 | files = (
196 | );
197 | runOnlyForDeploymentPostprocessing = 0;
198 | };
199 | EFC27F87246D7E9C0093D8B3 /* Frameworks */ = {
200 | isa = PBXFrameworksBuildPhase;
201 | buildActionMask = 2147483647;
202 | files = (
203 | );
204 | runOnlyForDeploymentPostprocessing = 0;
205 | };
206 | /* End PBXFrameworksBuildPhase section */
207 |
208 | /* Begin PBXGroup section */
209 | 42B12EFB1C6DFC7600C280BD /* Sources */ = {
210 | isa = PBXGroup;
211 | children = (
212 | 42F426DB1C662CF9001FED46 /* Rx+WebKit.swift */,
213 | C48E61831F9E336000C6A753 /* WKNavigationDelegateEvents+Rx.swift */,
214 | C48E617D1F9E27A700C6A753 /* RxWKNavigationDelegateProxy.swift */,
215 | C4607FCF1FA0DAC9002DA12F /* RxWKUIDelegateProxy.swift */,
216 | C4607FD51FA0DC40002DA12F /* RxWKUIDelegateEvents+Rx.swift */,
217 | F6D7DD0C224F62860066C90F /* RxWKUserContentController.swift */,
218 | );
219 | path = Sources;
220 | sourceTree = "";
221 | };
222 | 42F4268E1C66200D001FED46 = {
223 | isa = PBXGroup;
224 | children = (
225 | EFC27F9F246D7F300093D8B3 /* RxTest.framework */,
226 | EFC27F9D246D7F2D0093D8B3 /* RxSwift.framework */,
227 | EFC27F9B246D7F290093D8B3 /* RxRelay.framework */,
228 | EFC27F99246D7F220093D8B3 /* RxCocoa.framework */,
229 | EFC27F97246D7F1A0093D8B3 /* Quick.framework */,
230 | EFC27F95246D7F160093D8B3 /* Nimble.framework */,
231 | 42F426991C66200D001FED46 /* Example */,
232 | 733B51F3D0F2B4B1E9A99FDC /* Frameworks */,
233 | 42F426981C66200D001FED46 /* Products */,
234 | 42F426CF1C6623C5001FED46 /* RxWebKit */,
235 | C4CB7D4422874E5600FB8D99 /* RxWebKitTests */,
236 | );
237 | sourceTree = "";
238 | };
239 | 42F426981C66200D001FED46 /* Products */ = {
240 | isa = PBXGroup;
241 | children = (
242 | 42F426971C66200D001FED46 /* Example.app */,
243 | 42F426CE1C6623C5001FED46 /* RxWebKit.framework */,
244 | C4CB7D4322874E5600FB8D99 /* RxWebKitTests-iOS.xctest */,
245 | EFC27F93246D7E9C0093D8B3 /* RxWebKitTests-macOS.xctest */,
246 | );
247 | name = Products;
248 | sourceTree = "";
249 | };
250 | 42F426991C66200D001FED46 /* Example */ = {
251 | isa = PBXGroup;
252 | children = (
253 | 42F426AF1C66223E001FED46 /* Base.lproj */,
254 | 42F426AD1C66223E001FED46 /* AppDelegate.swift */,
255 | 42F426AE1C66223E001FED46 /* Assets.xcassets */,
256 | 42F426AC1C66223E001FED46 /* Info.plist */,
257 | 42F426B41C66223E001FED46 /* ViewController.swift */,
258 | C4607FDA1FA0E68F002DA12F /* JavaScriptAlertPanelViewController.swift */,
259 | C4607FDC1FA0F1D3002DA12F /* JavaScriptConfirmPanelViewController.swift */,
260 | C4607FE01FA0F549002DA12F /* AuthChallengeViewController.swift */,
261 | C4878CD51FA1066C00B12C60 /* FailedRequestViewController.swift */,
262 | C4878CD71FA117E900B12C60 /* RedirectViewController.swift */,
263 | C4878CD91FA11B5A00B12C60 /* OtherRequestViewController.swift */,
264 | F68CEB9D22521B1D00498607 /* InvokeJSFunctionViewController.swift */,
265 | F68CEB9F22521B2B00498607 /* ObservingJSEventViewController.swift */,
266 | );
267 | path = Example;
268 | sourceTree = "";
269 | };
270 | 42F426AF1C66223E001FED46 /* Base.lproj */ = {
271 | isa = PBXGroup;
272 | children = (
273 | 42F426B01C66223E001FED46 /* LaunchScreen.storyboard */,
274 | 42F426B21C66223E001FED46 /* Main.storyboard */,
275 | );
276 | path = Base.lproj;
277 | sourceTree = "";
278 | };
279 | 42F426CF1C6623C5001FED46 /* RxWebKit */ = {
280 | isa = PBXGroup;
281 | children = (
282 | C4CA6B15228D752C0088A7A3 /* RxWebKit.podspec */,
283 | C4CA6B18228D75420088A7A3 /* Cartfile */,
284 | C4CA6B16228D75410088A7A3 /* Cartfile.private */,
285 | C4CA6B17228D75420088A7A3 /* Cartfile.resolved */,
286 | C4A50F9E229AF3EF0037E608 /* config.yml */,
287 | 42B12EFB1C6DFC7600C280BD /* Sources */,
288 | 42F426D21C6623C5001FED46 /* Info.plist */,
289 | 42F426D01C6623C5001FED46 /* RxWebKit.h */,
290 | );
291 | path = RxWebKit;
292 | sourceTree = "";
293 | };
294 | 733B51F3D0F2B4B1E9A99FDC /* Frameworks */ = {
295 | isa = PBXGroup;
296 | children = (
297 | C41360162287651B0061933C /* RxRelay.framework */,
298 | C4D323B3228748A0004B05A5 /* Nimble.framework */,
299 | C4D323B2228748A0004B05A5 /* Quick.framework */,
300 | C4D323B4228748A0004B05A5 /* RxTest.framework */,
301 | 424205831C89E9DF00214DA1 /* RxSwift.framework */,
302 | 424205841C89E9DF00214DA1 /* RxCocoa.framework */,
303 | );
304 | name = Frameworks;
305 | sourceTree = "";
306 | };
307 | C4CB7D4422874E5600FB8D99 /* RxWebKitTests */ = {
308 | isa = PBXGroup;
309 | children = (
310 | C4CB7D5322874EE700FB8D99 /* RxWebKitTests.swift */,
311 | C41360192288135F0061933C /* HasEventsBehavior.swift */,
312 | C4CA6B06228AB1680088A7A3 /* ForwardsEventsBehavior.swift */,
313 | C4CB7D4722874E5600FB8D99 /* Info.plist */,
314 | );
315 | path = RxWebKitTests;
316 | sourceTree = "";
317 | };
318 | /* End PBXGroup section */
319 |
320 | /* Begin PBXHeadersBuildPhase section */
321 | 42F426CB1C6623C5001FED46 /* Headers */ = {
322 | isa = PBXHeadersBuildPhase;
323 | buildActionMask = 2147483647;
324 | files = (
325 | 42F426D11C6623C5001FED46 /* RxWebKit.h in Headers */,
326 | );
327 | runOnlyForDeploymentPostprocessing = 0;
328 | };
329 | /* End PBXHeadersBuildPhase section */
330 |
331 | /* Begin PBXNativeTarget section */
332 | 42F426961C66200D001FED46 /* Example */ = {
333 | isa = PBXNativeTarget;
334 | buildConfigurationList = 42F426A91C66200D001FED46 /* Build configuration list for PBXNativeTarget "Example" */;
335 | buildPhases = (
336 | 42F426931C66200D001FED46 /* Sources */,
337 | 42F426941C66200D001FED46 /* Frameworks */,
338 | 42F426951C66200D001FED46 /* Resources */,
339 | 42F426DA1C6623C5001FED46 /* Embed Frameworks */,
340 | );
341 | buildRules = (
342 | );
343 | dependencies = (
344 | 42F426D41C6623C5001FED46 /* PBXTargetDependency */,
345 | );
346 | name = Example;
347 | productName = RxWebKit;
348 | productReference = 42F426971C66200D001FED46 /* Example.app */;
349 | productType = "com.apple.product-type.application";
350 | };
351 | 42F426CD1C6623C5001FED46 /* RxWebKit */ = {
352 | isa = PBXNativeTarget;
353 | buildConfigurationList = 42F426D71C6623C5001FED46 /* Build configuration list for PBXNativeTarget "RxWebKit" */;
354 | buildPhases = (
355 | 42F426C91C6623C5001FED46 /* Sources */,
356 | 42F426CA1C6623C5001FED46 /* Frameworks */,
357 | 42F426CB1C6623C5001FED46 /* Headers */,
358 | 42F426CC1C6623C5001FED46 /* Resources */,
359 | );
360 | buildRules = (
361 | );
362 | dependencies = (
363 | );
364 | name = RxWebKit;
365 | productName = RxWebKit;
366 | productReference = 42F426CE1C6623C5001FED46 /* RxWebKit.framework */;
367 | productType = "com.apple.product-type.framework";
368 | };
369 | C4CB7D4222874E5600FB8D99 /* RxWebKitTests-iOS */ = {
370 | isa = PBXNativeTarget;
371 | buildConfigurationList = C4CB7D4B22874E5600FB8D99 /* Build configuration list for PBXNativeTarget "RxWebKitTests-iOS" */;
372 | buildPhases = (
373 | C4CB7D3F22874E5600FB8D99 /* Sources */,
374 | C4CB7D4022874E5600FB8D99 /* Frameworks */,
375 | C4CB7D4122874E5600FB8D99 /* Resources */,
376 | C41360102287644B0061933C /* Embed Frameworks */,
377 | );
378 | buildRules = (
379 | );
380 | dependencies = (
381 | C4CB7D4A22874E5600FB8D99 /* PBXTargetDependency */,
382 | );
383 | name = "RxWebKitTests-iOS";
384 | productName = RxWebKitTests;
385 | productReference = C4CB7D4322874E5600FB8D99 /* RxWebKitTests-iOS.xctest */;
386 | productType = "com.apple.product-type.bundle.unit-test";
387 | };
388 | EFC27F80246D7E9C0093D8B3 /* RxWebKitTests-macOS */ = {
389 | isa = PBXNativeTarget;
390 | buildConfigurationList = EFC27F90246D7E9C0093D8B3 /* Build configuration list for PBXNativeTarget "RxWebKitTests-macOS" */;
391 | buildPhases = (
392 | EFC27F83246D7E9C0093D8B3 /* Sources */,
393 | EFC27F87246D7E9C0093D8B3 /* Frameworks */,
394 | EFC27F88246D7E9C0093D8B3 /* Resources */,
395 | EFC27F89246D7E9C0093D8B3 /* Embed Frameworks */,
396 | );
397 | buildRules = (
398 | );
399 | dependencies = (
400 | EFC27F81246D7E9C0093D8B3 /* PBXTargetDependency */,
401 | );
402 | name = "RxWebKitTests-macOS";
403 | productName = RxWebKitTests;
404 | productReference = EFC27F93246D7E9C0093D8B3 /* RxWebKitTests-macOS.xctest */;
405 | productType = "com.apple.product-type.bundle.unit-test";
406 | };
407 | /* End PBXNativeTarget section */
408 |
409 | /* Begin PBXProject section */
410 | 42F4268F1C66200D001FED46 /* Project object */ = {
411 | isa = PBXProject;
412 | attributes = {
413 | LastSwiftUpdateCheck = 1020;
414 | LastUpgradeCheck = 1020;
415 | ORGANIZATIONNAME = MokuMokuCloud;
416 | TargetAttributes = {
417 | 42F426961C66200D001FED46 = {
418 | CreatedOnToolsVersion = 7.2;
419 | DevelopmentTeamName = "Daichi Ichihara (Personal Team)";
420 | LastSwiftMigration = 0800;
421 | };
422 | 42F426CD1C6623C5001FED46 = {
423 | CreatedOnToolsVersion = 7.2;
424 | DevelopmentTeam = 6XJDQ2F5E3;
425 | DevelopmentTeamName = "Daichi Ichihara (Personal Team)";
426 | LastSwiftMigration = 1020;
427 | };
428 | C4CB7D4222874E5600FB8D99 = {
429 | CreatedOnToolsVersion = 10.2.1;
430 | ProvisioningStyle = Manual;
431 | };
432 | EFC27F80246D7E9C0093D8B3 = {
433 | ProvisioningStyle = Manual;
434 | };
435 | };
436 | };
437 | buildConfigurationList = 42F426921C66200D001FED46 /* Build configuration list for PBXProject "RxWebKit" */;
438 | compatibilityVersion = "Xcode 3.2";
439 | developmentRegion = English;
440 | hasScannedForEncodings = 0;
441 | knownRegions = (
442 | English,
443 | en,
444 | Base,
445 | );
446 | mainGroup = 42F4268E1C66200D001FED46;
447 | productRefGroup = 42F426981C66200D001FED46 /* Products */;
448 | projectDirPath = "";
449 | projectRoot = "";
450 | targets = (
451 | 42F426961C66200D001FED46 /* Example */,
452 | 42F426CD1C6623C5001FED46 /* RxWebKit */,
453 | C4CB7D4222874E5600FB8D99 /* RxWebKitTests-iOS */,
454 | EFC27F80246D7E9C0093D8B3 /* RxWebKitTests-macOS */,
455 | );
456 | };
457 | /* End PBXProject section */
458 |
459 | /* Begin PBXResourcesBuildPhase section */
460 | 42F426951C66200D001FED46 /* Resources */ = {
461 | isa = PBXResourcesBuildPhase;
462 | buildActionMask = 2147483647;
463 | files = (
464 | 42F426B81C66223E001FED46 /* LaunchScreen.storyboard in Resources */,
465 | 42F426B71C66223E001FED46 /* Assets.xcassets in Resources */,
466 | 42F426B91C66223E001FED46 /* Main.storyboard in Resources */,
467 | );
468 | runOnlyForDeploymentPostprocessing = 0;
469 | };
470 | 42F426CC1C6623C5001FED46 /* Resources */ = {
471 | isa = PBXResourcesBuildPhase;
472 | buildActionMask = 2147483647;
473 | files = (
474 | );
475 | runOnlyForDeploymentPostprocessing = 0;
476 | };
477 | C4CB7D4122874E5600FB8D99 /* Resources */ = {
478 | isa = PBXResourcesBuildPhase;
479 | buildActionMask = 2147483647;
480 | files = (
481 | );
482 | runOnlyForDeploymentPostprocessing = 0;
483 | };
484 | EFC27F88246D7E9C0093D8B3 /* Resources */ = {
485 | isa = PBXResourcesBuildPhase;
486 | buildActionMask = 2147483647;
487 | files = (
488 | );
489 | runOnlyForDeploymentPostprocessing = 0;
490 | };
491 | /* End PBXResourcesBuildPhase section */
492 |
493 | /* Begin PBXSourcesBuildPhase section */
494 | 42F426931C66200D001FED46 /* Sources */ = {
495 | isa = PBXSourcesBuildPhase;
496 | buildActionMask = 2147483647;
497 | files = (
498 | C4607FE11FA0F549002DA12F /* AuthChallengeViewController.swift in Sources */,
499 | F68CEB9E22521B1D00498607 /* InvokeJSFunctionViewController.swift in Sources */,
500 | 42F426BA1C66223E001FED46 /* ViewController.swift in Sources */,
501 | C4878CDA1FA11B5A00B12C60 /* OtherRequestViewController.swift in Sources */,
502 | F68CEBA022521B2B00498607 /* ObservingJSEventViewController.swift in Sources */,
503 | C4878CD81FA117E900B12C60 /* RedirectViewController.swift in Sources */,
504 | C4607FDD1FA0F1D3002DA12F /* JavaScriptConfirmPanelViewController.swift in Sources */,
505 | C4878CD61FA1066C00B12C60 /* FailedRequestViewController.swift in Sources */,
506 | 42F426B61C66223E001FED46 /* AppDelegate.swift in Sources */,
507 | C4607FDB1FA0E68F002DA12F /* JavaScriptAlertPanelViewController.swift in Sources */,
508 | );
509 | runOnlyForDeploymentPostprocessing = 0;
510 | };
511 | 42F426C91C6623C5001FED46 /* Sources */ = {
512 | isa = PBXSourcesBuildPhase;
513 | buildActionMask = 2147483647;
514 | files = (
515 | 42F426DC1C662CF9001FED46 /* Rx+WebKit.swift in Sources */,
516 | C48E61841F9E336000C6A753 /* WKNavigationDelegateEvents+Rx.swift in Sources */,
517 | C48E617E1F9E27A700C6A753 /* RxWKNavigationDelegateProxy.swift in Sources */,
518 | C4607FD01FA0DAC9002DA12F /* RxWKUIDelegateProxy.swift in Sources */,
519 | F6D7DD0D224F62860066C90F /* RxWKUserContentController.swift in Sources */,
520 | C4607FD61FA0DC40002DA12F /* RxWKUIDelegateEvents+Rx.swift in Sources */,
521 | );
522 | runOnlyForDeploymentPostprocessing = 0;
523 | };
524 | C4CB7D3F22874E5600FB8D99 /* Sources */ = {
525 | isa = PBXSourcesBuildPhase;
526 | buildActionMask = 2147483647;
527 | files = (
528 | C4135FFE22875FBE0061933C /* RxWebKitTests.swift in Sources */,
529 | C4CA6B07228AB1680088A7A3 /* ForwardsEventsBehavior.swift in Sources */,
530 | C413601A2288135F0061933C /* HasEventsBehavior.swift in Sources */,
531 | );
532 | runOnlyForDeploymentPostprocessing = 0;
533 | };
534 | EFC27F83246D7E9C0093D8B3 /* Sources */ = {
535 | isa = PBXSourcesBuildPhase;
536 | buildActionMask = 2147483647;
537 | files = (
538 | EFC27F84246D7E9C0093D8B3 /* RxWebKitTests.swift in Sources */,
539 | EFC27F85246D7E9C0093D8B3 /* ForwardsEventsBehavior.swift in Sources */,
540 | EFC27F86246D7E9C0093D8B3 /* HasEventsBehavior.swift in Sources */,
541 | );
542 | runOnlyForDeploymentPostprocessing = 0;
543 | };
544 | /* End PBXSourcesBuildPhase section */
545 |
546 | /* Begin PBXTargetDependency section */
547 | 42F426D41C6623C5001FED46 /* PBXTargetDependency */ = {
548 | isa = PBXTargetDependency;
549 | target = 42F426CD1C6623C5001FED46 /* RxWebKit */;
550 | targetProxy = 42F426D31C6623C5001FED46 /* PBXContainerItemProxy */;
551 | };
552 | C4CB7D4A22874E5600FB8D99 /* PBXTargetDependency */ = {
553 | isa = PBXTargetDependency;
554 | target = 42F426CD1C6623C5001FED46 /* RxWebKit */;
555 | targetProxy = C4CB7D4922874E5600FB8D99 /* PBXContainerItemProxy */;
556 | };
557 | EFC27F81246D7E9C0093D8B3 /* PBXTargetDependency */ = {
558 | isa = PBXTargetDependency;
559 | target = 42F426CD1C6623C5001FED46 /* RxWebKit */;
560 | targetProxy = EFC27F82246D7E9C0093D8B3 /* PBXContainerItemProxy */;
561 | };
562 | /* End PBXTargetDependency section */
563 |
564 | /* Begin PBXVariantGroup section */
565 | 42F426B01C66223E001FED46 /* LaunchScreen.storyboard */ = {
566 | isa = PBXVariantGroup;
567 | children = (
568 | 42F426B11C66223E001FED46 /* Base */,
569 | );
570 | name = LaunchScreen.storyboard;
571 | path = .;
572 | sourceTree = "";
573 | };
574 | 42F426B21C66223E001FED46 /* Main.storyboard */ = {
575 | isa = PBXVariantGroup;
576 | children = (
577 | 42F426B31C66223E001FED46 /* Base */,
578 | );
579 | name = Main.storyboard;
580 | path = .;
581 | sourceTree = "";
582 | };
583 | /* End PBXVariantGroup section */
584 |
585 | /* Begin XCBuildConfiguration section */
586 | 42F426A71C66200D001FED46 /* Debug */ = {
587 | isa = XCBuildConfiguration;
588 | buildSettings = {
589 | ALWAYS_SEARCH_USER_PATHS = NO;
590 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
591 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
592 | CLANG_CXX_LIBRARY = "libc++";
593 | CLANG_ENABLE_MODULES = YES;
594 | CLANG_ENABLE_OBJC_ARC = YES;
595 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
596 | CLANG_WARN_BOOL_CONVERSION = YES;
597 | CLANG_WARN_COMMA = YES;
598 | CLANG_WARN_CONSTANT_CONVERSION = YES;
599 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
600 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
601 | CLANG_WARN_EMPTY_BODY = YES;
602 | CLANG_WARN_ENUM_CONVERSION = YES;
603 | CLANG_WARN_INFINITE_RECURSION = YES;
604 | CLANG_WARN_INT_CONVERSION = YES;
605 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
606 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
607 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
608 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
609 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
610 | CLANG_WARN_STRICT_PROTOTYPES = YES;
611 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
612 | CLANG_WARN_UNREACHABLE_CODE = YES;
613 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
614 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
615 | COPY_PHASE_STRIP = NO;
616 | DEBUG_INFORMATION_FORMAT = dwarf;
617 | ENABLE_STRICT_OBJC_MSGSEND = YES;
618 | ENABLE_TESTABILITY = YES;
619 | "FRAMEWORK_SEARCH_PATHS[sdk=iphoneos*]" = (
620 | "$(SRCROOT)/Carthage/Build/iOS",
621 | "$(inherited)",
622 | );
623 | "FRAMEWORK_SEARCH_PATHS[sdk=iphonesimulator*]" = (
624 | "$(SRCROOT)/Carthage/Build/iOS",
625 | "$(inherited)",
626 | );
627 | "FRAMEWORK_SEARCH_PATHS[sdk=macosx*]" = (
628 | "$(SRCROOT)/Carthage/Build/Mac",
629 | "$(inherited)",
630 | );
631 | GCC_C_LANGUAGE_STANDARD = gnu99;
632 | GCC_DYNAMIC_NO_PIC = NO;
633 | GCC_NO_COMMON_BLOCKS = YES;
634 | GCC_OPTIMIZATION_LEVEL = 0;
635 | GCC_PREPROCESSOR_DEFINITIONS = (
636 | "DEBUG=1",
637 | "$(inherited)",
638 | );
639 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
640 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
641 | GCC_WARN_UNDECLARED_SELECTOR = YES;
642 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
643 | GCC_WARN_UNUSED_FUNCTION = YES;
644 | GCC_WARN_UNUSED_VARIABLE = YES;
645 | IPHONEOS_DEPLOYMENT_TARGET = 10.0;
646 | MACOSX_DEPLOYMENT_TARGET = 10.13;
647 | MTL_ENABLE_DEBUG_INFO = YES;
648 | ONLY_ACTIVE_ARCH = YES;
649 | SDKROOT = "";
650 | SUPPORTED_PLATFORMS = "iphonesimulator iphoneos macosx";
651 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
652 | SWIFT_VERSION = 5.0;
653 | };
654 | name = Debug;
655 | };
656 | 42F426A81C66200D001FED46 /* Release */ = {
657 | isa = XCBuildConfiguration;
658 | buildSettings = {
659 | ALWAYS_SEARCH_USER_PATHS = NO;
660 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
661 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
662 | CLANG_CXX_LIBRARY = "libc++";
663 | CLANG_ENABLE_MODULES = YES;
664 | CLANG_ENABLE_OBJC_ARC = YES;
665 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
666 | CLANG_WARN_BOOL_CONVERSION = YES;
667 | CLANG_WARN_COMMA = YES;
668 | CLANG_WARN_CONSTANT_CONVERSION = YES;
669 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
670 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
671 | CLANG_WARN_EMPTY_BODY = YES;
672 | CLANG_WARN_ENUM_CONVERSION = YES;
673 | CLANG_WARN_INFINITE_RECURSION = YES;
674 | CLANG_WARN_INT_CONVERSION = YES;
675 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
676 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
677 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
678 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
679 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
680 | CLANG_WARN_STRICT_PROTOTYPES = YES;
681 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
682 | CLANG_WARN_UNREACHABLE_CODE = YES;
683 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
684 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
685 | COPY_PHASE_STRIP = NO;
686 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
687 | ENABLE_NS_ASSERTIONS = NO;
688 | ENABLE_STRICT_OBJC_MSGSEND = YES;
689 | "FRAMEWORK_SEARCH_PATHS[sdk=iphoneos*]" = (
690 | "$(SRCROOT)/Carthage/Build/iOS",
691 | "$(inherited)",
692 | );
693 | "FRAMEWORK_SEARCH_PATHS[sdk=iphonesimulator*]" = (
694 | "$(SRCROOT)/Carthage/Build/iOS",
695 | "$(inherited)",
696 | );
697 | "FRAMEWORK_SEARCH_PATHS[sdk=macosx*]" = (
698 | "$(SRCROOT)/Carthage/Build/Mac",
699 | "$(inherited)",
700 | );
701 | GCC_C_LANGUAGE_STANDARD = gnu99;
702 | GCC_NO_COMMON_BLOCKS = YES;
703 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
704 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
705 | GCC_WARN_UNDECLARED_SELECTOR = YES;
706 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
707 | GCC_WARN_UNUSED_FUNCTION = YES;
708 | GCC_WARN_UNUSED_VARIABLE = YES;
709 | IPHONEOS_DEPLOYMENT_TARGET = 10.0;
710 | MACOSX_DEPLOYMENT_TARGET = 10.13;
711 | MTL_ENABLE_DEBUG_INFO = NO;
712 | SDKROOT = "";
713 | SUPPORTED_PLATFORMS = "iphonesimulator iphoneos macosx";
714 | SWIFT_VERSION = 5.0;
715 | VALIDATE_PRODUCT = YES;
716 | };
717 | name = Release;
718 | };
719 | 42F426AA1C66200D001FED46 /* Debug */ = {
720 | isa = XCBuildConfiguration;
721 | buildSettings = {
722 | CLANG_ENABLE_MODULES = YES;
723 | DEVELOPMENT_TEAM = "";
724 | INFOPLIST_FILE = "$(SRCROOT)/Example/Info.plist";
725 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
726 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
727 | PRODUCT_BUNDLE_IDENTIFIER = mokumoku.Example;
728 | PRODUCT_NAME = "$(TARGET_NAME)";
729 | SDKROOT = iphoneos;
730 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
731 | SWIFT_VERSION = 5.0;
732 | };
733 | name = Debug;
734 | };
735 | 42F426AB1C66200D001FED46 /* Release */ = {
736 | isa = XCBuildConfiguration;
737 | buildSettings = {
738 | CLANG_ENABLE_MODULES = YES;
739 | DEVELOPMENT_TEAM = "";
740 | INFOPLIST_FILE = "$(SRCROOT)/Example/Info.plist";
741 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
742 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
743 | PRODUCT_BUNDLE_IDENTIFIER = mokumoku.Example;
744 | PRODUCT_NAME = "$(TARGET_NAME)";
745 | SDKROOT = iphoneos;
746 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
747 | SWIFT_VERSION = 5.0;
748 | };
749 | name = Release;
750 | };
751 | 42F426D81C6623C5001FED46 /* Debug */ = {
752 | isa = XCBuildConfiguration;
753 | buildSettings = {
754 | CLANG_ENABLE_MODULES = YES;
755 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
756 | CURRENT_PROJECT_VERSION = 1;
757 | DEFINES_MODULE = YES;
758 | DYLIB_COMPATIBILITY_VERSION = 1;
759 | DYLIB_CURRENT_VERSION = 1;
760 | DYLIB_INSTALL_NAME_BASE = "@rpath";
761 | INFOPLIST_FILE = "$(SRCROOT)/RxWebKit/Info.plist";
762 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
763 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
764 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
765 | PRODUCT_BUNDLE_IDENTIFIER = mokumoku.RxWebKit;
766 | PRODUCT_NAME = "$(TARGET_NAME)";
767 | SKIP_INSTALL = YES;
768 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
769 | SWIFT_VERSION = 5.0;
770 | TARGETED_DEVICE_FAMILY = "1,2";
771 | VERSIONING_SYSTEM = "apple-generic";
772 | VERSION_INFO_PREFIX = "";
773 | };
774 | name = Debug;
775 | };
776 | 42F426D91C6623C5001FED46 /* Release */ = {
777 | isa = XCBuildConfiguration;
778 | buildSettings = {
779 | CLANG_ENABLE_MODULES = YES;
780 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
781 | CURRENT_PROJECT_VERSION = 1;
782 | DEFINES_MODULE = YES;
783 | DYLIB_COMPATIBILITY_VERSION = 1;
784 | DYLIB_CURRENT_VERSION = 1;
785 | DYLIB_INSTALL_NAME_BASE = "@rpath";
786 | INFOPLIST_FILE = "$(SRCROOT)/RxWebKit/Info.plist";
787 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
788 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
789 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
790 | PRODUCT_BUNDLE_IDENTIFIER = mokumoku.RxWebKit;
791 | PRODUCT_NAME = "$(TARGET_NAME)";
792 | SKIP_INSTALL = YES;
793 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
794 | SWIFT_VERSION = 5.0;
795 | TARGETED_DEVICE_FAMILY = "1,2";
796 | VERSIONING_SYSTEM = "apple-generic";
797 | VERSION_INFO_PREFIX = "";
798 | };
799 | name = Release;
800 | };
801 | C4CB7D4C22874E5600FB8D99 /* Debug */ = {
802 | isa = XCBuildConfiguration;
803 | buildSettings = {
804 | CLANG_ANALYZER_NONNULL = YES;
805 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
806 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
807 | CLANG_ENABLE_OBJC_WEAK = YES;
808 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
809 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
810 | CODE_SIGN_IDENTITY = "iPhone Developer";
811 | "CODE_SIGN_IDENTITY[sdk=macosx*]" = "-";
812 | CODE_SIGN_STYLE = Manual;
813 | DEVELOPMENT_TEAM = "";
814 | GCC_C_LANGUAGE_STANDARD = gnu11;
815 | INFOPLIST_FILE = RxWebKitTests/Info.plist;
816 | IPHONEOS_DEPLOYMENT_TARGET = 12.2;
817 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
818 | "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks @loader_path/../Frameworks";
819 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
820 | MTL_FAST_MATH = YES;
821 | PRODUCT_BUNDLE_IDENTIFIER = bobgodwinx.RxWebKitTests;
822 | PRODUCT_NAME = "$(TARGET_NAME)";
823 | PROVISIONING_PROFILE_SPECIFIER = "";
824 | "PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*]" = "";
825 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
826 | SWIFT_VERSION = 5.0;
827 | TARGETED_DEVICE_FAMILY = "1,2";
828 | };
829 | name = Debug;
830 | };
831 | C4CB7D4D22874E5600FB8D99 /* Release */ = {
832 | isa = XCBuildConfiguration;
833 | buildSettings = {
834 | CLANG_ANALYZER_NONNULL = YES;
835 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
836 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
837 | CLANG_ENABLE_OBJC_WEAK = YES;
838 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
839 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
840 | CODE_SIGN_IDENTITY = "iPhone Developer";
841 | "CODE_SIGN_IDENTITY[sdk=macosx*]" = "-";
842 | CODE_SIGN_STYLE = Manual;
843 | DEVELOPMENT_TEAM = "";
844 | GCC_C_LANGUAGE_STANDARD = gnu11;
845 | INFOPLIST_FILE = RxWebKitTests/Info.plist;
846 | IPHONEOS_DEPLOYMENT_TARGET = 12.2;
847 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
848 | "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks @loader_path/../Frameworks";
849 | MTL_FAST_MATH = YES;
850 | PRODUCT_BUNDLE_IDENTIFIER = bobgodwinx.RxWebKitTests;
851 | PRODUCT_NAME = "$(TARGET_NAME)";
852 | PROVISIONING_PROFILE_SPECIFIER = "";
853 | "PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*]" = "";
854 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
855 | SWIFT_VERSION = 5.0;
856 | TARGETED_DEVICE_FAMILY = "1,2";
857 | };
858 | name = Release;
859 | };
860 | EFC27F91246D7E9C0093D8B3 /* Debug */ = {
861 | isa = XCBuildConfiguration;
862 | buildSettings = {
863 | CLANG_ANALYZER_NONNULL = YES;
864 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
865 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
866 | CLANG_ENABLE_OBJC_WEAK = YES;
867 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
868 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
869 | CODE_SIGN_IDENTITY = "-";
870 | CODE_SIGN_STYLE = Manual;
871 | DEVELOPMENT_TEAM = "";
872 | GCC_C_LANGUAGE_STANDARD = gnu11;
873 | INFOPLIST_FILE = RxWebKitTests/Info.plist;
874 | IPHONEOS_DEPLOYMENT_TARGET = 12.2;
875 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
876 | "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks @loader_path/../Frameworks";
877 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
878 | MTL_FAST_MATH = YES;
879 | PRODUCT_BUNDLE_IDENTIFIER = bobgodwinx.RxWebKitTests;
880 | PRODUCT_NAME = "$(TARGET_NAME)";
881 | PROVISIONING_PROFILE_SPECIFIER = "";
882 | SDKROOT = macosx;
883 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
884 | SWIFT_VERSION = 5.0;
885 | TARGETED_DEVICE_FAMILY = "1,2";
886 | };
887 | name = Debug;
888 | };
889 | EFC27F92246D7E9C0093D8B3 /* Release */ = {
890 | isa = XCBuildConfiguration;
891 | buildSettings = {
892 | CLANG_ANALYZER_NONNULL = YES;
893 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
894 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
895 | CLANG_ENABLE_OBJC_WEAK = YES;
896 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
897 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
898 | CODE_SIGN_IDENTITY = "-";
899 | CODE_SIGN_STYLE = Manual;
900 | DEVELOPMENT_TEAM = "";
901 | GCC_C_LANGUAGE_STANDARD = gnu11;
902 | INFOPLIST_FILE = RxWebKitTests/Info.plist;
903 | IPHONEOS_DEPLOYMENT_TARGET = 12.2;
904 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
905 | "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks @loader_path/../Frameworks";
906 | MTL_FAST_MATH = YES;
907 | PRODUCT_BUNDLE_IDENTIFIER = bobgodwinx.RxWebKitTests;
908 | PRODUCT_NAME = "$(TARGET_NAME)";
909 | PROVISIONING_PROFILE_SPECIFIER = "";
910 | SDKROOT = macosx;
911 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
912 | SWIFT_VERSION = 5.0;
913 | TARGETED_DEVICE_FAMILY = "1,2";
914 | };
915 | name = Release;
916 | };
917 | /* End XCBuildConfiguration section */
918 |
919 | /* Begin XCConfigurationList section */
920 | 42F426921C66200D001FED46 /* Build configuration list for PBXProject "RxWebKit" */ = {
921 | isa = XCConfigurationList;
922 | buildConfigurations = (
923 | 42F426A71C66200D001FED46 /* Debug */,
924 | 42F426A81C66200D001FED46 /* Release */,
925 | );
926 | defaultConfigurationIsVisible = 0;
927 | defaultConfigurationName = Release;
928 | };
929 | 42F426A91C66200D001FED46 /* Build configuration list for PBXNativeTarget "Example" */ = {
930 | isa = XCConfigurationList;
931 | buildConfigurations = (
932 | 42F426AA1C66200D001FED46 /* Debug */,
933 | 42F426AB1C66200D001FED46 /* Release */,
934 | );
935 | defaultConfigurationIsVisible = 0;
936 | defaultConfigurationName = Release;
937 | };
938 | 42F426D71C6623C5001FED46 /* Build configuration list for PBXNativeTarget "RxWebKit" */ = {
939 | isa = XCConfigurationList;
940 | buildConfigurations = (
941 | 42F426D81C6623C5001FED46 /* Debug */,
942 | 42F426D91C6623C5001FED46 /* Release */,
943 | );
944 | defaultConfigurationIsVisible = 0;
945 | defaultConfigurationName = Release;
946 | };
947 | C4CB7D4B22874E5600FB8D99 /* Build configuration list for PBXNativeTarget "RxWebKitTests-iOS" */ = {
948 | isa = XCConfigurationList;
949 | buildConfigurations = (
950 | C4CB7D4C22874E5600FB8D99 /* Debug */,
951 | C4CB7D4D22874E5600FB8D99 /* Release */,
952 | );
953 | defaultConfigurationIsVisible = 0;
954 | defaultConfigurationName = Release;
955 | };
956 | EFC27F90246D7E9C0093D8B3 /* Build configuration list for PBXNativeTarget "RxWebKitTests-macOS" */ = {
957 | isa = XCConfigurationList;
958 | buildConfigurations = (
959 | EFC27F91246D7E9C0093D8B3 /* Debug */,
960 | EFC27F92246D7E9C0093D8B3 /* Release */,
961 | );
962 | defaultConfigurationIsVisible = 0;
963 | defaultConfigurationName = Release;
964 | };
965 | /* End XCConfigurationList section */
966 | };
967 | rootObject = 42F4268F1C66200D001FED46 /* Project object */;
968 | }
969 |
--------------------------------------------------------------------------------
/RxWebKit.xcodeproj/xcshareddata/xcschemes/Example.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
33 |
39 |
40 |
41 |
42 |
43 |
49 |
50 |
51 |
52 |
53 |
54 |
64 |
66 |
72 |
73 |
74 |
75 |
76 |
77 |
83 |
85 |
91 |
92 |
93 |
94 |
96 |
97 |
100 |
101 |
102 |
--------------------------------------------------------------------------------
/RxWebKit.xcodeproj/xcshareddata/xcschemes/RxWebKit.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
37 |
38 |
39 |
40 |
41 |
42 |
52 |
53 |
59 |
60 |
61 |
62 |
68 |
69 |
75 |
76 |
77 |
78 |
80 |
81 |
84 |
85 |
86 |
--------------------------------------------------------------------------------
/RxWebKit.xcodeproj/xcshareddata/xcschemes/RxWebKitTests-iOS.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
14 |
15 |
17 |
23 |
24 |
25 |
26 |
27 |
37 |
38 |
44 |
45 |
47 |
48 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/RxWebKit.xcodeproj/xcshareddata/xcschemes/RxWebKitTests-macOS.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
14 |
15 |
17 |
23 |
24 |
25 |
26 |
27 |
37 |
38 |
44 |
45 |
47 |
48 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/RxWebKit.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/RxWebKit.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/RxWebKitTests/ForwardsEventsBehavior.swift:
--------------------------------------------------------------------------------
1 |
2 | import Foundation
3 | import Quick
4 | import Nimble
5 | import RxSwift
6 | import RxCocoa
7 | import RxTest
8 | import WebKit
9 | @testable import RxWebKit
10 |
11 | struct ForwardsEventsBehaviorContext {
12 | let sut: WKWebView
13 | let scheduler: TestScheduler
14 | let selector: Selector
15 | let invoked: (() -> ())
16 |
17 | init(_ sut: WKWebView, _ scheduler: TestScheduler, _ selector: Selector, invoked: @escaping(() -> ())) {
18 | self.sut = sut
19 | self.scheduler = scheduler
20 | self.selector = selector
21 | self.invoked = invoked
22 | }
23 | }
24 |
25 | class ForwardsEventsBehavior: Quick.Behavior {
26 | override class func spec(_ context: @escaping () -> ForwardsEventsBehaviorContext) {
27 |
28 | var sut: WKWebView!
29 | var scheduler: TestScheduler!
30 | var selector: Selector!
31 | var invoked: (() -> ())!
32 |
33 | beforeEach {
34 | let cxt = context()
35 | sut = cxt.sut
36 | scheduler = cxt.scheduler
37 | selector = cxt.selector
38 | invoked = cxt.invoked
39 | }
40 |
41 | afterEach {
42 | sut = nil
43 | scheduler = nil
44 | selector = nil
45 | }
46 |
47 | describe("Has Events Behavior") {
48 | it("sentMessage") {
49 | SharingScheduler.mock(scheduler: scheduler) {
50 | let sentMessage = scheduler.record(source: sut.rx.delegate.sentMessage(selector))
51 | invoked()
52 | scheduler.start()
53 | expect(sentMessage.events.count).to(equal(1))
54 | }
55 | }
56 |
57 | it("methodInvoke") {
58 | SharingScheduler.mock(scheduler: scheduler) {
59 | let methodInvoked = scheduler.record(source: sut.rx.delegate.methodInvoked(selector))
60 | invoked()
61 | scheduler.start()
62 | expect(methodInvoked.events.count).to(equal(1))
63 | }
64 | }
65 | }
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/RxWebKitTests/HasEventsBehavior.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 | import Quick
3 | import Nimble
4 | import RxSwift
5 | import RxCocoa
6 | import RxTest
7 | import WebKit
8 | @testable import RxWebKit
9 |
10 | struct HasEventsBehaviorContext {
11 | let scheduler: TestScheduler
12 | let observable: Observable
13 | let expected: T?
14 | init(_ scheduler: TestScheduler, _ observable: Observable, _ expected: T?) {
15 | self.scheduler = scheduler
16 | self.observable = observable
17 | self.expected = expected
18 | }
19 | }
20 |
21 | class HasEventsBehavior: Quick.Behavior> {
22 | override class func spec(_ context: @escaping () -> HasEventsBehaviorContext) {
23 | var scheduler: TestScheduler!
24 | var observable: Observable!
25 | var expected: T?
26 |
27 | beforeEach {
28 | let cxt = context()
29 | scheduler = cxt.scheduler
30 | observable = cxt.observable
31 | expected = cxt.expected
32 | }
33 |
34 | afterEach {
35 | scheduler = nil
36 | observable = nil
37 | }
38 |
39 | describe("Has Events Behavior") {
40 | it("Actually got the event") {
41 | SharingScheduler.mock(scheduler: scheduler) {
42 | let recorded = scheduler.record(source: observable)
43 | scheduler.start()
44 | expect(recorded.events.count).to(equal(1))
45 | expect(recorded.events[0].value.element).to(equal(expected))
46 | }
47 | }
48 | }
49 | }
50 | }
51 |
52 | extension TestScheduler {
53 | /// Builds testable observer for s specific observable sequence, binds it's results and sets up disposal.
54 | /// parameter source: Observable sequence to observe.
55 | /// returns: Observer that records all events for observable sequence.
56 | func record(source: O) -> TestableObserver {
57 | let observer = self.createObserver(O.Element.self)
58 | let disposable = source.asObservable().bind(to: observer)
59 | self.scheduleAt(100000) {
60 | disposable.dispose()
61 | }
62 | return observer
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/RxWebKitTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/RxWebKitTests/RxWebKitTests.swift:
--------------------------------------------------------------------------------
1 | import WebKit
2 | import Quick
3 | import Nimble
4 | import RxSwift
5 | import RxTest
6 | @testable import RxWebKit
7 |
8 | class RxWebKitTests: QuickSpec {
9 | override func spec() {
10 | var scheduler: TestScheduler!
11 | var sut: WKWebView!
12 | let html = """
13 |
14 |
15 |
16 | RxWebKit
17 |
18 |
19 |
20 | This is a Heading
21 | This is a paragraph.
22 |
23 |
24 |
25 | """
26 |
27 | beforeEach {
28 | scheduler = TestScheduler(initialClock: 0)
29 | sut = WKWebView(frame: CGRect.zero)
30 | }
31 |
32 | afterEach {
33 | scheduler = nil
34 | sut = nil
35 | }
36 |
37 | itBehavesLike(HasEventsBehavior.self) {
38 | HasEventsBehaviorContext(scheduler, sut.rx.title, "")
39 | }
40 |
41 | itBehavesLike(HasEventsBehavior.self) {
42 | sut.loadHTMLString(html, baseURL: Bundle.main.resourceURL)
43 | return HasEventsBehaviorContext(scheduler, sut.rx.loading, true)
44 | }
45 |
46 | itBehavesLike(HasEventsBehavior.self) {
47 | HasEventsBehaviorContext(scheduler, sut.rx.loading, false)
48 | }
49 |
50 | itBehavesLike(HasEventsBehavior.self) {
51 | HasEventsBehaviorContext(scheduler, sut.rx.estimatedProgress, 0.0)
52 | }
53 |
54 | itBehavesLike(HasEventsBehavior.self) {
55 | sut.loadHTMLString(html, baseURL: Bundle.main.resourceURL)
56 | return HasEventsBehaviorContext(scheduler, sut.rx.estimatedProgress, 0.1)
57 | }
58 |
59 | itBehavesLike(HasEventsBehavior.self) {
60 | HasEventsBehaviorContext(scheduler, sut.rx.canGoBack, false)
61 | }
62 |
63 | itBehavesLike(HasEventsBehavior.self) {
64 | HasEventsBehaviorContext(scheduler, sut.rx.canGoForward, false)
65 | }
66 |
67 | itBehavesLike(ForwardsEventsBehavior.self) {
68 | ForwardsEventsBehaviorContext(sut, scheduler, .didTerminate) {
69 | sut.navigationDelegate?.webViewWebContentProcessDidTerminate?(sut)
70 | }
71 | }
72 |
73 | itBehavesLike(ForwardsEventsBehavior.self) {
74 | ForwardsEventsBehaviorContext(sut, scheduler, .didCommitNavigation) {
75 | let navigation = sut.loadHTMLString(html, baseURL: Bundle.main.resourceURL)
76 | sut.navigationDelegate?.webView?(sut, didCommit: navigation)
77 | }
78 | }
79 |
80 | itBehavesLike(ForwardsEventsBehavior.self) {
81 | ForwardsEventsBehaviorContext(sut, scheduler, .didFinishNavigation) {
82 | let navigation = sut.loadHTMLString(html, baseURL: Bundle.main.resourceURL)
83 | sut.navigationDelegate?.webView?(sut, didFinish: navigation)
84 | }
85 | }
86 |
87 | itBehavesLike(ForwardsEventsBehavior.self) {
88 | ForwardsEventsBehaviorContext(sut, scheduler, .didReceiveServerRedirectForProvisionalNavigation) {
89 | let navigation = sut.loadHTMLString(html, baseURL: Bundle.main.resourceURL)
90 | sut.navigationDelegate?.webView?(sut, didReceiveServerRedirectForProvisionalNavigation: navigation)
91 | }
92 | }
93 |
94 | itBehavesLike(ForwardsEventsBehavior.self) {
95 | ForwardsEventsBehaviorContext(sut, scheduler, .didFailNavigation) {
96 | let navigation = sut.loadHTMLString(html, baseURL: Bundle.main.resourceURL)
97 | sut.navigationDelegate?.webView?(sut, didFail: navigation, withError: TestError.didFailNavigation)
98 | }
99 | }
100 |
101 | itBehavesLike(ForwardsEventsBehavior.self) {
102 | ForwardsEventsBehaviorContext(sut, scheduler, .didFailProvisionalNavigation) {
103 | let navigation = sut.loadHTMLString(html, baseURL: Bundle.main.resourceURL)
104 | sut.navigationDelegate?.webView?(sut, didFailProvisionalNavigation: navigation, withError: TestError.didFailProvisionalNavigation)
105 | }
106 | }
107 |
108 | itBehavesLike(ForwardsEventsBehavior.self) {
109 | ForwardsEventsBehaviorContext(sut, scheduler, .didReceiveChallenge) {
110 | let protectionSpace = URLProtectionSpace(host: "fake", port: 8443, protocol: nil, realm: nil, authenticationMethod: nil)
111 | let credential = URLCredential(user: "bad-user", password: "bad-password", persistence: URLCredential.Persistence.forSession)
112 | let sender = MockURLAuthenticationChallengeSender()
113 |
114 | let challenge = URLAuthenticationChallenge(protectionSpace: protectionSpace, proposedCredential: credential, previousFailureCount: 0, failureResponse:nil, error: TestError.didReceiveChallenge, sender: sender)
115 |
116 | sut.navigationDelegate?.webView?(sut, didReceive: challenge, completionHandler: { (_, _) in })
117 | }
118 | }
119 |
120 | itBehavesLike(ForwardsEventsBehavior.self) {
121 | ForwardsEventsBehaviorContext(sut, scheduler, .decidePolicyNavigationAction) {
122 | let delegate:WKNavigationDelegate? = sut.navigationDelegate
123 | delegate?.webView?(sut, decidePolicyFor: WKNavigationAction(), decisionHandler: { (_) in })
124 | }
125 | }
126 |
127 | itBehavesLike(ForwardsEventsBehavior.self) {
128 | ForwardsEventsBehaviorContext(sut, scheduler, .decidePolicyNavigationResponse) {
129 | let delegate:WKNavigationDelegate? = sut.navigationDelegate
130 | delegate?.webView?(sut, decidePolicyFor: WKNavigationResponse(), decisionHandler: { (_) in })
131 | }
132 | }
133 | }
134 | }
135 |
136 | enum TestError: Error {
137 | case didFailNavigation
138 | case didFailProvisionalNavigation
139 | case didReceiveChallenge
140 | }
141 |
142 | @objc class MockURLAuthenticationChallengeSender: NSObject, URLAuthenticationChallengeSender {
143 | override func `self`() -> Self {
144 | return self
145 | }
146 |
147 | override init() {}
148 | func use(_ credential: URLCredential, for challenge: URLAuthenticationChallenge) { }
149 |
150 | func continueWithoutCredential(for challenge: URLAuthenticationChallenge) {}
151 |
152 | func cancel(_ challenge: URLAuthenticationChallenge) { }
153 | }
154 |
--------------------------------------------------------------------------------
/Sources/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 | FMWK
17 | CFBundleShortVersionString
18 | 0.3
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | $(CURRENT_PROJECT_VERSION)
23 | NSPrincipalClass
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/Sources/RxWebKit.h:
--------------------------------------------------------------------------------
1 | //
2 | // RxWebKit.h
3 | // RxWebKit
4 | //
5 | // Created by Daichi Ichihara on 2016/02/06.
6 | // Copyright © 2016年 RxSwift Community. All rights reserved.
7 | //
8 |
9 | #if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR
10 | #import
11 | #elseif TARGET_OS_MAC
12 | #endif
13 | //! Project version number for RxWebKit.
14 | extern double RxWebKitVersionNumber;
15 |
16 | //! Project version string for RxWebKit.
17 | extern const unsigned char RxWebKitVersionString[];
18 |
19 | // In this header, you should import all the public headers of your framework using statements like #import
20 |
21 |
22 |
--------------------------------------------------------------------------------
/Sources/RxWebKit/Rx+WebKit.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Rx+WebKit.swift
3 | // RxWebKit
4 | //
5 | // Created by Daichi Ichihara on 2016/02/06.
6 | // Copyright © 2016年 RxSwift Community. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import WebKit
11 | import RxSwift
12 | import RxCocoa
13 |
14 | extension Reactive where Base: WKWebView {
15 | /**
16 | Reactive wrapper for `title` property
17 | */
18 | public var title: Observable {
19 | return self.observeWeakly(String.self, "title")
20 | }
21 |
22 | /**
23 | Reactive wrapper for `loading` property.
24 | */
25 | public var loading: Observable {
26 | return self.observeWeakly(Bool.self, "loading")
27 | .map { $0 ?? false }
28 | }
29 |
30 | /**
31 | Reactive wrapper for `estimatedProgress` property.
32 | */
33 | public var estimatedProgress: Observable {
34 | return self.observeWeakly(Double.self, "estimatedProgress")
35 | .map { $0 ?? 0.0 }
36 | }
37 |
38 | /**
39 | Reactive wrapper for `url` property.
40 | */
41 | public var url: Observable {
42 | return self.observeWeakly(URL.self, "URL")
43 | }
44 |
45 |
46 | /**
47 | Reactive wrapper for `canGoBack` property.
48 | */
49 | public var canGoBack: Observable {
50 | return self.observeWeakly(Bool.self, "canGoBack")
51 | .map { $0 ?? false }
52 | }
53 |
54 | /**
55 | Reactive wrapper for `canGoForward` property.
56 | */
57 | public var canGoForward: Observable {
58 | return self.observeWeakly(Bool.self, "canGoForward")
59 | .map { $0 ?? false }
60 | }
61 |
62 |
63 | /// Reactive wrapper for `evaluateJavaScript(_:completionHandler:)` method.
64 | ///
65 | /// - Parameter javaScriptString: The JavaScript string to evaluate.
66 | /// - Returns: Observable sequence of result of the script evaluation.
67 | public func evaluateJavaScript(_ javaScriptString:String) -> Observable {
68 | return Observable.create { [weak base] observer in
69 | base?.evaluateJavaScript(javaScriptString) { value, error in
70 | if let error = error {
71 | observer.onError(error)
72 | } else {
73 | observer.onNext(value)
74 | observer.onCompleted()
75 | }
76 | }
77 | return Disposables.create()
78 | }
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/Sources/RxWebKit/RxWKNavigationDelegateProxy.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RxWKNavigationDelegateProxy.swift
3 | // RxWebKit
4 | //
5 | // Created by Bob Obi on 23.10.17.
6 | // Copyright © 2017 RxSwift Community. All rights reserved.
7 | //
8 |
9 | import WebKit
10 | #if !RX_NO_MODULE
11 | import RxSwift
12 | import RxCocoa
13 | #endif
14 |
15 | public typealias RxWKNavigationDelegate = DelegateProxy
16 |
17 | open class RxWKNavigationDelegateProxy: RxWKNavigationDelegate, DelegateProxyType, WKNavigationDelegate {
18 |
19 | /// Type of parent object
20 | public weak private(set) var webView: WKWebView?
21 |
22 | /// Init with ParentObject
23 | public init(parentObject: ParentObject) {
24 | webView = parentObject
25 | super.init(parentObject: parentObject, delegateProxy: RxWKNavigationDelegateProxy.self)
26 | }
27 |
28 | /// Register self to known implementations
29 | public static func registerKnownImplementations() {
30 | self.register { parent -> RxWKNavigationDelegateProxy in
31 | RxWKNavigationDelegateProxy(parentObject: parent)
32 | }
33 | }
34 |
35 | /// Gets the current `WKNavigationDelegate` on `WKWebView`
36 | open class func currentDelegate(for object: ParentObject) -> WKNavigationDelegate? {
37 | return object.navigationDelegate
38 | }
39 |
40 | /// Set the navigationDelegate for `WKWebView`
41 | open class func setCurrentDelegate(_ delegate: WKNavigationDelegate?, to object: ParentObject) {
42 | object.navigationDelegate = delegate
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/Sources/RxWebKit/RxWKUIDelegateEvents+Rx.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RxWKUIDelegateEvents+Rx.swift
3 | // RxWebKit
4 | //
5 | // Created by Bob Obi on 25.10.17.
6 | // Copyright © 2017 RxSwift Community. All rights reserved.
7 | //
8 |
9 | #if !RX_NO_MODULE
10 | import RxSwift
11 | import RxCocoa
12 | #endif
13 |
14 | import WebKit
15 |
16 | extension Reactive where Base: WKWebView {
17 | public typealias JSAlertEvent = (webView: WKWebView, message: String, frame: WKFrameInfo, handler: () -> ())
18 | public typealias JSConfirmEvent = (webView: WKWebView, message: String, frame: WKFrameInfo, handler: (Bool) -> ())
19 | #if os(iOS)
20 | public typealias CommitPreviewEvent = (webView: WKWebView, controller: UIViewController)
21 | #endif
22 |
23 | /// Reactive wrapper for `navigationDelegate`.
24 | public var uiDelegate: DelegateProxy {
25 | return RxWKUIDelegateProxy.proxy(for: base)
26 | }
27 |
28 | /// Reactive wrapper for `func webView(_ webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping () -> Swift.Void)`
29 | public var javaScriptAlertPanel: ControlEvent {
30 | typealias __CompletionHandler = @convention(block) () -> ()
31 | let source:Observable = uiDelegate
32 | .methodInvoked(.jsAlert).map { args in
33 | let view = try castOrThrow(WKWebView.self, args[0])
34 | let message = try castOrThrow(String.self, args[1])
35 | let frame = try castOrThrow(WKFrameInfo.self, args[2])
36 | var closureObject: AnyObject? = nil
37 | var mutableArgs = args
38 | mutableArgs.withUnsafeMutableBufferPointer { ptr in
39 | closureObject = ptr[3] as AnyObject
40 | }
41 | let __completionBlockPtr = UnsafeRawPointer(Unmanaged.passUnretained(closureObject as AnyObject).toOpaque())
42 | let handler = unsafeBitCast(__completionBlockPtr, to: __CompletionHandler.self)
43 | return (view, message, frame, handler)
44 | }
45 |
46 | return ControlEvent(events: source)
47 | }
48 |
49 | /// Reactive wrapper for `func webView(_ webView: WKWebView, runJavaScriptConfirmPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (Bool) -> Swift.Void)`
50 | public var javaScriptConfirmPanel: ControlEvent {
51 | typealias __ConfirmHandler = @convention(block) (Bool) -> ()
52 | let source:Observable = uiDelegate
53 | .methodInvoked(.jsConfirm).map { args in
54 | let view = try castOrThrow(WKWebView.self, args[0])
55 | let message = try castOrThrow(String.self, args[1])
56 | let frame = try castOrThrow(WKFrameInfo.self, args[2])
57 | var closureObject: AnyObject? = nil
58 | var mutableArgs = args
59 | mutableArgs.withUnsafeMutableBufferPointer { ptr in
60 | closureObject = ptr[3] as AnyObject
61 | }
62 | let __confirmBlockPtr = UnsafeRawPointer(Unmanaged.passUnretained(closureObject as AnyObject).toOpaque())
63 | let handler = unsafeBitCast(__confirmBlockPtr, to: __ConfirmHandler.self)
64 | return (view, message, frame, handler)
65 | }
66 |
67 | return ControlEvent(events: source)
68 | }
69 |
70 | #if os(iOS)
71 | /// Reactive wrappper for `func webView(_ webView: WKWebView, commitPreviewingViewController previewingViewController: UIViewController)`
72 | @available(iOS 10.0, *)
73 | public var commitPreviewing: ControlEvent {
74 | let source: Observable = uiDelegate
75 | .methodInvoked(.commitPreviewing)
76 | .map { args in
77 | let view = try castOrThrow(WKWebView.self, args[0])
78 | let controller = try castOrThrow(UIViewController.self, args[1])
79 | return (view, controller)
80 | }
81 |
82 | return ControlEvent(events: source)
83 | }
84 | #endif
85 | }
86 |
87 | fileprivate extension Selector {
88 | static let jsAlert = #selector(WKUIDelegate.webView(_:runJavaScriptAlertPanelWithMessage:initiatedByFrame:completionHandler:))
89 | static let jsConfirm = #selector(WKUIDelegate.webView(_:runJavaScriptConfirmPanelWithMessage:initiatedByFrame:completionHandler:))
90 |
91 | #if os(iOS)
92 | @available(iOS 10.0, *)
93 | static let commitPreviewing = #selector(WKUIDelegate.webView(_:commitPreviewingViewController:))
94 | #endif
95 | }
96 |
--------------------------------------------------------------------------------
/Sources/RxWebKit/RxWKUIDelegateProxy.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RxWKUIDelegateProxy.swift
3 | // RxWebKit
4 | //
5 | // Created by Bob Obi on 25.10.17.
6 | // Copyright © 2017 RxSwift Community. All rights reserved.
7 | //
8 |
9 | import WebKit
10 | #if !RX_NO_MODULE
11 | import RxSwift
12 | import RxCocoa
13 | #endif
14 |
15 | public typealias RxWKUIDelegate = DelegateProxy
16 |
17 | open class RxWKUIDelegateProxy: RxWKUIDelegate, DelegateProxyType, WKUIDelegate {
18 |
19 | /// Type of parent object
20 | /// must be WKWebView!
21 | public weak private(set) var webView: WKWebView?
22 |
23 | /// Init with ParentObject
24 | public init(parentObject: ParentObject) {
25 | webView = parentObject
26 | super.init(parentObject: parentObject, delegateProxy: RxWKUIDelegateProxy.self)
27 | }
28 |
29 | /// Register self to known implementations
30 | public static func registerKnownImplementations() {
31 | self.register { parent -> RxWKUIDelegateProxy in
32 | RxWKUIDelegateProxy(parentObject: parent)
33 | }
34 | }
35 |
36 | /// Gets the current `WKUIDelegate` on `WKWebView`
37 | open class func currentDelegate(for object: ParentObject) -> WKUIDelegate? {
38 | return object.uiDelegate
39 | }
40 |
41 | /// Set the uiDelegate for `WKWebView`
42 | open class func setCurrentDelegate(_ delegate: WKUIDelegate?, to object: ParentObject) {
43 | object.uiDelegate = delegate
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/Sources/RxWebKit/RxWKUserContentController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RxWKUserContentController.swift
3 | // RxWebKit
4 | //
5 | // Created by Jesse Hao on 2019/3/30.
6 | // Copyright © 2019 RxSwift Community. All rights reserved.
7 | //
8 |
9 | import WebKit
10 | #if !RX_NO_MODULE
11 | import RxSwift
12 | import RxCocoa
13 | #endif
14 |
15 | extension WKUserContentController {
16 | fileprivate class MessageHandler : NSObject, WKScriptMessageHandler {
17 | typealias MessageReceiveHandler = (WKScriptMessage) -> Void
18 | private var messageReceiveHandler:MessageReceiveHandler?
19 |
20 | func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
21 | self.messageReceiveHandler?(message)
22 | }
23 |
24 | func onReceive(_ handler:@escaping MessageReceiveHandler) {
25 | self.messageReceiveHandler = handler
26 | }
27 | }
28 | }
29 |
30 | public extension Reactive where Base : WKUserContentController {
31 | /// Observable sequence of script message.
32 | ///
33 | /// - Parameter name: The name of the message handler
34 | /// - Returns: Observable sequence of script message.
35 | func scriptMessage(forName name:String) -> ControlEvent {
36 | return ControlEvent(events: Observable.create { [weak base] observer in
37 | let handler = WKUserContentController.MessageHandler()
38 | base?.add(handler, name: name)
39 | handler.onReceive {
40 | observer.onNext($0)
41 | }
42 | return Disposables.create {
43 | base?.removeScriptMessageHandler(forName: name)
44 | }
45 | })
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/Sources/RxWebKit/WKNavigationDelegateEvents+Rx.swift:
--------------------------------------------------------------------------------
1 | //
2 | // WKNavigationDelegateEvents+Rx.swift
3 | // RxWebKit
4 | //
5 | // Created by Bob Obi on 23.10.17.
6 | // Copyright © 2017 RxSwift Community. All rights reserved.
7 | //
8 |
9 | #if !RX_NO_MODULE
10 | import RxSwift
11 | import RxCocoa
12 | #endif
13 |
14 | import WebKit
15 |
16 | func castOrThrow(_ resultType: T.Type, _ object: Any) throws -> T {
17 | guard let returnValue = object as? T else {
18 | throw RxCocoaError.castingError(object: object, targetType: resultType)
19 | }
20 | return returnValue
21 | }
22 |
23 | extension Reactive where Base: WKWebView {
24 | /// WKNavigationEvent emits a tuple that contains both
25 | /// WKWebView + WKNavigation
26 | public typealias WKNavigationEvent = (webView: WKWebView, navigation: WKNavigation)
27 |
28 | /// WKNavigationFailedEvent emits a tuple that contains both
29 | /// WKWebView + WKNavigation + Swift.Error
30 | public typealias WKNavigationFailEvent = (webView: WKWebView, navigation: WKNavigation, error: Error)
31 |
32 | /// ChallengeHandler this is exposed to the user on subscription
33 | public typealias ChallengeHandler = (URLSession.AuthChallengeDisposition, URLCredential?) -> Void
34 | /// WKNavigationChallengeEvent emits a tuple event of WKWebView + challenge + ChallengeHandler
35 | public typealias WKNavigationChallengeEvent = (webView: WKWebView, challenge: URLAuthenticationChallenge, handler: ChallengeHandler)
36 |
37 | /// DecisionHandler this is the block exposed to the user on subscription
38 | public typealias DecisionHandler = (WKNavigationResponsePolicy) -> Void
39 | /// WKNavigationResponsePolicyEvent emits a tuple event of WKWebView + WKNavigationResponse + DecisionHandler
40 | public typealias WKNavigationResponsePolicyEvent = ( webView: WKWebView, reponse: WKNavigationResponse, handler: DecisionHandler)
41 | /// ActionHandler this is the block exposed to the user on subscription
42 | public typealias ActionHandler = (WKNavigationActionPolicy) -> Void
43 | /// WKNavigationActionPolicyEvent emits a tuple event of WKWebView + WKNavigationAction + ActionHandler
44 | public typealias WKNavigationActionPolicyEvent = ( webView: WKWebView, action: WKNavigationAction, handler: ActionHandler)
45 |
46 | /// Reactive wrapper for `navigationDelegate`.
47 | public var delegate: DelegateProxy {
48 | return RxWKNavigationDelegateProxy.proxy(for: base)
49 | }
50 |
51 | /// Reactive wrapper for delegate method `webView(_ webView: WKWebView, didCommit navigation: WKNavigation!)`.
52 | public var didCommitNavigation: ControlEvent {
53 | let source: Observable = delegate
54 | .methodInvoked(.didCommitNavigation)
55 | .map { arg in
56 | let view = try castOrThrow(WKWebView.self, arg[0])
57 | let nav = try castOrThrow(WKNavigation.self, arg[1])
58 | return (view, nav)
59 | }
60 | return ControlEvent(events: source)
61 | }
62 |
63 | /// Reactive wrapper for delegate method `webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!)`.
64 | public var didStartProvisionalNavigation: ControlEvent {
65 | let source: Observable = delegate
66 | .methodInvoked(.didStartProvisionalNavigation)
67 | .map { arg in
68 | let view = try castOrThrow(WKWebView.self, arg[0])
69 | let nav = try castOrThrow(WKNavigation.self, arg[1])
70 | return (view, nav)
71 | }
72 | return ControlEvent(events: source)
73 | }
74 |
75 | /// Reactive wrapper for delegate method `webView(_ webView: WKWebView, didFinish navigation: WKNavigation!)`
76 | public var didFinishNavigation: ControlEvent {
77 | let source: Observable = delegate
78 | .methodInvoked(.didFinishNavigation)
79 | .map { arg in
80 | let view = try castOrThrow(WKWebView.self, arg[0])
81 | let nav = try castOrThrow(WKNavigation.self, arg[1])
82 | return (view, nav)
83 | }
84 | return ControlEvent(events: source)
85 | }
86 |
87 | /// Reactive wrapper for delegate method `webViewWebContentProcessDidTerminate(_ webView: WKWebView)`.
88 | @available(iOS 9.0, *)
89 | public var didTerminate: ControlEvent {
90 | let source: Observable = delegate
91 | .methodInvoked(.didTerminate)
92 | .map { try castOrThrow(WKWebView.self, $0[0]) }
93 | return ControlEvent(events: source)
94 | }
95 |
96 | /// Reactive wrapper for delegate method `webView(_ webView: WKWebView, didReceiveServerRedirectForProvisionalNavigation navigation: WKNavigation!)`.
97 | public var didReceiveServerRedirectForProvisionalNavigation: ControlEvent {
98 | let source: Observable = delegate
99 | .methodInvoked(.didReceiveServerRedirectForProvisionalNavigation)
100 | .map { arg in
101 | let view = try castOrThrow(WKWebView.self, arg[0])
102 | let nav = try castOrThrow(WKNavigation.self, arg[1])
103 | return (view, nav)
104 | }
105 | return ControlEvent(events: source)
106 | }
107 |
108 | /// Reactive wrapper for delegate method `webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error)`.
109 | public var didFailNavigation: ControlEvent {
110 | let source: Observable = delegate
111 | .methodInvoked(.didFailNavigation)
112 | .map { arg in
113 | let view = try castOrThrow(WKWebView.self, arg[0])
114 | let nav = try castOrThrow(WKNavigation.self, arg[1])
115 | let error = try castOrThrow(Swift.Error.self, arg[2])
116 | return (view, nav, error)
117 | }
118 | return ControlEvent(events: source)
119 | }
120 |
121 | /// Reactive wrapper for delegate method `webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error)`.
122 | public var didFailProvisionalNavigation: ControlEvent {
123 | let source: Observable = delegate
124 | .methodInvoked(.didFailProvisionalNavigation)
125 | .map { arg in
126 | let view = try castOrThrow(WKWebView.self, arg[0])
127 | let nav = try castOrThrow(WKNavigation.self, arg[1])
128 | let error = try castOrThrow(Swift.Error.self, arg[2])
129 | return (view, nav, error)
130 | }
131 | return ControlEvent(events: source)
132 | }
133 |
134 | /// Reactive wrapper for delegate method `webView(_ webView: WKWebView, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void)`
135 | public var didReceiveChallenge: ControlEvent {
136 | /// __ChallengeHandler is same as ChallengeHandler
137 | /// They are interchangeable, __ChallengeHandler is for internal use.
138 | /// ChallengeHandler is exposed to the user on subscription.
139 | /// @convention attribute makes the swift closure compatible with Objc blocks
140 | typealias __ChallengeHandler = @convention(block) (URLSession.AuthChallengeDisposition, URLCredential?) -> Void
141 | /*! @abstract Invoked when the web view needs to respond to an authentication challenge.
142 | @param webView The web view that received the authentication challenge.
143 | @param challenge The authentication challenge.
144 | @param completionHandler The completion handler you must invoke to respond to the challenge. The
145 | disposition argument is one of the constants of the enumerated type
146 | NSURLSessionAuthChallengeDisposition. When disposition is NSURLSessionAuthChallengeUseCredential,
147 | the credential argument is the credential to use, or nil to indicate continuing without a
148 | credential.
149 | @discussion If you do not implement this method, the web view will respond to the authentication challenge with the NSURLSessionAuthChallengeRejectProtectionSpace disposition.
150 | */
151 | let source: Observable = delegate
152 | .sentMessage(.didReceiveChallenge)
153 | .map { arg in
154 | /// Extracting the WKWebView from the array at index zero
155 | /// which is the first argument of the function signature
156 | let view = try castOrThrow(WKWebView.self, arg[0])
157 | /// Extracting the URLAuthenticationChallenge from the array at index one
158 | /// which is the second argument of the function signature
159 | let challenge = try castOrThrow(URLAuthenticationChallenge.self, arg[1])
160 | /// Now you `Can't` transform closure easily because they are excuted
161 | /// in the stack if try it you will get the famous error
162 | /// `Could not cast value of type '__NSStackBlock__' (0x12327d1a8) to`
163 | /// this is because closures are transformed into a system type which is `__NSStackBlock__`
164 | /// the above mentioned type is not exposed to `developer`. So everytime
165 | /// you execute a closure the compiler transforms it into this Object.
166 | /// So you go through the following steps to get a human readable type
167 | /// of the closure signature:
168 | /// 1. closureObject is type of AnyObject to that holds the raw value from
169 | /// the array.
170 | var closureObject: AnyObject? = nil
171 | /// 2. make the array mutable in order to access the `withUnsafeMutableBufferPointer`
172 | /// fuctionalities
173 | var mutableArg = arg
174 | /// 3. Grab the closure at index 3 of the array, but we have to use the C-style
175 | /// approach to access the raw memory underpinning the array and store it in closureObject
176 | /// Now the object stored in the `closureObject` is `Unmanaged` and `some unspecified type`
177 | /// the intelligent swift compiler doesn't know what sort of type it contains. It is Raw.
178 | mutableArg.withUnsafeMutableBufferPointer { ptr in
179 | closureObject = ptr[2] as AnyObject
180 | }
181 | /// 4. instantiate an opaque pointer to referenc the value of the `unspecified type`
182 | let __challengeBlockPtr = UnsafeRawPointer(Unmanaged.passUnretained(closureObject as AnyObject).toOpaque())
183 | /// 5. Here the magic happen we forcefully tell the compiler that anything
184 | /// found at this memory address that is refrenced should be a type of
185 | /// `__ChallengeHandler`!
186 | let handler = unsafeBitCast(__challengeBlockPtr, to: __ChallengeHandler.self)
187 | return (view, challenge, handler)
188 | }
189 |
190 | return ControlEvent(events: source)
191 |
192 | /**
193 | Reference:
194 |
195 | This is a holy grail part for more information please read the following articles.
196 | 1: http://codejaxy.com/q/332345/ios-objective-c-memory-management-automatic-ref-counting-objective-c-blocks-understand-one-edge-case-of-block-memory-management-in-objc
197 | 2: http://www.galloway.me.uk/2012/10/a-look-inside-blocks-episode-2/
198 | 3: https://maniacdev.com/2013/11/tutorial-an-in-depth-guide-to-objective-c-block-debugging
199 | 4: get know how [__NSStackBlock__ + UnsafeRawPointer + unsafeBitCast] works under the hood
200 | 5: https://en.wikipedia.org/wiki/Opaque_pointer
201 | 6: https://stackoverflow.com/questions/43662363/cast-objective-c-block-nsstackblock-into-swift-3
202 | */
203 | }
204 |
205 | /// Reactive wrapper for `func webView(_ webView: WKWebView, decidePolicyFor navigationResponse: WKNavigationResponse, decisionHandler: @escaping (WKNavigationResponsePolicy) -> Swift.Void)`
206 | public var decidePolicyNavigationResponse: ControlEvent {
207 | typealias __DecisionHandler = @convention(block) (WKNavigationResponsePolicy) -> ()
208 | let source:Observable = delegate
209 | .methodInvoked(.decidePolicyNavigationResponse).map { args in
210 | let view = try castOrThrow(WKWebView.self, args[0])
211 | let response = try castOrThrow(WKNavigationResponse.self, args[1])
212 | var closureObject: AnyObject? = nil
213 | var mutableArgs = args
214 | mutableArgs.withUnsafeMutableBufferPointer { ptr in
215 | closureObject = ptr[2] as AnyObject
216 | }
217 | let __decisionBlockPtr = UnsafeRawPointer(Unmanaged.passUnretained(closureObject as AnyObject).toOpaque())
218 | let handler = unsafeBitCast(__decisionBlockPtr, to: __DecisionHandler.self)
219 | return (view, response, handler)
220 | }
221 |
222 | return ControlEvent(events: source)
223 | }
224 |
225 | /// Reactive wrapper for `func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Swift.Void)`
226 | public var decidePolicyNavigationAction: ControlEvent {
227 | typealias __ActionHandler = @convention(block) (WKNavigationActionPolicy) -> ()
228 | let source:Observable = delegate
229 | .methodInvoked(.decidePolicyNavigationAction).map { args in
230 | let view = try castOrThrow(WKWebView.self, args[0])
231 | let action = try castOrThrow(WKNavigationAction.self, args[1])
232 | var closureObject: AnyObject? = nil
233 | var mutableArgs = args
234 | mutableArgs.withUnsafeMutableBufferPointer { ptr in
235 | closureObject = ptr[2] as AnyObject
236 | }
237 | let __actionBlockPtr = UnsafeRawPointer(Unmanaged.passUnretained(closureObject as AnyObject).toOpaque())
238 | let handler = unsafeBitCast(__actionBlockPtr, to: __ActionHandler.self)
239 | return (view, action, handler)
240 | }
241 |
242 | return ControlEvent(events: source)
243 | }
244 | }
245 | extension Selector {
246 | static let didCommitNavigation = #selector(WKNavigationDelegate.webView(_:didCommit:))
247 | static let didStartProvisionalNavigation = #selector(WKNavigationDelegate.webView(_:didStartProvisionalNavigation:))
248 | static let didFinishNavigation = #selector(WKNavigationDelegate.webView(_:didFinish:))
249 | static let didReceiveServerRedirectForProvisionalNavigation = #selector(WKNavigationDelegate.webView(_:didReceiveServerRedirectForProvisionalNavigation:))
250 | static let didFailNavigation = #selector(WKNavigationDelegate.webView(_:didFail:withError:))
251 | static let didFailProvisionalNavigation = #selector(WKNavigationDelegate.webView(_:didFailProvisionalNavigation:withError:))
252 | static let didReceiveChallenge = #selector(WKNavigationDelegate.webView(_:didReceive:completionHandler:))
253 | @available(iOS 9.0, *)
254 | static let didTerminate = #selector(WKNavigationDelegate.webViewWebContentProcessDidTerminate(_:))
255 | /// Xcode give error when selectors results into having same signature
256 | /// because of swift style you get for example:
257 | /// Ambiguous use of 'webView(_:decidePolicyFor:decisionHandler:)'
258 | /// please see this link for further understanding
259 | /// https://bugs.swift.org/browse/SR-3062
260 | #if swift(>=5.7)
261 | static let decidePolicyNavigationResponse = #selector(WKNavigationDelegate.webView(_:decidePolicyFor:decisionHandler:) as (WKNavigationDelegate) -> ((WKWebView, WKNavigationResponse, @escaping(WKNavigationResponsePolicy) -> Void) -> Void)?)
262 | static let decidePolicyNavigationAction = #selector(WKNavigationDelegate.webView(_:decidePolicyFor:decisionHandler:) as (WKNavigationDelegate) -> ((WKWebView, WKNavigationAction, @escaping (WKNavigationActionPolicy) -> Void) -> Void)?)
263 | #else
264 | static let decidePolicyNavigationResponse = #selector(WKNavigationDelegate.webView(_:decidePolicyFor:decisionHandler:) as ((WKNavigationDelegate) -> (WKWebView, WKNavigationResponse, @escaping(WKNavigationResponsePolicy) -> Void) -> Void)?)
265 | static let decidePolicyNavigationAction = #selector(WKNavigationDelegate.webView(_:decidePolicyFor:decisionHandler:) as ((WKNavigationDelegate) -> (WKWebView, WKNavigationAction, @escaping(WKNavigationActionPolicy) -> Void) -> Void)?)
266 | #endif
267 | }
268 |
269 |
270 |
--------------------------------------------------------------------------------