WPF Cefsharp программно разрешает уведомления браузера

#c# #wpf #cefsharp

#c# #wpf #cefsharp

Вопрос:

Я работаю над приложением WPF с браузером CefSharp chromium. У меня есть TabControl, где каждый элемент вкладки содержит браузер chromium и содержит разные веб-сайты.

Проблема: я вижу пустой экран для одного веб-сайта в одном из элементов вкладки, тогда как тот же веб-сайт нормально загружается в автономном браузере (Google Chrome / Microsoft Edge).

Наблюдения / анализ: когда веб-сайт загружается в автономном браузере (Google Chrome / Microsoft Edge), я получаю всплывающее окно браузера с просьбой разрешить или заблокировать уведомления, НО я не получил это всплывающее окно в своем приложении. Когда я открыл инструменты разработки для конкретного браузера chromium в своем приложении, я обнаружил в консоли ошибку ниже: ОШИБКА ReferenceError: уведомление не определено

Я знаю, что мы можем разрешить или заблокировать микрофон / камеру из кода C #, как показано ниже:

 CefSettings settings = new CefSettings();
settings.CefCommandLineArgs.Add("enable-media-stream", "1");
Cef.Initialize(settings);
 

Есть ли какой-либо аргумент команды для разрешения / блокировки уведомлений, подобных приведенному выше коду?
Пожалуйста, помогите.

Комментарии:

1. Согласно magpcss.org/ceforum/viewtopic.php?f=6amp;t=16009 CEF не поддерживает API уведомлений. Вы можете создать полизаполнение JavaScript для добавления базовой поддержки. См . github.com/Haltroy/Korot/issues/22 для обсуждения этой темы.

Ответ №1:

CefSharp не поддерживает API уведомлений. https://github.com/cefsharp/CefSharp/issues/2890 Но вы можете сделать свою собственную реализацию. Используйте JavaScript, чтобы переопределить конструктор уведомлений и отправить сообщение из CefSharp в ваш код, предварительно упаковав его в JSON.

 public void OnFrameLoadEnd(object sender, FrameLoadEndEventArgs e)
{
Browser.ExecuteScriptAsync(@"(function(){ class Notification {
    static permission = 'granted';
    static maxActions = 2;
    static name = 'Notification';
    constructor(title, options) {
        let packageSet = new Set();
        packageSet.add(title).add(options);
        let json_package = JSON.stringify([...packageSet]);
        CefSharp.PostMessage(json_package);
        //alert(title);
    }
    static requestPermission() {
        return new Promise((res, rej) => {
            res('granted');
        })
    }   
};
window.Notification = Notification;
})();");
}
 

Получите сообщение и поместите его в очередь. Я использовал Newtonsoft для распаковки из JSON.

 private void OnBrowserJavascriptMessageReceived(object sender, JavascriptMessageReceivedEventArgs e)
{
    object[] objArray = JsonConvert.DeserializeObject<object[]>(e.Message.ToString());
    Options options = JsonConvert.DeserializeObject<Options>(objArray[1].ToString(), new ImageConverter());
    // Add to Notification queue
    MessageQueue.Enqueue(new object[] { objArray[0], options });
}
 

MessageQueue — это простая очередь объектов массива, которые мы затем обрабатываем в другом потоке.

 public Queue<object[]> MessageQueue = new Queue<object[]>();
 

Структура уведомлений.

 public class Options
{
    public byte[] icon { get; set; }               
    public string body { get; set; }               
    public string tag { get; set; }                
    public bool canReply { get; set; }             
    public bool silent { get; set; }               
    public bool requireInteraction { get; set; }
}
 

Конвертер изображений

 public class ImageConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(byte[]);
    }
    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var str = reader.Value.ToString();
        var index = reader.Value.ToString().IndexOf("base64,");
        if (index == -1)
        {
            try
            {
                // Download the icon
                Task<byte[]> task = App.ImageDownloaderObj.GetImageBytesAsync(new Uri(str));
                task.Wait(500);
                return task.Resu<
            }
            catch { return new byte[] { }; }
        }
        else
        {
            var m = new MemoryStream(Convert.FromBase64String(str.Substring(index   7)));
            return m.ToArray();
        }
        //return (Bitmap)Image.FromStream(m);
    }
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        Bitmap bmp = (Bitmap)value;
        MemoryStream m = new MemoryStream();
        bmp.Save(m, System.Drawing.Imaging.ImageFormat.Png);

        writer.WriteValue(Convert.ToBase64String(m.ToArray()));
    }
}
 

Комментарии:

1. Несколько комментариев, JavascriptMessageReceived вызывается в пуле потоков, поэтому вызывается MessageBox. Показывать не рекомендуется, поскольку цикл сообщений не выполняется, лучше всего использовать поток пользовательского интерфейса для всего, что связано с пользовательским интерфейсом. Было бы здорово, если бы пример действительно отправлял текст уведомления, а не фиксированную строку.

2. Спасибо за комментарий, я внес изменения. Теперь это код, фактически запущенный в одном из проектов.