GATT サーバーへの接続

BLE デバイスと通信するには、まずデバイスに接続します。さらに表示 具体的にはデバイスの GATT サーバーに接続します。GATT に接続する 使用するには、 connectGatt() メソッドを呼び出します。このメソッドは、次の 3 つのパラメータを取ります。 Context オブジェクト、autoConnect(ブール値) すぐに BLE デバイスに自動的に接続するかどうかを 参照)、および BluetoothGattCallback:

Kotlin

var bluetoothGatt: BluetoothGatt? = null
...

bluetoothGatt = device.connectGatt(this, false, gattCallback)

Java

bluetoothGatt = device.connectGatt(this, false, gattCallback);

BLE デバイスがホストする GATT サーバーに接続し、 BluetoothGatt インスタンスを作成し、 これを使用して GATT クライアント操作を実行できます。呼び出し元(Android アプリ) GATT クライアントです。「 BluetoothGattCallback は、クライアントに次のような結果を提供するために使用されます。 その他の GATT クライアント オペレーションも示されます。

バインドされたサービスを設定する

次の例では、BLE アプリが (DeviceControlActivity)Bluetooth デバイスへの接続、デバイスデータの表示、 デバイスでサポートされている GATT サービスと特性を表示します。ベース ユーザー入力に基づき、このアクティビティは ServiceBluetoothLeService を呼び出し、これは BLE API 経由で BLE デバイスとやり取りします。コミュニケーションは バインドされたサービスを使用して実行されるため、 BluetoothLeService に接続し、関数を呼び出すためのアクティビティ 接続します。BluetoothLeService には 以下へのアクセスを提供する Binder 実装。 必要があります。

Kotlin

class BluetoothLeService : Service() {

    private val binder = LocalBinder()

    override fun onBind(intent: Intent): IBinder? {
        return binder
    }

    inner class LocalBinder : Binder() {
        fun getService() : BluetoothLeService {
            return this@BluetoothLeService
        }
    }
}

Java

class BluetoothLeService extends Service {

    private Binder binder = new LocalBinder();

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return binder;
    }

    class LocalBinder extends Binder {
        public BluetoothLeService getService() {
            return BluetoothLeService.this;
        }
    }
}

アクティビティは、 bindService() Intent を渡して サービス、ServiceConnection 接続イベントと接続解除イベントをリッスンする実装、 追加の接続オプションを指定できます。

Kotlin

class DeviceControlActivity : AppCompatActivity() {

    private var bluetoothService : BluetoothLeService? = null

    // Code to manage Service lifecycle.
    private val serviceConnection: ServiceConnection = object : ServiceConnection {
        override fun onServiceConnected(
            componentName: ComponentName,
            service: IBinder
        ) {
            bluetoothService = (service as LocalBinder).getService()
            bluetoothService?.let { bluetooth ->
                // call functions on service to check connection and connect to devices
            }
        }

        override fun onServiceDisconnected(componentName: ComponentName) {
            bluetoothService = null
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.gatt_services_characteristics)

        val gattServiceIntent = Intent(this, BluetoothLeService::class.java)
        bindService(gattServiceIntent, serviceConnection, Context.BIND_AUTO_CREATE)
    }
}

Java

class DeviceControlActivity extends AppCompatActivity {

    private BluetoothLeService bluetoothService;

    private ServiceConnection serviceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            bluetoothService = ((LocalBinder) service).getService();
            if (bluetoothService != null) {
                // call functions on service to check connection and connect to devices
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            bluetoothService = null;
        }
    };

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.gatt_services_characteristics);

        Intent gattServiceIntent = new Intent(this, BluetoothLeService.class);
        bindService(gattServiceIntent, serviceConnection, Context.BIND_AUTO_CREATE);
    }
}

BluetoothAdapter を設定する

バインドされたサービスは、 BluetoothAdapter。本来は アダプターがデバイスで利用できることを確認します。セットアップ BluetoothBluetoothAdapter。次の例では、この設定コードを 成功したことを示す Boolean 値を返す initialize() 関数。

Kotlin

private const val TAG = "BluetoothLeService"

class BluetoothLeService : Service() {

    private var bluetoothAdapter: BluetoothAdapter? = null

    fun initialize(): Boolean {
        bluetoothAdapter = BluetoothAdapter.getDefaultAdapter()
        if (bluetoothAdapter == null) {
            Log.e(TAG, "Unable to obtain a BluetoothAdapter.")
            return false
        }
        return true
    }

    ...
}

Java

class BluetoothLeService extends Service {

    public static final String TAG = "BluetoothLeService";

    private BluetoothAdapter bluetoothAdapter;

    public boolean initialize() {
        bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
        if (bluetoothAdapter == null) {
            Log.e(TAG, "Unable to obtain a BluetoothAdapter.");
            return false;
        }
        return true;
    }

    ...
}

アクティビティは、ServiceConnection の実装内でこの関数を呼び出します。 initialize() 関数からの false 戻り値の処理は、 説明します。ユーザーにエラー メッセージを表示して、 現在のデバイスは Bluetooth 操作に対応していないか、どの機能も無効になっています 対応しています。以下の例では、 アクティビティで finish() が呼び出される 前の画面に戻ります。

Kotlin

class DeviceControlActivity : AppCompatActivity() {

    // Code to manage Service lifecycle.
    private val serviceConnection: ServiceConnection = object : ServiceConnection {
        override fun onServiceConnected(
            componentName: ComponentName,
            service: IBinder
        ) {
            bluetoothService = (service as LocalBinder).getService()
            bluetoothService?.let { bluetooth ->
                if (!bluetooth.initialize()) {
                    Log.e(TAG, "Unable to initialize Bluetooth")
                    finish()
                }
                // perform device connection
            }
        }

        override fun onServiceDisconnected(componentName: ComponentName) {
            bluetoothService = null
        }
    }

    ...
}

Java

class DeviceControlsActivity extends AppCompatActivity {

    private ServiceConnection serviceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            bluetoothService = ((LocalBinder) service).getService();
            if (bluetoothService != null) {
                if (!bluetoothService.initialize()) {
                    Log.e(TAG, "Unable to initialize Bluetooth");
                    finish();
                }
                // perform device connection
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            bluetoothService = null;
        }
    };

    ...
}

デバイスに接続

BluetoothLeService インスタンスが初期化されると、BLE に接続できるようになります。 ダウンロードしますアクティビティは、サービスに対してデバイスのアドレスを送信し、 接続を開始します。サービスは最初に getRemoteDevice()BluetoothAdapter)でデバイスにアクセスします。スマート デバイスが見つからない場合 そのアドレスを持つデバイスである場合、getRemoteDevice()IllegalArgumentException

Kotlin

fun connect(address: String): Boolean {
    bluetoothAdapter?.let { adapter ->
        try {
            val device = adapter.getRemoteDevice(address)
        } catch (exception: IllegalArgumentException) {
            Log.w(TAG, "Device not found with provided address.")
            return false
        }
    // connect to the GATT server on the device
    } ?: run {
        Log.w(TAG, "BluetoothAdapter not initialized")
        return false
    }
}

Java

public boolean connect(final String address) {
    if (bluetoothAdapter == null || address == null) {
        Log.w(TAG, "BluetoothAdapter not initialized or unspecified address.");
        return false;
    }

    try {
        final BluetoothDevice device = bluetoothAdapter.getRemoteDevice(address);
    } catch (IllegalArgumentException exception) {
        Log.w(TAG, "Device not found with provided address.");
        return false;
    }
    // connect to the GATT server on the device
}

サービスが有効化されると、DeviceControlActivity はこの connect() 関数を呼び出します。 初期化されます。アクティビティは BLE デバイスのアドレスを渡す必要があります。イン 以下の例では、デバイスの住所がインテントとしてアクティビティに渡されています。 追加できます

Kotlin

// Code to manage Service lifecycle.
private val serviceConnection: ServiceConnection = object : ServiceConnection {
    override fun onServiceConnected(
    componentName: ComponentName,
    service: IBinder
    ) {
        bluetoothService = (service as LocalBinder).getService()
        bluetoothService?.let { bluetooth ->
            if (!bluetooth.initialize()) {
                Log.e(TAG, "Unable to initialize Bluetooth")
                finish()
            }
            // perform device connection
            bluetooth.connect(deviceAddress)
        }
    }

    override fun onServiceDisconnected(componentName: ComponentName) {
        bluetoothService = null
    }
}

Java

private ServiceConnection serviceConnection = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        bluetoothService = ((LocalBinder) service).getService();
        if (bluetoothService != null) {
            if (!bluetoothService.initialize()) {
                Log.e(TAG, "Unable to initialize Bluetooth");
                finish();
            }
            // perform device connection
            bluetoothService.connect(deviceAddress);
        }
    }

    @Override
    public void onServiceDisconnected(ComponentName name) {
        bluetoothService = null;
    }
};

GATT コールバックを宣言する

アクティビティによって、接続先のデバイスとサービスが がデバイスに接続すると、サービスはそのデバイスの GATT サーバーに接続する必要があります。 BLE デバイス。この接続を利用するには、BluetoothGattCallback が必要です サービス ディスカバリ、VM の特性などの 特徴の通知などがあります

このトピックでは、接続状態の通知について説明します。BLE の転送 データをご覧ください。 サービス ディスカバリ、特性読み取り、リクエストの特性 通知を受け取れます。

onConnectionStateChange() デバイスの GATT サーバーへの接続が変更されたときにトリガーされます。 次の例では、コールバックが Service クラスで定義されているため、 使用できる BluetoothDevice が サービスに接続します。

Kotlin

private val bluetoothGattCallback = object : BluetoothGattCallback() {
    override fun onConnectionStateChange(gatt: BluetoothGatt?, status: Int, newState: Int) {
        if (newState == BluetoothProfile.STATE_CONNECTED) {
            // successfully connected to the GATT Server
        } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
            // disconnected from the GATT Server
        }
    }
}

Java

private final BluetoothGattCallback bluetoothGattCallback = new BluetoothGattCallback() {
    @Override
    public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
        if (newState == BluetoothProfile.STATE_CONNECTED) {
            // successfully connected to the GATT Server
        } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
            // disconnected from the GATT Server
        }
    }
};

GATT サービスへの接続

BluetoothGattCallback を宣言すると、サービスは connect() 関数から BluetoothDevice オブジェクトを取得して GATT に接続する アクセスします。

connectGatt() 関数を使用します。これには、Context オブジェクト(autoConnect ブール値)が必要です。 フラグ、BluetoothGattCallback です。この例では、アプリは直接 BLE デバイスに接続するため、autoConnect には false が渡されます。

また、BluetoothGatt プロパティも追加されています。これにより、サービスは 接続されていないときは 時間が長くなります。

Kotlin

class BluetoothLeService : Service() {

...

    private var bluetoothGatt: BluetoothGatt? = null

    ...

    fun connect(address: String): Boolean {
        bluetoothAdapter?.let { adapter ->
            try {
                val device = adapter.getRemoteDevice(address)
                // connect to the GATT server on the device
                bluetoothGatt = device.connectGatt(this, false, bluetoothGattCallback)
                return true
            } catch (exception: IllegalArgumentException) {
                Log.w(TAG, "Device not found with provided address.  Unable to connect.")
                return false
            }
        } ?: run {
            Log.w(TAG, "BluetoothAdapter not initialized")
            return false
        }
    }
}

Java

class BluetoothLeService extends Service {

...

    private BluetoothGatt bluetoothGatt;

    ...

    public boolean connect(final String address) {
        if (bluetoothAdapter == null || address == null) {
            Log.w(TAG, "BluetoothAdapter not initialized or unspecified address.");
            return false;
        }
        try {
            final BluetoothDevice device = bluetoothAdapter.getRemoteDevice(address);
            // connect to the GATT server on the device
            bluetoothGatt = device.connectGatt(this, false, bluetoothGattCallback);
            return true;
        } catch (IllegalArgumentException exception) {
            Log.w(TAG, "Device not found with provided address.  Unable to connect.");
            return false;
        }
    }
}

最新情報をブロードキャストする

サーバーが GATT サーバーに接続または接続解除したとき、 維持します。これにはいくつかの方法があります。「 次の例では、broadcasts を使用して 情報をサービスからアクティビティに送ります。

サービスが、新しい状態をブロードキャストする関数を宣言します。この関数は、 ブロードキャスト前に Intent オブジェクトに渡されるアクション文字列内 指定することもできます。

Kotlin

private fun broadcastUpdate(action: String) {
    val intent = Intent(action)
    sendBroadcast(intent)
}

Java

private void broadcastUpdate(final String action) {
    final Intent intent = new Intent(action);
    sendBroadcast(intent);
}

ブロードキャスト関数を設定すると、 BluetoothGattCallback: 接続状態に関する情報を GATT サーバーです。定数とサービスの現在の接続状態が宣言される Intent アクションを表すサービス。

Kotlin

class BluetoothLeService : Service() {

    private var connectionState = STATE_DISCONNECTED

    private val bluetoothGattCallback: BluetoothGattCallback = object : BluetoothGattCallback() {
        override fun onConnectionStateChange(gatt: BluetoothGatt, status: Int, newState: Int) {
            if (newState == BluetoothProfile.STATE_CONNECTED) {
                // successfully connected to the GATT Server
                connectionState = STATE_CONNECTED
                broadcastUpdate(ACTION_GATT_CONNECTED)
            } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
                // disconnected from the GATT Server
                connectionState = STATE_DISCONNECTED
                broadcastUpdate(ACTION_GATT_DISCONNECTED)
            }
        }
    }

    ...

    companion object {
        const val ACTION_GATT_CONNECTED =
            "com.example.bluetooth.le.ACTION_GATT_CONNECTED"
        const val ACTION_GATT_DISCONNECTED =
            "com.example.bluetooth.le.ACTION_GATT_DISCONNECTED"

        private const val STATE_DISCONNECTED = 0
        private const val STATE_CONNECTED = 2

    }
}

Java


class BluetoothLeService extends Service {

    public final static String ACTION_GATT_CONNECTED =
            "com.example.bluetooth.le.ACTION_GATT_CONNECTED";
    public final static String ACTION_GATT_DISCONNECTED =
            "com.example.bluetooth.le.ACTION_GATT_DISCONNECTED";

    private static final int STATE_DISCONNECTED = 0;
    private static final int STATE_CONNECTED = 2;

    private int connectionState;
    ...

    private final BluetoothGattCallback bluetoothGattCallback = new BluetoothGattCallback() {
        @Override
        public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
            if (newState == BluetoothProfile.STATE_CONNECTED) {
                // successfully connected to the GATT Server
                connectionState = STATE_CONNECTED;
                broadcastUpdate(ACTION_GATT_CONNECTED);
            } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
                // disconnected from the GATT Server
                connectionState = STATE_DISCONNECTED;
                broadcastUpdate(ACTION_GATT_DISCONNECTED);
            }
        }
    };

    …
}

アクティビティの更新情報をリッスンする

サービスが接続の更新をブロードキャストしたら、アクティビティは BroadcastReceiver を実装する。 アクティビティのセットアップ時にこのレシーバを登録し、 画面から離れますサービスからのイベントをリッスンすることで アクティビティは、現在のアクティビティに基づいてユーザー インターフェースを BLE デバイスとの間の接続状態を把握できます。

Kotlin

class DeviceControlActivity : AppCompatActivity() {

...

    private val gattUpdateReceiver: BroadcastReceiver = object : BroadcastReceiver() {
        override fun onReceive(context: Context, intent: Intent) {
            when (intent.action) {
                BluetoothLeService.ACTION_GATT_CONNECTED -> {
                    connected = true
                    updateConnectionState(R.string.connected)
                }
                BluetoothLeService.ACTION_GATT_DISCONNECTED -> {
                    connected = false
                    updateConnectionState(R.string.disconnected)
                }
            }
        }
    }

    override fun onResume() {
        super.onResume()
        registerReceiver(gattUpdateReceiver, makeGattUpdateIntentFilter())
        if (bluetoothService != null) {
            val result = bluetoothService!!.connect(deviceAddress)
            Log.d(DeviceControlsActivity.TAG, "Connect request result=$result")
        }
    }

    override fun onPause() {
        super.onPause()
        unregisterReceiver(gattUpdateReceiver)
    }

    private fun makeGattUpdateIntentFilter(): IntentFilter? {
        return IntentFilter().apply {
            addAction(BluetoothLeService.ACTION_GATT_CONNECTED)
            addAction(BluetoothLeService.ACTION_GATT_DISCONNECTED)
        }
    }
}

Java

class DeviceControlsActivity extends AppCompatActivity {

...

    private final BroadcastReceiver gattUpdateReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            final String action = intent.getAction();
            if (BluetoothLeService.ACTION_GATT_CONNECTED.equals(action)) {
                connected = true;
                updateConnectionState(R.string.connected);
            } else if (BluetoothLeService.ACTION_GATT_DISCONNECTED.equals(action)) {
                connected = false;
                updateConnectionState(R.string.disconnected);
            }
        }
    };

    @Override
    protected void onResume() {
        super.onResume();

        registerReceiver(gattUpdateReceiver, makeGattUpdateIntentFilter());
        if (bluetoothService != null) {
            final boolean result = bluetoothService.connect(deviceAddress);
            Log.d(TAG, "Connect request result=" + result);
        }
    }

    @Override
    protected void onPause() {
        super.onPause();
        unregisterReceiver(gattUpdateReceiver);
    }

    private static IntentFilter makeGattUpdateIntentFilter() {
        final IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(BluetoothLeService.ACTION_GATT_CONNECTED);
        intentFilter.addAction(BluetoothLeService.ACTION_GATT_DISCONNECTED);
        return intentFilter;
    }
}

[BLE データの転送] で、 BroadcastReceiver は、サービス ディスカバリをサービス ディスカバリに伝達するためにも デバイスからの特性データも含まれます。

GATT 接続を閉じる

Bluetooth 接続を扱う際の重要なステップは、 行われません。そのためには、close() を呼び出します。 BluetoothGatt オブジェクトに対して行います。次の例では、サービス アカウントは BluetoothGatt への参照を保持します。アクティビティが デバイスのバッテリーが消耗しないように接続が閉じられます。

Kotlin

class BluetoothLeService : Service() {

...

    override fun onUnbind(intent: Intent?): Boolean {
        close()
        return super.onUnbind(intent)
    }

    private fun close() {
        bluetoothGatt?.let { gatt ->
            gatt.close()
            bluetoothGatt = null
        }
    }
}

Java

class BluetoothLeService extends Service {

...

      @Override
      public boolean onUnbind(Intent intent) {
          close();
          return super.onUnbind(intent);
      }

      private void close() {
          if (bluetoothGatt == null) {
              Return;
          }
          bluetoothGatt.close();
          bluetoothGatt = null;
      }
}