Skip to content

fix(ios): auto-grant WKWebView media capture permission - #635

Open
jadamspiers wants to merge 1 commit into
Cap-go:mainfrom
jadamspiers:fix/auto-grant-media-capture-permission
Open

fix(ios): auto-grant WKWebView media capture permission#635
jadamspiers wants to merge 1 commit into
Cap-go:mainfrom
jadamspiers:fix/auto-grant-media-capture-permission

Conversation

@jadamspiers

@jadamspiers jadamspiers commented Jul 17, 2026

Copy link
Copy Markdown

What

Implements webView(_:requestMediaCapturePermissionFor:initiatedByFrame:type:decisionHandler:)
(iOS 15+) on the WKUIDelegate in WKWebViewController, auto-granting media capture the same
way the plugin already auto-grants geolocation.

Why

When a page opened with openWebView calls getUserMedia (microphone/camera):

  1. iOS shows the system permission prompt (from the host app's Info.plist usage description) — correct, once ever.
  2. WebKit then shows its own per-origin prompt ("example.com would like to access the microphone") on top of it.

That second prompt is not persisted across app launches for WKWebView
(WebKit bug 220416), so users are re-prompted
every cold start of the host app. For apps embedding a voice/WebRTC experience this breaks the UX.

decisionHandler(.grant) defers entirely to the OS-level permission: if the app doesn't have
microphone/camera permission, capture still fails and the system prompt still governs access.
This is exactly what Capacitor core does in its own WebViewDelegationHandler
(capacitor/ios WebViewDelegationHandler.swift),
so pages running inside the InAppBrowser WebView now behave like pages in the main Capacitor WebView.

Platform parity

  • Android already grants WebView permission requests via onPermissionRequest in WebViewDialog.java — iOS was the gap.
  • Geolocation on iOS is already auto-granted by this class (requestGeolocationPermissionFor); this mirrors that handler, including the log line style.

Testing

Running in production inside a Capacitor 8 conference app (via patch-package) that embeds a
WebRTC push-to-talk web app: with the patch, the mic prompt appears exactly once (system prompt);
without it, WebKit re-prompts on every app relaunch.

Review in cubic

Summary by CodeRabbit

  • Bug Fixes
    • Improved camera and microphone access handling in the in-app browser.
    • Prevented additional per-site permission prompts when media capture is requested.

Matches Capacitor core's WebViewDelegationHandler behavior and the
plugin's existing geolocation handling. Without this delegate method,
WebKit shows its own per-origin camera/microphone prompt on top of the
iOS system permission prompt, and because the grant is not persisted
across app launches (WebKit bug 220416) users are re-prompted on every
cold start of the host app.

The OS-level permission (Info.plist usage descriptions + system prompt)
still fully applies.
@github-actions

Copy link
Copy Markdown
Contributor

Beta npm build

This PR comes from a fork, so beta publish is disabled for security.

If you need a beta package, move the branch into this repository first.

@coderabbitai

coderabbitai Bot commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

WKWebViewController now handles iOS 15+ WebKit media capture permission requests by logging the origin host and granting the requested camera or microphone access.

Changes

iOS media capture permissions

Layer / File(s) Summary
Media capture permission callback
ios/Sources/InAppBrowserPlugin/WKWebViewController.swift
Adds the iOS 15+ WKUIDelegate callback, logs the requesting origin, and calls decisionHandler(.grant) for media capture requests.

Estimated code review effort: 1 (Trivial) | ~2 minutes

Suggested reviewers: riderx

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: auto-granting WKWebView media capture permission on iOS.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@sonarqubecloud

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@ios/Sources/InAppBrowserPlugin/WKWebViewController.swift`:
- Line 3354: Update the
webView(_:requestMediaCapturePermissionFor:initiatedByFrame:type:decisionHandler:)
delegate signature to replace the unused webView, frame, and type bindings with
underscores while preserving the required external labels and types.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: d1fdc887-9ed9-4d1c-b22b-1569ae8b8ae9

📥 Commits

Reviewing files that changed from the base of the PR and between 73d2459 and 96df496.

📒 Files selected for processing (1)
  • ios/Sources/InAppBrowserPlugin/WKWebViewController.swift
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • Cap-go/capacitor-updater (manual)

}

@available(iOS 15.0, *)
public func webView(_ webView: WKWebView, requestMediaCapturePermissionFor origin: WKSecurityOrigin, initiatedByFrame frame: WKFrameInfo, type: WKMediaCaptureType, decisionHandler: @escaping (WKPermissionDecision) -> Void) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Mark unused delegate parameters explicitly.

webView, frame, and type are unused and trigger the three reported SonarCloud warnings. Preserve the required delegate labels while replacing their local bindings with _ (for example, webView(_: WKWebView, ... initiatedByFrame _: WKFrameInfo, type _: WKMediaCaptureType)).

🧰 Tools
🪛 GitHub Check: SonarCloud Code Analysis

[warning] 3354-3354: Remove the unused function parameter "frame" or name it "_".

See more on https://sonarcloud.io/project/issues?id=Cap-go_capacitor-inappbrowser&issues=AZ9t7J2T4_OYKs1TdaYm&open=AZ9t7J2T4_OYKs1TdaYm&pullRequest=635


[warning] 3354-3354: Remove the unused function parameter "type" or name it "_".

See more on https://sonarcloud.io/project/issues?id=Cap-go_capacitor-inappbrowser&issues=AZ9t7J2T4_OYKs1TdaYn&open=AZ9t7J2T4_OYKs1TdaYn&pullRequest=635


[warning] 3354-3354: Remove the unused function parameter "webView" or name it "_".

See more on https://sonarcloud.io/project/issues?id=Cap-go_capacitor-inappbrowser&issues=AZ9t7J2T4_OYKs1TdaYl&open=AZ9t7J2T4_OYKs1TdaYl&pullRequest=635

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ios/Sources/InAppBrowserPlugin/WKWebViewController.swift` at line 3354,
Update the
webView(_:requestMediaCapturePermissionFor:initiatedByFrame:type:decisionHandler:)
delegate signature to replace the unused webView, frame, and type bindings with
underscores while preserving the required external labels and types.

Source: Linters/SAST tools

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 1 file

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="ios/Sources/InAppBrowserPlugin/WKWebViewController.swift">

<violation number="1" location="ios/Sources/InAppBrowserPlugin/WKWebViewController.swift:3363">
P1: Any HTTP(S) origin reached through navigation or redirect can receive camera/microphone access without WebKit's origin prompt once the host app has OS permission. Unlike Capacitor's trusted app WebView, this browser accepts arbitrary remote pages, so auto-granting should be restricted to an explicit trusted-origin policy and otherwise return `.prompt` or `.deny`.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Fix all with cubic | Re-trigger cubic

// suppresses WebKit's extra per-origin prompt, which is not persisted
// across app launches (WebKit bug 220416) and would otherwise re-prompt
// users on every cold start.
decisionHandler(.grant)

@cubic-dev-ai cubic-dev-ai Bot Jul 17, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: Any HTTP(S) origin reached through navigation or redirect can receive camera/microphone access without WebKit's origin prompt once the host app has OS permission. Unlike Capacitor's trusted app WebView, this browser accepts arbitrary remote pages, so auto-granting should be restricted to an explicit trusted-origin policy and otherwise return .prompt or .deny.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At ios/Sources/InAppBrowserPlugin/WKWebViewController.swift, line 3363:

<comment>Any HTTP(S) origin reached through navigation or redirect can receive camera/microphone access without WebKit's origin prompt once the host app has OS permission. Unlike Capacitor's trusted app WebView, this browser accepts arbitrary remote pages, so auto-granting should be restricted to an explicit trusted-origin policy and otherwise return `.prompt` or `.deny`.</comment>

<file context>
@@ -3349,6 +3349,19 @@ extension WKWebViewController: WKUIDelegate {
+        // suppresses WebKit's extra per-origin prompt, which is not persisted
+        // across app launches (WebKit bug 220416) and would otherwise re-prompt
+        // users on every cold start.
+        decisionHandler(.grant)
+    }
 }
</file context>
Fix with cubic

@riderx

riderx commented Jul 26, 2026

Copy link
Copy Markdown
Member

hey @jadamspiers can you check comments and resolve them?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants