【问题标题】:Notification.requestPermission throws an error in Mac versions of SafariNotification.requestPermission 在 Mac 版本的 Safari 中引发错误
【发布时间】:2016-11-02 00:39:24
【问题描述】:

我正在尝试在页面加载时使用 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 抛出此异常

undefined 不是对象(评估 'Notification.requestPermission().then')

【问题讨论】:

    标签: javascript jquery html safari web-notifications


    【解决方案1】:

    您必须为 Safari 使用回调函数,因为它不会返回 Promise。

    根据MDN

    这使用了该方法的 promise-version,正如最近支持的那样 实现(例如 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;                                                                                                                                                                                       
            }                                                                                                                                                                                                      
        }      
    

    【讨论】:

    • 由于某些浏览器(即 iOS 11.4 上的 Safari)不支持 Notification,因此在执行 try/catch 块之前检查 typeof Notification !== 'undefined' 可能是一个好习惯。
    【解决方案2】:

    更好的解决方案是将结果包装在Promise 中,然后然后(没有双关语)运行您的代码。此代码适用于所有浏览器(包括 Safari),并且没有复杂的 if 块(概念​​在 this question 中有详细讨论)

    Promise.resolve(Notification.requestPermission()).then(function(permission) {
        // Do something
    });
    

    这是因为Promise.resolvePromise 没有任何作用,但会将Safari 的requestPermission() 转换为Promise

    请注意,iOS Safari 仍然不支持 Notification API,因此您需要 check if it is available first

    【讨论】:

    • 在 safari 上,权限在 Safari 上是未定义的,对吧?
    • permission 只是我选择的参数名称。 promise 会将通知权限对象传递给回调函数
    • 这不起作用,因为Notification.requestPermission()在Safari上立即返回undefinedthen函数会立即被调用,无需等待权限请求对话框被解析,并且不管用户选择什么。
    【解决方案3】:

    要返回一个在用户授予或拒绝显示通知的权限之前不会解析的承诺:

            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;
    

    【讨论】:

      猜你喜欢
      • 2020-08-11
      • 2022-07-03
      • 2016-07-30
      • 1970-01-01
      • 2010-09-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多