투케이2K

413. (android/java) [android 12 / target 31] [간단 소스] beacon 비콘 신호 활성 및 비콘 스캔 - 타겟 31 대응 본문

Android

413. (android/java) [android 12 / target 31] [간단 소스] beacon 비콘 신호 활성 및 비콘 스캔 - 타겟 31 대응

투케이2K 2022. 11. 24. 16:16

[개발 환경 설정]

개발 툴 : AndroidStudio

 

[AndroidManifest.xml : 소스 코드]

    <!--  블루투스 및 GPS : 퍼미션 설정 선언  -->
    <uses-permission android:name="android.permission.BLUETOOTH"/>
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>





    <!--블루투스 권한 추가 sdk 31 대응-->
    <uses-permission android:name="android.permission.BLUETOOTH_SCAN"/>
    <uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE"/>
    <uses-permission android:name="android.permission.BLUETOOTH_CONNECT"/>
 
 

[build.gradle : 소스 코드]

    // -----------------------------------------------------------

    // [altbeacon : 비콘 스캔 및 신호 활성 라이브러리]
    implementation 'org.altbeacon:android-beacon-library:2.+' // [최신 버전 사용]
    //implementation 'org.altbeacon:android-beacon-library:2.9.2'
    //implementation 'org.altbeacon:android-beacon-library:2.16.3', ext: 'aar'
    //noinspection GradleCompatible
    implementation 'com.android.support:localbroadcastmanager:28.0.0'

    // -----------------------------------------------------------
 

[java : 소스 코드]

 

[1]. 클래스 import 및 implements 설정

import org.altbeacon.beacon.Beacon;
import org.altbeacon.beacon.BeaconConsumer;
import org.altbeacon.beacon.BeaconManager;
import org.altbeacon.beacon.BeaconParser;
import org.altbeacon.beacon.BeaconTransmitter;
import org.altbeacon.beacon.RangeNotifier;
import org.altbeacon.beacon.Region;

public class A_Main extends AppCompatActivity implements BeaconConsumer { }










[2]. 전역 변수 설정

    // TODO [비콘 스캔 관련 전역 변수]
    private BeaconManager beaconManager; // [비콘 매니저 객체]
    private List<Beacon> beaconList = new ArrayList<>(); // [실시간 비콘 감지 배열]
    int beaconScanCount = 1; // [비콘 스캔 횟수를 카운트하기 위함]
    ArrayList beaconFormatList = new ArrayList<>(); // [스캔한 비콘 리스트를 포맷해서 저장하기 위함]


    // TODO [비콘 신호 활성 관련 전역 변수]
    Beacon beacon; // [비콘 객체]
    BeaconParser beaconParser; // [비콘 파서 객체]
    BeaconTransmitter beaconTransmitter; // [BeaconTransmitter]
    String sendUuid = ""; // [UUID : 비콘 신호 활성 시 사용하는 값]
    String sendMajor = ""; // [MAJOR : 비콘 신호 활성 시 사용하는 값]
    String sendMinor = ""; // [MINOR : 비콘 신호 활성 시 사용하는 값]










[3]. 비콘 정보 셋팅

    //TODO [비콘 스캐닝을 위한 초기 설정]
    public void beaconSettiong(){
        Log.i("---","---");
        Log.d("//===========//","================================================");
        Log.i("","\n"+"["+String.valueOf(ACTIVITY_NAME)+" >> beaconSettiong() :: 비콘 매니저 초기 설정 수행]");
        Log.i("","\n"+"[레이아웃 :: m:2-3=0215,i:4-19,i:20-21,i:22-23,p:24-24,d:25-25]");
        Log.d("//===========//","================================================");
        Log.i("---","---");
        try {
            // [비콘 매니저 생성]
            beaconManager = BeaconManager.getInstanceForApplication(A_Main.this);

            // [블루투스가 스캔을 중지하지 않도록 설정]
            beaconManager.setEnableScheduledScanJobs(false); // TODO 이코드를 설정해야 지맘대로 블루투스가 스캔을 중지하지 않는다.
            //beaconManager.setRegionStatePeristenceEnabled(false);

            // [레이아웃 지정 - 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"));
        }
        catch (Exception e){
            e.printStackTrace();
        }
    }









[4]. 비콘 신호 활성 및 종료
    // TODO [SEARCH FAST] : [비콘 신호 활성]
    public void startBeaconSend(final String UUID, final String MAJOR, final String MINOR){
        Log.i("---","---");
        Log.d("//===========//","================================================");
        Log.i("","\n"+"["+String.valueOf(ACTIVITY_NAME)+" >> startBeaconSend() :: 비콘 신호 활성 수행 실시]");
        Log.i("","\n"+"[UUID :: "+String.valueOf(UUID)+"]");
        Log.i("","\n"+"[MAJOR :: "+String.valueOf(MAJOR)+"]");
        Log.i("","\n"+"[MINOR :: "+String.valueOf(MINOR)+"]");
        Log.d("//===========//","================================================");
        Log.i("---","---");

        // ------------------------------------------
        // [이미 비콘 신호 활성이 진행 중인 경우 먼저 종료 위함]
        try {
            if (beaconTransmitter != null) {
                stopBeaconSend();
            }
        }
        catch (Exception e) {
            //e.printStackTrace();
        }
        // ------------------------------------------
        // [비콘 신호 활성 수행 실시]
        try {
            // [beacon 객체 설정 실시]
            beacon = new Beacon.Builder()
                    .setId1(UUID.toLowerCase()) // [UUID 지정 : 소문자]
                    //.setId1(UUID.toUpperCase()) // [UUID 지정 : 대문자]
                    .setId2(MAJOR) // [major 지정]
                    .setId3(MINOR) // [minor 지정]
                    .setManufacturer(0x004c) // [제조사 지정 : IOS 호환]
                    //.setManufacturer(0x0118) // [제조사 지정]
                    .setTxPower(-59) // [신호 세기]
                    //.setTxPower(59) //[신호 세기]
                    .setDataFields(Arrays.asList(new Long[]{0L})) // [레이아웃 필드]
                    .build();

            // [레이아웃 지정 : IOS 호환 (ibeacon)]
            beaconParser = new BeaconParser().setBeaconLayout("m:2-3=0215,i:4-19,i:20-21,i:22-23,p:24-24");
            //beaconParser = new BeaconParser().setBeaconLayout("m:2-3=beac,i:4-19,i:20-21,i:22-23,p:24-24,d:25-25");

            // [비콘 신호 활성 상태 확인 실시]
            beaconTransmitter = new BeaconTransmitter(getApplicationContext(), beaconParser);
            beaconTransmitter.startAdvertising(beacon, new AdvertiseCallback() {
                @Override
                public void onStartSuccess(AdvertiseSettings settingsInEffect) {
                    super.onStartSuccess(settingsInEffect);
                    Log.i("---","---");
                    Log.w("//===========//","================================================");
                    Log.i("","\n"+"["+String.valueOf(ACTIVITY_NAME)+" >> startBeaconSend() :: 비콘 신호 활성 [성공]]");
                    Log.i("","\n"+"[UUID :: "+String.valueOf(UUID.toLowerCase())+"]");
                    Log.i("","\n"+"[MAJOR :: "+String.valueOf(MAJOR)+"]");
                    Log.i("","\n"+"[MINOR :: "+String.valueOf(MINOR)+"]");
                    Log.i("","\n"+"[시작 시간 :: "+String.valueOf(C_Util.getNowDateTime24())+"]");
                    Log.w("//===========//","================================================");
                    Log.i("---","---");

                    // [팝업창 호출 실시]
                    activityShowAlert(
                            0, // [블루투스 신호 활성 종료]
                            "[비콘 신호 활성]",
                            "[정상] 비콘 신호를 활성했습니다." + "\n" + "\n"
                                    + "UUID : " + String.valueOf(UUID.toLowerCase()) + "\n" + "\n"
                                    + "MAJOR : " + String.valueOf(MAJOR) + "\n" + "\n"
                                    + "MINOR : " + String.valueOf(MINOR) + "\n",
                            "종료",
                            "",
                            "");
                }
                @Override
                public void onStartFailure(int errorCode) {
                    super.onStartFailure(errorCode);
                    Log.i("---","---");
                    Log.e("//===========//","================================================");
                    Log.i("","\n"+"["+String.valueOf(ACTIVITY_NAME)+" >> startBeaconSend() :: 비콘 신호 활성 [실패]]");
                    Log.i("","\n"+"[UUID :: "+String.valueOf(UUID)+"]");
                    Log.i("","\n"+"[MAJOR :: "+String.valueOf(MAJOR)+"]");
                    Log.i("","\n"+"[MINOR :: "+String.valueOf(MINOR)+"]");
                    Log.i("","\n"+"[Error :: "+String.valueOf(errorCode)+"]");
                    Log.e("//===========//","================================================");
                    Log.i("---","---");

                    // [팝업창 호출 실시]
                    activityShowAlert(
                            0, // [블루투스 신호 활성 종료]
                            "[비콘 신호 활성]",
                            "[에러] 비콘 신호 활성에 문제가 발생했습니다." + "\n" + "\n"
                                    + "errorCode : " + String.valueOf(errorCode) + "\n",
                            "확인",
                            "",
                            "");
                }
            });
        }
        catch (Exception e){
            e.printStackTrace();
        }
        // ------------------------------------------
    }


    // TODO [SEARCH FAST] : [비콘 신호 활성]
    public void stopBeaconSend(){
        Log.i("---","---");
        Log.e("//===========//","================================================");
        Log.i("","\n"+"["+String.valueOf(ACTIVITY_NAME)+" >> stopBeaconSend() :: 비콘 신호 활성 종료 실시]");
        Log.e("//===========//","================================================");
        Log.i("---","---");
        try {
            // [변수 값 초기화 지정 실시]
            beacon = null;
            if (beaconTransmitter != null) {
                beaconTransmitter.stopAdvertising();
            }
        }
        catch (Exception e){
            e.printStackTrace();
        }
    }











[5]. 비콘 신호 스캔 및 종료

    // TODO [SEARCH FAST] : [비콘 스캔 수행]
    public void startBeaconScan(){
        Log.i("---","---");
        Log.w("//===========//","================================================");
        Log.i("","\n"+"["+String.valueOf(ACTIVITY_NAME)+" >> startBeaconScan() :: 실시간 비콘 스캔 [시작] 실시]");
        Log.w("//===========//","================================================");
        Log.i("---","---");
        try {
            // [이미 비콘이 진행 중인 경우 종료 실시]
            stopBeaconScan();

            // [비콘 스캔 카운트 변수값 초기화 실시]
            beaconScanCount = 1;

            // [비콘 배열 데이터 초기화 실시]
            if (beaconList != null && beaconList.size()>0){
                beaconList.clear();
            }
            if (beaconFormatList != null && beaconFormatList.size()>0){
                beaconFormatList.clear();
            }

            // [beaconManager Bind 설정]
            beaconManager.bind(A_Main.this);

            // [실시간 비콘 스캔 수행 핸들러 호출]
            beaconScanHandler.sendEmptyMessage(0);
        }
        catch (Exception e){
            e.printStackTrace();
        }
    }


    // TODO [SEARCH FAST] : [비콘 스캔 수행]
    public void stopBeaconScan(){
        Log.i("---","---");
        Log.e("//===========//","================================================");
        Log.i("","\n"+"["+String.valueOf(ACTIVITY_NAME)+" >> stopBeaconScan() :: 실시간 비콘 스캔 [종료] 실시]");
        Log.e("//===========//","================================================");
        Log.i("---","---");
        try {
            // -----------------------------------------
            // [비콘 스캔 카운트 초기화]
            beaconScanCount = 1;
            // -----------------------------------------
            // [비콘 배열 데이터 초기화 실시]
            if (beaconList != null && beaconList.size()>0){
                beaconList.clear();
            }
            if (beaconFormatList != null && beaconFormatList.size()>0){
                beaconFormatList.clear();
            }
            // -----------------------------------------
            // [핸들러 사용 종료]
            try {
                if (beaconScanHandler != null){
                    beaconScanHandler.removeMessages(0);
                    beaconScanHandler.removeCallbacks(null);
                }
            }
            catch (Exception e){
                e.printStackTrace();
            }
            // -----------------------------------------
            // [beaconManager Bind 해제]
            try {
                if(beaconManager != null){
                    beaconManager.unbind(A_Main.this);
                }
            }
            catch (Exception e){
                e.printStackTrace();
            }
            // -----------------------------------------
        }
        catch (Exception e){
            e.printStackTrace();
        }
    }


    // TODO [SEARCH FAST] : [비콘 스캔 수행] : [실시간 비콘 스캐닝 감지 부분]
    @Override
    public void onBeaconServiceConnect() {
        RangeNotifier rangeNotifier = new RangeNotifier() {
            @Override
            public void didRangeBeaconsInRegion(Collection<Beacon> beacons, Region region) {
                // [비콘이 감지되면 해당 함수가 호출]
                // TODO [비콘들에 대응하는 Region 객체가 들어들어옴]
                if (beacons.size() > 0) {

                    if (beaconList != null){
                        beaconList.clear();
                    }

                    for (Beacon beacon : beacons) {
                        if (beaconList != null){
                            beaconList.add(beacon);
                        }
                    }
                }
                else {
                    // TODO [실시간 스캔 반영을 위해 스캔 된 것이 없어도 기존 목록 초기화 실시]
                    if (beaconList != null && beaconList.size() > 0){
                        beaconList.clear();
                    }
                }
            }
        };
        try {
            beaconManager.startRangingBeaconsInRegion(new Region("myRangingUniqueId", null, null, null));
            beaconManager.addRangeNotifier(rangeNotifier);
            beaconManager.startRangingBeaconsInRegion(new Region("myRangingUniqueId", null, null, null));
            beaconManager.addRangeNotifier(rangeNotifier);
        }
        catch (RemoteException e) {
            e.printStackTrace();
        }
    }
    Handler beaconScanHandler = new Handler() {
        public void handleMessage(Message msg) {
            try {
                // [기존에 저장된 배열 데이터 초기화 실시]
                if(beaconFormatList != null && beaconFormatList.size() > 0){
                    beaconFormatList.clear();
                }



                // [for 문 사용해 실시간 스캔된 비콘 개별 정보 확인]
                if (beaconList != null){
                    for(Beacon beacon : beaconList){
                        // TODO [비콘 스캔 정보 추출 참고]
                        /*
                        Log.d("//===========//","================================================");
                        Log.i("","\n"+"["+String.valueOf(ACTIVITY_NAME)+" >> beaconScanHandler() :: 실시간 비콘 스캔 [개별] 정보 확인 실시]");
                        Log.i("","\n"+"[비콘 스캔 Name] "+" ["+String.valueOf(beacon.getBluetoothName())+"]");
                        Log.i("","\n"+"[비콘 스캔 MAC] "+" ["+String.valueOf(beacon.getBluetoothAddress())+"]");
                        Log.i("","\n"+"[비콘 스캔 UUID] "+" ["+String.valueOf(beacon.getId1().toString())+"]");
                        Log.i("","\n"+"[비콘 스캔 Major] "+" ["+String.valueOf(beacon.getId2().toString())+"]");
                        Log.i("","\n"+"[비콘 스캔 Minor] "+" ["+String.valueOf(beacon.getId3().toString())+"]");
                        Log.i("","\n"+"[비콘 스캔 MPower] "+" ["+String.valueOf(beacon.getTxPower())+"]");
                        Log.i("","\n"+"[비콘 스캔 RSSI] "+" ["+String.valueOf(beacon.getRssi())+"]");
                        Log.i("","\n"+"[비콘 스캔 ServiceUuid] "+" ["+String.valueOf(beacon.getServiceUuid())+"]");
                        Log.i("","\n"+"[비콘 스캔 beacon] "+" ["+String.valueOf(beacon.toString())+"]");
                        Log.d("//===========//","================================================");
                        // */

                        // [스캔한 비콘 정보 포맷 실시]
                        JSONObject jsonBeacon = new JSONObject();

                        // [UUID : 소문자 변환]
                        jsonBeacon.put("uuid", String.valueOf(beacon.getId1().toString().toLowerCase()));

                        // [minor (36)]
                        jsonBeacon.put("minor", String.valueOf(beacon.getId3().toString()));

                        // [major (1)]
                        jsonBeacon.put("major", String.valueOf(beacon.getId2().toString()));

                        // [배열에 데이터 저장 실시]
                        beaconFormatList.add(jsonBeacon.toString());

                    } // [for 문 종료]
                }



                // [실시간 스캔된 비콘 정보 확인 실시]
                Log.i("---","---");
                Log.w("//===========//","================================================");
                Log.i("","\n"+"["+String.valueOf(ACTIVITY_NAME)+" >> beaconScanHandler() :: 실시간 비콘 스캔 [전체] 정보 확인 실시]");
                Log.i("","\n"+"[비콘 스캔 실행 횟수] "+" ["+String.valueOf(beaconScanCount)+"]");
                Log.i("","\n"+"[비콘 스캔 개수 확인] "+" ["+String.valueOf(beaconFormatList.size())+"]");
                Log.i("","\n"+"[비콘 스캔 정보 확인] [스캔 포맷 값] "+" ["+String.valueOf(beaconFormatList.toString())+"]");
                Log.w("//===========//","================================================");
                Log.i("---","---");



                // [자바스크립트로 데이터 전송 실시]
                new Android_To_Javascript().scanList(beaconFormatList.toString());



                // [비콘 스캔 카운트 증가]
                beaconScanCount ++;



                // [핸들러 자기 자신을 1초마다 호출]
                beaconScanHandler.sendEmptyMessageDelayed(0, 1000);
            }
            catch (Exception e){
                e.printStackTrace();
            }
        }
    };

 
반응형
Comments