在Safari的Mac版本中,Notification.requestPermission会抛出一个错误。

10

我正在尝试使用jQuery在页面加载时本地显示通知。 通知在Firefox,Firefox Developer和Chrome中正确显示。 尽管在通知首选项设置中允许,但Safari中未显示通知。

相似的代码在MDN网站https://developer.mozilla.org/en/docs/Web/API/notification上运行良好。

代码片段如下。

// Display a sample notification
  if (window.Notification) {
    return $(".au-notifications-page").show(function() {
      var notification;
      notification = new Notification(
        'Success Text', {
        //tag: $("[name=tag]").val(),
        body: 'Success Message',
        iconUrl: 'img/avatar-male.png',
        icon: 'img/avatar-male.png'
      });
      return notification.onclick = function() {
        notification.close();
        window.open().close();
        return window.focus();
      };
    });
  };

完整代码如下。

$(document).ready(function () {

  // Request permission on site load
  Notification.requestPermission().then(function(result) {
    if (result === 'denied') {
      //alert('denied');
      $(".au-notif-disabled-header").removeClass('hide');
      $(".au-notif-disabled-header .btn").addClass('hide');
      return;
    }
    if (result === 'default') {
      //alert('ignored');
      $(".au-notif-disabled-header").removeClass('hide');
      return;
    }
    //alert('granted');
    $(".au-notif-disabled-header").addClass('hide');
  });

  // Request permission with button
  $('.au-notif-disabled-header .btn').click(function () {
    Notification.requestPermission().then(function(result) {
      if (result === 'denied') {
        $(".au-notif-disabled-header").removeClass('hide');
        $(".au-notif-disabled-header .btn").addClass('hide');
        return;
      }
      if (result === 'default') {
        $(".au-notif-disabled-header").removeClass('hide');
        return;
      }
      $(".au-notif-disabled-header").addClass('hide');
    });
  });

  $( ".au-notification-icon" ).hover(
    function() {
      $(".au-notifications-menu .au-notif-msg-realtime").slideDown();
      $('.au-notification-icon .badge').html("2");
    }, function() {
      $(".au-notifications-menu .au-notif-msg-realtime").slideUp();
      $('.au-notification-icon .badge').html("1");
    }
  );

  //To show notification received while on notifications page
  $(".au-notif-msg-realtime").hide();
  //$(".au-notifications-page .au-notif-msg-realtime").slideDown();

  $(".au-notifications-page .au-notif-msg-realtime").slideDown({
    complete: function(){
      $('.au-notification-icon .badge').html("2");
      $('head title').html("(2) Notifications");
    }
  });


  // Display a sample notification
  if (window.Notification) {
    return $(".au-notifications-page").show(function() {
      var notification;
      notification = new Notification(
        'Success Heading', {
          body: 'Success Text',
          iconUrl: 'img/avatar-male.png',
          icon: 'img/avatar-male.png'
      });
      return notification.onclick = function() {
        notification.close();
        window.open().close();
        return window.focus();
      };
    });
  };
});

编辑1: Safari抛出以下异常

未定义的对象(评估'Notification.requestPermission().then')

5个回答

20

由于Safari不返回Promise,您必须使用回调函数。

根据MDN

这使用了方法的promise版本,如最近的实现所支持(例如Firefox 47)。如果您想要支持旧版本,则可能需要使用旧的回调版本,其代码如下:

这是他们提供的示例代码:

Notification.requestPermission(function (permission) {
    // If the user accepts, let's create a notification
    if (permission === "granted") {
        var notification = new Notification("Hi there!");
    }
});

为了支持Safari通知,这就是我最终的结果:
    try {
        Notification.requestPermission()
            .then(() => doSomething())                                                                                                                                               
    } catch (error) {
        // Safari doesn't return a promise for requestPermissions and it                                                                                                                                       
        // throws a TypeError. It takes a callback as the first argument                                                                                                                                       
        // instead.
        if (error instanceof TypeError) {
            Notification.requestPermission(() => {                                                                                                                                                             
                doSomething();
            });
        } else {
            throw error;                                                                                                                                                                                       
        }                                                                                                                                                                                                      
    }      

2
由于某些浏览器(例如iOS 11.4上的Safari)不支持“Notification”,因此在执行try/catch块之前检查“typeof Notification!== 'undefined'”可能是一个好习惯。 - Tsunamis

13

更好的解决方案是将结果包装在一个Promise中,然后(无意冒犯)运行你的代码。此代码适用于所有浏览器(包括Safari),而不需要复杂的if块(详细概念可以在这个问题中讨论)

Promise.resolve(Notification.requestPermission()).then(function(permission) {
    // Do something
});
这是因为Promise.resolve不会对Promise做任何处理,但会将Safari的requestPermission()转换为Promise。请注意,iOS Safari仍然不支持通知API,因此您需要先检查其是否可用

在Safari上,权限会未定义,对吧? - besserwisser
“permission” 仅是我选择的参数名称。该 Promise 将会将通知权限对象传递给回调函数。 - Machavity
2
这段代码无法正常工作,因为在Safari浏览器上Notification.requestPermission()会立即返回undefined,导致then函数会立即被调用,而不管用户是否已经做出了权限请求的决定。 - Sam Barnum

1
返回一个promise,直到用户授权或拒绝显示通知。
        if (!permissionPromise && Notification.permission === 'granted' ) {
            permissionPromise = Promise.resolve(Notification.permission);
        }
        if (!permissionPromise) {
            permissionPromise = new Promise(function (resolve, reject) {
                // Safari uses callback, everything else uses a promise
                var maybePromise = $window.Notification.requestPermission(resolve, reject);
                if (maybePromise && maybePromise.then) {
                    resolve(maybePromise);
                }
            });
        }
        return permissionPromise;

0
现代化解决方案,应对过时的问题:
new Promise((resolve) => {
   Notification.requestPermission(resolve)?.then(resolve);
}).then(permission => console.log(permission))

Safari只接受第一个回调并忽略?.then(...)。Chrome和FF可能会解决promise两次,但这并不重要。
与大多数投票答案不同,这个答案不会在我的Safari v13.1.2中请求两次权限,从而打开2个权限弹窗。

0
async function requestPermission() {
  return new Promise((resolve) => {

    const timeoutId = setInterval(() => {
      if (Notification.permission === 'granted') {
        handleComplete(Notification.permission);
      }
    }, 3000);

    const handleComplete = (permission) => {
      clearInterval(timeoutId);
      resolve(permission);
    };

    Notification.requestPermission(handleComplete)?.then?.(handleComplete);
  });
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接