native-bridge-js
v1.0.3
Published
A lightweight JavaScript bridge for web ↔ native app communication in WebView
Downloads
16
Maintainers
Readme
native-bridge-js
🌉 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-jsIn 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)
- 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())
}
}
}- 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)!))")
}
}- 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)
}- Push Events to Web
func sendBatteryUpdate(level: Int) {
let event = ["method": "batteryLevel", "data": ["level": level]]
executeJs("window.NativeBridge(\(toJson(event)!))")
}- Then in JS:
nativeBridge.on('batteryLevel', (data) => {
console.log(`🔋 ${data.level}%`);
});Android (Kotlin) – WebView
- 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")
}
}- 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()
}
}
}- 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"))
}- 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)
}- Then in JS:
nativeBridge.on('locationUpdate', (loc) => {
console.log('📍', loc.lat, loc.lng);
});