투케이2K

12. (ios/swift) 실시간 비콘 beacon 목록 스캔 실시 본문

IOS

12. (ios/swift) 실시간 비콘 beacon 목록 스캔 실시

투케이2K 2021. 10. 18. 21:39

[개발 환경 설정]

개발 툴 : XCODE

개발 언어 : SWIFT


[방법 설명]

 


[소스 코드]

 

import UIKit
import AVFoundation
import Photos
import CoreLocation
import CoreBluetooth

// [CLLocationManagerDelegate 추가 필요]
class MainController: UIViewController , CLLocationManagerDelegate {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        print("")
        print("===============================")
        print("[MainController > viewDidLoad() : 뷰 로드 실시]")
        print("===============================")
        print("")
        
        // [위치 권한 설정 퍼미션 확인 실시]
        checkLocationPermission()
    }


    /*
    [위치 권한 요청]
    필요 : import CoreLocation
    */
    var locationManager : CLLocationManager!
    func checkLocationPermission(){
        print("")
        print("===============================")
        print("[MainController > checkLocationPermission() : 위치 사용 권한 요청 실시]")
        print("===============================")
        print("")
        self.locationManager = CLLocationManager.init() // locationManager 초기화
        self.locationManager.delegate = self // 델리게이트 넣어줌
        self.locationManager.requestAlwaysAuthorization() // 위치 권한 설정 값을 받아옵니다

        self.locationManager.startUpdatingLocation() // 위치 업데이트 시작
        //self.locationManager.allowsBackgroundLocationUpdates = true // 백그라운드에서도 위치를 체크할 것인지에 대한 여부
        //self.locationManager.pausesLocationUpdatesAutomatically = false // false 설정해야 백그라운드에서 멈추지 않고 돈다
    }
    
    
    // [위치 서비스에 대한 권한 확인 실시]
    func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
        if status == .authorizedAlways {
            print("")
            print("===============================")
            print("[MainController > locationManager() : 위치 사용 권한 항상 허용]")
            print("===============================")
            print("")
            // [실시간 비콘 스캔 호출]
            self.startBeaconScanning()
        }
        if status == .authorizedWhenInUse {
            print("")
            print("===============================")
            print("[MainController > locationManager() : 위치 사용 권한 앱 사용 시 허용]")
            print("===============================")
            print("")
            // [실시간 비콘 스캔 호출]
            self.startBeaconScanning()
        }
        if status == .denied {
            print("")
            print("===============================")
            print("[MainController > locationManager() : 위치 사용 권한 거부]")
            print("===============================")
            print("")
            // [권한 설정 창 이동 실시]
            self.intentAppSettings(content: "위치사용 권한을 허용해주세요")
        }
        if status == .restricted || status == .notDetermined {
            print("")
            print("===============================")
            print("[MainController > locationManager() : 위치 사용 권한 대기 상태]")
            print("===============================")
            print("")
            // [권한 설정 창 이동 실시]
            self.intentAppSettings(content: "위치사용 권한을 허용해주세요")
        }
    }


    // [실시간 비콘 스캐닝 진행]
    var startBeaconScanFlag = false // 비콘 스캔 진행 플래그 값
    var beaconScanCount = 1 // 비콘 스캔 진행 카운트 값
    var beaconScanCheck = false // 일치하는 비콘을 찾은 경우 플래그 값
    
    // [비콘 설정 셋팅 : 설정한 uuid , major , minor 값을 가지고 실시간 비콘 스캔 진행]
    let uuid = UUID(uuidString: "F7A3E806-F5BB-43F8-BA87-0783669EBEB1")!
    //let major = 123 // 필요시 사용
    //let minor = 456 // 필요시 사용
    
    // [특정 uuid , major, minor 일치 값 설정]
    var beaconRegion: CLBeaconRegion!
    var beaconRegionConstraints: CLBeaconIdentityConstraint!
    
    // [특정 비콘을 찾은 경우 저장할 변수]
    var searchUUID : String = ""
    var searchMAJOR : Int = 0
    var searchMINOR : Int = 0
    
    func startBeaconScanning() {
        // [비콘 스캔 진행 실시]
        if CLLocationManager.isMonitoringAvailable(for: CLBeaconRegion.self) {
            if CLLocationManager.isRangingAvailable() { // 비콘 스캔 기능을 이용할 수 있는 경우
                
                // [비콘 스캔이 진행 되지 않은 경우 확인]
                if self.startBeaconScanFlag == false {
                    print("")
                    print("===============================")
                    print("[MainController > startBeaconScanning() : 실시간 비콘 스캔 실시 [정상]]")
                    print("===============================")
                    print("")
                    
                    // [필요시 사용 [1 셋팅] : 특정 uuid , major, minor 일치 값 설정]
                    //self.beaconRegion = CLBeaconRegion.init(uuid: self.uuid, major: CLBeaconMajorValue(self.major), minor: CLBeaconMinorValue(self.minor), identifier: self.uuid.uuidString)
                    //self.beaconRegionConstraints = CLBeaconIdentityConstraint(uuid: self.uuid, major: CLBeaconMajorValue(self.major), minor: CLBeaconMinorValue(self.minor))
                    
                    
                    
                    // [필요시 사용 [2 셋팅] : 특정 uuid 일치 값 설정]
                    self.beaconRegion = CLBeaconRegion.init(uuid: self.uuid, identifier: self.uuid.uuidString)
                    self.beaconRegionConstraints = CLBeaconIdentityConstraint(uuid: self.uuid)

                    
                    
                    // [비콘 스캔 시작]
                    self.locationManager.startMonitoring(for: self.beaconRegion)
                    self.locationManager.startRangingBeacons(satisfying: self.beaconRegionConstraints)
                    
                    
                    // [비콘 스캔 시작 플래그 값 지정]
                    self.startBeaconScanFlag = true
                    self.startTimer() // 타이머 시작 호출
                }
                else {
                    print("")
                    print("===============================")
                    print("[MainController > startBeaconScanning() : 실시간 비콘 스캔 실시 [이미 스캔 진행 중]]")
                    print("===============================")
                    print("")
                }
            }
            else {
                print("")
                print("===============================")
                print("[MainController > startBeaconScanning() : isRangingAvailable == false]")
                print("===============================")
                print("")
                // [권한 설정 창 이동 실시]
                self.showAlert(tittle: "알림", content: "비콘스캔 기능 확인이 필요합니다", okBtb: "확인", noBtn: "")
            }
        }
        else {
            print("")
            print("===============================")
            print("[MainController > startBeaconScanning() : isMonitoringAvailable == false]")
            print("===============================")
            print("")
            // [권한 설정 창 이동 실시]
            self.showAlert(tittle: "알림", content: "비콘스캔 기능 확인이 필요합니다", okBtb: "확인", noBtn: "")
        }
    }


    // [실시간 비콘 감지 수행 부분]
    func locationManager(_ manager: CLLocationManager, didRangeBeacons beacons: [CLBeacon], in region: CLBeaconRegion) {
        if beacons.count > 0 { // [스캔된 비콘 개수가 있는 경우]
            for beacon in beacons {
                print("")
                print("===============================")
                print("[MainController > 실시간 비콘 스캔 목록 확인 [IF]]")
                print("beacon uuid : ", beacon.uuid)
                print("beacon major : ", beacon.major)
                print("beacon minor : ", beacon.minor)
                print("beacon rssi : ", beacon.rssi)
                print("===============================")
                print("")
                
                // [찾으려는 비콘을 발견한 경우]
                if String(beacon.uuid.uuidString) == String(self.uuid.uuidString) &&
                    Int(beacon.major.intValue) == 1 &&
                    Int(beacon.minor.intValue) == 36 {
                    self.searchUUID = beacon.uuid.uuidString // uuid 저장
                    self.searchMAJOR = beacon.major.intValue // major 저장
                    self.searchMINOR = beacon.minor.intValue // minor 저장
                    
                    // 비콘 스캔 종료 실시
                    self.beaconScanCheck = true
                    self.stopTimer() // 타이머 종료 호출
                }
            }
        }
        else {
            for beacon in beacons {
                print("")
                print("===============================")
                print("[MainController > 실시간 비콘 스캔 목록 확인 [ELSE]]")
                print("beacon uuid : ", beacon.uuid)
                print("beacon major : ", beacon.major)
                print("beacon minor : ", beacon.minor)
                print("===============================")
                print("")
            }
        }
    }
    
    
    
    // [실시간 비콘 스캐닝 종료]
    func stopBeaconScanning(){
        print("")
        print("===============================")
        print("[MainController > stopBeaconScanning() : 실시간 비콘 스캔 종료]")
        print("===============================")
        print("")
        // [실시간 비콘 스캔을 진행한 경우]
        if self.startBeaconScanFlag == true {
            self.locationManager.stopMonitoring(for: self.beaconRegion)
            self.locationManager.stopRangingBeacons(satisfying: self.beaconRegionConstraints)
            self.startBeaconScanFlag = false // 비콘 스캔 시작 플래그 초기화
            self.beaconScanCount = 1 // 비콘 스캔 카운트 초기화
            if self.beaconScanCheck == true { // 카운트 동안에 비콘 스캔 일치값 찾음
                self.beaconScanCheck = false // 비콘 일치값 찾음 플래그 초기화
                print("")
                print("===============================")
                print("[MainController > stopBeaconScanning() : 실시간 비콘 스캔 일치값 찾기 성공]")
                print("uuid : ", self.searchUUID)
                print("major : ", self.searchMAJOR)
                print("minor : ", self.searchMINOR)
                print("===============================")
                print("")
                // 저장 값 초기화 실시
                self.searchUUID = ""
                self.searchMAJOR = 0
                self.searchMINOR = 0
            }
            else { // 카운트 동안에 비콘 스캔 일치값 찾지 못함
                self.beaconScanCheck = false // 비콘 일치값 찾음 플래그 초기화
                print("")
                print("===============================")
                print("[MainController > stopBeaconScanning() : 실시간 비콘 스캔 일치값 찾기 실패]")
                print("===============================")
                print("")
            }
        }
    }


    // [실시간 반복 작업 시작 호출]
    var timer : Timer?
    func startTimer(){
        print("")
        print("===============================")
        print("[MainController > startTimer : 비콘 스캔 타이머 동작 시작]")
        print("===============================")
        print("")
        // [타이머 객체 생성 실시]
        self.timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(self.timerCallback), userInfo: nil, repeats: true)
    }
    // [실시간 반복 작업 수행 부분]
    @objc func timerCallback() {
        print("")
        print("===============================")
        print("[MainController > timerCallback : 비콘 스캔 타이머 동작 진행]")
        print("[beaconScanCount : \(beaconScanCount)]")
        print("===============================")
        print("")
        
        // [처리할 로직 작성 실시]
        self.beaconScanCount += 1 // 1씩 카운트 값 증가 실시
        if self.beaconScanCount > 10 { // 카운트 값이 10인 경우
            self.stopTimer() // 타이머 종료 실시
        }
    }
    // [실시간 반복 작업 정지 호출]
    func stopTimer(){
        print("")
        print("===============================")
        print("[MainController > stopTimer : 비콘 스캔 타이머 동작 종료]")
        print("===============================")
        print("")
        // [실시간 반복 작업 중지]
        if self.timer != nil && self.timer!.isValid {
            self.timer!.invalidate()
            self.stopBeaconScanning() // 비콘 스캔 종료 호출
        }
    }

    
    
    
    // [애플리케이션 설정창 이동 실시 메소드]
    func intentAppSettings(content:String){
        // 앱 설정창 이동 실시
        let settingsAlert = UIAlertController(title: "권한 설정 알림", message: content, preferredStyle: UIAlertController.Style.alert)
        
        let okAction = UIAlertAction(title: "확인", style: .default) { (action) in
            // [확인 버튼 클릭 이벤트 내용 정의 실시]
            if let url = URL(string: UIApplication.openSettingsURLString) {
                print("")
                print("===============================")
                print("[MainController > intentAppSettings() : 앱 설정 화면 이동]")
                print("===============================")
                print("")
                UIApplication.shared.open(url, options: [:], completionHandler: nil)
            }
        }
        settingsAlert.addAction(okAction) // 버튼 클릭 이벤트 객체 연결
        
        let noAction = UIAlertAction(title: "취소", style: .default) { (action) in
            // [취소 버튼 클릭 이벤트 내용 정의 실시]
            return
        }
        settingsAlert.addAction(noAction) // 버튼 클릭 이벤트 객체 연결
        
        // [alert 팝업창 활성 실시]
        present(settingsAlert, animated: false, completion: nil)
    }


    // [alert 팝업창 호출 메소드 정의 실시 : 이벤트 호출 시]
    // 호출 방법 : showAlert(tittle: "title", content: "content", okBtb: "확인", noBtn: "취소")
    func showAlert(tittle:String, content:String, okBtb:String, noBtn:String) {
        // [UIAlertController 객체 정의 실시]
        let alert = UIAlertController(title: tittle, message: content, preferredStyle: UIAlertController.Style.alert)
        
        // [인풋으로 들어온 확인 버튼이 nil 아닌 경우]
        if(okBtb != "" && okBtb.count>0){
            let okAction = UIAlertAction(title: okBtb, style: .default) { (action) in
                // [확인 버튼 클릭 이벤트 내용 정의 실시]
                return
            }
            alert.addAction(okAction) // 버튼 클릭 이벤트 객체 연결
        }
        
        // [인풋으로 들어온 취소 버튼이 nil 아닌 경우]
        if(noBtn != "" && noBtn.count>0){
            let noAction = UIAlertAction(title: noBtn, style: .default) { (action) in
                // [취소 버튼 클릭 이벤트 내용 정의 실시]
                return
            }
            alert.addAction(noAction) // 버튼 클릭 이벤트 객체 연결
        }
        
        // [alert 팝업창 활성 실시]
        present(alert, animated: false, completion: nil)
    }
    
}

[결과 출력]

 


 

반응형
Comments