使用CefSharp开发一个12306“安心刷票弹窗通知”工具
有需求就要改进
最近两年没有在春节回家过年了,主要是票太难买,虽然之前写了一个12306“无声购票弹窗”工具,解决了抢票问题,但是全家老小一起回去还是很累,干脆就在北京过年了。这两天突然有一个朋友问我你之前的抢票工具还能用不,我让他试试,他说可以,于是我觉得这样一个小工具居然还有人继续使用啊,既然有人用我就继续把他做好点,让大家过年抢票更“安心”!
之前的抢票工具是基于IEBrowser控件做的,不用说大家都知道这个控件在不同的Windows系统上表现各异,因为它主要依赖于IE内核,坑爹的是它有时候还没有直接使用IE效果好,所以使用我这个抢票工具总有不顺收的地方,比如一些显示问题,提交订单后无法直接支付问题等。看到朋友介绍说CefSharp控件不错,于是决定试试,没想到出了网上介绍的坑,还有些其它的坑没有人写过,这里写出来给大家做一个参考。
1,CefSharp版本问题
最新版的CefSharp要求.NET应用程序至少支持 .NET 4.5.2以上,而我这次要整合的工具程序还是 .NET 4.0的,照做相关资料去下载了一个之前的版本,结果在JS无法调用VB.NET写的方法,而它去可以在X64模式下调用C#写的方法。没法只好升级到CefSharp 57.0.0 ,才解决了这个问题。
JS调用VB.NET的代码如下:
VB.NET代码:
Public Class TicketNotify Dim owerForm As Form Public Sub New(ByVal owner As Form) Me.owerForm = owner End Sub Public Sub MyNotify() Dim target As frm12306Ticket = Me.owerForm target.FoundTickt = True \' target.Notify() End Sub End Class
将这个.NET类注册到Cef浏览器里面去:
Dim WithEvents WebBrowser1 As CefSharp.WinForms.ChromiumWebBrowser Me.WebBrowser1 = New CefSharp.WinForms.ChromiumWebBrowser(Me.ticketUrl) Me.WebBrowser1.RegisterJsObject("jsObj", New TicketNotify(Me), Nothing)
然后,将一段调用这个.NET方法的JS函数注入到Cef浏览器内:
Private Sub WebBrowser1_FrameLoadEnd(sender As Object, e As FrameLoadEndEventArgs) Handles WebBrowser1.FrameLoadEnd Dim js As String = <string> var divAlert=true; function checkHaveTicket() { var div = document.getElementById(\'autosubmitcheckticketinfo\'); if (div) { if (div.style.display == \'block\' || div.style.display == \'\') { //txtName.value = \'有票了!!!\'; jsObj.myNotify(); } } } </string> \'下面两行代码效果一样 \'Me.WebBrowser1.GetMainFrame().ExecuteJavaScriptAsync(js) Me.WebBrowser1.ExecuteScriptAsync(js) End Sub
这样,浏览器执行 jsObj.myNotify(); 这个方法就可以调用我们的.NET对象的方法 MyNotify() 了。
PS:注意上面有一个代码 <string>...</string> ,这个是VB.NET独特的XML语句块,XML是VB.NET的一种数据类型,就像你自定义的类型一样,这里用来表示一个字符串,所以用它来表示多行字符串是最合适的了。
由于CefSharp版本问题,这个JS代码必须写到 浏览器控件的 FrameLoadEnd 事件中,但是之前查询到文章里面都说可以在 IsBrowserInitializedChanged 事件里面,现在是找不到的,但不报错,例如下面实际的代码说明:
Private Sub WebBrowser1_IsBrowserInitializedChanged(sender As Object, e As IsBrowserInitializedChangedEventArgs) Handles WebBrowser1.IsBrowserInitializedChanged If e.IsBrowserInitialized Then \'不可以在这里注册JS代码,新版CefSharp 找不到 \'不可以在这里开启定时器,否则定时器的事件会在当前线程,也就是UI线程之外运行,相关UI访问代码会发生“线程间操作无效”的异常 \'Me.Timer1.Start() End If End Sub
2.Windows 8.1 闪屏问题
我在公司的Windows 10系统下CefSharp运行正常,但是回家在Windows 8.1系统上,发现Cef浏览器总是不能填充满窗口,只有一半大小,但是滚动条位置却能鼓动,滚动的时候会看到闪屏,同时页面上控件的点击位置也是错位的,需要点击下才能回复页面大小,但很快又变小了。查了下资料,说可以通过程序集清单设置文件进行设置:
<?xml version="1.0" encoding="utf-8"?> <asmv1:assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1" xmlns:asmv1="urn:schemas-microsoft-com:asm.v1" xmlns:asmv2="urn:schemas-microsoft-com:asm.v2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <assemblyIdentity version="1.0.0.0" name="MyApplication.app"/> <trustInfo xmlns="urn:schemas-microsoft-com:asm.v2"> <security> <requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3"> <!-- UAC 清单选项 如果希望更改 Windows 用户帐户控制级别,请用以下节点之一替换 requestedExecutionLevel 节点。 <requestedExecutionLevel level="asInvoker" uiAccess="false" /> <requestedExecutionLevel level="requireAdministrator" uiAccess="false" /> <requestedExecutionLevel level="highestAvailable" uiAccess="false" /> 如果您希望利用文件和注册表虚拟化提供 向后兼容性,请删除 requestedExecutionLevel 节点。 --> <requestedExecutionLevel level="asInvoker" uiAccess="false" /> </requestedPrivileges> </security> </trustInfo> <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1"> <application> <!-- 此应用程序设计使用的所有 Windows 版本的列表。 Windows 将会自动选择最兼容的环境。--> <!-- 如果应用程序设计为使用 Windows Vista,请取消注释以下 supportedOS 节点--> <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"></supportedOS> <!-- 如果应用程序设计使用 Windows 7,请取消注释以下 supportedOS 节点--> <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/> <!-- 如果应用程序设计为使用 Windows 8,请取消注释以下 supportedOS 节点--> <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"></supportedOS> <!-- 如果应用程序设计为使用 Windows 8.1,请取消对以下 supportedOS 节点的注释--> <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/> </application> </compatibility> <!--<application xmlns="urn:schemas-microsoft-com:asm.v3"> <windowsSettings> <dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware> </windowsSettings> </application>--> </asmv1:assembly>
结果无效,后来看到可能没有禁用GPU有关,于是做下设置:
Dim setting As CefSettings = New CefSettings() With setting .Locale = "zh-CN" .AcceptLanguageList = "zh-CN" .MultiThreadedMessageLoop = True End With Dim osVersion = Environment.OSVersion \'//Disable GPU for Windows 7 ,8,8.1 If osVersion.Version.Major = 6 Then \'// Disable GPU in WPF and Offscreen examples until #1634 has been resolved setting.CefCommandLineArgs.Add("disable-gpu", "1") End If CefSharp.Cef.Initialize(setting)
经过这样的设置后,终于显示正常了。
3,定时器失效问题
小工具是通过定时器不断监控页面有没有出现特定的标记来表示有票的,就是上面注入的JS代码中的 checkHaveTicket 函数。之前是在 CefSharp控件的 IsBrowserInitializedChanged 事件中处理的,结果发现运行时偶发错误,而且是Win 10不报错但是Win 8.1报错:
相关UI访问代码会发生“线程间操作无效”的异常
推测是CefSharp控件的这些事件可能不一定运行在UI线程,在非UI线程启动定时器那么定时器的“定时事件”也不在UI线程了,所以报错。
其它问题和运行效果
本次更新增加了“声音通知”功能,发现有票后会不断播放音乐提示,以方便你不在电脑跟前也能知道。
这样不论你是否在电脑跟前并且不想被刷票问题打扰,这就是本工具最大的优势了,第一时间弹窗通知,不用时时刻刻去看。
最后关于安全问题,既然开源了,就不会有什么偷窥您隐私问题的可能性了,可以放心使用!
其它问题就没有了,处理方式跟之前的弹窗工具一样,代码我已经签入到了SOD的Github代码库中,地址如下:https://github.com/znlgis/sod
下面附带一个运行测试效果图:
下面是打开12306自动刷票功能的效果图:
如果有问题,或者想获取编译好的程序包,请加QQ群:18215717 ,加群请注明暗号:博客园看到12306刷票工具
稍后我会放到****下载频道,请大家注意本篇博客文章的更新。
PS:
“安心刷票弹窗通知工具”现在集成到了 "PDF.NET集成开发工具"里面,所以这意味着你既可以用它来做一个轻量级的多种数据库的查询客户端,也可以做一个简单的谷歌浏览器。
注意:
虽然“SOD框架”是基于LGPL协议发布的开源软件,但是集成开发工具属于GPL开源协议,你可以*的免费的使用本软件,但不可以使用这个工具的源码用作商业用途。SOD框架的其它部分源码不在此限制范围。
详细问题请看PDF.NET框架官网 http://www.pwmis.com/sqlmap ,如果有问题请和我们联系。