npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

native-bridge-js

v1.0.3

Published

A lightweight JavaScript bridge for web ↔ native app communication in WebView

Downloads

16

Readme

native-bridge-js

npm version License npm downloads minified size

🌉 A lightweight JavaScript bridge for bi-directional communication between web apps and native apps (iOS/Android) via WebView.

Supports:

  • call() – Call native methods (Promise-based)
  • on() – Listen to native events (e.g., GPS, push)
  • Cross-platform: iOS & Android
  • Zero dependencies
  • Works with React, Vue, vanilla JS

📦 Installation

npm install native-bridge-js

In Your Web App (JavaScript)

import nativeBridge from 'native-bridge-js';

// 1. Call native method
nativeBridge.call('requestLocation')
  .then(location => console.log('📍', location))
  .catch(err => console.error('❌', err));

// 2. Listen to real-time events
nativeBridge.on('batteryUpdate', (data) => {
  console.log(`🔋 ${data.level}% charged`);
});

// 3. Send data to native
nativeBridge.send('logEvent', { name: 'profile_view' });

// 4. Register a custom command (Command Pattern)
nativeBridge.registerCommand('sayHello', (name) => `Hello, ${name}!`);

// 5. Execute a registered command
const greeting = nativeBridge.executeCommand('sayHello', 'World');
console.log(greeting); // "Hello, World!"

// 6. Unregister a command
nativeBridge.unregisterCommand('sayHello');

Command Pattern API

The command pattern allows you to register, execute, and unregister custom commands on the bridge instance:

  • registerCommand(commandName, handler) – Register a command handler function.
  • executeCommand(commandName, ...args) – Execute a registered command with arguments.
  • unregisterCommand(commandName) – Remove a command handler.

This is useful for modular, decoupled logic and advanced integrations.

Native App: Sample Integration Code

iOS Webview (Swift)

  1. Setup WebView
import WebKit
class WebViewController: UIViewController, WKScriptMessageHandler {
    var webView: WKWebView!

    override func viewDidLoad() {
        super.viewDidLoad()

        // Configure WebView
        let config = WKWebViewConfiguration()
        config.userContentController.add(self, name: "NativeBridge")
        
        webView = WKWebView(frame: view.bounds, configuration: config)
        view.addSubview(webView)

        // Load your web app
        if let url = Bundle.main.url(forResource: "index", withExtension: "html") {
            webView.loadFileURL(url, allowingReadAccessTo: url.deletingLastPathComponent())
        }
    }
}
  1. Handle Messages from JS
func userContentController(_ controller: WKUserContentController, didReceive message: WKScriptMessage) {
    guard let body = message.body as? [String: Any],
          let method = body["method"] as? String,
          let callbackId = body["callbackId"] as? Int else { return }

    switch method {
    case "requestLocation":
        let response = ["callbackId": callbackId, "data": ["lat": 37.7749, "lng": -122.4194]]
        executeJs("window.NativeBridge(\(toJson(response)!))")

    case "share":
        if let text = (body["data"] as? [String: Any])?["text"] as? String {
            showShareSheet(text)
        }

    default:
        let error = ["callbackId": callbackId, "error": "Unknown method"]
        executeJs("window.NativeBridge(\(toJson(error)!))")
    }
}
  1. Helper Functions
private func executeJs(_ js: String) {
    webView.evaluateJavaScript(js) { _, error in
        if let error = error {
            print("JS Error: $error)")
        }
    }
}

private func toJson(_ dict: [String: Any]) -> String? {
    guard let data = try? JSONSerialization.data(withJSONObject: dict),
          let str = String( data, encoding: .utf8) else { return nil }
    return str
}

private func showShareSheet(_ text: String) {
    let activity = UIActivityViewController(activityItems: [text], applicationActivities: nil)
    present(activity, animated: true)
}
  1. Push Events to Web
func sendBatteryUpdate(level: Int) {
    let event = ["method": "batteryLevel", "data": ["level": level]]
    executeJs("window.NativeBridge(\(toJson(event)!))")
}
  1. Then in JS:
nativeBridge.on('batteryLevel', (data) => {
  console.log(`🔋 ${data.level}%`);
});

Android (Kotlin) – WebView

  1. Setup WebView
class WebActivity : AppCompatActivity() {
    private lateinit var webView: WebView

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        webView = WebView(this)
        setContentView(webView)
        webView.settings.javaScriptEnabled = true
        webView.addJavascriptInterface(NativeBridgeInterface(), "AndroidBridge")
        webView.loadUrl("file:///android_asset/index.html")
    }
}
  1. Handle JS Messages
@Suppress("unused")
inner class NativeBridgeInterface {

    @JavascriptInterface
    fun postMessage(jsonString: String) {
        try {
            val json = JSONObject(jsonString)
            val method = json.getString("method")
            val callbackId = json.getInt("callbackId")

            when (method) {
                "requestLocation" -> {
                    val data = JSONObject().apply {
                        put("lat", 37.7749)
                        put("lng", -122.4194)
                    }
                    val response = JSONObject().apply {
                        put("callbackId", callbackId)
                        put("data", data)
                    }
                    runJs("window.NativeBridge($response)")
                }

                "share" -> {
                    val text = json.getJSONObject("data").getString("text")
                    shareText(text)
                }

                else -> {
                    val error = JSONObject().apply {
                        put("callbackId", callbackId)
                        put("error", "Unknown method: $method")
                    }
                    runJs("window.NativeBridge($error)")
                }
            }
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }
}
  1. Helper Functions
private fun runJs(js: String) {
    webView.evaluateJavascript(js, null)
}

private fun shareText(text: String) {
    val intent = Intent(Intent.ACTION_SEND).apply {
        type = "text/plain"
        putExtra(Intent.EXTRA_TEXT, text)
    }
    startActivity(Intent.createChooser(intent, "Share"))
}
  1. Push Events to Web
private fun sendLocationUpdate(lat: Double, lng: Double) {
    val js = """
        window.NativeBridge({
            "method": "locationUpdate",
            "data": { "lat": $lat, "lng": $lng }
        })
    """.trimIndent()
    webView.evaluateJavascript(js, null)
}
  1. Then in JS:
nativeBridge.on('locationUpdate', (loc) => {
  console.log('📍', loc.lat, loc.lng);
});