# WKWebViewJavascriptBridge: messaging between Swift and web content

> WKWebViewJavascriptBridge is an MIT licensed Swift library that lets native code and JavaScript in a WKWebView call each other by handler name, with no subclassing and no request interception. It is three files, it supports Swift 3.2 through 5, and the last push was on 2026-06-21.

**Lision/WKWebViewJavascriptBridge** — 🌉 A Bridge for Sending Messages between Swift and JavaScript in WKWebViews.

- Repository: https://github.com/Lision/WKWebViewJavascriptBridge
- Stars: 1,331 · Forks: 146
- Language: Swift
- License: MIT
- Published: 2026-10-19 · Updated: 2026-10-19 · Language: en
- Canonical page: https://hysenlabs.com/projects/lision-wkwebviewjavascriptbridge

## A hybrid module in a few lines

WKWebViewJavascriptBridge is described as a bridge for sending messages between Swift and JavaScript in WKWebViews, and the README's opening claim is that you can write hybrid modules in just a few lines of code without needing to be concerned with the underlying messaging implementation.

The whole library is three files. That is the entire framework, and it is a design decision rather than a limitation of scope, because the mechanism underneath is a feature the operating system already provides.

The bridge is instantiated with a web view and nothing else:

```swift
bridge = WKWebViewJavascriptBridge(webView: webView)
```

And it does not require the web view class to inherit from anything, which the README calls out as non-intrusive. That matters in practice, because a bridge that requires subclassing forces you to change the class of the view you already have, and in an app with a shared web view base class that is a fight.

The messaging model is name based on both sides. Native registers a handler under a name and receives parameters plus an optional callback:

```swift
bridge.register(handlerName: "testiOSCallback") { (parameters, callback) in
    print("testiOSCallback called: \(String(describing: parameters))")
    callback?("Response from testiOSCallback")
}

bridge.call(handlerName: "testJavascriptHandler", data: ["foo": "before ready"], callback: nil)
```

So the native side can both receive and initiate, and a callback can carry a response back. The pattern is symmetric, which is what makes it usable for anything beyond a one-way call.

The performance claim is specific and is worth understanding: the messaging performance is higher than intercept requests, and there is no need to consider an alert box safety timeout. Both of those are references to the alternative approach, where you intercept web view requests and pass data through the URL, which involves a request interception cycle and a JavaScript dialog whose dismissal has a timeout.

## The JavaScript side and the injection handshake

On the web side, the setup is a function you paste into your JavaScript, and the mechanism is a message handler injection rather than a native bridge object.

```js
function setupWKWebViewJavascriptBridge(callback) {
    if (window.WKWebViewJavascriptBridge) { return callback(WKWebViewJavascriptBridge); }
    if (window.WKWVJBCallbacks) { return window.WKWVJBCallbacks.push(callback); }
    window.WKWVJBCallbacks = [callback];
    window.webkit.messageHandlers.iOS_Native_InjectJavascript.postMessage(null)
}
```

Read that carefully, because it handles the case that breaks most hand-rolled bridges. If the bridge object is already on the window, the callback fires immediately with it. If the callbacks array already exists, the callback is pushed onto it. Only if neither exists does the function create the array and post the injection message, which is what tells the native side to inject the bridge object into the page.

So the ordering problem, where the page's script runs before the bridge has been injected, is handled by the queue rather than by requiring the developer to order things correctly. The page can call setup at any point and the bridge turns up when it is ready.

After setup, the API on the JavaScript side mirrors the native one:

```js
setupWKWebViewJavascriptBridge(function(bridge) {

	/* Initialize your app here */

	bridge.registerHandler('testJavascriptHandler', function(data, responseCallback) {
		console.log('iOS called testJavascriptHandler with', data)
		responseCallback({ 'Javascript Says':'Right back atcha!' })
	})

	bridge.callHandler('testiOSCallback', {'foo': 'bar'}, function(response) {
		console.log('JS got response', response)
	})
})
```

The names are registerHandler and callHandler on the JavaScript side against register and call on the Swift side, and both directions carry data and a response callback.

## Why WKWebView and not UIWebView

The project explicitly answers the question of why it supports only WKWebView, and there are two reasons, one of them a security one.

The first is performance. It is well known that WKWebView loads web pages faster and more efficiently than UIWebView, and does not have as much memory overhead. Under the current timeline, most iOS apps only support iOS 9.0 and later, so the choice costs nothing in practice.

The second reason is the interesting one, and it is a vulnerability. The reason for the iOS platform cross-domain access vulnerability is that UIWebView turns on the WebKitAllowUniversalAccessFromFileURLs and WebKitAllowFileAccessFromFileURLs options. WKWebView's allowFileAccessFromFileURLs and allowUniversalAccessFromFileURLs options default to false.

That difference is the one to sit with. In UIWebView, a web page loaded from a file URL could reach across to other file URLs and beyond. In WKWebView those doors are closed unless the application explicitly opens them. A bridge library that has to exist anyway should at least be sitting on the more restricted of the two web views.

It also means the library carries no responsibility for that class of problem, because the decisions about file access are made by the application that instantiates the web view, not by the bridge.

## Four ways to install it

The installation options cover the four usual Swift distribution channels, and the documentation is explicit about the steps for each.

Swift Package Manager is first, and the route goes through Xcode's interface. In Xcode you select File, then Add Package Dependencies, enter the repository URL https://github.com/Lision/WKWebViewJavascriptBridge.git, add the WKWebViewJavascriptBridge package to your app target, and add the import statement.

CocoaPods goes through the Podfile, adding `pod 'WKWebViewJavascriptBridge', '~> 1.2.0'`, then running pod install or pod update, then adding the import.

Carthage adds `github "Lision/WKWebViewJavascriptBridge" ~> 1.2.0` to the Cartfile, then running carthage update --platform ios, then adding the WKWebViewJavascriptBridge framework to the project.

The fourth option is manual, which means cloning the repository and adding the files in the WKWebViewJavascriptBridge directory to your project by hand.

The pinned versions in the CocoaPods and Carthage examples, 1.2.0, are the ones the documentation was written against. There are no GitHub releases, so the version numbers in the package managers and the state of the master branch are two different things.

The requirements are stated as iOS 9.0 or later and Xcode 9.0 or later, and the Swift support range is given as Swift 3.2 through 5. That range is a genuine constraint and not a formality, because Swift's language and API have moved considerably since 5, and a project still supporting 3.2 is a project that has not been recompiled against recent toolchains recently.

## What the repository actually contains

The repository layout is small and shows the shape of a Swift package that has been around a while.

There is a Package.swift at the root for Swift Package Manager, a WKWebViewJavascriptBridge.podspec for CocoaPods, a.swift-version file, and a.travis.yml for the original continuous integration setup. The WKWebViewJavascriptBridge/ directory holds the framework sources, and it is also the directory the manual installation route points at.

There is an xcodeproj/ directory, a WKWebViewJavascriptBridgeDemo/ directory for the demo application, and a WKWebViewJavascriptBridgeTests/ directory for the test target. The README also links a Chinese version of the documentation, README_ZH-CN.md, and the README credits the design as inspired by the WebViewJavascriptBridge project by Marcus Westin.

The badges show the distribution channels the project has been published through: Carthage compatible, MIT licence, CocoaPods with a version badge, Swift language badge, and a support badge for iOS 9 and later.

One detail in the top level listing is worth noticing. There is a.gitignore but no CHANGELOG, and there are no GitHub releases, so the history of this library is not documented in the repository in a way a new user can read. The version 1.2.0 referenced in the installation instructions is the only version number a reader is given, and it comes from the package managers rather than from a tag.

The contact details point to a single maintainer, with an email address and social media accounts for Lision, which is the pattern of a project maintained by one person alongside a day job.

## Conclusion

WKWebViewJavascriptBridge is a good pick for an iOS hybrid app that needs a handful of named calls across the web and native boundary and nothing more, because the handler registration model is small enough to read in one sitting and it leaves your web view class alone; it is the wrong pick if you need bidirectional streaming, a large API surface, or a bridge that works on Android too, and before you adopt it you should confirm your Xcode and Swift toolchain still fit the stated range, because the project supports Swift 3.2 through 5 and iOS 9, which is a long way behind current releases.

## FAQ

### How do I use WKWebViewJavascriptBridge?

Create the bridge with WKWebViewJavascriptBridge(webView: webView), register a native handler with bridge.register(handlerName:callback:), and call into JavaScript with bridge.call(handlerName:data:callback:). On the web side, paste in the setupWKWebViewJavascriptBridge function, which queues the callback until the native side has injected the bridge object.

### How do I install WKWebViewJavascriptBridge?

Through Swift Package Manager by adding the repository URL in Xcode, through CocoaPods with pod 'WKWebViewJavascriptBridge', '~> 1.2.0' in the Podfile, through Carthage with a Cartfile entry, or manually by cloning the repository and adding the files in the WKWebViewJavascriptBridge directory to your project.

### Why does WKWebViewJavascriptBridge only support WKWebView?

For performance, since WKWebView loads pages faster and uses less memory than UIWebView, and for security, since UIWebView turns on the WebKitAllowUniversalAccessFromFileURLs and WebKitAllowFileAccessFromFileURLs options while WKWebView defaults those to false.

### What are the requirements for WKWebViewJavascriptBridge?

iOS 9.0 or later and Xcode 9.0 or later, with Swift 3.2 through 5 supported. The framework contains only three files and does not require the web view class to inherit from a base class.

### What licence is WKWebViewJavascriptBridge released under?

MIT, with the licence text in the LICENSE file at the repository root. The project is inspired by the WebViewJavascriptBridge project by Marcus Westin, and the repository is not archived with the last push on 2026-06-21.

## Sources

- [Issues](https://github.com/Lision/WKWebViewJavascriptBridge/issues)
- [License: MIT](https://github.com/Lision/WKWebViewJavascriptBridge/blob/master/LICENSE)
- [Lision/WKWebViewJavascriptBridge on GitHub](https://github.com/Lision/WKWebViewJavascriptBridge)
- [README](https://github.com/Lision/WKWebViewJavascriptBridge/blob/master/README.md)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/lision-wkwebviewjavascriptbridge
