使用Java调用Windows通知并显示自定义图标

使用Java调用Windows通知并显示自定义图标

一 实现原理,java调用shell脚本,实现弹出通知,其实是有两种shell脚本的方式,任何编程语言都可以调用shell的,底部附源码

在现代应用程序中,通知系统是一个非常重要的功能,它可以帮助用户及时了解应用程序的状态或重要信息。本文将详细介绍如何使用Java调用Windows通知,并在通知中显示自定义图标。我们将通过一个完整的代码示例来展示这一功能的实现。

代码功能概述

本文的代码实现了一个Java方法
showWindowsNotificationWithIconA,它可以在Windows系统上显示一个带有自定义图标的通知。通知的标题和内容可以通过参数传递,图标则从项目的资源文件中加载。如果图标无法直接从资源文件中加载,代码还会尝试将图标提取到临时文件中,并使用该临时文件的路径来显示图标。

此外,代码还包含一个辅助方法 executeShellScriptEx,用于执行PowerShell脚本。该方法会将脚本保存到临时文件中,然后通过 ProcessBuilder 启动PowerShell进程来执行脚本,并捕获脚本的输出。

代码实现逻辑

    1. 加载图标资源

首先,代码尝试从项目的资源文件中加载图标。图标文件位于 resources/static/A.ico 路径下。通过
GlobalKeyListener.class.getResource(“/static/A.ico”) 方法获取图标的URL。

URL iconUrl = GlobalKeyListener.class.getResource("/static/A.ico");
if (iconUrl == null) {
    System.err.println("无法加载图标资源!");
    return;
}

如果图标资源无法加载,代码会输出错误信息并返回。

    1. 处理图标路径
      获取到图标的URL后,代码将其转换为适合PowerShell脚本使用的字符串形式,并进行必要的转义。如果URL不包含 file 协议(即图标不是从文件系统中加载的),代码会调用 extractIconToTemp 方法将图标提取到临时文件中。
String file = iconUrl.toString().replace("\\", "/");
if(!file.contains("file")){
    try {
        file = extractIconToTemp();
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}
    1. 构建PowerShell脚本

接下来,代码构建一个PowerShell脚本来显示通知。脚本使用了Windows的Toast通知系统,并指定了带图标的模板
ToastImageAndText02。通知的标题、内容和图标路径通过格式化字符串插入到脚本中。

String script = String.format("""
    $ErrorActionPreference = 'Stop';
    Add-Type -AssemblyName System.Runtime.WindowsRuntime;
    [Windows.UI.Notifications.ToastNotificationManager, Windows.UI.Notifications, ContentType = WindowsRuntime] | Out-Null;
    $template = [Windows.UI.Notifications.ToastTemplateType]::ToastImageAndText02;  # 使用带图标的模板
    $toastContent = [Windows.UI.Notifications.ToastNotificationManager]::GetTemplateContent($template);
    $toastXml = [xml] $toastContent.GetXml();
    $toastXml.SelectSingleNode('//text[1]').InnerText = '%s';  # 标题
    $toastXml.SelectSingleNode('//text[2]').InnerText = '%s';  # 内容
    $toastXml.SelectSingleNode('//image').Attributes['src'].Value = '%s';  # 图标路径
    $toastNode = [Windows.Data.Xml.Dom.XmlDocument]::new();
    $toastNode.LoadXml($toastXml.OuterXml);
    $toast = [Windows.UI.Notifications.ToastNotification]::new($toastNode);
    $notifier = [Windows.UI.Notifications.ToastNotificationManager]::CreateToastNotifier('柚柚通知');  # 应用名称
    $notifier.Show($toast);
    """,
    title.replace("'", "''"), message.replace("'", "''"), file);
    1. 执行PowerShell脚本

最后,代码通过 WindowsSystemUtil.executeShellScriptEx
方法执行构建好的PowerShell脚本,从而在Windows系统上显示通知。

WindowsSystemUtil.executeShellScriptEx(script);
5. 提取图标到临时文件
如果图标无法直接从资源文件中加载,代码会调用 extractIconToTemp 方法将图标提取到临时文件中。该方法首先通过 ClassLoader 加载图标资源,然后将其写入一个临时文件,并返回该临时文件的绝对路径。

public static String extractIconToTemp() throws IOException {
    InputStream inputStream = GlobalKeyListener.class.getClassLoader().getResourceAsStream("static/A.ico");
    if (inputStream == null) {
        throw new FileNotFoundException("图标文件未找到!");
    }

    try {
        File tempFile = File.createTempFile("appicon", ".ico");
        tempFile.deleteOnExit(); // 程序正常退出时删除临时文件

        try (OutputStream outputStream = new FileOutputStream(tempFile)) {
            byte[] buffer = new byte[1024];
            int bytesRead;
            while ((bytesRead = inputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, bytesRead);
            }
        }

        return tempFile.getAbsolutePath();
    } finally {
        inputStream.close();
    }
}

完整代码

public static void showWindowsNotificationWithIconA(String title, String message)  {
    // 获取图标文件的URL。这里假设图标位于项目的resources/static/A.ico。
    URL iconUrl = GlobalKeyListener.class.getResource("/static/A.ico");
    if (iconUrl == null) {
        System.err.println("无法加载图标资源!");
        return;
    }

    // 将URL转换为适合PowerShell脚本使用的字符串形式,并进行必要的转义
    String file = iconUrl.toString().replace("\\", "/");
    if(!file.contains("file")){
        try {
            file = extractIconToTemp();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    // 构建PowerShell脚本
    String script = String.format("""
        $ErrorActionPreference = 'Stop';
        Add-Type -AssemblyName System.Runtime.WindowsRuntime;
        [Windows.UI.Notifications.ToastNotificationManager, Windows.UI.Notifications, ContentType = WindowsRuntime] | Out-Null;
        $template = [Windows.UI.Notifications.ToastTemplateType]::ToastImageAndText02;  # 使用带图标的模板
        $toastContent = [Windows.UI.Notifications.ToastNotificationManager]::GetTemplateContent($template);
        $toastXml = [xml] $toastContent.GetXml();
        $toastXml.SelectSingleNode('//text[1]').InnerText = '%s';  # 标题
        $toastXml.SelectSingleNode('//text[2]').InnerText = '%s';  # 内容
        $toastXml.SelectSingleNode('//image').Attributes['src'].Value = '%s';  # 图标路径
        $toastNode = [Windows.Data.Xml.Dom.XmlDocument]::new();
        $toastNode.LoadXml($toastXml.OuterXml);
        $toast = [Windows.UI.Notifications.ToastNotification]::new($toastNode);
        $notifier = [Windows.UI.Notifications.ToastNotificationManager]::CreateToastNotifier('柚柚通知');  # 应用名称
        $notifier.Show($toast);
        """,
        title.replace("'", "''"), message.replace("'", "''"), file);

    // 打印构建好的脚本(可选)
    System.out.println(script);

    // 执行构建好的脚本
    WindowsSystemUtil.executeShellScriptEx(script);
}

public static String extractIconToTemp() throws IOException {
    // 使用ClassLoader加载资源
    InputStream inputStream = GlobalKeyListener.class.getClassLoader().getResourceAsStream("static/A.ico");

    if (inputStream == null) {
        throw new FileNotFoundException("图标文件未找到!");
    }

    try {
        // 创建临时文件
        File tempFile = File.createTempFile("appicon", ".ico");
        tempFile.deleteOnExit(); // 程序正常退出时删除临时文件

        // 将输入流的数据写入临时文件
        try (OutputStream outputStream = new FileOutputStream(tempFile)) {
            byte[] buffer = new byte[1024];
            int bytesRead;
            while ((bytesRead = inputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, bytesRead);
            }
        }

        // 返回临时文件的绝对路径
        return tempFile.getAbsolutePath();
    } finally {
        inputStream.close();
    }
}

总结

通过本文的代码示例,我们展示了如何使用Java调用Windows通知并显示自定义图标。代码通过加载资源文件、处理图标路径、构建PowerShell脚本以及执行脚本等步骤,实现了这一功能。希望本文能帮助你更好地理解如何在Java应用程序中集成Windows通知功能。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不一样的老墨

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值