{"id":63,"date":"2019-07-04T23:25:39","date_gmt":"2019-07-04T14:25:39","guid":{"rendered":"http:\/\/www.space4u.co.kr\/wp\/?p=63"},"modified":"2019-07-04T23:25:40","modified_gmt":"2019-07-04T14:25:40","slug":"%ec%95%88%eb%93%9c%eb%a1%9c%ec%9d%b4%eb%93%9c-ble-%ed%94%84%eb%a1%9c%ea%b7%b8%eb%9e%98%eb%b0%8d","status":"publish","type":"post","link":"http:\/\/www.space4u.co.kr\/wp\/?p=63","title":{"rendered":"\uc548\ub4dc\ub85c\uc774\ub4dc BLE \ud504\ub85c\uadf8\ub798\ubc0d"},"content":{"rendered":"\n<p><strong>Bluetooth Low Energy<\/strong> 4.3\ubd80\ud130 BLE central role\uc744 \uc9c0\uc6d0\ud558\uae30 \uc2dc\uc791\ud588\ub2e4. \uadf8\ub9ac\uace0 \ub514\ubc14\uc774\uc2a4 \uac80\uc0c9\uacfc \uc11c\ube44\uc2a4 \uac80\uc0c9 \uadf8\ub9ac\uace0 \uc18d\uc131\ub4e4\uc758 \uc77d\uae30\/\uc4f0\uae30\ub97c \uc9c0\uc6d0\ud55c\ub2e4. BLE\ub97c \ud1b5\ud574 \uc800\uc804\ub825\uc73c\ub85c \uc124\uacc4\ub41c \ub2e4\uc591\ud55c \ub514\ubc14\uc774\uc2a4\uc640\ud1b5\uc2e0\uc774 \uac00\ub2a5\ud574\uc84c\ub2e4.<br>Key Terms and Concepts<\/p>\n\n\n\n<ul><li>Generic Attribute Profile (GATT) &#8211; BLE link\uc0c1\uc5d0\uc11c \uc1a1\uc218\uc2e0 \uac00\ub2a5\ud55c \uc77c\ubc18\uc801\uc778 \uc0ac\uc591\uc744 \ub9d0\ud558\uba70 \ubaa8\ub4e0 LE \uc560\ud50c\ub9ac\ucf00\uc774\uc158\ud504\ub85c\ud30c\uc77c\uc740 GATT\uc5d0 \uae30\ubc18\ud55c\ub2e4.<ul><li>\ube14\ub8e8\ud22c\uc2a4 SIG\ub294 \ub9ce\uc740 \ud504\ub85c\ud30c\uc77c\uc744 \uc815\uc758\ud558\uc600\ub294\ub370 \ud558\ub098\uc758 \ud504\ub85c\ud30c\uc77c\uc740 \uc571\uc5d0\uc11c \uc5b4\ub5bb\uac8c \ub3d9\uc791\ud560\uc9c0\uc5d0 \ub300\ud55c \uc0ac\uc591\uc744 \uc758\ubbf8\ud55c\ub2e4. \ud558\ub098\uc758 \uc7a5\uce58\ub294 \uc5ec\ub7ec \ud504\ub85c\ud30c\uc77c\uc744 \uad6c\ud604\ud560 \uc218 \uc788\ub2e4.&nbsp;<\/li><\/ul><\/li><li>Attribute Protocol (ATT) &#8211; GATT\ub294 ATT\uc758 \ucd5c\uc0c1\uc704 \uad6c\ud604\uccb4\uc774\uba70 GATT\/ATT\ub85c \ucc38\uc870\ub418\uae30\ub3c4 \ud55c\ub2e4. ATT\ub294 BLE\uc7a5\uce58\uc5d0\uc11c \ub3d9\uc791\ud558\ub3c4\ub85d \ucd5c\uc801\ud654 \ub418\uc5b4 \uc788\ub2e4. \uac1c\uac1c\uc758 \uc18d\uc131(Attribute)\uc740 UUID\ub97c \uac00\uc9c0\uba70 128\ube44\ud2b8\ub85c \uad6c\uc131\ub41c\ub2e4. ATT\uc5d0 \uc758\ud574 \ubd80\uc5ec\ub41c \uc18d\uc131\uc740 \ud2b9\uc131\uacfc \uc11c\ube44\uc2a4\ub97c \uacb0\uc815\ud55c\ub2e4.<\/li><li>Characteristic &#8211; \ud558\ub098\uc758 \ud2b9\uc131(characteristic)\uc740 \ud558\ub098\uc758 \uac12\uacfc n\uac1c\uc758 \ub514\uc2a4\ud06c\ub9bd\ud130\ub97c \ud3ec\ud568\ud558\ub294\ub370 \ub514\uc2a4\ud06c\ub9bd\ud130\ub294 \ud2b9\uc131 \uac12\uc744 \uae30\uc220\ud55c\ub2e4. \ud558\ub098\uc758 \ud2b9\uc131\uc740 \ud074\ub798\uc2a4\uc640 \uc720\uc0ac\ud55c \ud0c0\uc785\uc73c\ub85c \uc0dd\uac01\ud558\uba74 \ub41c\ub2e4.&nbsp;<\/li><li>Descriptor &#8211; \ub514\uc2a4\ud06c\ub9bd\ud130\ub294 \ud2b9\uc131\uc758 \uac12\uc744 \uae30\uc220\ud55c\ub2e4.<\/li><li>Service &#8211; \ud558\ub098\uc758 \uc11c\ube44\uc2a4\ub294 \ud2b9\uc131\ub4dc\uc758 \uc9d1\ud569\ub2c8\ub2e4. \uc608\ub97c \ub4e4\uc5b4 &#8220;Heart Rate Monitor&#8221;\ub77c\uace0 \ubd88\ub9ac\ub294 \uc11c\ube44\uc2a4\ub97c \uac00\uc9c0\uace0 \uc788\ub2e4\uba74 \uadf8 \uc11c\ube44\uc2a4\ub294 &#8220;heart rate measurement&#8221;\uac19\uc740 \ud2b9\uc131\uc744 \ud3ec\ud568\ud55c\ub2e4. GATT-based profile\uc758 \ub9ac\uc2a4\ud2b8\uc640 \uc11c\ube44\uc2a4\ub97c \ud655\uc778\ud558\ub824\uba74 bluetooth.org\ub97c \ubc29\ubb38\ud558\ub77c.<\/li><\/ul>\n\n\n\n<p>Roles and Responsibilities\uc774 \ubb38\uc11c\uc5d0\uc11c \uc124\uba85\ud558\ub294 \uc5ed\ud560\uacfc \ucc45\uc784\uc740 Android\uc7a5\uce58\uac00 &nbsp;BLE\uc7a5\uce58\uc640 \uc5f0\ub3d9\ud558\ub294\ub370 \uc801\uc6a9\ub418\ub294\uac83\ub4e4\uc774\ub2e4.<\/p>\n\n\n\n<ul><li>Central vs. peripheral &#8211; BLE \uc5f0\uacb0\uc5d0 \uc801\uc6a9\ub41c\ub2e4. central \uc5ed\ud560\uc740 scan, \uac8c\uc2dc\uac80\uc0c9(looking for advertisement), \uadf8\ub9ac\uace0 peripheral\uc5ed\ud560\uc740 \uac8c\uc2dc\ub97c \ub9cc\ub4e0\ub2e4.<\/li><li>GATT server vs. GATT client &#8211; \ub514\ubc14\uc774\uc2a4\uac00 \uc5f0\uacb0\ub41c \uc774 \ud6c4 \uc11c\ub85c \uc5b4\ub5bb\uac8c \ub300\ud654\ud558\ub294\uc9c0\uc5d0 \ub300\ud574 \uc815\uc758\ud55c\ub2e4.&nbsp;<\/li><\/ul>\n\n\n\n<p>\ucc28\uc774\uc810\uc744 \uc774\ud574\ud558\ub824\uba74 \uc548\ub4dc\ub85c\uc774\ub4dc\ud3f0\ud558\ub098\uc640 \uc6c0\uc9c1\uc784\uc744 \uac10\uc9c0\ud558\ub294 BLE\uc7a5\uce58\ub97c \uac00\uc9c0\uace0 \uc788\ub2e4\uace0 \uac00\uc815 \ud574\ubcf4\uc790. \ud3f0\uc740 central\uc5ed\ud560\uc744 \ud55c\ub2e4. BLE\uc7a5\uce58\ub294 peripheral\uc5ed\ud560\uc744 \ud55c\ub2e4.&nbsp;<br>\ud3f0\uacfc BLE\uc7a5\uce58\uac00 \ud55c\ubc88 \uc5f0\uacb0\uc774 \ub418\uba74 \ub450 \uc7a5\uce58\ub294 \uc11c\ub85c &nbsp;GATT metadata\ub97c \uc8fc\uace0 \ubc1b\ub294\ub2e4. \uc8fc\uace0\ubc1b\ub294 \ub370\uc774\ud130\uc5d0 \ub530\ub77c \ud558\ub098\uc774\uc0c1\uc758 \uc11c\ubc84 \uc561\uc158\uc774 \uc788\uc744 \uc218 \uc788\ub2e4. \uc608\ub97c \ub4e4\uc5b4 BLE\uc7a5\uce58\uac00 \ud3f0\uc5d0 \uc13c\uc11c\uc815\ubcf4\ub97c \uc804\ub2ec\ud558\ub824\uace0 \ud560 \uc218 \uc788\ub2e4. \uc774 \ub54c \uc7a5\uce58\ub294 \uc11c\ubc84\ub85c \ub3d9\uc791\ud55c\ub2e4. \uc7a5\uce58\uac00 \ud3f0\uc73c\ub85c\ubd80\ud130 \uc5c5\ub370\uc774\ud2b8\ub97c \ubc1b\uace0\uc790 \ud560\uc218 \uc788\ub2e4 \uc774 \ub54c\ub294 \ud3f0\uc774 \uc11c\ubc84\ub85c \ub3d9\uc791\ud55c\ub2e4.<br>\uc774 \ubb38\uc11c\uc5d0\uc11c \uc81c\uacf5\ud558\ub294 \uc0d8\ud50c\uc740 \uc548\ub4dc\ub85c\uc774\ub4dc \ub514\ubc14\uc774\uc2a4\ub85c \ub3d9\uc791\ud558\ub294 \uc571\uc73c\ub85c GATT client\uc774\ub2e4. \uc571\uc740 GATT server\ub85c\ubd80\ud130 \ub370\uc774\ud130\ub97c \uac00\uc838\uc624\ub294\ub370 \uadf8\uac83\uc740 Heart Rate Profile\uc744 \uc9c0\uc6d0\ud558\ub294 BLE heart rate monitor\uc774\ub2e4.\ubc18\uba74\uc5d0 \uc571\uc744 GATT \uc11c\ubc84\uc5ed\ud560\uc744 \ud558\ub3c4\ub85d \uad6c\ud604\ud560 \uc218 \ub3c4 \uc788\ub2e4. BluetoothGattServer\ub97c \ucc38\uc870\ud558\ub77c.<br>BLE permissions\ube14\ub8e8\ud22c\uc2a4\ud1b5\uc2e0(\uc5f0\uacb0\uc694\uccad, \uc5f0\uacb0\uc218\ub77d, \ub370\uc774\ud130 \uc804\uc1a1)\uc744 \ud558\ub824\uba74 BLUETOOTH \ud37c\ubbf8\uc158\uc744 \ucd94\uac00\ud574\uc57c \ud568\ub2e4.\ube14\ub8e8\ud22c\uc2a4\uc7a5\uce58\ub97c \uac80\uc0c9\ud558\uace0 \uc124\uc815\uc744 \uc870\uc791\ud558\ub824\uba74 BLUETOOTH_ADMIN \ud37c\ubbf8\uc158\uc744 \ucd94\uac00\ud574\uc57c \ud55c\ub2e4.BLUETOOTH_ADMIN\uc740 BLUETOOTH\ud37c\ubbf8\uc158\uacfc \ud568\uaed8 \uc815\uc758\ub418\uc5b4\uc57c \ud55c\ub2e4.<br><\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">&lt;uses-permission android:name=\"android.permission.BLUETOOTH\"\/&gt;<br>&lt;uses-permission android:name=\"android.permission.BLUETOOTH_ADMIN\"\/&gt;<\/pre>\n\n\n\n<p>\ube14\ub8e8\ud22c\uc2a4 BLE\ub9cc \uc0ac\uc6a9\ud560\uac70\ub77c\uba74 \uc544\ub798\uc640 \uac19\uc774 manifest\uc5d0 \ud3ec\ud568\uc2dc\ucf1c\uc57c \ud55c\ub2e4.<br><\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">&lt;uses-feature android:name=\"android.hardware.bluetooth_le\" android:required=\"true\"\/&gt;<\/pre>\n\n\n\n<p>BLE\ub97c \uc9c0\uc6d0\ud558\uc9c0 \uc54a\ub294 \uc571\uc73c\ub85c \ub9cc\ub4e4\uace0\uc790 \ud55c\ub2e4\uba74 \uc5ec\uc804\ud788 \ub3d9\uc77c\ud55c &nbsp;feature\ub97c \ucd94\uac00\ud574\uc57c \ud558\uba70 \ub2e4\ub9cc required=&#8221;false&#8221;\ub85c \ud558\uba74 \ub41c\ub2e4. \ub7f0\ud0c0\uc784\uc5d0 BLE\ud65c\uc131\ud654 \uc5ec\ubd80\ub97c PackageManager.hasSystemFeature\ub85c \uc54c\uc544\ub0bc \uc218 \uc788\ub2e4.<br><\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">\/\/ Use this check to determine whether BLE is supported on the device. Then<br>\/\/ you can selectively disable BLE-related features.<br>if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {<br>&nbsp; &nbsp; Toast.makeText(this, R.string.ble_not_supported, Toast.LENGTH_SHORT).show();<br>&nbsp; &nbsp; finish();<br>}<\/pre>\n\n\n\n<p>Setting Up BLE<br>BLE\ub85c \ud1b5\uc2e0\ud558\uae30 \uc804\uc5d0 \ub514\ubc14\uc774\uc2a4\uac00 BLE\ub97c \uc9c0\uc6d0\ud558\ub294\uc9c0 \ud655\uc774\ud574\uc57c \ud55c\ub2e4. \uc9c0\uc6d0\ud55c\ub2e4\uba74 \ud65c\uc131\ud654\ub418\uc5b4\uc57c \ud55c\ub2e4.&nbsp;\ub9cc\uc77c &nbsp;BLE\ub97c \uc9c0\uc6d0\ud558\uc9c0 \uc54a\ub294\ub2e4\uba74 BLE feature\ub4e4\uc744 \ube44\ud65c\uc131\ud654\ud574\uc57c \ud55c\ub2e4. \uc9c0\uc6d0\ud55c\ub2e4\uba74 \uc0ac\uc6a9\uc790\uc5d0\uac8c BT\ub97c \uc571\uc744 \ub5a0\ub098\uc9c0 \uc54a\uace0 \ud65c\uc131\ud654\ud558\ub3c4\ub85d \uc720\ub3c4\ud574\uc57c \ud55c\ub2e4. \uc774 \uacfc\uc815\uc740 BluetoothAdapter\ub97c \uc0ac\uc6a9\ud558\uc5ec 2\ub2e8\uacc4\ub85c \uac00\ub2a5\ud558\ub2e4.<\/p>\n\n\n\n<p>1. BluetoothAdapter\uc5bb\uae30<\/p>\n\n\n\n<p>BluetoothAdapter\ub294 \ube14\ub8e8\ud22c\uc2a4\uad00\ub828 \uc77c\ubd80 \ub610\ub294 \ubaa8\ub4e0 \ube14\ub8e8\ud22c\uc2a4 \ub3d9\uc791\ub4e4\uc744 \ud544\uc694\ub85c \ud55c\ub2e4. BluetoothAdapter\ub294 \ub514\ubc14\uc774\uc2a4\uc790\uccb4\uc758 BluetoothAdapter\ub97c \ub098\ud0c0\ub0b8\ub2e4. &nbsp;\uc804\uccb4\uc2dc\uc2a4\ud15c\uc744 \uc704\ud55c \ud558\ub098\uc758 \uc5b4\ub311\ud130\uac00 \uc788\uace0 \uc571\uc740 \uc774 \uac1d\uccb4\ub97c \ud1b5\ud574\uc11c \uc0c1\ud638\uc791\uc6a9\uc744 \ud55c\ub2e4. \ub2e4\uc74c \ucf54\ub4dc\uc870\uac01\uc740 \uc5b4\ub311\ud130\ub97c \uc5bb\ub294 \ubc29\ubc95\uc744 \ubcf4\uc5ec\uc900\ub2e4.<\/p>\n\n\n\n<ol><li>\/\/ Initializes Bluetooth adapter.<br>final BluetoothManager bluetoothManager =<br>&nbsp; &nbsp; &nbsp; &nbsp; (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);<br>mBluetoothAdapter = bluetoothManager.getAdapter();<\/li><\/ol>\n\n\n\n<p>2. Bluetooth \ud65c\uc131\ud654.\ub2e4\uc74c\uc5d0 \ube14\ub8e8\ud22c\uc2a4\ub97c \ud65c\uc131\ud654\ud574\uc57c \ud55c\ub2e4. isEnabled()\ub85c \ud65c\uc131\ud654\uc5ec\ubd80\ub97c \ud655\uc778 \uac00\ub2a5\ud558\ub2e4. false\uba74 \ube44\ud65c\uc131\ud654\uc774\ub2e4. \ub2e4\uc74c\uc740 \uadf8 \uc0d8\ud50c\uc774\ub2e4.<\/p>\n\n\n\n<ol><li>private BluetoothAdapter mBluetoothAdapter;<br>&#8230;<br>\/\/ Ensures Bluetooth is available on the device and it is enabled. If not,<br>\/\/ displays a dialog requesting user permission to enable Bluetooth.<br>if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {<br>&nbsp; &nbsp; Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);<br>&nbsp; &nbsp; startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);<br>}<\/li><\/ol>\n\n\n\n<p>BLE \uc7a5\uce58 \ucc3e\uae30BLE\uc7a5\uce58\ub97c \ucc3e\uc73c\ub824\uba74 startLeScan() \uba54\uc18c\ub4dc\ub97c \ud638\ucd9c\ud55c\ub2e4. LeScanCallack\uc774 \ud30c\ub77c\uba54\ud130\ub85c \ud638\ucd9c\ub41c\ub2e4. \uc774 \uba54\uc18c\ub4dc\ub97c \uad6c\ud604\ud574\uc57c \ud558\uace0 \uc2a4\uce94\uacb0\uacfc\ub97c \ubc1b\uc744 \uc218 \uc788\ub2e4. \ubc30\ud130\ub9ac \uc18c\ubaa8\uac00 \uc2ec\uc2ec\ud558\uae30 \ub54c\ubb38\uc5d0 \ub2e4\uc74c\uc758 \uac00\uc774\ub4dc\ub77c\uc778\uc744 \uc798 \uc9c0\ucf1c\uc57c \ud55c\ub2e4.<\/p>\n\n\n\n<ul><li>\uc6d0\ud558\ub294 \ub514\ubc14\uc774\uc2a4\ub97c \ucc3e\uc73c\uba74 \ubc14\ub85c \uc2a4\uce94\uc744 \uc911\ub2e8\ud574\uc57c \ud55c\ub2e4.<\/li><li>\ud558\ub098\uc758 \ub8e8\ud504\uc5d0\uc11c \uc2a4\uce94\ud558\uc9c0 \ub9d0\uace0 \ud0c0\uc784\uc544\uc6c3\uc744 \uc801\uc6a9\ud574\ub77c. \ub514\ubc14\uc774\uc2a4\uac00 \ubc94\uc704\uc548\uc5d0\uc11c \ubc97\uc5b4\ub0ac\uc744 \uc218\ub3c4 \uc788\uace0 \uadf8\ub7f4\uacbd\uc6b0 \ubc30\ud130\ub9ac \ub294 \uace8\ub85c \uac04\ub2e4.<\/li><\/ul>\n\n\n\n<p>\ub2e4\uc74c \ucf54\ub4dc\ub294 \uc2a4\uce94\uc744 \uc2dc\uc791\ud558\uace0 \uc911\ub2e8\ud558\ub294 \uc608\uc774\ub2e4.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">\/**<br>&nbsp;* Activity for scanning and displaying available BLE devices.<br>&nbsp;*\/<br>public class DeviceScanActivity extends ListActivity {<br><br>&nbsp; &nbsp; private BluetoothAdapter mBluetoothAdapter;<br>&nbsp; &nbsp; private boolean mScanning;<br>&nbsp; &nbsp; private Handler mHandler;<br><br>&nbsp; &nbsp; \/\/ Stops scanning after 10 seconds.<br>&nbsp; &nbsp; private static final long SCAN_PERIOD = 10000;<br>&nbsp; &nbsp; ...<br>&nbsp; &nbsp; private void scanLeDevice(final boolean enable) {<br>&nbsp; &nbsp; &nbsp; &nbsp; if (enable) {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; \/\/ Stops scanning after a pre-defined scan period.<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; mHandler.postDelayed(new Runnable() {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; @Override<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; public void run() {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; mScanning = false;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; mBluetoothAdapter.stopLeScan(mLeScanCallback);<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }, SCAN_PERIOD);<br><br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; mScanning = true;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; mBluetoothAdapter.startLeScan(mLeScanCallback);<br>&nbsp; &nbsp; &nbsp; &nbsp; } else {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; mScanning = false;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; mBluetoothAdapter.stopLeScan(mLeScanCallback);<br>&nbsp; &nbsp; &nbsp; &nbsp; }<br>&nbsp; &nbsp; &nbsp; &nbsp; ...<br>&nbsp; &nbsp; }<br>...<br>}<\/pre>\n\n\n\n<p>\ud2b9\uc815\ud0c0\uc785\uc758 \ud398\ub9ac\ud37c\ub801\ub9cc \uc2a4\uce94\ud558\uace0\uc790 \ud55c\ub2e4\uba74 startLeScan(UUID[], BluetoothAdapter.LeScanCallback)\uc744 \uc0ac\uc6a9\ud560 \uc218 \uc788\ub2e4. UUID[]\uc5d0\ub294 \uc571\uc5d0\uc11c \uc9c0\uc6d0\ud558\uace0\uc790 \ud558\ub294 &nbsp;GATT \uc11c\ube44\uc2a4\ubaa9\ub85d\uc774 \ub4e4\uc5b4\uac04\ub2e4.\ub2e4\uc74c\ucf54\ub4dc \uc608\ub97c \ubcf4\uc544\ub77c.<br><\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">private LeDeviceListAdapter mLeDeviceListAdapter;<br>...<br>\/\/ Device scan callback.<br>private BluetoothAdapter.LeScanCallback mLeScanCallback =<br>&nbsp; &nbsp; &nbsp; &nbsp; new BluetoothAdapter.LeScanCallback() {<br>&nbsp; &nbsp; @Override<br>&nbsp; &nbsp; public void onLeScan(final BluetoothDevice device, int rssi,<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; byte[] scanRecord) {<br>&nbsp; &nbsp; &nbsp; &nbsp; runOnUiThread(new Runnable() {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;@Override<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;public void run() {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;mLeDeviceListAdapter.addDevice(device);<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;mLeDeviceListAdapter.notifyDataSetChanged();<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}<br>&nbsp; &nbsp; &nbsp; &nbsp;});<br>&nbsp; &nbsp;}<br>};<\/pre>\n\n\n\n<p>BLE\ub610\ub294 Class BT\uc7a5\uce58\ub97c \uac80\uc0c9\ud560 \uc218 \ub294 \uc788\uc9c0\ub9cc \ub450\uac00\uc9c0\ub97c \ub3d9\uc2dc\uc5d0 \uac80\uc0c9\uc740 \ud560 \uc218 \uc5c6\ub2e4.<br>GATT \uc11c\ubc84\uc5d0 \uc5f0\uacb0\ud558\uae30\uccab\ubc88\uc9f8 \uc5f0\ub3d9\uc744 \uc704\ud55c \uacfc\uc815\uc740 BLE\ub514\ubc14\uc774\uc2a4\uc5d0 \uc5f0\uacb0\ud558\ub294\uac83\uc778\ub370 \uc880\ub354 \uc790\uc138\ud788 \ub9d0\ud558\uba74 \ub514\ubc14\uc774\uc2a4\uc758 GATT\uc11c\ubc84\uc5d0 \uc5f0\uacb0\ud558\ub294 \uac83\uc774\ub2e4. connectGatt()\uba54\uc18c\ub4dc\ub85c \ud558\uba74 \ub41c\ub2e4. \uc774 \uba54\uc18c\ub4dc\ub294 3\uac1c\uc758 \ud30c\ub77c\uba54\ud130\uac00 \uc788\ub294\ub370 context, autoConnect, \uadf8\ub9ac\uace0 BluetoothGattCallback\uc774 \uc788\ub2e4. autoConnect\ub294 \uac80\uc0c9\ub418\uc5c8\uc744 \ub54c \uc790\ub3d9\uc73c\ub85c \uc5f0\uacb0\ud560\uc9c0\uc5d0 \ub300\ud55c \ud30c\ub77c\uba54\ud130\ub2e4.<br><\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">mBluetoothGatt = device.connectGatt(this, false, mGattCallback);<\/pre>\n\n\n\n<p>\uc774 \ucf54\ub4dc\ub294 BLE device\ub97c GATT \uc11c\ubc84 \ud638\uc2a4\ud2b8\ub85c \uc5f0\uacb0\ud55c\ub2e4. \uadf8\ub9ac\uace0 BluetoothGatt \uc778\uc2a4\ud134\uc2a4\ub97c \ubc18\ud658\ud55c\ub2e4. \uc774 \uc778\uc2a4\ud134\uc2a4\ub85c GATT client\ub97c \uc6b4\uc601\ud55c\ub2e4.BluetoothGattCallback\uc740 \ud074\ub77c\uc774\uc5b8\ud2b8\uc5d0 \uc5f0\uacb0\uc0c1\ud0dc\ub098 client \uc6b4\uc601\uc5d0 \ub300\ud55c \uacb0\uacfc\ub97c \uc804\ub2ec\ud55c\ub2e4.<br>\uc774 \uc608\uc81c\uc5d0\uc11c BLE \uc571\uc740 \ud558\ub098\uc758 \uc561\ud2f0\ube44\ud2f0\uac00 \uc5f0\uacb0\ud558\uace0 \ub370\uc774\ud130\ub97c \ud45c\uc2dc\ud558\uace0 GATT \uc11c\ube44\uc2a4\uc640 \ud2b9\uc131\ub4e4\uc744 \ud45c\uc2dc\ud55c\ub2e4. \uc0ac\uc6a9\uc790 \uc785\ub825\uc5d0 \uae30\ubc18\ud558\uc5ec BluetoothLeService\ub85c \ubd88\ub9ac\ub294 \uc11c\ube44\uc2a4\uc640 \ud1b5\uc2e0\uc744 \uc218\ud589\ud558\ub3c4 Android BLE API\ub97c \ud1b5\ud574 \uc7a5\uce58\uc640 \uc0c1\ud638\uc5f0\ub3d9\uc744 \ud55c\ub2e4.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">\/\/ A service that interacts with the BLE device via the Android BLE API.<br>public class BluetoothLeService extends Service {<br>&nbsp; &nbsp; private final static String TAG = BluetoothLeService.class.getSimpleName();<br><br>&nbsp; &nbsp; private BluetoothManager mBluetoothManager;<br>&nbsp; &nbsp; private BluetoothAdapter mBluetoothAdapter;<br>&nbsp; &nbsp; private String mBluetoothDeviceAddress;<br>&nbsp; &nbsp; private BluetoothGatt mBluetoothGatt;<br>&nbsp; &nbsp; private int mConnectionState = STATE_DISCONNECTED;<br><br>&nbsp; &nbsp; private static final int STATE_DISCONNECTED = 0;<br>&nbsp; &nbsp; private static final int STATE_CONNECTING = 1;<br>&nbsp; &nbsp; private static final int STATE_CONNECTED = 2;<br><br>&nbsp; &nbsp; public final static String ACTION_GATT_CONNECTED =<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; \"com.example.bluetooth.le.ACTION_GATT_CONNECTED\";<br>&nbsp; &nbsp; public final static String ACTION_GATT_DISCONNECTED =<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; \"com.example.bluetooth.le.ACTION_GATT_DISCONNECTED\";<br>&nbsp; &nbsp; public final static String ACTION_GATT_SERVICES_DISCOVERED =<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; \"com.example.bluetooth.le.ACTION_GATT_SERVICES_DISCOVERED\";<br>&nbsp; &nbsp; public final static String ACTION_DATA_AVAILABLE =<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; \"com.example.bluetooth.le.ACTION_DATA_AVAILABLE\";<br>&nbsp; &nbsp; public final static String EXTRA_DATA =<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; \"com.example.bluetooth.le.EXTRA_DATA\";<br><br>&nbsp; &nbsp; public final static UUID UUID_HEART_RATE_MEASUREMENT =<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; UUID.fromString(SampleGattAttributes.HEART_RATE_MEASUREMENT);<br><br>&nbsp; &nbsp; \/\/ Various callback methods defined by the BLE API.<br>&nbsp; &nbsp; private final BluetoothGattCallback mGattCallback =<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; new BluetoothGattCallback() {<br>&nbsp; &nbsp; &nbsp; &nbsp; @Override<br>&nbsp; &nbsp; &nbsp; &nbsp; public void onConnectionStateChange(BluetoothGatt gatt, int status,<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; int newState) {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; String intentAction;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (newState == BluetoothProfile.STATE_CONNECTED) {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; intentAction = ACTION_GATT_CONNECTED;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; mConnectionState = STATE_CONNECTED;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; broadcastUpdate(intentAction);<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Log.i(TAG, \"Connected to GATT server.\");<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Log.i(TAG, \"Attempting to start service discovery:\" +<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; mBluetoothGatt.discoverServices());<br><br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; intentAction = ACTION_GATT_DISCONNECTED;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; mConnectionState = STATE_DISCONNECTED;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Log.i(TAG, \"Disconnected from GATT server.\");<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; broadcastUpdate(intentAction);<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br>&nbsp; &nbsp; &nbsp; &nbsp; }<br><br>&nbsp; &nbsp; &nbsp; &nbsp; @Override<br>&nbsp; &nbsp; &nbsp; &nbsp; \/\/ New services discovered<br>&nbsp; &nbsp; &nbsp; &nbsp; public void onServicesDiscovered(BluetoothGatt gatt, int status) {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (status == BluetoothGatt.GATT_SUCCESS) {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED);<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } else {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Log.w(TAG, \"onServicesDiscovered received: \" + status);<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br>&nbsp; &nbsp; &nbsp; &nbsp; }<br><br>&nbsp; &nbsp; &nbsp; &nbsp; @Override<br>&nbsp; &nbsp; &nbsp; &nbsp; \/\/ Result of a characteristic read operation<br>&nbsp; &nbsp; &nbsp; &nbsp; public void onCharacteristicRead(BluetoothGatt gatt,<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; BluetoothGattCharacteristic characteristic,<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; int status) {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (status == BluetoothGatt.GATT_SUCCESS) {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br>&nbsp; &nbsp; &nbsp; &nbsp; }<br>&nbsp; &nbsp; &nbsp;...<br>&nbsp; &nbsp; };<br>...<br>}<\/pre>\n\n\n\n<p>\ucf5c\ubc31\uc774 \ud638\ucd9c\ub418\uba74 broadcastUpdate()\ub97c \ud638\ucd9c\ud55c\ub2e4. \uc5ec\uae30\uc11c \ub370\uc774\ud130 \ud30c\uc2f1\uc740 Bluetooth Heart Rate Measurement profile \uc0ac\uc591\uc5d0 \ub9de\ucdb0\uc11c \uc218\ud589\ud558\uace0 \uc788\ub2e4.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">private void broadcastUpdate(final String action) {<br>&nbsp; &nbsp; final Intent intent = new Intent(action);<br>&nbsp; &nbsp; sendBroadcast(intent);<br>}<br><br>private void broadcastUpdate(final String action,<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;final BluetoothGattCharacteristic characteristic) {<br>&nbsp; &nbsp; final Intent intent = new Intent(action);<br><br>&nbsp; &nbsp; \/\/ This is special handling for the Heart Rate Measurement profile. Data<br>&nbsp; &nbsp; \/\/ parsing is carried out as per profile specifications.<br>&nbsp; &nbsp; if (UUID_HEART_RATE_MEASUREMENT.equals(characteristic.getUuid())) {<br>&nbsp; &nbsp; &nbsp; &nbsp; int flag = characteristic.getProperties();<br>&nbsp; &nbsp; &nbsp; &nbsp; int format = -1;<br>&nbsp; &nbsp; &nbsp; &nbsp; if ((flag &amp; 0x01) != 0) {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; format = BluetoothGattCharacteristic.FORMAT_UINT16;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Log.d(TAG, \"Heart rate format UINT16.\");<br>&nbsp; &nbsp; &nbsp; &nbsp; } else {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; format = BluetoothGattCharacteristic.FORMAT_UINT8;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Log.d(TAG, \"Heart rate format UINT8.\");<br>&nbsp; &nbsp; &nbsp; &nbsp; }<br>&nbsp; &nbsp; &nbsp; &nbsp; final int heartRate = characteristic.getIntValue(format, 1);<br>&nbsp; &nbsp; &nbsp; &nbsp; Log.d(TAG, String.format(\"Received heart rate: %d\", heartRate));<br>&nbsp; &nbsp; &nbsp; &nbsp; intent.putExtra(EXTRA_DATA, String.valueOf(heartRate));<br>&nbsp; &nbsp; } else {<br>&nbsp; &nbsp; &nbsp; &nbsp; \/\/ For all other profiles, writes the data formatted in HEX.<br>&nbsp; &nbsp; &nbsp; &nbsp; final byte[] data = characteristic.getValue();<br>&nbsp; &nbsp; &nbsp; &nbsp; if (data != null &amp;&amp; data.length &gt; 0) {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; final StringBuilder stringBuilder = new StringBuilder(data.length);<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for(byte byteChar : data)<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; stringBuilder.append(String.format(\"%02X \", byteChar));<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; intent.putExtra(EXTRA_DATA, new String(data) + \"\\n\" +<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; stringBuilder.toString());<br>&nbsp; &nbsp; &nbsp; &nbsp; }<br>&nbsp; &nbsp; }<br>&nbsp; &nbsp; sendBroadcast(intent);<br>}<\/pre>\n\n\n\n<p>\uc774 \uc774\ubca4\ub4dc\ub4e4\uc740 B roadcastReceiver\uc5d0 \uc758\ud574 \ucc98\ub9ac\ub41c\ub2e4.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">\/\/ Handles various events fired by the Service.<br>\/\/ ACTION_GATT_CONNECTED: connected to a GATT server.<br>\/\/ ACTION_GATT_DISCONNECTED: disconnected from a GATT server.<br>\/\/ ACTION_GATT_SERVICES_DISCOVERED: discovered GATT services.<br>\/\/ ACTION_DATA_AVAILABLE: received data from the device. This can be a<br>\/\/ result of read or notification operations.<br>private final BroadcastReceiver mGattUpdateReceiver = new BroadcastReceiver() {<br>&nbsp; &nbsp; @Override<br>&nbsp; &nbsp; public void onReceive(Context context, Intent intent) {<br>&nbsp; &nbsp; &nbsp; &nbsp; final String action = intent.getAction();<br>&nbsp; &nbsp; &nbsp; &nbsp; if (BluetoothLeService.ACTION_GATT_CONNECTED.equals(action)) {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; mConnected = true;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; updateConnectionState(R.string.connected);<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; invalidateOptionsMenu();<br>&nbsp; &nbsp; &nbsp; &nbsp; } else if (BluetoothLeService.ACTION_GATT_DISCONNECTED.equals(action)) {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; mConnected = false;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; updateConnectionState(R.string.disconnected);<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; invalidateOptionsMenu();<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; clearUI();<br>&nbsp; &nbsp; &nbsp; &nbsp; } else if (BluetoothLeService.<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ACTION_GATT_SERVICES_DISCOVERED.equals(action)) {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; \/\/ Show all the supported services and characteristics on the<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; \/\/ user interface.<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; displayGattServices(mBluetoothLeService.getSupportedGattServices());<br>&nbsp; &nbsp; &nbsp; &nbsp; } else if (BluetoothLeService.ACTION_DATA_AVAILABLE.equals(action)) {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; displayData(intent.getStringExtra(BluetoothLeService.EXTRA_DATA));<br>&nbsp; &nbsp; &nbsp; &nbsp; }<br>&nbsp; &nbsp; }<br>};<\/pre>\n\n\n\n<p>BLE \uc18d\uc131 \uc77d\uae30\uc571\uc774 GATT \uc11c\ubc84\uc5d0 \uc5f0\uacb0\ud558\uace0 \uc11c\ube44\uc2a4\ub97c \ucc3e\uac8c \ub418\uba74 \uc18d\uc131\uc744 &nbsp;\uc77d\uace0\/\uc4f8\uc218 \uc788\uac8c \ub41c\ub2e4. \ub2e4\uc74c \ucf54\ub4dc\ub294 \uc11c\ube44\uc2a4\uc640 \ud2b9\uc131\ub4e4\uc744 \ub098\uc5f4\ud558\uc5ec \ud45c\uc2dc\ud574\uc900\ub2e4.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">public class DeviceControlActivity extends Activity {<br>&nbsp; &nbsp; ...<br>&nbsp; &nbsp; \/\/ Demonstrates how to iterate through the supported GATT<br>&nbsp; &nbsp; \/\/ Services\/Characteristics.<br>&nbsp; &nbsp; \/\/ In this sample, we populate the data structure that is bound to the<br>&nbsp; &nbsp; \/\/ ExpandableListView on the UI.<br>&nbsp; &nbsp; private void displayGattServices(List&lt;BluetoothGattService&gt; gattServices) {<br>&nbsp; &nbsp; &nbsp; &nbsp; if (gattServices == null) return;<br>&nbsp; &nbsp; &nbsp; &nbsp; String uuid = null;<br>&nbsp; &nbsp; &nbsp; &nbsp; String unknownServiceString = getResources().<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; getString(R.string.unknown_service);<br>&nbsp; &nbsp; &nbsp; &nbsp; String unknownCharaString = getResources().<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; getString(R.string.unknown_characteristic);<br>&nbsp; &nbsp; &nbsp; &nbsp; ArrayList&lt;HashMap&lt;String, String&gt;&gt; gattServiceData =<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; new ArrayList&lt;HashMap&lt;String, String&gt;&gt;();<br>&nbsp; &nbsp; &nbsp; &nbsp; ArrayList&lt;ArrayList&lt;HashMap&lt;String, String&gt;&gt;&gt; gattCharacteristicData<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; = new ArrayList&lt;ArrayList&lt;HashMap&lt;String, String&gt;&gt;&gt;();<br>&nbsp; &nbsp; &nbsp; &nbsp; mGattCharacteristics =<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; new ArrayList&lt;ArrayList&lt;BluetoothGattCharacteristic&gt;&gt;();<br><br>&nbsp; &nbsp; &nbsp; &nbsp; \/\/ Loops through available GATT Services.<br>&nbsp; &nbsp; &nbsp; &nbsp; for (BluetoothGattService gattService : gattServices) {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; HashMap&lt;String, String&gt; currentServiceData =<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; new HashMap&lt;String, String&gt;();<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; uuid = gattService.getUuid().toString();<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; currentServiceData.put(<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; LIST_NAME, SampleGattAttributes.<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; lookup(uuid, unknownServiceString));<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; currentServiceData.put(LIST_UUID, uuid);<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; gattServiceData.add(currentServiceData);<br><br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ArrayList&lt;HashMap&lt;String, String&gt;&gt; gattCharacteristicGroupData =<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; new ArrayList&lt;HashMap&lt;String, String&gt;&gt;();<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; List&lt;BluetoothGattCharacteristic&gt; gattCharacteristics =<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; gattService.getCharacteristics();<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ArrayList&lt;BluetoothGattCharacteristic&gt; charas =<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; new ArrayList&lt;BluetoothGattCharacteristic&gt;();<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;\/\/ Loops through available Characteristics.<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for (BluetoothGattCharacteristic gattCharacteristic :<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; gattCharacteristics) {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; charas.add(gattCharacteristic);<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; HashMap&lt;String, String&gt; currentCharaData =<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; new HashMap&lt;String, String&gt;();<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; uuid = gattCharacteristic.getUuid().toString();<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; currentCharaData.put(<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; LIST_NAME, SampleGattAttributes.lookup(uuid,<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; unknownCharaString));<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; currentCharaData.put(LIST_UUID, uuid);<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; gattCharacteristicGroupData.add(currentCharaData);<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; mGattCharacteristics.add(charas);<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; gattCharacteristicData.add(gattCharacteristicGroupData);<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}<br>&nbsp; &nbsp; ...<br>&nbsp; &nbsp; }<br>...<br>}<\/pre>\n\n\n\n<p>GATT \ud1b5\uc9c0 \uc218\uc2e0\ub514\ubc14\uc774\uc2a4\uc758 \ud2b9\uc131\uc774 \ubcc0\uacbd\uc5d0 \ub300\ud55c \ud1b5\uc9c0\ub97c \uc571\uc774 \uc54c\uc218 \uc788\ub2e4. \ub2e4\uc74c \ucf54\ub4dc\ub294 setCharacteristicNotification()\uba54\uc18c\ub4dc\ub85c \uc5b4\ub5bb\uac8c \ud1b5\uc9c0\ub97c \uc124\uc815\ud558\ub294\uc9c0 \ubcf4\uc5ec\uc900\ub2e4.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">private BluetoothGatt mBluetoothGatt;<br>BluetoothGattCharacteristic characteristic;<br>boolean enabled;<br>...<br>mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);<br>...<br>BluetoothGattDescriptor descriptor = characteristic.getDescriptor(<br>&nbsp; &nbsp; &nbsp; &nbsp; UUID.fromString(SampleGattAttributes.CLIENT_CHARACTERISTIC_CONFIG));<br>descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);<br>mBluetoothGatt.writeDescriptor(descriptor);<\/pre>\n\n\n\n<p>\ud558\ub098\uc758 \ud2b9\uc131\uc5d0 \ub300\ud574 \ud1b5\uc9c0\uac00 \ud65c\uc131\ud654\ub418\uba74 onCharacteristicChanged()\uac00 \uc7a5\uce58\uc5d0\uc11c \ud574\ub2f9 \ud2b9\uc131\uc815\ubcf4\uac00 \ubcc0\uacbd\uc774 \ub418\uba74 \ud638\ucd9c\ub41c\ub2e4.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">@Override<br>\/\/ Characteristic notification<br>public void onCharacteristicChanged(BluetoothGatt gatt,<br>&nbsp; &nbsp; &nbsp; &nbsp; BluetoothGattCharacteristic characteristic) {<br>&nbsp; &nbsp; broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);<br>}<\/pre>\n\n\n\n<p>\ud074\ub77c\uc774\uc5b8\ud2b8 \uc571\uc758 \uc885\ub8ccBLE \uc7a5\uce58\ub97c \uc0ac\uc6a9\ud558\ub294 \uc571\uc774 \uc885\ub8cc\ub418\uba74 \ubc18\ub4dc\uc2dc close()\ub97c \ud638\ucd9c\ud558\uc5ec \uc2dc\uc2a4\ud15c\uc774 \uad00\ub828 \ub9ac\uc18c\uc2a4\ub97c \ubc18\ud658\ud558\ub3c4\ub85d \ud574\uc57c \ud55c\ub2e4.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">public void close() {<br>&nbsp; &nbsp; if (mBluetoothGatt == null) {<br>&nbsp; &nbsp; &nbsp; &nbsp; return;<br>&nbsp; &nbsp; }<br>&nbsp; &nbsp; mBluetoothGatt.close();<br>&nbsp; &nbsp; mBluetoothGatt = null;<br>}<\/pre>\n\n\n\n<p>\ucd9c\ucc98: <a href=\"https:\/\/samse.tistory.com\/entry\/android-Bluetooth-LE-programmingBLE\">https:\/\/samse.tistory.com\/entry\/android-Bluetooth-LE-programmingBLE<\/a> [\uace0 \ud22c \ub354 \uba58\ud1a0]<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Bluetooth Low Energy 4.3\ubd80\ud130 BLE central role\uc744 \uc9c0\uc6d0\ud558\uae30 \uc2dc\uc791\ud588\ub2e4. \uadf8\ub9ac\uace0 \ub514\ubc14\uc774\uc2a4 \uac80\uc0c9\uacfc \uc11c\ube44\uc2a4 \uac80\uc0c9 \uadf8\ub9ac\uace0 \uc18d\uc131\ub4e4\uc758 \uc77d\uae30\/\uc4f0\uae30\ub97c \uc9c0\uc6d0\ud55c\ub2e4. BLE\ub97c \ud1b5\ud574 \uc800\uc804\ub825\uc73c\ub85c \uc124\uacc4\ub41c \ub2e4\uc591\ud55c \ub514\ubc14\uc774\uc2a4\uc640\ud1b5\uc2e0\uc774 \uac00\ub2a5\ud574\uc84c\ub2e4.Key&#8230;<\/p>\n<div class=\"more-link-wrapper\"><a class=\"more-link\" href=\"http:\/\/www.space4u.co.kr\/wp\/?p=63\">\ub354 \uc77d\uae30<span class=\"screen-reader-text\">\uc548\ub4dc\ub85c\uc774\ub4dc BLE \ud504\ub85c\uadf8\ub798\ubc0d<\/span> <i class=\"fas fa-angle-right\"><\/i><\/a><\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[6],"tags":[14,15,17,16,13],"aioseo_notices":[],"_links":{"self":[{"href":"http:\/\/www.space4u.co.kr\/wp\/index.php?rest_route=\/wp\/v2\/posts\/63"}],"collection":[{"href":"http:\/\/www.space4u.co.kr\/wp\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.space4u.co.kr\/wp\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.space4u.co.kr\/wp\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/www.space4u.co.kr\/wp\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=63"}],"version-history":[{"count":2,"href":"http:\/\/www.space4u.co.kr\/wp\/index.php?rest_route=\/wp\/v2\/posts\/63\/revisions"}],"predecessor-version":[{"id":240,"href":"http:\/\/www.space4u.co.kr\/wp\/index.php?rest_route=\/wp\/v2\/posts\/63\/revisions\/240"}],"wp:attachment":[{"href":"http:\/\/www.space4u.co.kr\/wp\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=63"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.space4u.co.kr\/wp\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=63"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.space4u.co.kr\/wp\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=63"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}