Notice
Recent Posts
Recent Comments
Link
투케이2K
920. (Android/Java) [TargetSdk 33] observableBeaconScanList : Altbeacon 실시간 비콘 스캔 Scan 소스 코드 본문
Android
920. (Android/Java) [TargetSdk 33] observableBeaconScanList : Altbeacon 실시간 비콘 스캔 Scan 소스 코드
투케이2K 2024. 12. 24. 17:28[개발 환경 설정]
개발 툴 : AndroidStudio
개발 언어 : Java / Kotlin
[소스 코드]
// --------------------------------------------------------------------------------------
[개발 및 테스트 환경]
// --------------------------------------------------------------------------------------
- 언어 : Java / Kotlin
- 개발 툴 : AndroidStudio
- 기술 구분 : Bluetooth / Beacon / Scan
// --------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------
[사전) 라이브러리 의존성 설정 및 퍼미션 권한 설정 정리]
// --------------------------------------------------------------------------------------
/**
* // --------------------------------------------------------
* TODO [클래스 설명]
* // --------------------------------------------------------
* 1. TODO [설명] : 비콘 스캔 및 신호 활성 수행 클래스 : 안드로이드 상위 버전 전용 (S 안드로이드 12 이상)
* // --------------------------------------------------------
* 2. 라이브러리 추가 방법 : Git (https://github.com/AltBeacon/android-beacon-library)
*
* // TODO [altbeacon : 비콘 스캔 및 신호 활성 라이브러리]
* implementation 'org.altbeacon:android-beacon-library:2.19'
* //noinspection GradleCompatible
* implementation 'com.android.support:localbroadcastmanager:28.0.0'
*
* // --------------------------------------------------------
* 3. 필요 퍼미션 권한 : 위치 및 GPS 권한 , 블루투스 권한 - SCAN , ADVERTISE , CONNECT
*
* // TODO [공통]
* <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
* <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
*
* <uses-permission android:name="android.permission.BLUETOOTH"/>
* <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
* <uses-feature android:name="android.hardware.bluetooth_le" />
*
* // TODO [안드로이드 12 이상 : S 버전]
* <uses-permission android:name="android.permission.BLUETOOTH_SCAN"/>
* <uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE"/>
* <uses-permission android:name="android.permission.BLUETOOTH_CONNECT"/>
* // --------------------------------------------------------
* */
// --------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------
[소스 코드]
// --------------------------------------------------------------------------------------
// ------------------------------------------------------------
// TODO [SEARCH FAST] : observableBeaconScanList : 비콘 실시간 목록 스캔 결과 반환
// ------------------------------------------------------------
// TODO [호출 방법 소스 코드]
// ------------------------------------------------------------
/*
try {
C_Beacon_Client_Module.observableBeaconScanList(A_Intro.this)
.subscribeOn(AndroidSchedulers.mainThread()) // [Observable (생성자) 로직을 IO 스레드에서 실행 : 백그라운드]
.observeOn(Schedulers.io()) // [Observer (관찰자) 로직을 메인 스레드에서 실행]
.subscribe(new Observer<ArrayList<HashMap<String, Object>>>() { // [Observable.create 타입 지정]
@Override
public void onSubscribe(@NonNull Disposable d) {
}
@Override
public void onNext(@NonNull ArrayList<HashMap<String, Object>> value) {
S_Log._W_(ACTIVITY_NAME + " :: 비콘 실시간 스캔 :: onNext", new String[]{String.valueOf(value)});
}
@Override
public void onError(@NonNull Throwable e) {
S_Log._E_(ACTIVITY_NAME + " :: 비콘 실시간 스캔 :: onError", new String[]{String.valueOf(e.getMessage())});
}
@Override
public void onComplete() {
}
});
} catch (Exception e) {
S_Log._printStackTrace_(mContext, S_FinalMsg.LOG_BUG_STATE, null, e);
}
*/
// ------------------------------------------------------------
// [필요 변수 선언]
static BeaconManager beaconManager = null;
static BluetoothAdapter ble_Adapter;
static int beacon_COUNT = 0;
static String beacon_LOG = "";
static ArrayList<HashMap<String, Object>> beacon_List = null;
public static final int beacon_Scan_TimeOut = 10;
// ------------------------------------------------------------
public static Observable<ArrayList<HashMap<String, Object>>> observableBeaconScanList(Context mContext) {
// [로직 처리 실시]
return Observable.create(subscriber -> {
// [변수 초기화]
ble_Adapter = null;
beacon_COUNT = 0;
beacon_LOG = "";
beacon_List = null;
beaconManager = null;
try {
// ===============================================================
S_Log._D_(ACTIVITY_NAME + " :: observableBeaconScanList :: 비콘 실시간 목록 리스트 스캔 시작", null);
// ===============================================================
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
@Override
public void run() {
// [퍼미션 권한 체크 실시]
if (ActivityCompat.checkSelfPermission(mContext, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED
|| ActivityCompat.checkSelfPermission(mContext, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// [퍼미션이 부여되어있지 않은 경우 종료]
beacon_LOG = "[ERROR] : Beacon Scan Permission Location Not Granted (비콘 실시간 목록 스캔에 필요한 권한을 확인해주세요. / 위치 권한)";
S_Log._E_(ACTIVITY_NAME + " :: observableBeaconScanList :: 에러 발생", new String[]{String.valueOf(beacon_LOG)});
// [리턴 반환 실시]
if (subscriber != null && subscriber.isDisposed() == false) {
subscriber.onError(new Throwable(beacon_LOG));
subscriber.onComplete();
}
return;
} else {
// ---------------------------------------------------------------
// TODO [Android 12 이상 권한 체크 방어 로직]
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S
&& ActivityCompat.checkSelfPermission(mContext, Manifest.permission.BLUETOOTH_SCAN) != PackageManager.PERMISSION_GRANTED
|| ActivityCompat.checkSelfPermission(mContext, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
// [퍼미션이 부여되어있지 않은 경우 종료]
beacon_LOG = "[ERROR] : Beacon Scan Permission Bluetooth Scan Or Connect Not Granted (비콘 실시간 목록 스캔에 필요한 권한을 확인해주세요. / 블루투스 스캔 및 연결 권한)";
S_Log._E_(ACTIVITY_NAME + " :: observableBeaconScanList :: 에러 발생", new String[]{String.valueOf(beacon_LOG)});
// [리턴 반환 실시]
if (subscriber != null && subscriber.isDisposed() == false) {
subscriber.onError(new Throwable(beacon_LOG));
subscriber.onComplete();
}
return;
}
// ---------------------------------------------------------------
// [블루투스 페어링 목록 리스트 스캔 실시]
BluetoothManager bluetoothManager = (BluetoothManager) mContext.getSystemService(Context.BLUETOOTH_SERVICE);
ble_Adapter = bluetoothManager.getAdapter();
if (ble_Adapter == null || ble_Adapter.isEnabled() == false) {
// [블루투스가 활성화 되어 있지 않은 경우 종료]
beacon_LOG = "[ERROR] : Bluetooth Adapter Is Null Or Enabled False (블루투스 기능 지원 여부 및 블루투스 기능 활성 상태 확인 필요)";
S_Log._E_(ACTIVITY_NAME + " :: observableBeaconScanList :: 에러 발생", new String[]{String.valueOf(beacon_LOG)});
// [리턴 반환 실시]
if (subscriber != null && subscriber.isDisposed() == false) {
subscriber.onError(new Throwable(beacon_LOG));
subscriber.onComplete();
}
return;
}
// ---------------------------------------------------------------
// [ArrayList 객체 생성]
beacon_List = new ArrayList();
// ---------------------------------------------------------------
// TODO [BeaconManager 인스턴스 획득 및 Region 등록]
beaconManager = BeaconManager.getInstanceForApplication(mContext); // [객체 생성]
Region region = new Region("myRangingUniqueId", null, null, null); // [Region 지정]
// TODO [Beacon 모니터링 addRangeNotifier 등록]
beaconManager.addRangeNotifier(new RangeNotifier() {
@Override
public void didRangeBeaconsInRegion(Collection<Beacon> beacons, Region region) {
if (beacons.size() > 0) {
S_Log.w("DID_RANGE_BEACON", "========================= [Beacon Scan Size : "+String.valueOf(beacons.size())+"] =========================");
ArrayList<Beacon> beaconList = new ArrayList<>(beacons);
for (int i=0; i<beaconList.size(); i++){
Beacon beacon = (Beacon) beaconList.get(i);
HashMap<String, Object> map = new HashMap<>();
map.put("Uuid", beacon.getId1().toString());
map.put("Major", beacon.getId2().toString());
map.put("Minor", beacon.getId3().toString());
if (beacon_List.contains(map) == false){
beacon_List.add(map);
}
}
}
else {
S_Log.e("DID_RANGE_BEACON", "========================= [Beacon Scan Size Null] =========================");
}
}
});
// TODO [블루투스가 스캔을 중지하지 않도록 설정]
beaconManager.setRegionStatePersistenceEnabled(false);
// TODO [레이아웃 지정 - IOS , Android 모두 스캔 가능]
beaconManager.getBeaconParsers().add(new BeaconParser().setBeaconLayout("m:2-3=0215,i:4-19,i:20-21,i:22-23,p:24-24,d:25-25"));
// TODO [실시간 비콘 스캔 모니터링 시작]
beaconManager.startRangingBeacons(region);
// ---------------------------------------------------------------
// TODO [비콘 스캔 종료 타이머 설정]
Handler handler = new Handler(Looper.getMainLooper());
handler.postDelayed(new Runnable() {
@Override
public void run() {
// [로그 추가]
beacon_LOG = "[Success] : Beacon List Scan";
S_Log._W_(ACTIVITY_NAME + " :: observableBeaconScanList :: 비콘 실시간 리스트 목록 스캔", new String[]{
"M_LOG :: " + String.valueOf(beacon_LOG),
"SCAN_COUNT :: " + String.valueOf(beacon_List.size()),
"SCAN_LIST :: " + String.valueOf(beacon_List)
});
// [리턴 반환 실시]
if (subscriber != null && subscriber.isDisposed() == false) {
subscriber.onNext(beacon_List);
subscriber.onComplete();
}
if (ActivityCompat.checkSelfPermission(mContext, Manifest.permission.BLUETOOTH_SCAN) != PackageManager.PERMISSION_GRANTED) {
return;
}
// TODO [비콘 리스트 스캔 종료]
if (beaconManager != null){
beaconManager.stopRangingBeacons(region);
}
}
}, beacon_Scan_TimeOut * 1000);
// ---------------------------------------------------------------
}
}
}, 0);
} catch (final Exception e) {
S_Log._printStackTrace_(mContext, S_FinalMsg.LOG_BUG_STATE, null, e);
S_Log._E_(ACTIVITY_NAME + " :: observableBeaconScanList :: EXCEPTION", new String[]{String.valueOf(e.getMessage())});
try {
// [에러 메시지 삽입]
beacon_LOG = "[EXCEPTION] : " + String.valueOf(e.getMessage());
// [리턴 반환 실시]
if (subscriber != null && subscriber.isDisposed() == false) {
subscriber.onError(new Throwable(beacon_LOG));
subscriber.onComplete();
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
});
}
// --------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------
[결과 출력]
// --------------------------------------------------------------------------------------
D///===========//: ================================================
I/: [LOG :: CLASS PLACE :: com.example.javaproject.C_Module.C_Beacon_Client_Module.lambda$observableBeaconScanList$0(C_Beacon_Client_Module.java:167)]
I/: ----------------------------------------------------
I/: [LOG :: DESCRIPTION :: C_Beacon_Client_Module :: observableBeaconScanList :: 비콘 실시간 목록 리스트 스캔 시작]
D///===========//: ================================================
I/BluetoothAdapter: BluetoothAdapter() : com.example.javaproject.staging
I/BeaconManager: BeaconManager started up on pid 14020 named 'com.example.javaproject.staging' for application package 'com.example.javaproject.staging'. isMainProcess=true
D/BeaconParser: Parsing beacon layout: m:2-3=beac,i:4-19,i:20-21,i:22-23,p:24-24,d:25-25
D/BeaconParser: Parsing beacon layout: m:2-3=0215,i:4-19,i:20-21,i:22-23,p:24-24,d:25-25
I/ScanJob: ScanJob Lifecycle START: org.altbeacon.beacon.service.ScanJob@6572009
I/CycledLeScanner: Using Android O scanner
I/ScanJob: Using immediateScanJobId from manifest: 208352939
I/ScanJob: Running immediate scan job: instance is org.altbeacon.beacon.service.ScanJob@6572009
I/ScanJob: scanJob version 2.19 is starting up on the main process
W/ModelSpecificDistanceCalculator: Cannot find match for this device. Using default
W/ModelSpecificDistanceCalculator: Cannot find match for this device. Using default
I/BluetoothAdapter: BluetoothAdapter() : com.example.javaproject.staging
I/BluetoothAdapter: STATE_ON
I/BluetoothAdapter: STATE_ON
D/BluetoothLeScanner: Stop Scan with callback intent
I/BluetoothAdapter: STATE_ON
I/BluetoothAdapter: STATE_ON
I/ScanJob: Scan job running for 300000 millis
I/BluetoothAdapter: STATE_ON
I/BluetoothAdapter: STATE_ON
D/BluetoothLeScanner: Start Scan with callback
D/BluetoothLeScanner: onScannerRegistered() - status=0 scannerId=13 mScannerId=0
W///===========//: ================================================
I/: [LOG :: CLASS PLACE :: com.example.javaproject.C_Module.C_Beacon_Client_Module$1$2.run(C_Beacon_Client_Module.java:292)]
I/: ----------------------------------------------------
I/: [LOG :: DESCRIPTION :: C_Beacon_Client_Module :: observableBeaconScanList :: 비콘 실시간 리스트 목록 스캔]
I/: ----------------------------------------------------
I/: [LOG :: M_LOG :: [Success] : Beacon List Scan]
I/: ----------------------------------------------------
I/: [LOG :: SCAN_COUNT :: 2]
I/: ----------------------------------------------------
I/: [LOG :: SCAN_LIST :: [{Uuid=03c3c219-588e-f909-db0a-320ac6deeff0, Major=0, Minor=263}, {Uuid=03e6addb-1a0c-5909-db0d-450ac9deeff0, Major=0, Minor=263}]]
W///===========//: ================================================
// --------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------
[참고 사이트]
// --------------------------------------------------------------------------------------
[altbeacon 라이브러리 사용해 실시간 비콘 신호 스캔 및 비콘 신호 활성 실시]
https://blog.naver.com/kkh0977/222346562441?trackingCode=blog_bloghome_searchlist
[alt beacon 비콘 빌드 오류 - debugCompileClasspath , Bad Gateway 502]
https://blog.naver.com/kkh0977/222623395643?trackingCode=blog_bloghome_searchlist
[비콘 (beacon) 스캔이 되지 않는 경우 해결 조치]
https://blog.naver.com/kkh0977/222696189077?trackingCode=blog_bloghome_searchlist
// --------------------------------------------------------------------------------------
반응형
'Android' 카테고리의 다른 글
Comments