BluetoothAdapter は、デバイスのローカルBluetoothアダプターを表すシステムAndroidクラスです。BluetoothAdapterは、AndroidでのすべてのBluetooth操作のエントリポイントです:ラジオの有効化(enable)、デバイスのスキャン、可視性の管理(setScanMode)、アダプター情報の取得(getName、getAddress、getState)。このクラスは、BluetoothManager.getAdapter()(API 18+)またはBluetoothAdapter.getDefaultAdapter()を介して利用できます。Bluetoothモジュールのないデバイスでは、getDefaultAdapter()はnullを返します。Android Developers、2026によると、BluetoothAdapterは、API 5以降のAndroid上のBLEアプリケーションに必須のコンポーネントです。
重要ポイント
BluetoothAdapter は、Androidデバイスの物理的なBluetoothアダプターを表します。各デバイスには正確に1つのアダプターがあります(複数のBluetoothチップを持つAndroid Automotiveは例外で、BluetoothManager.getAdapterList()を使用します)。BluetoothAdapterはラジオの状態をカプセル化します:STATE_OFF(0)、STATE_TURNING_ON(1)、STATE_ON(2)、STATE_TURNING_OFF(3)。状態はACTION_STATE_CHANGEDのBroadcastReceiverを介して追跡されます。
BluetoothAdapterインスタンスの取得は、Android上のBLEアプリケーションの最初のステップです。推奨される方法は、API 18+からBluetoothManager.getAdapter()を介するものです。代替方法は静的メソッドBluetoothAdapter.getDefaultAdapter()で、API 5から動作しますが、柔軟性に欠けます。どちらのメソッドも、デバイスにBluetoothモジュールがない場合(Wi-Fiのみのタブレット、エミュレーター)はnullを返します。nullチェックは必須です:アプリケーションは正常に終了するか、BLE機能を無効にする必要があります。
// BluetoothAdapterの取得(推奨)
import android.bluetooth.BluetoothAdapter
import android.bluetooth.BluetoothManager
import android.content.Context
class BluetoothHelper(context: Context) {
private val bluetoothAdapter: BluetoothAdapter?
init {
// 方法1:BluetoothManager経由(API 18+)
val manager = context.getSystemService(Context.BLUETOOTH_SERVICE)
as BluetoothManager?
bluetoothAdapter = manager?.adapter
// 方法2:静的メソッド経由(API 5+)
// val adapter = BluetoothAdapter.getDefaultAdapter()
// nullチェック
if (bluetoothAdapter == null) {
// デバイスがBluetoothをサポートしていません
}
}
// Bluetooth状態を確認
fun isBluetoothEnabled(): Boolean {
return bluetoothAdapter?.isEnabled == true
}
// アダプター情報を取得
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")
)
}
}
BluetoothHelper クラスは、BluetoothManagerを介してBluetoothAdapterを取得し、その後にnullチェックを行う方法を示しています。isBluetoothEnabledはisEnabledをチェックします — BLE操作の前の必須条件です。getAdapterInfoはデバイス名、MACアドレス、状態、可視性モードを返します。重要:Android 10+(API 29+)では、アプリケーションにBLUETOOTH_ADMINとACCESS_FINE_LOCATIONの権限がない場合、システムサービスは偽のMACアドレス(02:00:00:00:00:00)を返します。
BluetoothAdapter はBluetoothラジオを制御するメソッドを提供します。enable()とdisable()はBluetoothをオン/オフにします。どちらのメソッドもBLUETOOTH_ADMIN権限が必要で、非同期に実行されます:enable()を呼び出した後、システムはラジオの有効化プロセスを開始し、状態はBluetoothAdapter.ACTION_STATE_CHANGEDアクションのBroadcastReceiverを介して追跡されます。Android 10+では、enable()とdisable()には追加のシステム特権が必要です — 通常のアプリケーションはユーザーダイアログなしでプログラムによってBluetoothを制御できません。
getState() は現在のアダプター状態を返します:STATE_OFF(10)、STATE_TURNING_ON(11)、STATE_ON(12)、STATE_TURNING_OFF(13)。getAddress() はBluetoothアダプターのMACアドレスを返します。Android 6+では、MACアドレスを要求するためにACCESS_FINE_LOCATION(またはAPI 31+の場合はACCESS_COARSE_LOCATION)が必要です。Android 10+では、getAddress()は定数アドレス02:00:00:00:00:00を返します — 実際のアドレスは公開APIを介して利用できません。
getScanMode() はアダプターの可視性モードを決定します:SCAN_MODE_NONE(不可視)、SCAN_MODE_CONNECTABLE(接続済みデバイスに可視)、SCAN_MODE_CONNECTABLE_DISCOVERABLE(すべてに可視)。可視性モードはセキュリティのために時間制限があります(通常60~300秒)。setScanMode()を介してモードを設定するには、Android 10+でBLUETOOTH_ADMINとシステム権限が必要です。
| メソッド | 説明 | 必要な権限 |
|---|---|---|
| enable() | Bluetoothラジオをオンにする | BLUETOOTH_ADMIN |
| disable() | Bluetoothラジオをオフにする | BLUETOOTH_ADMIN |
| getState() | 現在のアダプター状態 | BLUETOOTH |
| getAddress() | アダプターのMACアドレス | BLUETOOTH + ACCESS_FINE_LOCATION(API 23+) |
| getScanMode() | デバイスの可視性モード | BLUETOOTH |
| setScanMode() | 可視性モードの設定 | BLUETOOTH_ADMIN |
BluetoothAdapter は2種類のスキャンをサポートしています。クラシックBluetoothスキャン(BR/EDR)はstartDiscovery()を介して起動します — 電話やヘッドセットを含むすべてのタイプのBluetoothデバイスを検出します。結果はBluetoothDevice.ACTION_FOUNDアクションのBroadcastReceiverを介して返されます。startDiscovery()は12秒間動作し、cancelDiscovery()を呼び出すことでキャンセルできます。このメソッドはBLEでは非推奨です — BluetoothLeScannerを使用してください。
BluetoothAdapterを介したBLEスキャンは、非推奨のメソッドstartLeScan(LeScanCallback)を使用します。API 21以降、GoogleはBluetoothAdapter.getBluetoothLeScanner()を介して取得されるBluetoothLeScannerの使用を推奨しています。BluetoothLeScannerはより柔軟なAPIを提供します:ScanSettingsを介したスキャン設定(モード、コールバックタイプ、マッチモード)、ScanFilterを介したフィルタリング(サービスUUID、デバイス名、MACアドレスによる)、およびバックグラウンドスキャンのためのPendingIntentのサポート。
// 古い(非推奨)BLEスキャンAPI vs 新しいAPI
import android.bluetooth.BluetoothAdapter
import android.bluetooth.le.*
class BLEScanner(private val bluetoothAdapter: BluetoothAdapter?) {
// 非推奨:startLeScan(API 18+、API 21)
@Suppress("DEPRECATION")
fun legacyScan() {
bluetoothAdapter?.startLeScan { device, rssi, scanRecord ->
print("Found (LE Scan): $device.name, RSSI: $rssi")
}
}
// 新:BluetoothLeScanner(API 21+)
fun modernScan() {
val scanner = bluetoothAdapter?.bluetoothLeScanner
?: return
// スキャン設定
val settings = ScanSettings.Builder()
.setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
.setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES)
.setMatchMode(ScanSettings.MATCH_MODE_AGGRESSIVE)
.build()
// サービスでフィルタリング(心拍数UUID)
val filters = listOf(
ScanFilter.Builder()
.setServiceUuid(ParcelUuid.fromString("0000180D-0000-1000-8000-00805F9B34FB"))
.build()
)
// スキャン開始
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")
}
})
}
}
BLEScanner クラスは、非推奨のstartLeScanと最新のBluetoothLeScannerを比較しています。legacyScanでは、LeScanCallbackはBluetoothDevice、RSSI、および生のscanRecordを受け取ります。modernScanでは、LOW_LATENCYモード(最大検出速度)のScanSettingsと、心拍数サービスUUID(0x180D)でフィルタリングするScanFilterが使用されます。ScanCallbackは、拡張情報を含むScanResultオブジェクトを提供します:名前、RSSI、アドバタイズデータ、接続タイプ。
BluetoothManager は、Bluetooth操作を管理するためにAPI 18(Android 4.3)で導入されたシステムAndroidサービスです。API 18より前は、BluetoothAdapterを取得する唯一の方法は静的メソッドgetDefaultAdapter()でした。BluetoothManagerは以下を提供します:adapter — BluetoothAdapterインスタンス、getConnectedDevices() — 接続済みデバイスのリスト、getDevicesMatchingConnectionStates() — 状態によるフィルタリング。BluetoothManagerは、古いAPIでBluetoothLeScannerを取得するためにも使用されます。
BluetoothManagerの利点 BluetoothAdapter.getDefaultAdapter()を直接呼び出す場合と比較して:アプリケーションは静的シングルトンに依存せず、マネージャーはコンテキスト(Activity/Application)を尊重します。これはAndroid Enterpriseのマルチアカウントシナリオにとって重要です。複数のBluetoothチップを備えたAndroid Automotiveでは、BluetoothManager.getAdapterList()はすべての利用可能なアダプターを返します — BluetoothAdapter.getDefaultAdapter()は最初のもののみを返します。
// BLEにBluetoothManagerを使用
class BLEConnection(context: Context) {
private val bluetoothManager: BluetoothManager =
context.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
private val adapter: BluetoothAdapter? = bluetoothManager.adapter
// 接続済みBLEデバイスリストを取得
fun getConnectedDevices(): List<BluetoothDevice> {
return bluetoothManager.getConnectedDevices(
BluetoothProfile.GATT
)
}
// 状態でデバイスをフィルタリング
fun getDevicesByState(states: IntArray): List<BluetoothDevice> {
return bluetoothManager.getDevicesMatchingConnectionStates(
BluetoothProfile.GATT, states
)
}
// デバイスのBLEサポートを確認
fun isBLESupported(): Boolean {
return adapter != null && context.packageManager
.hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)
}
// システムダイアログ経由でBluetooth有効化を要求
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
}
}
BLEConnection クラスは、BluetoothManagerを使用してBluetoothAdapterにアクセスし、接続済みのGATTデバイスのリストを取得します。isBLESupportedは、PackageManager.hasSystemFeature(FEATURE_BLUETOOTH_LE)を介してBLEラジオの存在をチェックします — BLEなしのBluetooth Classicデバイスにとって重要なチェックです。requestEnableBluetoothは、Bluetoothを有効にするシステムダイアログ(ACTION_REQUEST_ENABLE)を表示し、BLUETOOTH_ADMIN権限は必要ありません — これはシステムアプリなしでAndroid 10+でBluetoothを有効にする唯一の合法的な方法です。
権限 BluetoothAdapterの権限は、Androidのバージョンごとに進化してきました。Android 6〜11(API 23〜30)では、BLEスキャンにBLUETOOTH、BLUETOOTH_ADMIN、およびACCESS_FINE_LOCATIONが必須です。Android 12+(API 31+)では、Googleは権限を分割しました:ACCESS_FINE_LOCATIONはBLUETOOTH_SCAN(スキャン)、BLUETOOTH_CONNECT(接続)、BLUETOOTH_ADVERTISE(アドバタイズ)に置き換えられました。BLEデバイスの検出には、BLUETOOTH_SCANで十分で、位置情報は必要ありません。
権限テーブル Androidバージョン別:
| 操作 | API 23–30 | API 31+ |
|---|---|---|
| BLEスキャン | ACCESS_FINE_LOCATION | BLUETOOTH_SCAN(位置情報なし) |
| BLE接続 | ACCESS_FINE_LOCATION | BLUETOOTH_CONNECT |
| BLEアドバタイズ | ACCESS_FINE_LOCATION | BLUETOOTH_ADVERTISE |
| 有効化/無効化 | BLUETOOTH_ADMIN | BLUETOOTH_ADMIN(システム) |
| MACアドレス取得 | ACCESS_FINE_LOCATION | BLUETOOTH_CONNECT(偽のアドレス) |
Android 12+では、すべてのBluetooth権限はランタイム権限です — ActivityResultContracts.RequestMultiplePermissionsを介してランタイムで要求する必要があります。BLUETOOTH_SCANとBLUETOOTH_ADVERTISEはNEARBY_DEVICESグループに属し、BLUETOOTH_CONNECTは同じグループに属します。BLUETOOTHとBLUETOOTH_ADMINの権限はAPI < 31との互換性のためにマニフェストに残りますが、API 31+では無視されます — Googleは新しい権限を明示的に指定する必要があります。
// Android 12+でBluetooth権限を要求
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+:BLE-
arrayOf(
Manifest.permission.BLUETOOTH_SCAN,
Manifest.permission.BLUETOOTH_CONNECT,
Manifest.permission.BLUETOOTH_ADVERTISE
)
} else {
// Android 6-11:BLE
arrayOf(
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.BLUETOOTH,
Manifest.permission.BLUETOOTH_ADMIN
)
}
}
// すべての権限を確認
fun hasPermissions(context: Context): Boolean {
return getRequiredPermissions().all { permission ->
ContextCompat.checkSelfPermission(context, permission)
== PackageManager.PERMISSION_GRANTED
}
}
}
PermissionHelper クラスは、APIレベルに応じて正しい権限セットを返します。Android 12+では、位置情報なしのBLUETOOTH_SCAN、BLUETOOTH_CONNECT、BLUETOOTH_ADVERTISEが使用されます。Android 6〜11では、BLEスキャンにまだACCESS_FINE_LOCATIONが必要です。開発者は、ActivityResultContractsまたはRxPermissionsを介して権限を要求する際に、両方のシナリオを考慮する必要があります。
完全な例 BluetoothAdapterを使用してBLEデバイスをスキャン、接続、データ読み取りを行うKotlinのBLEアプリケーションの例です。この例では、権限チェック、アダプターの取得、BluetoothLeScannerを介したスキャン、BluetoothDevice.connectGattを介した接続をカバーしています。
// Kotlinの完全なBLEマネージャー
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. サービス検出
fun canScan(): Boolean {
return adapter?.isEnabled == true
&& scanner != null
&& PermissionHelper(context).hasPermissions(context)
}
// 2. フィルター付き
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. スキャン停止
fun stopScanning() {
scanner?.stopScan(object : ScanCallback() {})
}
// 4. 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) {
// サービスが見つかりました、特性を読み取れます
}
},
BluetoothDevice.TRANSPORT_LE
)
}
// 5. リソースを解放
fun disconnect() {
gatt?.disconnect()
gatt?.close()
gatt = null
}
}
BLEManager クラスは、Androidでの完全なBLEサイクルを統合します:アダプターと権限のチェック(canScan)、ScanSettingsを使用したBluetoothLeScannerを介したスキャン(startScanning)、TRANSPORT_LEを使用したBluetoothDevice.connectGattを介した接続(connectToDevice)、リソースの解放(disconnect)。すべてのBLE操作はUIスレッドで実行されます — AndroidはメインスレッドでBluetoothGattCallbackを呼び出します。パフォーマンスが重要なBLEタスクでは、GATT操作をバックグラウンドのHandlerThreadにオフロードすることをお勧めします。
よくある質問
BluetoothAdapter は、AndroidデバイスのローカルBluetoothアダプターを表すクラスです。BluetoothManager.getAdapter()(API 18+)またはBluetoothAdapter.getDefaultAdapter()を介して取得されます。Bluetoothの有効化/無効化、デバイスのスキャン、可視性の管理、アダプター情報の取得のメソッドを提供します。Bluetoothモジュールのないデバイスではnullを返します。
理由はデバイスにBluetoothラジオがないことです。Wi-Fiのみのタブレット、Androidエミュレーター、BluetoothなしのAndroid TVに典型的です。アプリ起動時にgetDefaultAdapter()がnullかどうかをチェックし、アダプターがない場合はBLE機能を無効にします。より正確な検出のためには、PackageManager.hasSystemFeature(FEATURE_BLUETOOTH_LE)を介したチェックが代替手段です。
BluetoothLeScanner(API 21+)は、ScanFilter、ScanSettings、PendingIntentをサポートするBLEスキャンの最新APIです。startLeScan(API 18+)は、限られたデータセットでLeScanCallbackを受け入れる非推奨のBluetoothAdapterメソッドです。Googleはすべての新しいプロジェクトでBluetoothLeScannerを推奨しており、UUIDによるフィルタリング、消費電力モードの設定、PendingIntentによるバックグラウンド操作が可能です。
Android 12+(API 31)では、BLEスキャンにはBLUETOOTH_SCAN、接続にはBLUETOOTH_CONNECT、アドバタイズにはBLUETOOTH_ADVERTISEが必要です。位置情報権限ACCESS_FINE_LOCATIONはBLEには不要になりました。Android 6〜11では、ACCESS_FINE_LOCATIONが必要です。すべての権限はActivityResultContractsを介してランタイムで要求されます。
Android 10+では、システムダイアログなしのプログラムによるBluetooth有効化は、BLUETOOTH_PRIVILEGED権限を持つシステムアプリのみ利用可能です。通常のアプリはIntent(BluetoothAdapter.ACTION_REQUEST_ENABLE)とstartActivityForResultを使用する必要があります — ユーザーがシステムダイアログで有効化を確認します。マニフェストのBLUETOOTH_ADMINはAndroid 10+でenable()権限を付与しません。
まとめ
ターンキー方式のモバイルアプリケーションを開発します
IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。