標籤:裝置 pair continue 相關 null 例子 state blog private
接著探索
上一篇講了一個微軟官方的Demo,這個Demo基本上已經把我們要做的事情做完了。
那麼基於這個Demo,我說下我的思路。
1.首先是要在介面程式中枚舉出藍牙裝置
2.為使用藍牙裝置的相關資訊建立解鎖用的Windows Hello裝置
3.當task收到解鎖事件的時候再次枚舉藍牙裝置,然後判斷每個枚舉到的藍牙裝置有沒有對應Windows Hello裝置
4. 有就使用使用這個Windows Hello裝置解鎖電腦
那這樣我先使用我的小米手環的資訊建立對應的解鎖裝置,當我的手環在附近的時候Task就能枚舉到它從而解鎖,當手環不在附近的時候Task自然就枚舉不到它,於是就不能使用Windows Hello解鎖。
開始實踐
關於枚舉藍牙裝置,我又在微軟的官方例子中找到了Demo
Demo地址:https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/DeviceEnumerationAndPairing
這個Demo就展示了使用DeviceWatch去枚舉裝置
DeviceWatcher m_deviceWatcher;string[] requestedProperties = { "System.Devices.Aep.DeviceAddress", "System.Devices.Aep.IsConnected" };m_deviceWatcher = DeviceInformation.CreateWatcher("(System.Devices.Aep.ProtocolId:=\"{bb7bb05e-5972-42b5-94fc-76eaa7084d49}\")",//m_deviceWatcher = DeviceInformation.CreateWatcher("(System.Devices.Aep.ProtocolId:=\"{e0cbf06c-cd8b-4647-bb8a-263b43f0f974}\")", requestedProperties, DeviceInformationKind.AssociationEndpoint);m_deviceWatcher.Added += DeviceWatcher_Added;m_deviceWatcher.Updated += DeviceWatcher_Updated;m_deviceWatcher.Removed += DeviceWatcher_Removed;m_deviceWatcher.EnumerationCompleted += DeviceWatcher_EnumerationCompleted;m_deviceWatcher.Stopped += DeviceWatcher_Stopped;m_deviceWatcher.Start();
這個代碼應該是一目瞭然的, 其中的關鍵就在於CreateWatcher時候使用的參數 {bb7bb05e-5972-42b5-94fc-76eaa7084d49} 能枚舉到小米手環,但是枚舉不到手機 {e0cbf06c-cd8b-4647-bb8a-263b43f0f974} 則相反,能枚舉到手機但是枚舉不到小米手環。
這個類還能枚舉到其他很多的裝置,就靠CreateWatcher的參數具體可以看官方的Demo。
下面是介面的定義,其中 DeviceInformation 和 DeviceInformationUpdate 就包含了裝置的資訊
private void DeviceWatcher_Added(DeviceWatcher Sender, DeviceInformation DeviceInfo){}private void DeviceWatcher_Updated(DeviceWatcher Sender, DeviceInformationUpdate DeviceInfoUpdate){}private void DeviceWatcher_Removed(DeviceWatcher Sender, DeviceInformationUpdate DeviceInfoUpdate){}private void DeviceWatcher_EnumerationCompleted(DeviceWatcher Sender, object e){}private void DeviceWatcher_Stopped(DeviceWatcher Sender, object e){}
基本屬性都有對應的變數,而我在CreateWatcher的時候附加的屬性 string[] requestedProperties = { "System.Devices.Aep.DeviceAddress", "System.Devices.Aep.IsConnected" }; 會以索引值對的形式儲存在 DeviceInformation 和 DeviceInformationUpdate 的 Properties中
我首先在介面程式中使用這套介面枚舉到了我的手環,基本資料是這樣的
DeviceID: BluetoothLE#BluetoothLExx:xx:xx:xx:xx:xx-xx:xx:xx:xx:xx:xx
Name: MI Band 2
一開始我是想直接使用 BluetoothLE#BluetoothLExx:xx:xx:xx:xx:xx-xx:xx:xx:xx:xx:xx 這個ID去建立解鎖裝置的,但是發現都失敗,實驗下來可能是只能使用GUID去建立解鎖裝置。於是我就需要把 BluetoothLE#BluetoothLExx:xx:xx:xx:xx:xx-xx:xx:xx:xx:xx:xx 也儲存起來,儲存的思路
其執行個體子中也給出了就是存在解鎖裝置的 DeviceConfigurationData 中,因為 我還要在 DeviceConfigurationData 中還要儲存解鎖用的兩個密碼,所以我乾脆就將在 DeviceConfigurationData 中儲存JSON格式的資料,專門寫了個序列化很還原序列化的類。
public class JsonData{ public string Sign { get; set; } public string DeviceID { get; set; } public string DeviceKey { get; set; } public string AuthKey { get; set; } public bool CanUnLock { get; set; }}public class CMyHelloWinJson{ public static JsonData ParesToData(string js) { JsonData rv = null; try { JsonObject schoolObject = JsonObject.Parse(js); if (schoolObject != null) { rv = new JsonData(); rv.Sign = schoolObject.GetNamedString("Sign"); rv.DeviceID = schoolObject.GetNamedString("DeviceID"); rv.DeviceKey = schoolObject.GetNamedString("DeviceKey"); rv.AuthKey = schoolObject.GetNamedString("AuthKey"); rv.CanUnLock = schoolObject.GetNamedBoolean("CanUnLock"); } }catch(Exception e) { return rv; } return rv; } public static string ParesToJson(JsonData Dat) { JsonObject schoolObject = new JsonObject(); schoolObject.SetNamedValue("Sign", JsonValue.CreateStringValue(Dat.Sign)); schoolObject.SetNamedValue("DeviceID", JsonValue.CreateStringValue(Dat.DeviceID)); schoolObject.SetNamedValue("DeviceKey", JsonValue.CreateStringValue(Dat.DeviceKey)); schoolObject.SetNamedValue("AuthKey", JsonValue.CreateStringValue(Dat.AuthKey)); schoolObject.SetNamedValue("CanUnLock", JsonValue.CreateBooleanValue(Dat.CanUnLock)); return schoolObject.ToString(); }}
所以在介面中建立解鎖裝置的代碼就變成了這樣
string modelnumber = "MyHelloWin";// 隨機數轉 string 可能會丟失資訊的byte[] deviceKeyArray = new byte[32];byte[] authKeyArray = new byte[32];IBuffer deviceKey = CryptographicBuffer.CreateFromByteArray(deviceKeyArray);IBuffer authKey = CryptographicBuffer.CreateFromByteArray(authKeyArray);JsonData Dat = new JsonData();Dat.Sign = "MyHellowin";Dat.DeviceKey = System.Text.Encoding.UTF8.GetString(deviceKeyArray);Dat.AuthKey = System.Text.Encoding.UTF8.GetString(authKeyArray);Dat.DeviceID = DeviceID;Dat.CanUnLock = false;string js = CMyHelloWinJson.ParesToJson(Dat);byte[] signArry = System.Text.Encoding.UTF8.GetBytes(js);IBuffer deviceConfigData = CryptographicBuffer.CreateFromByteArray(signArry);String deviceGUId = System.Guid.NewGuid().ToString();int state = await WinHello.RegisterDeviceAsync(deviceGUId, bleDeviceDisplay.DeviceName, modelnumber, deviceConfigData, deviceKey, authKey);// 註冊SecondaryAuthenticationFactorDeviceCapabilities Capabilities = SecondaryAuthenticationFactorDeviceCapabilities.SecureStorage;SecondaryAuthenticationFactorRegistrationResult RegistrationResult = await SecondaryAuthenticationFactorRegistration.RequestStartRegisteringDeviceAsync(DervicesID, Capabilities, FriendlyName, ModelNumber, deviceKey, authKey);if (RegistrationResult.Status == SecondaryAuthenticationFactorRegistrationStatus.Started) { await RegistrationResult.Registration.FinishRegisteringDeviceAsync(DerviceContext);}return (int)RegistrationResult.Status;
介面寫好了,那麼解鎖的時候思路大致就是這樣的
先是枚舉出所有的藍牙裝置,使用和上面相同的方法。
private void DeviceWatcher_Added(DeviceWatcher Sender, DeviceInformation DeviceInfo){
IReadOnlyList<SecondaryAuthenticationFactorInfo> deviceList = await SecondaryAuthenticationFactorRegistration.FindAllRegisteredDeviceInfoAsync(SecondaryAuthenticationFactorDeviceFindScope.AllUsers);
for (int i = 0; i < deviceList.Count; i++) { SecondaryAuthenticationFactorInfo deviceInfo = deviceList.ElementAt(i); byte[] combinedDataArray; CryptographicBuffer.CopyToByteArray(deviceInfo.DeviceConfigurationData, out combinedDataArray); string JS = System.Text.Encoding.UTF8.GetString(combinedDataArray); JsonData Dat = CMyHelloWinJson.ParesToData(JS); if (Dat == null) { continue; } if (String.Equals(Dat.DeviceID, DeviceInfo.DeviceID)) { // 使用這個裝置進行解鎖 }
}
}
具體解鎖的方法,上面一篇文章中有相應的介紹。或者你直接看我寫的Demo: http://git.oschina.net/alwaysking/MyHelloWin
然而,當我天真的這樣就搞定的時候,來了個晴天霹靂,因為在Task中使用DeviceWatcher枚舉裝置的時候他的回呼函數根本不會被觸發。注意我的藍牙裝置是配對的裝置。
解決方案也是有的,我們下一篇再講
Windows Hello 淺嘗(2)