Untitled
Anonymous
plain_text
01/27/2026 6:16 PM
4.6 KB
10
Indexable
1. Universal permission logger (works everywhere)
This checks actual capability, not just API support.
export async function logPermissions() {
const results: Record<string, any> = {};
// ---------- MICROPHONE ----------
try {
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
results.microphone = "granted";
stream.getTracks().forEach(t => t.stop());
} catch (e: any) {
results.microphone = {
state: "blocked_or_denied",
name: e.name,
message: e.message,
};
}
// ---------- CAMERA ----------
try {
const stream = await navigator.mediaDevices.getUserMedia({ video: true });
results.camera = "granted";
stream.getTracks().forEach(t => t.stop());
} catch (e: any) {
results.camera = {
state: "blocked_or_denied",
name: e.name,
message: e.message,
};
}
// ---------- SPEAKERS / AUDIO PLAYBACK ----------
try {
const audio = new Audio();
await audio.play();
results.audioPlayback = "granted";
} catch {
results.audioPlayback = "blocked_until_user_gesture";
}
// ---------- DEVICE ENUMERATION ----------
try {
const devices = await navigator.mediaDevices.enumerateDevices();
results.devices = devices.map(d => ({
kind: d.kind,
labelAvailable: Boolean(d.label), // labels only appear after permission
}));
} catch (e: any) {
results.devices = {
state: "blocked",
name: e.name,
};
}
console.group("🔐 Permission diagnostics");
console.table(results);
console.groupEnd();
return results;
}
2. Permissions API (works on Chrome / Edge / Android, LIMITED on iOS)
Safari (especially iOS) does not fully implement navigator.permissions, but you can safely attempt it:
export async function logPermissionsAPI() {
if (!("permissions" in navigator)) {
console.warn("Permissions API not supported");
return;
}
const permissions: PermissionName[] = [
"microphone",
"camera",
"geolocation",
"notifications",
];
console.group("🧭 Permissions API states");
for (const name of permissions) {
try {
const status = await navigator.permissions.query({ name });
console.log(name, status.state); // granted | denied | prompt
} catch {
console.log(name, "unsupported");
}
}
console.groupEnd();
Detect iOS Safari–specific mic blocks (very important for UneeQ)
iOS Safari has hidden failure modes:
export function isIOSSafari() {
return (
/iP(hone|ad|od)/.test(navigator.userAgent) &&
/Safari/.test(navigator.userAgent) &&
!/Chrome|CriOS|FxiOS/.test(navigator.userAgent)
);
}
Then log contextual info:
console.log({
isIOSSafari: isIOSSafari(),
secureContext: window.isSecureContext,
hasMediaDevices: !!navigator.mediaDevices,
hasGetUserMedia: !!navigator.mediaDevices?.getUserMedia,
});
❌ If secureContext === false → mic will never work
❌ If mic requested outside a tap handler → silent failure on iOS
3. Best debug button (recommended)
Add this temporarily to your app:
<button
onClick={async () => {
await logPermissions();
await logPermissionsAPI();
}}
>
Debug Permissions
</button>
Tap it once on iPhone Safari → check console via Mac Safari Web Inspector.
4. Permissions-Policy:
microphone=(self), camera=(self), autoplay=(self)
Referrer-Policy: strict-origin-when-cross-origin
Editor is loading...
Leave a Comment