{
  "collectedAt": "2026-10-20T07:15:21.950Z",
  "href": "https://openpwa.net/demo/push/",
  "title": "Push permission — OpenPWA Demo",
  "userAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 18_6_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.6 Mobile/15E148 Safari/604.1",
  "platform": "iPhone",
  "vendor": "Apple Computer, Inc.",
  "language": "zh-CN",
  "languages": [
    "zh-CN"
  ],
  "maxTouchPoints": 5,
  "hardwareConcurrency": 4,
  "deviceMemory": "undefined",
  "navigator.standalone": false,
  "displayModes": {
    "browser": true,
    "minimal-ui": false,
    "standalone": false,
    "fullscreen": false,
    "window-controls-overlay": false,
    "picture-in-picture": false,
    "application": false
  },
  "features": {
    "'serviceWorker' in navigator": true,
    "serviceWorker.controller": true,
    "serviceWorkerRegistrations": [
      {
        "scope": "https://openpwa.net/demo/",
        "active": true,
        "state": "activated"
      },
      {
        "scope": "https://openpwa.net/lab/device-tests/",
        "active": true,
        "state": "activated"
      }
    ],
    "'PushManager' in window": false,
    "'pushManager' in window": true,
    "typeof window.pushManager?.subscribe": "function",
    "typeof window.pushManager?.permissionState": "function",
    "typeof window.pushManager?.getSubscription": "function",
    "PushManager.supportedContentEncodings": "n/a",
    "'Notification' in window": false,
    "Notification.permission": "n/a",
    "typeof Notification.requestPermission": "undefined",
    "'setAppBadge' in navigator": false,
    "'clearAppBadge' in navigator": false,
    "'install' in navigator": false,
    "typeof navigator.install": "undefined",
    "'BeforeInstallPromptEvent' in window": false,
    "'onbeforeinstallprompt' in window": false,
    "'onappinstalled' in window": false,
    "'getInstalledRelatedApps' in navigator": false,
    "'share' in navigator": true,
    "'canShare' in navigator": true,
    "canShare({url})": true,
    "canShare({files:[txt]})": true,
    "'launchQueue' in window": false,
    "'showOpenFilePicker' in window": false,
    "'showSaveFilePicker' in window": false,
    "'showDirectoryPicker' in window": false,
    "typeof navigator.storage?.getDirectory (OPFS)": "function",
    "'storage' in navigator": true,
    "storage.estimate()": {
      "quota": 41231686042,
      "usage": 86592
    },
    "storage.persisted()": false,
    "typeof navigator.storage?.persist": "function",
    "'cookieStore' in window": true,
    "'CookieStore' in window": true,
    "'BroadcastChannel' in window": true,
    "'wakeLock' in navigator": true,
    "'contacts' in navigator": false,
    "'getBattery' in navigator": false,
    "'vibrate' in navigator": false,
    "'bluetooth' in navigator": false,
    "'usb' in navigator": false,
    "'serial' in navigator": false,
    "'hid' in navigator": false,
    "'NDEFReader' in window": false,
    "'PaymentRequest' in window": true,
    "'PublicKeyCredential' in window": true,
    "'IdentityCredential' in window": false,
    "'DigitalCredential' in window": false,
    "'credentials' in navigator": true,
    "'clipboard' in navigator": true,
    "'mediaSession' in navigator": true,
    "'periodicSync' in ServiceWorkerRegistration.prototype": false,
    "'sync' in ServiceWorkerRegistration.prototype": false,
    "'navigationPreload' in ServiceWorkerRegistration.prototype": true,
    "'windowControlsOverlay' in navigator": false,
    "'documentPictureInPicture' in window": false,
    "'ViewTransition' in window": true,
    "'startViewTransition' in document": true,
    "'navigation' in window": false,
    "'scheduler' in window": false,
    "'userActivation' in navigator": true,
    "'virtualKeyboard' in navigator": false,
    "'screen.orientation.lock'": "undefined",
    "'requestFullscreen' in documentElement": false,
    "'webkitRequestFullscreen' in documentElement": false,
    "'xr' in navigator": false
  },
  "css": {
    "env(safe-area-inset-top)": true,
    "env(titlebar-area-height)": true,
    "env(viewport-segment-width 0 0)": false,
    "height: 100dvh": true,
    "@supports selector(:has(a))": true,
    "color: oklch()": true,
    "safeAreaInsetsComputed": {
      "top": "0px",
      "right": "0px",
      "bottom": "0px",
      "left": "0px"
    }
  },
  "viewportSegments": {
    "window.viewport": "undefined",
    "window.viewport?.segments": "n/a",
    "(horizontal-viewport-segments: 1)": false,
    "(horizontal-viewport-segments: 2)": false,
    "(vertical-viewport-segments: 1)": false,
    "(vertical-viewport-segments: 2)": false,
    "getWindowSegments": "undefined"
  },
  "screen": {
    "width": 402,
    "height": 874,
    "availWidth": 402,
    "availHeight": 874,
    "colorDepth": 24,
    "orientation": "portrait-primary",
    "angle": 0
  },
  "devicePixelRatio": 3,
  "innerWidth": 402,
  "innerHeight": 678,
  "outerWidth": 402,
  "outerHeight": 874,
  "documentElementClient": {
    "w": 402,
    "h": 678
  },
  "visualViewport": {
    "width": 402,
    "height": 678,
    "scale": 1,
    "offsetTop": 0,
    "offsetLeft": 0,
    "pageTop": 484
  },
  "mediaQueries": {
    "(prefers-color-scheme: dark)": false,
    "(prefers-reduced-motion: reduce)": false,
    "(prefers-contrast: more)": false,
    "(dynamic-range: high)": true,
    "(color-gamut: p3)": true,
    "(hover: hover)": false,
    "(pointer: coarse)": true,
    "(orientation: portrait)": true
  },
  "declarations": {
    "manifest": "/demo/manifest.webmanifest",
    "appleTouchIcon": [
      "/demo/icons/icon-192.png"
    ],
    "icons": [
      "/demo/icons/icon.svg"
    ],
    "themeColor": "#161616",
    "appleCapable": "yes",
    "appleStatusBarStyle": null,
    "appleTitle": "OpenPWA",
    "viewportMeta": "width=device-width, initial-scale=1"
  },
  "pageText": "OpenPWA Demo\n全部能力\nEnglish\n推送权限\n\n请求通知权限，然后用为本演示生成的 VAPID 公钥把当前浏览器订阅到推送。得到的 PushSubscription JSON 会打印在下方，但不会发往任何地方：没有服务器，因此永远不会收到消息。完成后请取消订阅。\n\n不会向 OpenPWA 发送任何数据。 订阅时，浏览器会向它自己的推送服务申请订阅，端点由推送服务签发；之后端点与密钥只留在本页。生成公钥后 VAPID 密钥对的私钥已被丢弃，因此没有人能使用这个订阅。\n前提条件\n需要满足的条件，以及当前浏览器的检测结果\n满足\n安全上下文（HTTPS 或 localhost）\n满足\n已为 /demo/ 注册 service worker\nscope: https://openpwa.net/demo/\n不满足\n可用 Notification API\n缺少 window.Notification，无法请求权限。\n不满足\n可用 PushManager\n没有 window.PushManager，此处无法创建推送订阅。\n不满足\n通知权限\nNotification.permission: unavailable\n不满足\niOS：已添加到主屏幕（iOS 16.4 起推送必需）\nSafari 标签页中不暴露 Push API；请先添加到主屏幕。\n满足\n用户手势\n由运行按钮提供；在点击或按键处理之外调用会失败。\n实际运行的代码\n通过各函数自身的 toString() 渲染；按钮调用的正是这段代码。\n\n请求权限并订阅\n\nasync function requestPermissionAndSubscribe() {\n  if (!('Notification' in window) || !('PushManager' in window)) {\n    throw new Error('Notifications or Push are not available here');\n  }\n  const permission = await Notification.requestPermission();\n  if (permission !== 'granted') return { permission, subscription: null };\n  const registration = await navigator.serviceWorker.ready;\n  const existing = await registration.pushManager.getSubscription();\n  const subscription = existing || (await registration.pushManager.subscribe({\n    userVisibleOnly: true,\n    applicationServerKey: base64UrlToUint8Array(DEMO_VAPID_PUBLIC_KEY),\n  }));\n  return { permission, reused: Boolean(existing), subscription: subscription.toJSON() };\n}\n取消订阅\n\nasync function unsubscribe() {\n  const registration = await navigator.serviceWorker.ready;\n  const subscription = await registration.pushManager.getSubscription();\n  if (!subscription) return { removed: false };\n  const removed = await subscription.unsubscribe();\n  return { removed };\n}\n运行\n请求权限并订阅\n取消订阅\n尚无结果。请点击运行按钮。\n参考条目\nWeb Push：端到端流程\n通知权限\niOS Safari 上的推送\nopenpwa.net 的一部分。纯静态文件，无构建步骤，无依赖。",
  "localStorageDump": {
    "openpwa-lab-marker": "TAB-2026-10-20T07:13:46Z",
    "starlight-theme": "",
    "openpwa-demo-lang": "zh"
  },
  "documentCookieNames": [],
  "labJsonTextarea": null,
  "labNotifyOut": null,
  "labEventsOut": null,
  "labProbeOut": null,
  "variantProbe": null
}
