Skip to content

[iOS] Add WKUIDelegate support to PlatformWebViewParams for JavaScript alert/confirm/prompt handling #400

@gitpushyj

Description

@gitpushyj

Problem

Currently, iOS PlatformWebViewParams is an empty class with no properties, making it impossible for developers to provide a custom WKUIDelegate implementation. This means JavaScript alert(), confirm(), and prompt() calls are silently ignored on iOS.

Android allows customization through PlatformWebViewParams:

// webview/src/androidMain/.../WebView.android.kt
actual data class PlatformWebViewParams(
    val chromeClient: AccompanistWebChromeClient? = null,
)

iOS has no such capability:
// webview/src/iosMain/.../WebView.ios.kt

actual class PlatformWebViewParams  // Empty class - no properties!

Additionally, IOSWebView composable doesn't use platformWebViewParams at all, and WKUIDelegate is never set on the WKWebView.

Why This Happens
The key difference between platforms:

  • Android - WebChromeClient.onJsAlert() not overridden → System dialog shown automatically
  • iOS - WKUIDelegate not set → Silently ignored (no response)

Android's WebChromeClient has built-in default implementations that show system dialogs. iOS's WKWebView has no default behavior - if WKUIDelegate is not set, JavaScript dialogs simply don't work.

Impact

On iOS, when a webpage calls:

alert("message") → Silently ignored
confirm("question") → Returns false immediately
prompt("input") → Returns null immediately
window.open() → Blocked
This creates a significant platform inconsistency between Android and iOS, breaking hybrid apps that rely on JavaScript dialogs.

Proposed Solution

Add uiDelegate property to iOS PlatformWebViewParams:

actual data class PlatformWebViewParams(
    val uiDelegate: WKUIDelegateProtocol? = null,
)

Apply the delegate in IOSWebView:

platformWebViewParams?.uiDelegate?.let {
    this.setUIDelegate(it)
}

Provide a default AccompanistUIDelegate implementation (similar to AccompanistWebChromeClient) that shows native iOS alerts:

class AccompanistUIDelegate : NSObject(), WKUIDelegateProtocol {
    override fun webView(
        webView: WKWebView,
        runJavaScriptAlertPanelWithMessage: String,
        initiatedByFrame: WKFrameInfo,
        completionHandler: () -> Unit,
    ) {
        // Show native iOS alert
    }
    
    override fun webView(
        webView: WKWebView,
        runJavaScriptConfirmPanelWithMessage: String,
        initiatedByFrame: WKFrameInfo,
        completionHandler: (Boolean) -> Unit,
    ) {
        // Show native iOS confirm dialog
    }
    
    override fun webView(
        webView: WKWebView,
        runJavaScriptTextInputPanelWithPrompt: String,
        defaultText: String?,
        initiatedByFrame: WKFrameInfo,
        completionHandler: (String?) -> Unit,
    ) {
        // Show native iOS prompt dialog
    }
}

Environment

Library version: latest (main branch)
Kotlin: 2.1.20
Compose Multiplatform: 1.8.0

Usage Example

// iosMain

@Composable
actual fun getPlatformWebViewParams(): PlatformWebViewParams? {
    val uiDelegate = remember { AccompanistUIDelegate() }
    return PlatformWebViewParams(uiDelegate = uiDelegate)
}

Question

Is there an alternative approach to handle JavaScript alert(), confirm(), and prompt() on iOS within this library that I might have missed? If not, would a PR implementing the proposed solution above be welcome?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions