GATT サーバーへの接続

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

KotlinJava
var bluetoothGatt: BluetoothGatt? = null
...

bluetoothGatt
= device.connectGatt(this, false, gattCallback)
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 実装。 必要があります。

KotlinJava
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
       
}
   
}
}
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 接続イベントと接続解除イベントをリッスンする実装、 追加の接続オプションを指定できます。

KotlinJava
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)
   
}
}
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() 関数。

KotlinJava
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
   
}

   
...
}
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() が呼び出される 前の画面に戻ります。

KotlinJava
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
       
}
   
}

   
...
}
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

KotlinJava
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
   
}
}
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 デバイスのアドレスを渡す必要があります。イン 以下の例では、デバイスの住所がインテントとしてアクティビティに渡されています。 追加できます

KotlinJava
// 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
   
}
}
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 が サービスに接続します。

KotlinJava
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
       
}
   
}
}
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 プロパティも追加されています。これにより、サービスは 接続されていないときは 時間が長くなります。

KotlinJava
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
       
}
   
}
}
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 オブジェクトに渡されるアクション文字列内 指定することもできます。

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

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

KotlinJava
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

   
}
}

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 デバイスとの間の接続状態を把握できます。

KotlinJava
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)
       
}
   
}
}
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 への参照を保持します。アクティビティが デバイスのバッテリーが消耗しないように接続が閉じられます。

KotlinJava
class BluetoothLeService : Service() {

...

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

   
private fun close() {
        bluetoothGatt
?.let { gatt ->
            gatt
.close()
            bluetoothGatt
= null
       
}
   
}
}
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;
     
}
}