やりたいこと
ハマった?事
最初は、下記の「Bluetooth LE Plugin for Xamarin」を使おうとしたが、「ペアリング済の機器情報」を取得する方法が分からなかった。(あったならすいません...)
Bluetoothの「UUID」は「機器ごと」に個別ではなく「サービス/プロファイル」ごとに個別だった。(同じ「スピーカー」ならUUIDは同じだが、それを知らずにハマった…いい勉強になりました。)
参考にした情報
【Xamarin.Forms】MVVMっぽくBluetoothを実装する(その1:ペアリング済みデバイス一覧を取得する) - なりたろぐだよ
書籍「Essential Xamarin 陰」https://booth.pm/ja/items/501110
ソース&結果
※すいません。時間の関係で、ソース&結果のみ表示します。
(詳細は後日追記します。)
■SearchDevicePage.xaml(VolChanger.View)
<?xml version="1.0" encoding="utf-8" ?> <ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="VolChanger.View.SearchDevicePage"> <ContentPage.Content> <StackLayout> <ActivityIndicator x:Name="AILoading" IsVisible="{Binding IsSearching}" IsRunning="{Binding IsSearching}" /> <Button x:Name="ButtonSearch" Text="Bluetoothデバイスを検出する" Command="{Binding GetDevicesCommand}" /> <ListView x:Name="ListViewDevices" ItemsSource="{Binding DeviceList}"> <!--ここに ItemTemplate を追加--> <ListView.ItemTemplate> <DataTemplate> <TextCell Text="{Binding Name}" Detail="{Binding Detail}"/> </DataTemplate> </ListView.ItemTemplate> </ListView> </StackLayout> </ContentPage.Content> </ContentPage>
■SearchDevicePage.xaml.cs(VolChanger.View)
using System; using System.Collections.Generic; using System.Linq; using System.Text; using Xamarin.Forms; using Xamarin.Forms.Xaml; using VolChanger.View; using VolChanger.ViewModel; using Plugin.BLE.Abstractions; using Plugin.BLE.Abstractions.Contracts; using Plugin.BLE.Abstractions.Exceptions; // using Reactive.Bindings; // using Reactive.Bindings.Extensions; namespace VolChanger.View { [XamlCompilation(XamlCompilationOptions.Compile)] public partial class SearchDevicePage : ContentPage { private readonly SearchDeviceViewModel vm; public SearchDevicePage () { InitializeComponent (); this.vm = new SearchDeviceViewModel(); BindingContext = vm; // ButtonSearch.Clicked += ButtonSearch_Clicked; } } }
■SearchDeviceViewModel.cs(VolChanger.ViewModel)
using System; using System.Collections.Generic; using System.Text; using System.Collections.ObjectModel; using System.ComponentModel; using System.Diagnostics; using System.Net.Http; using System.Runtime.CompilerServices; using System.Threading.Tasks; using VolChanger.View; using VolChanger.ViewModel; using VolChanger.Model; using Plugin.BLE.Abstractions; using Plugin.BLE.Abstractions.Contracts; using Plugin.BLE.Abstractions.Exceptions; using Xamarin.Forms; using Plugin.BLE.Abstractions.EventArgs; namespace VolChanger.ViewModel { public class SearchDeviceViewModel : INotifyPropertyChanged { public ObservableCollection<BTDevice> DeviceList { get; set; } public Command GetDevicesCommand { get; } public event PropertyChangedEventHandler PropertyChanged; private static PropertyChangedEventArgs SearchPropertyChangedEventArgs = new PropertyChangedEventArgs(nameof(IsSearching)); bool isSearching = false; public bool IsSearching { get { return isSearching; } set { if(isSearching == value) { return; } isSearching = value; OnPropertyChanged(nameof(IsSearching)); // CanExecute (このコマンドが実行可能かどうか)を更新 GetDevicesCommand.ChangeCanExecute(); } } public SearchDeviceViewModel() { DeviceList = new ObservableCollection<BTDevice>(); GetDevicesCommand = new Command( () => GetDevices(), // 実行する処理 () => !IsSearching); // このコマンドが実行可能の時にtrueを返す } private void GetDevices() { if (IsSearching) return; try { IsSearching = true; DeviceList.Clear(); IBTManager manager = DependencyService.Get<IBTManager>(); var list = manager.GetBondedDevices(); // await Adapter.StartScanningForDevicesAsync(); if(list != null && list.Count > 0) { foreach(var dev in list) { DeviceList.Add(dev); } } else { Application.Current.MainPage.DisplayAlert("VolChanger", "ペアリング済デバイスが見つかりませんでした。", "OK"); } } catch (Exception e) { Application.Current.MainPage.DisplayAlert("Error!", e.Message, "OK"); } finally { IsSearching = false; } } void OnPropertyChanged([CallerMemberName] string name = null) => PropertyChanged?.Invoke(this, SearchPropertyChangedEventArgs); } }
■BTDevice.cs(VolChanger.Model)
using System; using System.Collections.Generic; using System.Text; namespace VolChanger.Model { public class BTDevice { public string Name { get; set; } public string Uuid { get; set; } public string Adress { get; set; } public string Detail { get; set; } } }
■IBTManager.cs(VolChanger.Model)
using System; using System.Collections.Generic; using System.Text; using VolChanger.Model; namespace VolChanger.Model { public interface IBTManager { List<BTDevice> GetBondedDevices(); } }
■BTManager.cs(VolChanger.Android)
using System; using System.Collections.Generic; using System.Linq; using System.Text; using Android.App; using Android.Content; using Android.OS; using Android.Runtime; using Android.Views; using Android.Widget; using VolChanger.Model; using Android.Bluetooth; using Xamarin.Forms; [assembly: Dependency(typeof(VolChanger.Droid.BTManager))] namespace VolChanger.Droid { public class BTManager: IBTManager { public List<BTDevice> GetBondedDevices() { // アダプター作成 BluetoothAdapter adapter = BluetoothAdapter.DefaultAdapter; // ペアリング済みデバイスの取得 var listBondedDevices = adapter.BondedDevices; var result = new List<BTDevice>(); if (listBondedDevices != null && listBondedDevices.Count > 0) { foreach (var device in listBondedDevices) { var btDevice = new BTDevice(); btDevice.Uuid = device.GetUuids().FirstOrDefault().ToString(); // Bluetoothスピーカーのみ取得する。 if (btDevice.Uuid.Substring(4, 4).ToUpper() == "110A" || btDevice.Uuid.Substring(4, 4).ToUpper() == "110B") { btDevice.Name = device.Name; btDevice.Adress = device.Address; btDevice.Detail = string.Format("MACアドレス:{0}", btDevice.Adress); result.Add(btDevice); } } } return result; } } }
あとは「音量の調整」なんですが、ここからが本当に難しいところでしょうね。
...まあ、それは旅行から帰ってきてからの続き、ということで。