Android
블루투스 및 블루투스 LE API
수색…
비고
Bluetooth Classic은 Android 2.0 (API 레벨 5) 이상에서 사용할 수 있습니다. Bluetooth LE는 Android 4.3 (API 레벨 18) 이상에서 사용할 수 있습니다.
권한
응용 프로그램에서 Bluetooth 기능을 사용하려면이 권한을 매니페스트 파일에 추가하십시오.
<uses-permission android:name="android.permission.BLUETOOTH" />
장치 검색을 시작하거나 Bluetooth 설정을 조작해야하는 경우이 권한을 추가해야합니다.
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
Android API 레벨 23 이상을 타겟팅하는 경우 위치 정보 액세스가 필요합니다.
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<!-- OR -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
* 사용 권한을 적절하게 사용하는 방법에 대한 자세한 내용은 사용 권한 항목을 참조하십시오.
블루투스가 사용 설정되어 있는지 확인
private static final int REQUEST_ENABLE_BT = 1; // Unique request code
BluetoothAdapter mBluetoothAdapter;
// ...
if (!mBluetoothAdapter.isEnabled()) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}
// ...
@Override
protected void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_ENABLE_BT) {
if (resultCode == RESULT_OK) {
// Bluetooth was enabled
} else if (resultCode == RESULT_CANCELED) {
// Bluetooth was not enabled
}
}
}
기기를 검색 가능하게 만들기
private static final int REQUEST_DISCOVERABLE_BT = 2; // Unique request code
private static final int DISCOVERABLE_DURATION = 120; // Discoverable duration time in seconds
// 0 means always discoverable
// maximum value is 3600
// ...
Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, DISCOVERABLE_DURATION);
startActivityForResult(discoverableIntent, REQUEST_DISCOVERABLE_BT);
// ...
@Override
protected void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_DISCOVERABLE_BT) {
if (resultCode == RESULT_OK) {
// Device is discoverable
} else if (resultCode == RESULT_CANCELED) {
// Device is not discoverable
}
}
}
주변의 블루투스 기기 찾기
먼저 BluetoothAdapter
선언하십시오.
BluetoothAdapter mBluetoothAdapter;
이제 ACTION_FOUND
대한 BroadcastReceiver
를 만듭니다.
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
//Device found
if (BluetoothDevice.ACTION_FOUND.equals(action))
{
// Get the BluetoothDevice object from the Intent
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
// Add the name and address to an array adapter to show in a list
mArrayAdapter.add(device.getName() + "\n" + device.getAddress());
}
}
};
BroadcastReceiver
등록
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
registerReceiver(mReceiver, filter);
그런 다음 startDiscovery
를 호출하여 근처의 블루투스 장치 검색을 시작합니다.
mBluetoothAdapter.startDiscovery();
onDestroy
내에서 BroadcastReceiver
등록을 잊지 마세요.
unregisterReceiver(mReceiver);
블루투스 장치에 연결
BluetoothDevice를 얻은 후에는 BluetoothDevice와 통신 할 수 있습니다. 소켓 입력 / 출력 스트림을 사용하여 수행되는 이러한 종류의 통신 :
그것들은 블루투스 통신 설립의 기본 단계입니다 :
1) 소켓 초기화 :
private BluetoothSocket _socket;
//...
public InitializeSocket(BluetoothDevice device){
try {
_socket = device.createRfcommSocketToServiceRecord(<Your app UDID>);
} catch (IOException e) {
//Error
}
}
2) 소켓에 연결 :
try {
_socket.connect();
} catch (IOException connEx) {
try {
_socket.close();
} catch (IOException closeException) {
//Error
}
}
if (_socket != null && _socket.isConnected()) {
//Socket is connected, now we can obtain our IO streams
}
3) 소켓 입력 / 출력 스트림 얻기
private InputStream _inStream;
private OutputStream _outStream;
//....
try {
_inStream = _socket.getInputStream();
_outStream = _socket.getOutputStream();
} catch (IOException e) {
//Error
}
입력 스트림 - 입력 데이터 채널로 사용 (연결된 장치로부터 데이터 수신)
출력 스트림 - 나가는 데이터 채널로 사용 (연결된 장치로 데이터 보내기)
세 번째 단계를 완료하면 이전에 초기화 된 스트림을 사용하여 두 장치간에 데이터를 송수신 할 수 있습니다.
1) 데이터 수신 (소켓 입력 스트림에서 읽기)
byte[] buffer = new byte[1024]; // buffer (our data)
int bytesCount; // amount of read bytes
while (true) {
try {
//reading data from input stream
bytesCount = _inStream.read(buffer);
if(buffer != null && bytesCount > 0)
{
//Parse received bytes
}
} catch (IOException e) {
//Error
}
}
2) 데이터 전송 (출력 스트림에 쓰기)
public void write(byte[] bytes) {
try {
_outStream.write(bytes);
} catch (IOException e) {
//Error
}
}
- 물론 연결, 읽기 및 쓰기 기능은 전용 스레드에서 수행해야합니다.
- 소켓 및 스트림 객체가 있어야합니다.
근처의 Bluetooth 저에너지 장치 찾기
BluetoothLE API는 API 18에서 소개되었습니다. 그러나 장치 검색 방법은 API 21에서 변경되었습니다. 장치 검색은 스캔 할 서비스 UUID (공식적으로 채택 된 16 비트 UUID 또는 독점적 인 것) . 이 예는 API를 BLE 장치를 검색하는 독립적 인 방법으로 만드는 방법을 보여줍니다.
- 블루투스 장치 모델 생성 :
public class BTDevice {
String address;
String name;
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
- 블루투스 스캔 인터페이스 정의 :
public interface ScanningAdapter {
void startScanning(String name, String[] uuids);
void stopScanning();
List<BTDevice> getFoundDeviceList();
}
- 스캐닝 팩토리 클래스 생성 :
public class BluetoothScanningFactory implements ScanningAdapter {
private ScanningAdapter mScanningAdapter;
public BluetoothScanningFactory() {
if (isNewerAPI()) {
mScanningAdapter = new LollipopBluetoothLEScanAdapter();
} else {
mScanningAdapter = new JellyBeanBluetoothLEScanAdapter();
}
}
private boolean isNewerAPI() {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP;
}
@Override
public void startScanning(String[] uuids) {
mScanningAdapter.startScanning(uuids);
}
@Override
public void stopScanning() {
mScanningAdapter.stopScanning();
}
@Override
public List<BTDevice> getFoundDeviceList() {
return mScanningAdapter.getFoundDeviceList();
}
}
- 각 API에 대한 팩토리 구현 만들기 :
API 18 :
import android.annotation.TargetApi;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.os.Build;
import android.os.Parcelable;
import android.util.Log;
import bluetooth.model.BTDevice;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
public class JellyBeanBluetoothLEScanAdapter implements ScanningAdapter{
BluetoothAdapter bluetoothAdapter;
ScanCallback mCallback;
List<BTDevice> mBluetoothDeviceList;
public JellyBeanBluetoothLEScanAdapter() {
bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
mCallback = new ScanCallback();
mBluetoothDeviceList = new ArrayList<>();
}
@Override
public void startScanning(String[] uuids) {
if (uuids == null || uuids.length == 0) {
return;
}
UUID[] uuidList = createUUIDList(uuids);
bluetoothAdapter.startLeScan(uuidList, mCallback);
}
private UUID[] createUUIDList(String[] uuids) {
UUID[] uuidList = new UUID[uuids.length];
for (int i = 0 ; i < uuids.length ; ++i) {
String uuid = uuids[i];
if (uuid == null) {
continue;
}
uuidList[i] = UUID.fromString(uuid);
}
return uuidList;
}
@Override
public void stopScanning() {
bluetoothAdapter.stopLeScan(mCallback);
}
@Override
public List<BTDevice> getFoundDeviceList() {
return mBluetoothDeviceList;
}
private class ScanCallback implements BluetoothAdapter.LeScanCallback {
@Override
public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {
if (isAlreadyAdded(device)) {
return;
}
BTDevice btDevice = new BTDevice();
btDevice.setName(new String(device.getName()));
btDevice.setAddress(device.getAddress());
mBluetoothDeviceList.add(btDevice);
Log.d("Bluetooth discovery", device.getName() + " " + device.getAddress());
Parcelable[] uuids = device.getUuids();
String uuid = "";
if (uuids != null) {
for (Parcelable ep : uuids) {
uuid += ep + " ";
}
Log.d("Bluetooth discovery", device.getName() + " " + device.getAddress() + " " + uuid);
}
}
private boolean isAlreadyAdded(BluetoothDevice bluetoothDevice) {
for (BTDevice device : mBluetoothDeviceList) {
String alreadyAddedDeviceMACAddress = device.getAddress();
String newDeviceMACAddress = bluetoothDevice.getAddress();
if (alreadyAddedDeviceMACAddress.equals(newDeviceMACAddress)) {
return true;
}
}
return false;
}
}
}
API 21 :
import android.annotation.TargetApi;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.le.BluetoothLeScanner;
import android.bluetooth.le.ScanFilter;
import android.bluetooth.le.ScanResult;
import android.bluetooth.le.ScanSettings;
import android.os.Build;
import android.os.ParcelUuid;
import bluetooth.model.BTDevice;
import java.util.ArrayList;
import java.util.List;
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public class LollipopBluetoothLEScanAdapter implements ScanningAdapter {
BluetoothLeScanner bluetoothLeScanner;
ScanCallback mCallback;
List<BTDevice> mBluetoothDeviceList;
public LollipopBluetoothLEScanAdapter() {
bluetoothLeScanner = BluetoothAdapter.getDefaultAdapter().getBluetoothLeScanner();
mCallback = new ScanCallback();
mBluetoothDeviceList = new ArrayList<>();
}
@Override
public void startScanning(String[] uuids) {
if (uuids == null || uuids.length == 0) {
return;
}
List<ScanFilter> filterList = createScanFilterList(uuids);
ScanSettings scanSettings = createScanSettings();
bluetoothLeScanner.startScan(filterList, scanSettings, mCallback);
}
private List<ScanFilter> createScanFilterList(String[] uuids) {
List<ScanFilter> filterList = new ArrayList<>();
for (String uuid : uuids) {
ScanFilter filter = new ScanFilter.Builder()
.setServiceUuid(ParcelUuid.fromString(uuid))
.build();
filterList.add(filter);
};
return filterList;
}
private ScanSettings createScanSettings() {
ScanSettings settings = new ScanSettings.Builder()
.setScanMode(ScanSettings.SCAN_MODE_BALANCED)
.build();
return settings;
}
@Override
public void stopScanning() {
bluetoothLeScanner.stopScan(mCallback);
}
@Override
public List<BTDevice> getFoundDeviceList() {
return mBluetoothDeviceList;
}
public class ScanCallback extends android.bluetooth.le.ScanCallback {
@Override
public void onScanResult(int callbackType, ScanResult result) {
super.onScanResult(callbackType, result);
if (result == null) {
return;
}
BTDevice device = new BTDevice();
device.setAddress(result.getDevice().getAddress());
device.setName(new StringBuffer(result.getScanRecord().getDeviceName()).toString());
if (device == null || device.getAddress() == null) {
return;
}
if (isAlreadyAdded(device)) {
return;
}
mBluetoothDeviceList.add(device);
}
private boolean isAlreadyAdded(BTDevice bluetoothDevice) {
for (BTDevice device : mBluetoothDeviceList) {
String alreadyAddedDeviceMACAddress = device.getAddress();
String newDeviceMACAddress = bluetoothDevice.getAddress();
if (alreadyAddedDeviceMACAddress.equals(newDeviceMACAddress)) {
return true;
}
}
return false;
}
}
}
다음을 호출하여 장치 목록을 찾습니다.
scanningFactory.startScanning({uuidlist}); wait few seconds... List<BTDevice> bluetoothDeviceList = scanningFactory.getFoundDeviceList();