Python 实现 Windows 微信消息通知(可显示发送人和消息内容)

2022-08-29 10:06:44 +08:00
 pytth

需求

Mac 微信是有一个消息通知的,这一点就挺好的,有时候根本不用点开开看就能看到消息内容。而 Windows 电脑版是没有这个消息通知的,只有右下角图标闪烁。

于是我想了不少的办法去实现这么一个功能,已经另辟蹊径实现了这个功能,其实也有一定的局限性,但是能满足办公期间的小需求。

效果如下:

实现方法

接收通知

首先是 Windows 的通知弹出的实现就是 Windows 自带的通知栏,我们可以通过 Python 去调用 Windows API 去发送 Windows 通知,让消息弹出来。

发送通知

相比于接收通知,那么发送通知就比较困难,因为 Windows 微信电脑版的窗口属于非 Windows 窗口标准,我们无法通过常规的方式去读取每个控件的内容,更无法监听到通知内容,所以我这边另辟蹊径,通过安卓手机去监听微信消息。

所以这里用到了 SmsForwarder 这款开源软件,安装在你的安卓手机上,然后设置转发规则,监听微信 APP 的通知,然后发送通道选择 WebHook ,将监听到的消息 POST 到 Python 开启的 HTTP 服务器,触发 Windows 通知就行了!

上代码

toasts.py

from flask import Flask, request
from winotify import Notification
import urllib.parse
import win32gui
import win32con

app = Flask(__name__)

@app.route('/')  # 获取 url 信息
def getUrlInfo():
    # 完整 url
    url = request.url
    # 主机部分
    hostUrl = request.host_url
    # 访问路径
    fullPath = request.full_path
    # 输出
    print('收到推送任务,推送内容是:'+str(urllib.parse.unquote(fullPath.split("/?")[1])).replace('+', ' ', 1))

    # 接收到的内容
    content = str(urllib.parse.unquote(fullPath.split("/?")[1])).replace('+', ' ', 1);

    # 错误处理
    # 因为监听软件那边监听到的首条消息是没有带上微信用户昵称的
    # 所以需要判断当前接收到的消息是不是首条消息
    # 如果不做这一步就会出错

    pdmh = ":" in content
    if pdmh == True:
        # 截取:前面的内容
        qianmian = content.split(":")[0]
        weixinMsg = content.split(":")[1]
        # 还要将[]这一块也去掉,这就提取到了微信昵称
        nickname = qianmian.split("]")[1]
    else:
        nickname = '微信消息通知'
        weixinMsg = content

    # 开发 Push 通知
    # toaster = ToastNotifier()
    # toaster.show_toast(title=nickname, msg=weixinMsg,icon_path="logo.ico", duration=5)
    toast = Notification(app_id="通知中心",title=nickname,msg=weixinMsg,icon=r"D:\Python\demo\wechat.png")
    toast.show()
    return "ok"


def notify(hwnd, msg, wparam, lparam):
    print("notify", msg)
    if lparam == win32con.WM_LBUTTONDBLCLK:  # 双击左键
        print("双击左键", msg)
        pass
    elif lparam == win32con.WM_RBUTTONUP:  # 右键弹起
        print("右键弹起", msg)
        pass
    elif lparam == win32con.WM_LBUTTONUP:  # 左键弹起
        print("左键弹起", msg)
        pass
    return True

wc = win32gui.WNDCLASS()
wc.hInstance = win32gui.GetModuleHandle(None)
wc.lpszClassName = "Windows 通知中心"
wc.style = win32con.CS_VREDRAW | win32con.CS_HREDRAW;
wc.lpfnWndProc = notify
classAtom = win32gui.RegisterClass(wc) 
hwnd =win32gui.CreateWindow(classAtom,"tst2",win32con.WS_OVERLAPPEDWINDOW,win32con.CW_USEDEFAULT,win32con.CW_USEDEFAULT,win32con.CW_USEDEFAULT,win32con.CW_USEDEFAULT,None,None,None,None)
notify_id = (hwnd,0,win32gui.NIF_ICON | win32gui.NIF_MESSAGE | win32gui.NIF_TIP,win32con.WM_USER + 20,win32gui.LoadIcon(0, win32con.IDI_APPLICATION),"Windows 通知中心")
win32gui.Shell_NotifyIcon(0,notify_id)

# 在指定 IP 和端口开启 HTTP 服务
if __name__ == '__main__':
    app.run(debug=False,host='192.168.1.100', port=8080)

代码说明

192.168.1.100 是我电脑的内网 ip ,8080 是端口号,你需要获取你电脑的内网 ip 换上去,不然后续配置安卓那边的监听转发端就无法正常转发通知。

执行代码后,会在你电脑开启一个 HTTP 服务,这时候你可以在浏览器进行本地测试,在浏览器按照以下格式粘贴:

http://内网 ip:端口号 /?通知内容

安卓手机配置

安装 SmsForwarder 这款软件。

下载地址: https://gitee.com/pp/SmsForwarder/releases/tag/v3.0.8

设置发送通道,选择 Webhook ,Webserver 按照以下格式填写:

http://内网 ip:端口号 /

WebParams 直接填写 [msg] ,请求方式是 GET

设置转发规则,添加规则,选择匹配 “APP 包名”,匹配模式选择 “是”,匹配值是 com.tencent.mm ,选择刚才配置的发送通道,自定义模板直接点击通知内容。

简单进行配置后,SmsForwarder 进行一些必要的设置后,就可以正常使用了。

需要优化的地方

目前还在想办法在电脑本地监听微信消息,毕竟通过安卓手机监听消息也不是办法,一方面是依赖本地的服务器,通过局域网才可以发送通知给电脑。另一方面就是安卓监听消息也不具备稳定性,而且也不是人人都用安卓,对于苹果手机的用户,也是难以实现这个。

需要注意的地方

  1. 内网 ip 可能会变化,如果你发现后面无法正常接收到通知,可以检查下内网 ip ,更换一下 ip 重启服务。

  2. 因为这是使用内网 ip 实现的 HTTP 服务,所以你安卓手机需要连接的 wifi 与电脑的一致,如果电脑是有线网络,那么你手机需要与电脑有线网络同一个网络环境,即 ip 相同。

  3. 如果不想通过局域网实现,可以自己配置内网穿透服务去实现外网请求服务。

监听微信消息的方案

  1. 自写 Hook 微信,读取内存去监听微信消息

  2. 使用现成的方案,市面上也有一些 Hook 微信的框架,例如可爱猫,这个框架提供了非常便利的 SDK 去调用 API 来监听微信聊天消息,甚至还可以做到发送消息。

4587 次点击
所在节点    Python
19 条回复
ysc3839
2022-08-29 12:21:53 +08:00
> 因为 Windows 微信电脑版的窗口属于非 Windows 窗口标准,我们无法通过常规的方式去读取每个控件的内容,更无法监听到通知内容
实测可以使用无障碍接口获取,微信是支持的。可以用 Windows SDK 附带的 inspect.exe 试试看。
brucmao
2022-08-29 14:11:00 +08:00
昨天看到一个 sublime text 通知插件,挺好玩的
http://facelessuser.github.io/SubNotify/
PRStarDust
2022-08-29 15:06:05 +08:00
话说你们不会觉得 Windows 的通知中心很难用吗?这个右下角的通知每次弹出来,既不能像安卓那样划掉,又不能点击那个 X 来彻底关掉,点 X 只是消除他的悬浮显示,并不能让它从通知中心彻底消失,所以我只好把所有应用的通知权限关掉...
pytth
2022-08-29 15:10:05 +08:00
是的,要进入通知中心列表再次 X 掉
@PRStarDust
icepie
2022-08-29 21:09:54 +08:00
貌似装个 kde connect 就解决了你的需求
01046
2022-08-30 00:16:00 +08:00
对呀,kde connect 就可以了啊。。。
话说 kde connect 什么时候可以修复手机剪贴板同步到 PC 无效的 BUG 啊,现在用 join ,感觉不是很稳定
RyanLin1995
2022-08-30 10:37:42 +08:00
我没记错的话,win11 好像已经实现了
pytth
2022-08-30 11:02:46 +08:00
@icepie
@01046

感谢推荐,我试了一下,确实是不错,这个软件还可以获取到微信头像!
pytth
2022-08-30 11:03:21 +08:00
@RyanLin1995 win11 也没有像 mac 一样弹出微信消息通知。
pytth
2022-08-30 11:04:50 +08:00
@ysc3839 感谢提醒,我用 ui spy.exe 试了下,之前试了一下是不行的,重新研究了,确实是可以得到每个控件,连每条聊天记录都可以获取到!感觉可以开发很多微信的小工具出来。
icepie
2022-08-30 11:18:39 +08:00
其实我也挺困扰的...为什么微信 pc 端不调用系统的通知 api...
kid740246048
2022-08-30 12:18:15 +08:00
@01046 Android 10 之后不允许后台读取剪贴板,可以装个 magisk 模块来绕过
RyanLin1995
2022-08-30 16:40:27 +08:00
@pytth 我记得我的预览版 win11 是有的,等我今晚回去确定一下
01046
2022-08-31 02:12:51 +08:00
@kid740246048 谢谢,请教一下模块名字? 剪贴板互通是刚需
kid740246048
2022-08-31 02:15:20 +08:00
01046
2022-08-31 02:44:46 +08:00
啊,没事了,用关键词搜到了,clipboard whitelist
01046
2022-08-31 02:45:16 +08:00
原来已经被回复了,还是非常感谢
llsquaer
2022-09-01 18:58:57 +08:00
思路很不错..我觉得直接自己写一个弹窗比 windows 自带的好用多了
cx1251cx
2022-12-04 19:20:12 +08:00
我只能说,你们玩 it 的……是真牛逼啊

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/876098

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX