Notice
Recent Posts
Recent Comments
Link
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
Tags
more
Archives
Today
Total
관리 메뉴

대웅짱님의 블로그

Bluetooth Low Energy 스캔 본문

안드로이드/ble통신

Bluetooth Low Energy 스캔

대웅짱 2018. 6. 22. 13:46

가장 먼저 안드로이드 기기가 BLE 스캔을 하기 위해선 퍼미션이 있어야한다.


프로젝트를 만들면 자동으로 생성되는


AndroidManifest.xml파일이있다.


이 파일에


1
2
3
<uses-permission android:name="android.permission.BLUETOOTH" />
 
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />



위의 두 줄(블루투스 퍼미션)을 추가해주자. (<application 위에다가 추가해주면 된다.)


그런데 위의 퍼미션을 추가해도 스캔이 안되는 상황이 발생할 수 있다.


1
2
3
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
 
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />



그럼 위의 두 줄(위치기반 퍼미션)을 추가해주면 된다.


그 후 scan할 activity에서


onCreate안에


1
2
3
4
5
//퍼미션 강제 발생코드
 
ActivityCompat.requestPermissions(this,
        new String[]{Manifest.permission.ACCESS_COARSE_LOCATION},
        MY_PERMISSIONS_REQUEST_ACCESS_COARSE_LOCATION);



위의 코드를 추가해주고


onCreate밖에 


1
private final int MY_PERMISSIONS_REQUEST_ACCESS_COARSE_LOCATION = 1



이렇게 써주자. 변수 만들기 귀찮으면 그냥 인자에 1 넣어주면 된다.


(사실 요즘 나오는 핸드폰은 그냥 블루투스 퍼미션만 키면 ble 스캔이 안된다. 웬만하면 위의 코드도 추가해주자.)


위의 코드가 하는 일은 스캔하는 activity가 켜지면 자동으로 퍼미션 요청을 하는 코드이다. (이미 있으면 요청안함)


그 후 Bluetooth 스캔을 위해 어뎁터와 매니저를 선언해야한다.


마찬가지로 onCreate밖에


1
2
private BluetoothManager bluetoothManager;
private BluetoothAdapter bluetoothAdapter;
cs


선언해주고


onCreate안에


1
2
bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
bluetoothAdapter = bluetoothManager.getAdapter();



이렇게 선언해주면 된다.


BluetoothManager는 간단하게 시스템 레벨 서비스 객체라고 생각하면 된다. 서비스를 직접 만드는게 아니고 


시스템으로부터 Manager 객체를 얻어온다.


BluetoothAdapter는 간단하게 Bluetooth 스캔과 페어링된 장치들을 읽어들일 수 있는 객체이다.


이를 바탕으로 원하는 장치와 연결을 할 수 있다.


스캔하기전에 ble를 지원하는 기기인지 확인을 해야한다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
private void bleCheck(BluetoothAdapter bluetoothAdapter) {
    if (bluetoothAdapter == null) {
       //블루투스를 지원하지 않으면 장치를 끈다
       Toast.makeText(this"블루투스를 지원하지 않는 장치입니다.", Toast.LENGTH_SHORT).show();
       finish();
    } else {
       //연결 안되었을 때
       if (!bluetoothAdapter.isEnabled()) {
            //블루투스 연결
            Intent i = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
            startActivity(i);
           }
    }
}



위와 같이 작성후


onCreate안에


1
bleCheck(bluetoothAdapter);



를 써주면 된다. 위 함수의 역할은 ble지원 기기체크도 있지만


안드로이드 핸드폰에 블루투스가 꺼져있을 경우 권한요청 창을 켜주는 역할을 한다.


기본적인 준비가 다 끝났다.


이제 Scan하면 된다.


scan은 


1
bluetoothAdapter.startLeScan(leScanCallback);


stop은


1
2
bluetoothAdapter.stopLeScan(leScanCallback);
mListViewAdapter.notifyDataSetChanged();



위의 코드를 상황에 맞게 넣어주면 된다.


나는 그냥 버튼으로 했다.


버튼 클릭 리스너로.


한번 클릭하면 scan, 다시 클릭하면 stop이 되게 변수를 하나 만들어서 사용했다.


갑자기 나온 mListViewAdapter가 뭐지 궁금할 수도 있는데 이건 내가 만든 scan화면 Listview adapter이다.


즉 스캔한 데이터를 뿌려주는 역할을 하는 객체인데 각자 원하는 UI로 만들면 된다.


Listview만드는 방법은 다른 블로그에 많이 많이 있다. 나도 보고 만들었다.


notifyDataSetChanged()의 역할을 설명하자면 listview의 데이터가 변동이 생겼을 시 그걸 적용해주는


간단히 말해 refresh해주는 역할이다. stop이후 써주는 이유는 UI를 clear하기 위해서인데 이게 싫은 사람은 빼면된다.



자 이제 스캔한 데이터가 어디에서 어떻게 나에게로 오는지 알아보자.


위의 코드 중


1
bluetoothAdapter.startLeScan(leScanCallback);



를 실행하게되면 장치가 스캔될 때 마다 호출되는 callback함수가 있다.

1
2
3
4
5
6
7
8
9
10
11
12
// 스캔 이후 장치 발견 이벤트
private BluetoothAdapter.LeScanCallback leScanCallback = new BluetoothAdapter.LeScanCallback() {
    @Override
    public void onLeScan(final BluetoothDevice device, final int rssi, final byte[] scanRecord) {
        runOnUiThread(new Runnable() {
            public void run() {
                mListViewAdapter.addDevice(device, rssi, scanRecord);
                mListViewAdapter.notifyDataSetChanged();
            }
        });
    }
};


바로 onLeScan 함수이다. 그냥 적당히 onCreate밖에 아무곳에나 위의 코드를 쓰면 된다.


이 함수는 BluetoothDevice, rssi, scanRecord라는 데이터를 인자로 나에게 전달해준다.


이렇게 전달 받은 값들을 이용해 만들어 놓았던 Listview adapter에 추가해주면된다.


마찬가지로 notifyDataSetChanged()를 사용하는데 이는 스캔될 때 마다의 변화를 refresh해주기 위해서이다.


runOnUiThread를 사용하는 이유는 UI가 바로바로 변할 수 있게 해주기 위해서이다.


runOnUiThread를 사용하지 않으면 아무리 notifyDataSetChanged()를 호출하여도 UI에 변화가 없다.


막 화면을 클릭하거나 하는 행동을 줘야지만 UI가 변한다.


인자에 대해 설명하자면


BluetoothDevice는 Device 고유의 객체라고 생각하면 된다. connect할 때 필요한 정보는 


Device Name과 Device Address라고 생각하면 되는데 (사실 Address만 있으면 되지만)


그 둘의 값을 모두 가지고 있는 객체이다.


쉽게 device.getName()과 device.getAddress()를 이용해 값을 받아올 수 있다. 둘다 String형이다.


특히 device.getAddress()는 MAC Address값인데 device의 유니크한 값이라고 생각하면된다. (name은 얼마든지 겹칠 수 있음)


rssi값은 int형으로 현재 device가 내 안드로이드 폰에 보낸 패킷이 얼마나 걸렸는지 대략적으로 나타내주는 값이다


그냥 내 안드로이드 폰과 device의 거리라고 생각하면 편하다.


하지만 신호이기 때문에 다른 요인에 많은 영향을 끼치므로 너무 신뢰하지 않는편이 좋다.


기본적으로 값은 음수 값이며 값이 높을수록 (0에 가까울수록) 가까이 있다는 뜻이다.


마지막으로 scanRecord는 byte배열 값으로 device를 scan한 결과 값들을 보내는 것이다.


사실 다른 기기들은 이 값을 어떻게 사용할지 모르겠다.


내가 만든 앱에서는 이 값을 파싱해서 해당 device의 UUID, Major, Minor 값을 가져왔었다.



스캔편 끝.






 

'안드로이드 > ble통신' 카테고리의 다른 글

Bluetooth Low Energy 시작  (0) 2018.06.22