BluetoothAdapter — kelas sistem Android yang mewakili adaptor Bluetooth lokal perangkat. BluetoothAdapter adalah titik masuk untuk semua operasi Bluetooth di Android: menyalakan radio (enable), memindai perangkat, mengelola visibilitas (setScanMode), mendapatkan informasi tentang adaptor (getName, getAddress, getState). Kelas tersedia melalui BluetoothManager.getAdapter() (API 18+) atau BluetoothAdapter.getDefaultAdapter(). Pada perangkat tanpa modul Bluetooth, getDefaultAdapter() mengembalikan null. Menurut Android Developers, 2026, BluetoothAdapter adalah komponen wajib untuk setiap aplikasi BLE di Android, mulai dari API 5.
Poin utama
BluetoothAdapter mewakili adaptor Bluetooth fisik perangkat Android. Setiap perangkat memiliki tepat satu adaptor (pengecualian — Android Automotive dengan beberapa chip Bluetooth, di mana BluetoothManager.getAdapterList() digunakan). BluetoothAdapter mengenkapsulasi status radio: STATE_OFF (0), STATE_TURNING_ON (1), STATE_ON (2), STATE_TURNING_OFF (3). Status dilacak melalui BroadcastReceiver pada ACTION_STATE_CHANGED.
Mendapatkan instance BluetoothAdapter adalah langkah pertama setiap aplikasi BLE di Android. Metode yang direkomendasikan — melalui BluetoothManager.getAdapter() dari API 18+. Alternatif — metode statis BluetoothAdapter.getDefaultAdapter(), yang berfungsi dari API 5 tetapi kurang fleksibel. Kedua metode mengembalikan null jika perangkat tidak memiliki modul Bluetooth (tablet Wi-Fi-only, emulator). Pemeriksaan null wajib dilakukan: aplikasi harus menyelesaikan dirinya dengan benar atau menonaktifkan fungsi BLE.
// Mendapatkan BluetoothAdapter (direkomendasikan)
import android.bluetooth.BluetoothAdapter
import android.bluetooth.BluetoothManager
import android.content.Context
class BluetoothHelper(context: Context) {
private val bluetoothAdapter: BluetoothAdapter?
init {
// Metode 1: melalui BluetoothManager (API 18+)
val manager = context.getSystemService(Context.BLUETOOTH_SERVICE)
as BluetoothManager?
bluetoothAdapter = manager?.adapter
// Metode 2: melalui metode statis (API 5+)
// val adapter = BluetoothAdapter.getDefaultAdapter()
// Pemeriksaan null
if (bluetoothAdapter == null) {
// Perangkat tidak mendukung Bluetooth
}
}
// Periksa status Bluetooth
fun isBluetoothEnabled(): Boolean {
return bluetoothAdapter?.isEnabled == true
}
// Dapatkan informasi adaptor
fun getAdapterInfo(): Map<String, String> {
return mapOf(
"name" to (bluetoothAdapter?.name ?: "N/A"),
"address" to (bluetoothAdapter?.address ?: "N/A"),
"state" to (bluetoothAdapter?.state?.toString() ?: "N/A"),
"scanMode" to (bluetoothAdapter?.scanMode?.toString() ?: "N/A")
)
}
}
Kelas BluetoothHelper menunjukkan cara mendapatkan BluetoothAdapter melalui BluetoothManager dengan pemeriksaan null berikutnya. isBluetoothEnabled memeriksa isEnabled — kondisi wajib sebelum operasi BLE apa pun. getAdapterInfo mengembalikan nama perangkat, alamat MAC, status dan mode visibilitas. Penting: pada Android 10+ (API 29+) layanan sistem mengembalikan alamat MAC palsu (02:00:00:00:00:00) jika aplikasi tidak memiliki izin BLUETOOTH_ADMIN dan ACCESS_FINE_LOCATION.
BluetoothAdapter menyediakan metode untuk mengelola radio Bluetooth. enable() dan disable() menyalakan dan mematikan Bluetooth. Kedua metode memerlukan izin BLUETOOTH_ADMIN dan dijalankan secara asinkron: setelah pemanggilan enable(), sistem memulai proses menyalakan radio, status dilacak melalui BroadcastReceiver dengan aksi BluetoothAdapter.ACTION_STATE_CHANGED. Sejak Android 10+, enable() dan disable() memerlukan izin sistem tambahan — aplikasi biasa tidak dapat mengelola Bluetooth secara terprogram tanpa dialog pengguna.
getState() mengembalikan status adaptor saat ini: STATE_OFF (10), STATE_TURNING_ON (11), STATE_ON (12), STATE_TURNING_OFF (13). getAddress() mengembalikan alamat MAC adaptor Bluetooth. Pada Android 6+, untuk meminta alamat MAC diperlukan ACCESS_FINE_LOCATION (atau ACCESS_COARSE_LOCATION untuk API 31+). Pada Android 10+, getAddress() mengembalikan alamat konstan 02:00:00:00:00:00 — alamat asli tidak tersedia melalui API publik.
getScanMode() menentukan mode visibilitas adaptor: SCAN_MODE_NONE (tidak terlihat), SCAN_MODE_CONNECTABLE (terlihat untuk yang terhubung), SCAN_MODE_CONNECTABLE_DISCOVERABLE (terlihat untuk semua). Mode visibilitas dibatasi waktu (biasanya 60–300 detik) untuk keamanan. Mengatur mode melalui setScanMode() memerlukan BLUETOOTH_ADMIN dan izin sistem pada Android 10+.
| Metode | Deskripsi | Izin yang diperlukan |
|---|---|---|
| enable() | Menyalakan radio Bluetooth | BLUETOOTH_ADMIN |
| disable() | Mematikan radio Bluetooth | BLUETOOTH_ADMIN |
| getState() | Status adaptor saat ini | BLUETOOTH |
| getAddress() | Alamat MAC adaptor | BLUETOOTH + ACCESS_FINE_LOCATION (API 23+) |
| getScanMode() | Mode visibilitas perangkat | BLUETOOTH |
| setScanMode() | Mengatur mode visibilitas | BLUETOOTH_ADMIN |
BluetoothAdapter mendukung dua jenis pemindaian. Pemindaian Bluetooth klasik (BR/EDR) dimulai melalui startDiscovery() — mendeteksi perangkat Bluetooth dari semua jenis, termasuk telepon dan headset. Hasil dikembalikan melalui BroadcastReceiver dengan aksi BluetoothDevice.ACTION_FOUND. startDiscovery() bekerja selama 12 detik dan dapat dibatalkan dengan memanggil cancelDiscovery(). Metode ini sudah usang untuk BLE — gunakan BluetoothLeScanner.
Pemindaian BLE melalui BluetoothAdapter dilakukan dengan metode usang startLeScan(LeScanCallback). Mulai API 21, Google merekomendasikan penggunaan BluetoothLeScanner, yang diperoleh melalui BluetoothAdapter.getBluetoothLeScanner(). BluetoothLeScanner menyediakan API yang lebih fleksibel: konfigurasi pemindaian melalui ScanSettings (mode, callback type, match mode), pemfilteran melalui ScanFilter (berdasarkan UUID layanan, nama perangkat, alamat MAC) dan dukungan PendingIntent untuk pemindaian latar belakang.
// API pemindaian BLE lama (usang) vs baru
import android.bluetooth.BluetoothAdapter
import android.bluetooth.le.*
class BLEScanner(private val bluetoothAdapter: BluetoothAdapter?) {
// USANG: startLeScan (API 18+, API 21)
@Suppress("DEPRECATION")
fun legacyScan() {
bluetoothAdapter?.startLeScan { device, rssi, scanRecord ->
print("Found (LE Scan): $device.name, RSSI: $rssi")
}
}
// BARU: BluetoothLeScanner (API 21+)
fun modernScan() {
val scanner = bluetoothAdapter?.bluetoothLeScanner
?: return
// Pengaturan pemindaian
val settings = ScanSettings.Builder()
.setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
.setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES)
.setMatchMode(ScanSettings.MATCH_MODE_AGGRESSIVE)
.build()
// Filter berdasarkan layanan (UUID detak jantung)
val filters = listOf(
ScanFilter.Builder()
.setServiceUuid(ParcelUuid.fromString("0000180D-0000-1000-8000-00805F9B34FB"))
.build()
)
// Mulai pemindaian
scanner.startScan(filters, settings, object : ScanCallback() {
override fun onScanResult(callbackType: Int, result: ScanResult) {
val device = result.device
val rssi = result.rssi
print("Found (BLE Scanner): ${device.name}, RSSI: $rssi, address: ${device.address}")
}
override fun onScanFailed(errorCode: Int) {
print("Scan error: $errorCode")
}
})
}
}
Kelas BLEScanner membandingkan startLeScan yang usang dan BluetoothLeScanner modern. Di legacyScan, callback LeScanCallback menerima BluetoothDevice, RSSI dan scanRecord mentah. Di modernScan, ScanSettings digunakan dengan mode LOW_LATENCY (kecepatan deteksi maksimum) dan ScanFilter untuk memfilter berdasarkan UUID layanan detak jantung (Heart Rate Service 0x180D). ScanCallback menyediakan onScanResult dengan objek ScanResult yang berisi informasi luas: nama, RSSI, data iklan, jenis koneksi.
BluetoothManager — layanan sistem Android, diperkenalkan di API 18 (Android 4.3), untuk mengelola operasi Bluetooth. Sebelum API 18, satu-satunya cara untuk mendapatkan BluetoothAdapter adalah metode statis getDefaultAdapter(). BluetoothManager menyediakan: adapter — instance BluetoothAdapter, getConnectedDevices() — daftar perangkat terhubung, getDevicesMatchingConnectionStates() — pemfilteran berdasarkan status. BluetoothManager juga digunakan untuk mendapatkan BluetoothLeScanner pada API lama.
Keunggulan BluetoothManager dibandingkan panggilan langsung BluetoothAdapter.getDefaultAdapter(): aplikasi tidak bergantung pada singleton statis, manajer mempertimbangkan konteks (Activity/Application), yang penting untuk skenario multi-akun Android Enterprise. Pada Android Automotive dengan beberapa chip Bluetooth, BluetoothManager.getAdapterList() mengembalikan semua adaptor yang tersedia — BluetoothAdapter.getDefaultAdapter() hanya mengembalikan yang pertama.
// Menggunakan BluetoothManager untuk BLE
class BLEConnection(context: Context) {
private val bluetoothManager: BluetoothManager =
context.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
private val adapter: BluetoothAdapter? = bluetoothManager.adapter
// Dapatkan daftar perangkat BLE yang terhubung
fun getConnectedDevices(): List<BluetoothDevice> {
return bluetoothManager.getConnectedDevices(
BluetoothProfile.GATT
)
}
// Filter perangkat berdasarkan status
fun getDevicesByState(states: IntArray): List<BluetoothDevice> {
return bluetoothManager.getDevicesMatchingConnectionStates(
BluetoothProfile.GATT, states
)
}
// Periksa dukungan BLE pada perangkat
fun isBLESupported(): Boolean {
return adapter != null && context.packageManager
.hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)
}
// Minta menyalakan Bluetooth melalui dialog sistem
fun requestEnableBluetooth(activity: MainActivity) {
if (adapter?.isEnabled == false) {
val intent = Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE)
activity.startActivityForResult(intent, REQUEST_ENABLE_BT)
}
}
companion object {
const val REQUEST_ENABLE_BT = 1001
}
}
Kelas BLEConnection menggunakan BluetoothManager untuk akses ke BluetoothAdapter dan mendapatkan daftar perangkat GATT yang terhubung. isBLESupported memeriksa keberadaan radio BLE melalui PackageManager.hasSystemFeature(FEATURE_BLUETOOTH_LE) — pemeriksaan penting untuk perangkat dengan Bluetooth Classic tanpa BLE. requestEnableBluetooth menampilkan dialog sistem untuk menyalakan Bluetooth (ACTION_REQUEST_ENABLE), tanpa memerlukan izin BLUETOOTH_ADMIN — ini adalah satu-satunya cara legal untuk menyalakan Bluetooth di Android 10+ tanpa aplikasi sistem.
Izin untuk BluetoothAdapter telah berevolusi dengan setiap versi Android. Pada Android 6–11 (API 23–30) untuk pemindaian BLE, BLUETOOTH, BLUETOOTH_ADMIN dan ACCESS_FINE_LOCATION wajib. Pada Android 12+ (API 31+) Google telah membagi izin: ACCESS_FINE_LOCATION digantikan oleh BLUETOOTH_SCAN (pemindaian), BLUETOOTH_CONNECT (koneksi), BLUETOOTH_ADVERTISE (iklan). Untuk mencari perangkat BLE, BLUETOOTH_SCAN sudah cukup, lokasi tidak diperlukan.
Tabel izin berdasarkan versi Android:
| Operasi | API 23–30 | API 31+ |
|---|---|---|
| Pemindaian BLE | ACCESS_FINE_LOCATION | BLUETOOTH_SCAN (tanpa lokasi) |
| Koneksi BLE | ACCESS_FINE_LOCATION | BLUETOOTH_CONNECT |
| Iklan BLE | ACCESS_FINE_LOCATION | BLUETOOTH_ADVERTISE |
| Menyalakan/mematikan | BLUETOOTH_ADMIN | BLUETOOTH_ADMIN (sistem) |
| Mendapatkan alamat MAC | ACCESS_FINE_LOCATION | BLUETOOTH_CONNECT (alamat palsu) |
Pada Android 12+, semua izin Bluetooth adalah izin runtime — harus diminta saat runtime melalui ActivityResultContracts.RequestMultiplePermissions. BLUETOOTH_SCAN dan BLUETOOTH_ADVERTISE termasuk dalam grup NEARBY_DEVICES, BLUETOOTH_CONNECT — grup yang sama. Izin BLUETOOTH dan BLUETOOTH_ADMIN tetap di manifes untuk kompatibilitas dengan API < 31, tetapi untuk API 31+ diabaikan — Google memerlukan penyebutan eksplisit izin baru.
// Meminta izin Bluetooth di Android 12+
import android.Manifest
import android.content.pm.PackageManager
import android.os.Build
import androidx.core.content.ContextCompat
class PermissionHelper(context: Context) {
fun getRequiredPermissions(): Array<String> {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
// Android 12+: pemindaian BLE
arrayOf(
Manifest.permission.BLUETOOTH_SCAN,
Manifest.permission.BLUETOOTH_CONNECT,
Manifest.permission.BLUETOOTH_ADVERTISE
)
} else {
// Android 6-11: pemindaian BLE
arrayOf(
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.BLUETOOTH,
Manifest.permission.BLUETOOTH_ADMIN
)
}
}
// Periksa semua izin
fun hasPermissions(context: Context): Boolean {
return getRequiredPermissions().all { permission ->
ContextCompat.checkSelfPermission(context, permission)
== PackageManager.PERMISSION_GRANTED
}
}
}
Kelas PermissionHelper mengembalikan set izin yang benar tergantung pada level API. Pada Android 12+, BLUETOOTH_SCAN, BLUETOOTH_CONNECT, BLUETOOTH_ADVERTISE digunakan tanpa lokasi. Pada Android 6–11 untuk pemindaian BLE masih diperlukan ACCESS_FINE_LOCATION. Pengembang harus mempertimbangkan kedua skenario saat meminta izin melalui ActivityResultContracts atau RxPermissions.
Contoh lengkap aplikasi BLE di Kotlin yang menggunakan BluetoothAdapter untuk memindai, menghubungkan dan membaca data perangkat BLE. Contoh ini mencakup pemeriksaan izin, mendapatkan adaptor, pemindaian melalui BluetoothLeScanner dan koneksi melalui BluetoothDevice.connectGatt.
// Manajer BLE lengkap di Kotlin
class BLEManager(private val context: Context) {
private val bluetoothManager: BluetoothManager =
context.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
private val adapter: BluetoothAdapter? = bluetoothManager.adapter
private var scanner: BluetoothLeScanner? = adapter?.bluetoothLeScanner
private var gatt: BluetoothGatt? = null
// 1. Penemuan layanan
fun canScan(): Boolean {
return adapter?.isEnabled == true
&& scanner != null
&& PermissionHelper(context).hasPermissions(context)
}
// 2. Pemindaian dengan filter
fun startScanning(callback: (BluetoothDevice, Int) -> Unit) {
if (!canScan()) return
val settings = ScanSettings.Builder()
.setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
.setReportDelay(0)
.build()
scanner?.startScan(null, settings, object : ScanCallback() {
override fun onScanResult(callbackType: Int, result: ScanResult) {
callback(result.device, result.rssi)
}
})
}
// 3. Hentikan pemindaian
fun stopScanning() {
scanner?.stopScan(object : ScanCallback() {})
}
// 4. Hubungkan ke perangkat BLE
fun connectToDevice(device: BluetoothDevice) {
if (adapter?.isEnabled != true) return
gatt = device.connectGatt(
context,
false,
object : BluetoothGattCallback() {
override fun onConnectionStateChange(gatt: BluetoothGatt, status: Int, newState: Int) {
if (newState == BluetoothProfile.STATE_CONNECTED) {
gatt.discoverServices()
}
}
override fun onServicesDiscovered(gatt: BluetoothGatt, status: Int) {
// Layanan ditemukan, dapat membaca karakteristik
}
},
BluetoothDevice.TRANSPORT_LE
)
}
// 5. Lepaskan sumber daya
fun disconnect() {
gatt?.disconnect()
gatt?.close()
gatt = null
}
}
Manajer BLEManager menggabungkan siklus BLE lengkap di Android: pemeriksaan adaptor dan izin (canScan), pemindaian melalui BluetoothLeScanner dengan ScanSettings (startScanning), koneksi melalui BluetoothDevice.connectGatt dengan TRANSPORT_LE (connectToDevice), pelepasan sumber daya (disconnect). Semua operasi BLE dijalankan di thread UI — Android memanggil callback BluetoothGattCallback di thread utama. Untuk tugas BLE yang produktif, disarankan untuk memindahkan operasi GATT ke HandlerThread latar belakang.
Pertanyaan yang sering diajukan
BluetoothAdapter — kelas yang mewakili adaptor Bluetooth lokal perangkat Android. Diperoleh melalui BluetoothManager.getAdapter() (API 18+) atau BluetoothAdapter.getDefaultAdapter(). Menyediakan metode menyalakan/mematikan Bluetooth, memindai perangkat, mengelola visibilitas dan mendapatkan informasi tentang adaptor. Mengembalikan null pada perangkat tanpa modul Bluetooth.
Penyebabnya adalah tidak adanya radio Bluetooth pada perangkat. Karakteristik untuk tablet Wi-Fi-only, emulator Android dan Android TV tanpa Bluetooth. Periksa getDefaultAdapter() untuk null saat memulai aplikasi dan nonaktifkan fungsi BLE jika adaptor tidak ada. Alternatif — pemeriksaan melalui PackageManager.hasSystemFeature(FEATURE_BLUETOOTH_LE) untuk penentuan yang lebih akurat.
BluetoothLeScanner (API 21+) — API modern untuk pemindaian BLE dengan dukungan ScanFilter, ScanSettings dan PendingIntent. startLeScan (API 18+) — metode usang BluetoothAdapter yang menerima LeScanCallback dengan set data terbatas. BluetoothLeScanner direkomendasikan oleh Google untuk semua proyek baru, memungkinkan pemfilteran berdasarkan UUID, konfigurasi mode konsumsi daya dan bekerja di latar belakang melalui PendingIntent.
Di Android 12+ (API 31) untuk pemindaian BLE diperlukan BLUETOOTH_SCAN, untuk koneksi — BLUETOOTH_CONNECT, untuk iklan — BLUETOOTH_ADVERTISE. Izin lokasi ACCESS_FINE_LOCATION tidak lagi diperlukan untuk BLE. Di Android 6–11 diperlukan ACCESS_FINE_LOCATION. Semua izin diminta saat runtime melalui ActivityResultContracts.
Sejak Android 10+, menyalakan Bluetooth secara terprogram tanpa dialog sistem hanya tersedia untuk aplikasi sistem dengan izin BLUETOOTH_PRIVILEGED. Aplikasi biasa harus menggunakan Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE) dan startActivityForResult — pengguna mengonfirmasi penyalakan di dialog sistem. BLUETOOTH_ADMIN di manifes tidak memberikan hak enable() di Android 10+.
Kesimpulan
Kami akan mengembangkan aplikasi seluler turnkey
IT Sectr membuat aplikasi iOS dan Android untuk startup dan bisnis sejak 2017. Kami akan memberi saran dan mengusulkan solusi terbaik.
Baca juga