使用Java调用Windows通知并显示自定义图标
使用Java调用Windows通知并显示自定义图标
一 实现原理,java调用shell脚本,实现弹出通知,其实是有两种shell脚本的方式,任何编程语言都可以调用shell的,底部附源码
在现代应用程序中,通知系统是一个非常重要的功能,它可以帮助用户及时了解应用程序的状态或重要信息。本文将详细介绍如何使用Java调用Windows通知,并在通知中显示自定义图标。我们将通过一个完整的代码示例来展示这一功能的实现。
代码功能概述
本文的代码实现了一个Java方法
showWindowsNotificationWithIconA,它可以在Windows系统上显示一个带有自定义图标的通知。通知的标题和内容可以通过参数传递,图标则从项目的资源文件中加载。如果图标无法直接从资源文件中加载,代码还会尝试将图标提取到临时文件中,并使用该临时文件的路径来显示图标。
此外,代码还包含一个辅助方法 executeShellScriptEx,用于执行PowerShell脚本。该方法会将脚本保存到临时文件中,然后通过 ProcessBuilder 启动PowerShell进程来执行脚本,并捕获脚本的输出。
代码实现逻辑
-
- 加载图标资源
首先,代码尝试从项目的资源文件中加载图标。图标文件位于 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;
}
如果图标资源无法加载,代码会输出错误信息并返回。
-
- 处理图标路径
获取到图标的URL后,代码将其转换为适合PowerShell脚本使用的字符串形式,并进行必要的转义。如果URL不包含 file 协议(即图标不是从文件系统中加载的),代码会调用 extractIconToTemp 方法将图标提取到临时文件中。
- 处理图标路径
String file = iconUrl.toString().replace("\\", "/");
if(!file.contains("file")){
try {
file = extractIconToTemp();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
-
- 构建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);
-
- 执行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通知功能。