使用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刷票工具
稍後我會放到CSDN下載頻道,請大家注意本篇部落格文章的更新。
PS:
“安心刷票彈窗通知工具”現在整合到了 "PDF.NET整合開發工具"裡面,所以這意味著你既可以用它來做一個輕量級的多種資料庫的查詢客戶端,也可以做一個簡單的谷歌瀏覽器。
注意:
雖然“SOD框架”是基於LGPL協議釋出的開源軟體,但是整合開發工具屬於GPL開源協議,你可以自由的免費的使用本軟體,但不可以使用這個工具的原始碼用作商業用途。SOD框架的其它部分原始碼不在此限制範圍。
詳細問題請看PDF.NET框架官網 http://www.pwmis.com/sqlmap ,如果有問題請和我們聯絡。