Flutter ile Bluetooth Cihazları Tarama ve Bağlantı Kurup/Kaldırma Uygulaması – 1 başlığı altında verilen kodda, import kısmında flutter_blue kutuphanesine prefix verilerek tanımlanmasının sebebi flutter_reactive_ble kutuphanesinin de BluetoothDevice sınıfına sahip olmasıdır. Hangi kutuphanenin BluetoothDevice sınıfını kullanacağımızı belirtmek için kütüphanelerin birine prefix vermemiz gerekti.
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_blue/flutter_blue.dart' as flutter_blue;
import 'package:flutter_reactive_ble/flutter_reactive_ble.dart';
import 'package:open_settings/open_settings.dart';
import 'package:permission_handler/permission_handler.dart';
flutter_blue kutuphanesine ait bir sınıf, metod veya özellik kullanıldığı zaman artık bunu belirtmemiz gerekmektedir. flutter_blue.FlutterBlue.instance veya flutter_blue.BluetoothDevice gibi kullanımlarının sebebi budur.
Uygulamanın amacı çevredeki bağlanabilecek cihazları taramak ve bu cihazlara bağlanıp, bağlı cihazlarla da bağlantıyı koparmak olduğundan iki tane boş liste tanımladık.
Bulunan cihazları listelemek için:
List<DiscoveredDevice> _discoveredDeviceList = [];
Bağlı olduğumuz cihazları listelemek için:
List<DiscoveredDevice> _connectedBluetoothDeviceList = [];
Konum ve bluetooth izinlerini uygulama başlatıldığında almak için _getBluetoothPermission(), _getLocationPermission(), _getPermissions() methodları initState içerisinde çağrıldılar.
@override
void initState() {
super.initState();
// setting devices orientation on landscape
SystemChrome.setPreferredOrientations([
DeviceOrientation.landscapeRight,
DeviceOrientation.landscapeLeft,
]);
_getBluetoothPermission();
_getLocationPermission();
_getPermissions();
}
Uygulamaya ilk defa giriş yapıldığında konum ve bluetooth izinleri verilmemiş olacağından if bloğuna ilk olarak bluetoothPermission.isDenied ve locationPermission.isDenied koşullarıyla başladık böylece izin verildikten sonra bu koşullar false döndüreceğinden if bloğu tekrar koşmayacaktır.
İzinler verildikten sonra if bloğu bluetoothPermission.isDenied koşulunu sağlamayıp false’a düştüğü için sonraki koşmalarda else bloğu içerisindeki print komutu koşacak ve konsola Not Granted yazılacak, bu print komutunu Granted olarak değiştirmeniz daha doğru olur.
Future<bool> _getBluetoothPermission() async {
var bluetoothPermission = await Permission.bluetoothScan.status;
if (bluetoothPermission.isDenied) {
if (await Permission.bluetoothScan.request().isGranted) {
if (await Permission.bluetoothConnect.request().isGranted) {
print("Blueooth Permission: Granted");
return true; // Permission granted
}
}
} else {
print("Blueooth Permission: Granted");
}
return false;
}
Future<bool> _getLocationPermission() async {
var locationPermission = await Permission.location.status;
if (locationPermission.isDenied) {
if (await Permission.location.request().isGranted) {
if (await Permission.accessMediaLocation.request().isGranted) {
print("Location Permission: Granted");
return true; // Permission granted
}
}
} else {
print("Location Permission: Granted");
}
return false;
}
Alttaki _getPermissions metodunun tanımlanmasının sebebi ise yukarıdaki gibi izinleri teker teker çağırmak yerine tüm izinleri tek seferde çağırmayı denemek içindir. if bloğu içerisindeki koşulda tüm izinler izin verilmediği sürece true döndürmesi istenmiştir ama şuanki durumda izinlerden sadece birine bile izin verildiği taktirde await Permission.location.status.isDenied && await Permission.bluetoothScan.status.isDenied ifadesi false döndürür.
Bunun için && (AND) ifadesi yerine || (OR) ifadesi kullanmamız gerekmektedir veya her iki ifadenin de başına ! işareti koyabilirsiniz. Böylece sadece tüm izinler verildiği takdirde koşulumuz false döndürür ve if bloğu koşmaz.
Future<void> _getPermissions() async {
// Requesting multiple permissions at once.
if (!await Permission.location.status.isDenied &&
!await Permission.bluetoothScan.status.isDenied) {
Map<Permission, PermissionStatus> statuses = await [
Permission.location,
Permission.bluetoothScan,
].request();
print(statuses[Permission.location]);
print(“\n”);
print(statuses[Permission.bluetoothScan]);
}
}
Çevredeki cihazları taramamız için gereken şartlar sadece izinler değil, aynı zamanda taramaya çalıştığımız zamanda hem bluetooth hem de konum özelliklerinin o anda açık olması gerekmektedir. Bunu kontrol etmek için de _chechkIfBluetoothIsOn ve _chechkIfLocationIsOn methodlarını tanımladık.
Future<bool> _chechkIfBluetoothIsOn() async {
// Check bluetooth service status
var isBluetoothOn = await Permission.bluetooth.serviceStatus.isEnabled;
if (!isBluetoothOn) {
// propmpt user to enable the bluetooth if the bluetooth is off
showDialog(
context: context,
builder: (_) => AlertDialog(
title:
Text("Bluetooth Özelliği ${isBluetoothOn ? "Açık" : "Kapalı"}"),
content: const Text(
"Bu özelliği kullanmak için bluetooth özelliğinin açık olması gerekir."),
actions: [
ElevatedButton(
onPressed: () =>
Navigator.of(context, rootNavigator: true).pop(false),
child: Text(isBluetoothOn ? "Kapat" : "Vazgeç")),
ElevatedButton(
// make the button not intractable when the location is on
onPressed: () async => isBluetoothOn
? null
: {
Navigator.of(context, rootNavigator: true).pop(),
await OpenSettings.openBluetoothSetting(),
},
child: Text(isBluetoothOn ? "" : "Aç")),
],
elevation: 12.0,
backgroundColor: Colors.white,
),
barrierDismissible: true,
);
} else {
//dismiss dialog box
}
return isBluetoothOn;
}
Burada bluetooth servisi açık değilse kullanıcıyı AlertDialog ile uyarıyoruz ve bluetooth servisini açması için yönlendiriyoruz.
await OpenSettings.openBluetoothSetting() satırının amacı Aç tuşuna tıklandığında kullanıcıyı bluetooth ayarlarına yönlendirmek, bu methodu ‘open_settings‘ kutuphanesini import ederek kullanabiliyoruz.
Navigator.of(context, rootNavigator: true).pop(), satırı ise kullanıcıyı yönlendirdiğimizde AlertDialog’u kapatmak içindir, böylece kullanıcı izin verip uygulamaya döndüğünde AlertBox ile karşılaşmayacak.
İlk başlıkta verilen kodda Scan Devices ve List Connected Devices tuşlarında hem if koşulunda hem de ek olarak onPressed metodu altında bluetooth ve konum izinleri istendiğinden iki tane AlertDialog üst üste oluşturulmaktadır. Bu durumu çözmek için _chechkIfBluetoothIsOn ve _checkIfLocationIsOn satırları “Scan Devices” ve “List Connected Devices” tuşlarının onPressed metodundan silinebilir.
TextButton(
onPressed: () async {
_getPermissions();
/* _chechkIfBluetoothIsOn();
_checkIfLocationIsOn(); */
if (await _chechkIfBluetoothIsOn() &&
await _checkIfLocationIsOn()) {
_scanForAvaileableBluetoothDevices();
} else {
print(
"Blueooth veya Location özellikleri açık olmadığından tarama yapılamadı.");
}
},
child: const Text('Scan Devices'),
Yukarıda gösterildiği gibi bu iki satırı yorum satırı da yapabilirsiniz, aynı durum “List Connected Devices” tuşu için de geçerlidir ve aynı işlemi o tuş için de uygulayabilirsiniz.