반응형

NdefFormatable은 NFC 태그를 NDEF 형식으로 포맷할 수 있을 때 사용하는 인터페이스이다. 만약 NFC 태그가 NDEF 형식으로 포맷되지 않은 경우, NDEF 포맷팅 작업을 수행할 수 있다. 이 기능은 주로 NFC 태그가 기본적으로 NDEF 메시지를 지원하지 않는 경우에 사용된다. NDEF 포맷팅은 태그에 데이터를 기록할 수 있는 형태로 변환하는 과정을 말한다.

NdefFormatable 사용 시점:

  • NFC 태그가 아직 NDEF 포맷으로 되어 있지 않은 경우 NdefFormatable을 사용하여 태그를 포맷하고 NDEF 메시지를 기록할 수 있다.
  • 한 번만 포맷할 수 있는 태그, 비어 있는 상태에서만 포맷할 수 있는 태그에 유용하다.

일반적으로 NFC 태그를 처음 사용하거나 비어 있는 상태에서 NDEF 메시지를 기록하려는 경우 NdefFormatable은 포맷할 수 있는 태그에 대해 connect(), format()  writeNdefMessage()와 같은 작업을 제공한다.

다음은 NdefFormatable을 사용하여 NFC 태그를 NDEF 형식으로 포맷하고 데이터를 기록하는 예이다.

fun formatTagWithNdefMessage(tag: Tag, ndefMessage: NdefMessage): Boolean {
    val ndefFormatable = NdefFormatable.get(tag)

    if (ndefFormatable != null) {
        try {
            // NDEF 포맷팅을 위해 태그 연결
            ndefFormatable.connect()

            // NDEF 메시지로 태그 포맷 및 데이터 기록
            ndefFormatable.format(ndefMessage)

            Log.d("NFC", "태그를 NDEF 형식으로 포맷하고 메시지를 기록했습니다.")
            return true
        } catch (e: IOException) {
            Log.e("NFC", "태그 포맷팅 실패: ${e.message}")
        } finally {
            try {
                ndefFormatable.close()
            } catch (e: IOException) {
                Log.e("NFC", "태그 닫기 실패: ${e.message}")
            }
        }
    } else {
        Log.e("NFC", "이 태그는 NDEF 포맷이 지원되지 않습니다.")
    }

    return false
}
 

 

주요 메서드 설명:

  • NdefFormatable.get(tag): Tag 객체에서 NdefFormatable 인스턴스를 얻는다. NDEF 포맷 미지원 시 null을 반환 한다.
  • connect(): NFC 태그와 연결을 시도한다.
  • format(NdefMessage): 태그를 NDEF 형식으로 포맷하고, 제공된 NDEF 메시지를 기록한다.
  • close(): 태그와의 연결 종료한다.

주의사항:

  • NDEF 형식으로 포맷하면 원래 상태로 되돌릴 수 없다.
  • 일부 태그는 포맷 후에도 더 이상 기록할 수 없는 경우가 있다. (읽기 전용 태그로 변환).
  • 모든 태그가 NDEF 포맷을 지원하지 않는다.

 

반응형

'개발 > Android' 카테고리의 다른 글

멀티라인 Toast 메시지 출력  (0) 2024.10.24
NFC 권한설정  (1) 2024.10.21
NFC Tag 상세정보 출력  (2) 2024.10.18
안드로이드 각 버전별 추가된 주요 기능  (0) 2024.10.15
JIT, AOT 컴파일 비교  (1) 2024.10.15
블로그 이미지

SKY STORY

,
반응형

NFC Tag에서 얻을 수 있는 정보를 json 문자열 포맷으로 반환하는 함수를 만들어보았다.

테그 정보 :

  1. UID (고유 ID): tag.id에서 추출한 고유 식별자.
  2. Tech List: 태그가 지원하는 모든 기술 목록 (tag.techList).
  3. NfcA (ISO 14443-3A): ATQA, SAK, 최대 전송 길이, 타임아웃 정보.
  4. IsoDep (ISO 14443-4): 역사적 바이트(historicalBytes), 고층 응답(hiLayerResponse), 최대 전송 길이, 타임아웃 정보.
  5. NfcB (ISO 14443-3B): 응용 데이터, 프로토콜 정보, 최대 전송 길이.
  6. NfcF (Felica): 제조사 정보, 시스템 코드, 최대 전송 길이, 타임아웃.
  7. NfcV (ISO 15693): 응답 플래그, DSFID, 최대 전송 길이.
  8. MifareClassic: 타입, 크기, 섹터 블록 .
  9. MifareUltralight: 타입 정보 (Ultralight, Ultralight C).

 

구현 함수는 다음과 같다.

fun readTagDetailsAsJson(tag: Tag): String {
    val tagInfo = mutableMapOf<String, Any>()

    // UID 정보 (태그 고유 ID)
    tagInfo["uid"] = tag.id.joinToString("") { String.format("%02X", it) }

    // 기술 스택 나열 (태그가 지원하는 모든 기술들)
    tagInfo["techList"] = tag.techList.joinToString()

    // NfcA (ISO 14443-3A) 정보
    val nfcA = NfcA.get(tag)
    if (nfcA != null) {
        tagInfo["NfcA"] = mapOf(
            // ATQA: Answer to Request Type A. 태그가 리더기에 응답할 때 사용하는 정보
            "atqa" to nfcA.atqa.joinToString("") { String.format("%02X", it) },
            // SAK: Select Acknowledge. 태그가 리더기에 제공하는 지원 기능 정보
            "sak" to String.format("%02X", nfcA.sak),
            // 한 번에 보낼 수 있는 최대 전송 길이 (바이트 단위)
            "maxTransceiveLength" to nfcA.maxTransceiveLength,
            // 통신 타임아웃 시간 (밀리초 단위)
            "timeout" to nfcA.timeout
        )
    }

    // IsoDep (ISO 14443-4) 정보
    val isoDep = IsoDep.get(tag)
    if (isoDep != null) {
        tagInfo["IsoDep"] = mapOf(
            // Historical Bytes: 태그가 초기 통신 설정 시 리더기에 제공하는 추가 정보
            "historicalBytes" to (isoDep.historicalBytes?.joinToString("") { String.format("%02X", it) } ?: "N/A"),
            // Higher Layer Response: 고급 프로토콜에 대한 응답 정보
            "hiLayerResponse" to (isoDep.hiLayerResponse?.joinToString("") { String.format("%02X", it) } ?: "N/A"),
            // 한 번에 전송할 수 있는 최대 데이터 길이 (바이트 단위)
            "maxTransceiveLength" to (isoDep.maxTransceiveLength.toString() ?: "N/A"),
            // 통신 타임아웃 시간 (밀리초 단위)
            "timeout" to isoDep.timeout
        )
    }

    // NfcB (ISO 14443-3B) 정보
    val nfcB = NfcB.get(tag)
    if (nfcB != null) {
        tagInfo["NfcB"] = mapOf(
            // Application Data: 태그의 애플리케이션과 관련된 데이터
            "applicationData" to (nfcB.applicationData?.joinToString("") { String.format("%02X", it) } ?: "N/A"),
            // Protocol Info: 태그가 제공하는 프로토콜 정보
            "protocolInfo" to (nfcB.protocolInfo?.joinToString("") { String.format("%02X", it) } ?: "N/A")
        )
    }

    // NfcF (Felica, JIS 6319-4) 정보
    val nfcF = NfcF.get(tag)
    if (nfcF != null) {
        tagInfo["NfcF"] = mapOf(
            // 제조사 코드
            "manufacturer" to (nfcF.manufacturer?.joinToString("") { String.format("%02X", it) } ?: "N/A"),
            // 시스템 코드
            "systemCode" to (nfcF.systemCode?.joinToString("") { String.format("%02X", it) } ?: "N/A"),
            // 한 번에 전송할 수 있는 최대 데이터 길이 (바이트 단위)
            "maxTransceiveLength" to nfcF.maxTransceiveLength.toString(),
            // 통신 타임아웃 시간 (밀리초 단위)
            "timeout" to nfcF.timeout.toString()
        )
    }

    // NfcV (ISO 15693) 정보
    val nfcV = NfcV.get(tag)
    if (nfcV != null) {
        tagInfo["NfcV"] = mapOf(
            // 응답 플래그
            "responseFlags" to String.format("%02X", nfcV.responseFlags),
            // DSFID (Data Storage Format Identifier)
            "dsfId" to String.format("%02X", nfcV.dsfId),
            // 한 번에 전송할 수 있는 최대 데이터 길이 (바이트 단위)
            "maxTransceiveLength" to nfcV.maxTransceiveLength
        )
    }

    // NfcBarcode (Type V or JIS 6319-4) 정보 - maxTransceiveLength 지원 없음
    val nfcBarcode = NfcBarcode.get(tag)
    if (nfcBarcode != null) {
        tagInfo["NfcBarcode"] = mapOf(
            // 바코드 타입 정보 (Type V or JIS 6319-4)
            "type" to nfcBarcode.type
        )
    }

    // MifareClassic 정보
    val mifareClassic = MifareClassic.get(tag)
    if (mifareClassic != null) {
        tagInfo["MifareClassic"] = mapOf(
            // MifareClassic 타입 (Classic, Plus, Pro)
            "type" to when (mifareClassic.type) {
                MifareClassic.TYPE_CLASSIC -> "Classic"
                MifareClassic.TYPE_PLUS -> "Plus"
                MifareClassic.TYPE_PRO -> "Pro"
                else -> "Unknown"
            },
            // MifareClassic 메모리 크기
            "size" to mifareClassic.size,
            // 섹터 개수
            "sectorCount" to mifareClassic.sectorCount,
            // 블록 개수
            "blockCount" to mifareClassic.blockCount
        )
    }

    // MifareUltralight 정보
    val mifareUltralight = MifareUltralight.get(tag)
    if (mifareUltralight != null) {
        tagInfo["MifareUltralight"] = mapOf(
            // MifareUltralight 타입 (Ultralight, Ultralight C)
            "type" to when (mifareUltralight.type) {
                MifareUltralight.TYPE_ULTRALIGHT -> "Ultralight"
                MifareUltralight.TYPE_ULTRALIGHT_C -> "Ultralight C"
                else -> "Unknown"
            }
        )
    }

    // JSON 형태로 변환하여 반환
    return JSONObject(tagInfo as Map<*, *>).toString()
}

 

결과값 로그 출력 값은 아래와 같다.

로그 출력 값 예 :
{
  "uid": "641B27A2B67881",  // 시리얼 번호
  "techList": "android.nfc.tech.IsoDep, android.nfc.tech.NfcA", // 태그에서 지원하는 NFC 기술 목록
  "NfcA": {		// NfcA (ISO/IEC 14443-3A) 기술에 대한 정보
    "atqa": "4800",		// Answer to Request, Type A (ATQA) 값
    "sak": "20",		// Select Acknowledge (SAK) 값
    "maxTransceiveLength": 253,	// NFC 통신에서 한 번에 전송할 수 있는 최대 데이터 길이(바이트)
    "timeout": 618		// 통신 타임아웃 시간(밀리초)
  },
  "IsoDep": {	// IsoDep (ISO/IEC 14443-4) 기술에 대한 정보
    "historicalBytes": "",	// NFC 태그가 최초로 통신을 시작할 때 제공하는 부가적인 정보를 포함
    "hiLayerResponse": "N\/A",	// 태그가 고급 프로토콜을 지원하는 경우 제공
    "maxTransceiveLength": "65279",// IsoDep에서 한 번에 전송할 수 있는 최대 데이터 길이
    "timeout": 618		// 통신 타임아웃 시간(밀리초)
  }
}

 

 

반응형

'개발 > Android' 카테고리의 다른 글

NFC 권한설정  (1) 2024.10.21
NdefFormatable 태그  (0) 2024.10.21
안드로이드 각 버전별 추가된 주요 기능  (0) 2024.10.15
JIT, AOT 컴파일 비교  (1) 2024.10.15
FCM 푸시설정  (0) 2024.10.14
블로그 이미지

SKY STORY

,
반응형

마지막 커밋을 취소하고 변경 사항 유지

git reset --soft HEAD~1

 

마지막 커밋을 취소하고 변경 사항을 스테이징 취소

git reset --mixed HEAD~1

 

커밋과 함께 변경 사항도 모두 취소하고 되돌리기

git reset --hard HEAD~1

 

특정 커밋을 취소하려면

git revert <커밋 해시>

Ex) git revert d6f7e92b1c8f9fcd0e5e0b8ad72f2d7ecb839eba

 

마지막 커밋 메시지 수정

git commit --amend

 

반응형
블로그 이미지

SKY STORY

,
반응형

Android 5.0 (API 21 - Lollipop)

  1. Material Design 도입: 새로운 디자인 언어로, 더 직관적이고 일관된 UI 제공.
    • Elevation: 뷰에 그림자와 깊이를 추가하여 더 입체적인 UI 구현.
    • Ripple Effect: 버튼 등에서 터치 반응 효과 추가.
  2. RecyclerView: ListView보다 효율적인 데이터 표시를 위한 컴포넌트.
    • 더 나은 성능과 애니메이션 지원.
    • ViewHolder 패턴을 강제하여 성능 최적화.
  3. JobScheduler API: 작업을 백그라운드에서 실행하는 API로 배터리 효율성을 높임.
    • 네트워크 상태, 충전 중 여부 등을 기반으로 작업 실행 제어 가능.
  4. **ART(Android Runtime)**로 전환: JIT(Just-In-Time) 컴파일 대신 AOT(Ahead-Of-Time) 컴파일을 도입하여 앱 성능 향상.
  5. Notifications: 알림의 스타일을 개선하고, 사용자가 바로 상호작용할 수 있는 Heads-up 알림 추가.

Android 5.1 (API 22 - Lollipop)

  1. HD Voice: 고화질 음성 통화 지원.
  2. Dual-SIM Support: 두 개의 SIM 카드를 사용하는 기능 지원.
  3. Device Protection: 기기가 초기화되었을 때도 Google 계정을 통해 잠금을 유지할 수 있는 기능.
  4. Wi-Fi Calling: Wi-Fi를 이용해 통화할 수 있는 기능 도입.

Android 6.0 (API 23 - Marshmallow)

  1. App Permissions: 런타임 권한 시스템 도입, 사용자가 앱 실행 중 개별적으로 권한을 승인할 수 있음.
  2. Doze Mode: 배터리 절약을 위해 기기가 오랫동안 사용되지 않으면 백그라운드 활동을 제한.
  3. Fingerprint API: 지문 인식 기능을 이용해 앱에서 인증할 수 있는 기능 제공.
  4. App Links: HTTP 링크를 앱과 직접 연결하여 앱 내에서 URL을 처리 가능.
  5. Adoptable Storage: SD 카드나 USB 저장소를 내부 저장소로 포맷하여 앱 데이터를 저장할 수 있도록 지원.

Android 7.0 (API 24 - Nougat)

  1. Multi-Window Support: 화면을 분할하여 두 개의 앱을 동시에 실행할 수 있는 기능 도입.
    • Split-Screen(화면 분할) 및 Picture-in-Picture(PiP) 모드 지원.
  2. Direct Reply Notifications: 알림에서 바로 메시지나 답장을 할 수 있는 기능 제공.
  3. Doze on the Go: 기기가 이동 중일 때도 배터리 절약 기능을 활성화.
  4. Vulkan API: 고성능 3D 그래픽 렌더링을 위한 API 도입.
  5. Java 8 Support: 새로운 언어 기능을 포함한 Java 8의 일부 기능 지원.

Android 7.1 (API 25 - Nougat)

  1. App Shortcuts: 홈 화면에서 앱 아이콘을 길게 눌러 자주 사용하는 기능으로 바로 이동할 수 있는 기능.
  2. Image Keyboard: 키보드를 통해 직접 이미지를 전송할 수 있는 기능 도입.
  3. Circular App Icons: 아이콘을 원형으로 표시할 수 있는 기능 추가.

Android 8.0 (API 26 - Oreo)

  1. Adaptive Icons: 아이콘의 모양이 런처에 따라 동적으로 변할 수 있는 기능. 여러 모양(정사각형, 원형, 물방울 등)을 지원.
    • 아이콘을 전경(foreground)과 배경(background)으로 분리하여 다이내믹한 효과를 줄 수 있음.
  2. Notification Channels: 알림을 카테고리별로 그룹화하고, 사용자에게 더 세밀한 알림 제어권 제공.
    • 사용자가 각 채널별로 알림의 중요도, 사운드 등을 설정할 수 있음.
  3. Picture-in-Picture (PiP): 사용자가 비디오를 작은 창으로 띄워 다른 앱을 사용할 수 있는 기능.
  4. Background Execution Limits: 앱의 백그라운드 활동에 제한을 두어 배터리 절약.
  5. Autofill Framework: 사용자 정보를 자동으로 입력할 수 있는 기능.

Android 8.1 (API 27 - Oreo)

  1. Neural Networks API: 머신 러닝을 위한 하드웨어 가속 API 제공.
  2. Autofill Enhancements: 자동 완성 기능이 향상되어 더 많은 앱에서 지원 가능.
  3. Shared Memory API: 프로세스 간 공유 메모리를 안전하게 사용할 수 있는 기능.

Android 9 (API 28 - Pie)

  1. Adaptive Battery: 앱의 사용 패턴을 학습하여 자주 사용하는 앱에 우선순위를 부여해 배터리 효율을 향상.
  2. App Actions: 사용자의 행동을 예측하고 적절한 기능을 앱에서 바로 실행할 수 있는 기능 제공.
  3. Slices API: 앱의 주요 기능을 검색 결과나 Google Assistant에서 사용할 수 있게 함.
  4. Gesture Navigation: 홈 버튼 대신 제스처를 통해 내비게이션하는 새로운 방식 도입.
  5. Background App Privacy Restrictions: 백그라운드 앱의 카메라, 마이크, 센서 접근을 제한하여 보안 강화.

Android 10 (API 29 - Q)

  1. Dark Theme: 시스템 전반에서 다크 모드 제공.
  2. Gesture Navigation: 더 직관적이고 개선된 제스처 내비게이션 도입.
  3. Privacy Enhancements: 위치 권한을 앱이 포그라운드일 때만 사용하도록 설정 가능.
  4. Scoped Storage: 각 앱이 자신의 영역에만 파일을 저장할 수 있도록 제한.
  5. Foldable Device Support: 폴더블 기기를 지원하기 위한 새로운 화면 전환 및 상태 관리 API.

Android 11 (API 30)

  1. Bubbles API: 메시지 앱에서 대화형 버블을 통해 멀티태스킹 가능.
  2. One-time Permissions: 위치, 카메라, 마이크에 대한 1회성 권한 부여 가능.
  3. Scoped Storage 개선: 앱의 저장소 접근 방식을 개선하여 데이터 보안 강화.
  4. Conversations in Notifications: 대화형 알림이 더 직관적이고 우선적으로 처리되도록 개선.

Android 12 (API 31)

  1. Material You: 사용자 맞춤형 색상 테마를 설정할 수 있는 기능으로 UI 개인화 가능.
  2. Privacy Dashboard: 사용자가 앱이 접근한 위치, 카메라, 마이크 정보에 대해 더 명확하게 볼 수 있는 대시보드 제공.
  3. Approximate Location: 앱이 대략적인 위치 정보만 요청할 수 있도록 지원.
  4. Mic/Camera Indicators: 상태 표시줄에 마이크와 카메라 사용 여부를 표시하는 기능 추가.
  5. Haptic Feedback Enhancements: 진동 패턴을 더 세밀하게 제어할 수 있는 기능 제공.

Android 12L (API 32)

  1. Large Screen Enhancements: 태블릿 및 폴더블 기기와 같은 큰 화면을 위한 UI 개선.
  2. Taskbar: 대형 화면에서 더 쉬운 멀티태스킹을 위한 태스크바 추가.

Android 13 (API 33)

  1. Per-App Language Preferences: 앱마다 다른 언어 설정이 가능.
  2. Photo Picker: 특정 사진만 앱에 제공할 수 있도록 새로운 사진 선택기 도입.
  3. Notification Permission: 앱에서 알림을 보내기 위해 사용자의 동의를 받아야 함.
  4. Bluetooth LE Audio: 저전력 오디오 전송을 위한 Bluetooth LE Audio 지원.

Android 14 (API 34)

  1. Predictive Back Gesture: 뒤로 가기 제스처를 미리 볼 수 있는 기능 도입.
  2. Regional Preferences: 사용자 지역에 따라 온도 단위, 시작 요일 등을 커스터마이징할 수 있음.
  3. App Cloning: 같은 앱을 여러 계정으로 실행할 수 있는 기능 지원.
  4. Credential Manager API: 패스워드 및 패스키 기반 인증을 통합 관리할 수 있는 새로운 API.
반응형

'개발 > Android' 카테고리의 다른 글

NdefFormatable 태그  (0) 2024.10.21
NFC Tag 상세정보 출력  (2) 2024.10.18
JIT, AOT 컴파일 비교  (1) 2024.10.15
FCM 푸시설정  (0) 2024.10.14
디버그 서명 인증서와 릴리즈 서명 인증서 차이  (0) 2024.10.14
블로그 이미지

SKY STORY

,
반응형

JIT(Just-In-Time) 컴파일과 AOT(Ahead-Of-Time) 컴파일의 차이점을 표로 정리하면 다음과 같다.

항목JIT(Just-In-Time) 컴파일AOT(Ahead-Of-Time) 컴파일
컴파일 시점 프로그램 실행 중 (런타임) 프로그램 실행 전에 (빌드 또는 배포 시)
초기 실행 속도 초기 실행 시간이 느림 (실시간 컴파일) 초기 실행 시간이 빠름 (미리 컴파일된 상태)
최적화 방식 동적 최적화 (실행 중 분석 후 최적화 가능) 정적 최적화 (컴파일 시 최적화, 실행 중 추가 최적화 불가)
메모리 사용 필요할 때만 컴파일하여 상대적으로 메모리 사용이 적음 모든 코드를 미리 컴파일하므로 더 많은 메모리 사용 가능
코드 분석 실행 중 코드 패턴을 분석해 최적화 가능 실행 중 코드 패턴 분석 불가
배포 파일 크기 컴파일러와 일부 런타임 데이터를 포함하여 다소 큼 컴파일된 바이너리만 포함하여 비교적 작음
플랫폼 의존성 플랫폼에 따라 다르게 컴파일할 수 있어 유연함 플랫폼에 맞게 미리 컴파일되므로 다소 제한적일 수 있음
사용 예시 Java (JVM), .NET, Android iOS (Swift), 일부 C++ 컴파일러, Angular (Ivy)
장점 런타임 최적화로 반복 실행 시 성능 향상 가능 빠른 실행 시간, 미리 컴파일된 바이너리로 보안성이 높음
단점 초기 로딩이 느릴 수 있으며, 컴파일로 인한 런타임 오버헤드 발생 가능 런타임 최적화 불가, 모든 코드를 미리 컴파일하므로 비효율 가능

장단점 요약

  • JIT: 동적 최적화를 통해 실행 중 성능을 개선할 수 있지만, 초기 실행 시간이 느릴 수 있다.
  • AOT: 빠른 시작 시간이 장점이지만, JIT처럼 동적인 최적화를 할 수 없고, 모든 코드를 미리 컴파일하므로 메모리 사용량이 많아질 수 있다.

사용 사례

  • JIT: 일반적으로 자바나 .NET 같은 플랫폼에서 많이 사용되며, 코드가 여러 번 실행되고 최적화가 중요한 경우 유리하다.
  • AOT: iOS의 Swift와 같은 환경에서는 AOT를 많이 사용하며, 프로그램의 빠른 시작 시간이 중요한 경우 적합하다.
반응형
블로그 이미지

SKY STORY

,

FCM 푸시설정

개발/Android 2024. 10. 14. 15:21
반응형

다음은 FCM 푸시 설정관련 내용을 알아보겠다.

Firebase 앱등록은 이미 완료됬다고 가정하겠다.

 

만약 아래 그림과 같이 'Product Flavors' 설정을 하지 않았다면 1번 위치에

설정을 하였다면 2번과 같이 'google-services.json'파일 복사한다.

 

프로젝트 수준 build.gradle :

 

모듈 수준 build.gradle :

 

AndroidManifest.xml에 알림 권한 추가:

<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />

 

권한 요청 코드 (MainActivity 등에서):

안드로이드 13(API 33) 이상에서는 알림 권한이 필요하다. 

import android.Manifest
import android.content.pm.PackageManager
import androidx.core.content.ContextCompat
import androidx.core.app.ActivityCompat
import android.os.Build

class MainActivity : ComponentActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // 푸시 알림 권한 요청
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
            if (ContextCompat.checkSelfPermission(
                    this,
                    Manifest.permission.POST_NOTIFICATIONS
                ) != PackageManager.PERMISSION_GRANTED
            ) {
                // 알림 권한 요청
                ActivityCompat.requestPermissions(
                    this,
                    arrayOf(Manifest.permission.POST_NOTIFICATIONS),
                    1000
                )
            }
        }

        // 그 외 FCM 설정
    }
}

 

FCM 토큰 생성 및 토큰 로그 확인

Firebase에서 푸시 메시지를 보내기 위해서는 FCM 토큰이 필요하다. 이 토큰은 앱 설치 시 자동으로 생성되며, 이를 통해 Firebase는 해당 기기에 푸시 메시지를 전송할 수 있다.

FCM 서비스 초기화 (FirebaseMessagingService 상속):

아래 코드와 같이 FirebaseMessagingService를 상속받아 FCM 토큰을 얻을 수 있다.

import com.google.firebase.messaging.FirebaseMessagingService
import com.google.firebase.messaging.FirebaseMessaging
import com.google.firebase.messaging.RemoteMessage
import android.util.Log

class MyFirebaseMessagingService : FirebaseMessagingService() {
	
    override fun onNewToken(token: String) {
        super.onNewToken(token)
        Log.d("FCM", "FCM 토큰 생성: $token")
        // 서버로 토큰 전송
    }

    override fun onMessageReceived(remoteMessage: RemoteMessage) {
        super.onMessageReceived(remoteMessage)
        Log.d("FCM", "푸시 메시지 수신: ${remoteMessage.notification?.body}")
        // 알림을 처리하거나 사용자에게 알림을 표시
    }
}

 

Firebase 토큰을 가져오는 코드 (선택적, 로그 확인용):

이미 생성된 토큰을 얻는다.

FirebaseMessaging.getInstance().token.addOnCompleteListener { task ->
    if (task.isSuccessful) {
        val token = task.result
        Log.d("FCM", "FCM 토큰: $token")
    } else {
        Log.w("FCM", "FCM 토큰 생성 실패", task.exception)
    }
}

 

푸시 수신 처리

푸시 알림이 수신되면, onMessageReceived 메서드에서 이를 처리한다. FCM 서버에서 전송된 메시지의 내용을 바탕으로 푸시 알림을 처리하고, 알림을 기기에 표시할 수 있다.

알림 표시 예제 (푸시 수신 시):

import android.app.NotificationChannel
import android.app.NotificationManager
import android.content.Context
import android.os.Build
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat

override fun onMessageReceived(remoteMessage: RemoteMessage) {
    super.onMessageReceived(remoteMessage)

    // 메시지의 제목과 본문을 가져옴
    val title = remoteMessage.notification?.title ?: "푸시 알림"
    val message = remoteMessage.notification?.body ?: "새로운 메시지가 있습니다."

    // Android 8.0 이상에서는 알림 채널이 필요
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        val channelId = "default_channel"
        val channelName = "기본 알림 채널"
        val importance = NotificationManager.IMPORTANCE_DEFAULT
        val notificationChannel = NotificationChannel(channelId, channelName, importance)
        val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
        notificationManager.createNotificationChannel(notificationChannel)
    }

    // 알림 생성
    val notificationBuilder = NotificationCompat.Builder(this, "default_channel")
        .setSmallIcon(android.R.drawable.ic_dialog_info)  // 알림 아이콘 설정
        .setContentTitle(title)
        .setContentText(message)
        .setPriority(NotificationCompat.PRIORITY_DEFAULT)

    // 알림 표시
    with(NotificationManagerCompat.from(this)) {
        notify(0, notificationBuilder.build())
    }
}

 

 

반응형
블로그 이미지

SKY STORY

,
반응형

디버그 서명 인증서 Android 앱을 개발하고 테스트할 때 사용됩니다. Android 앱은 개발 중일 때와 실제 배포 시에 서명되어야 하는데, 이 두 경우에 각각 다른 인증서를 사용합니다. 디버그 서명 인증서는 앱이 아직 개발 중일 때, 주로 디버깅 테스트를 위해 사용된다.

 

디버그 서명 인증서와 릴리스 서명 인증서의 차이

용도 개발 및 테스트용 실제 배포용
생성 방법 Android Studio에서 자동 생성 개발자가 직접 생성
키스토어 위치 ~/.android/debug.keystore 개발자가 지정한 경로 (예: my-release-key.jks)
비밀번호 기본값: android 개발자가 설정한 비밀번호
서명 목적 테스트 기기에서 설치 및 실행 Google Play 스토어 또는 외부 배포
유효 기간 30년 개발자가 설정한 기간 (일반적으로 25년 이상)
보안 수준 낮음 (자동 생성된 인증서) 높음 (개발자가 관리하는 인증서)
사용 시점 개발 중, Firebase와 같은 기능 테스트 시 앱 배포 시 (Google Play 스토어 또는 외부 배포)

 

 

반응형
블로그 이미지

SKY STORY

,
반응형

디버그 서명 인증서 Android 앱을 개발하고 테스트할 때 사용된다. Android 앱은 개발 중일 때와 실제 배포 시에 서명되어야 하는데, 이 두 경우에 각각 다른 인증서를 사용한다. 디버그 서명 인증서는 앱이 아직 개발 중일 때, 주로 디버깅 테스트를 위해 사용된다.

Firebase 설정에서 디버그 서명 인증서 사용은 Firebase Authentication 또는 Firebase Cloud Messaging(FCM)과 같은 기능을 테스트할 때, 디버그 서명 인증서의 SHA-1 해시 값이 필요하다. 이는 Firebase가 디버그 빌드에서도 Firebase 기능을 사용할 수 있도록 앱을 식별하기 위해 사용된다.

 

Android 앱에 Firebase를 추가할 때, 디버그 서명 인증서의 SHA-1 정보를 등록하는 방법을 알아보자.

https://console.firebase.google.com/

 

디버그 서명 인증서 SHA-1 정보 확인하기

Android Studio를 사용하여 SHA-1 해시 값을 확인할 수 있는 방법이 두 가지 있다.


방법 1: Android Studio를 통해 SHA-1 값 확인

  1. Android Studio에서 Gradle 창을 연다.
    • 화면 우측의 Gradle 탭을 클릭. (보이지 않으면 View > Tool Windows > Gradle)
  2. Gradle Tasks 실행:
    • 프로젝트 이름을 선택한 후, Tasks > android > signingReport를 더블 클릭.
  3. SHA-1 값 확인:
    • signingReport를 실행하면 디버그 및 릴리스 키의 SHA-1  SHA-256 해시 값이 Android Studio의 Run 창에 출력된다.
    • 아래와 같은 내용 출력:
      Variant: debug 
      Config: debug 
      Store: /Users/username/.android/debug.keystore 
      Alias: AndroidDebugKey 
      MD5: A1:B2:C3:... 
      SHA1: AA:BB:CC:DD:... 
      SHA-256: AB:CD:...
  4. SHA-1 값 복사:
    • 여기서 SHA-1 값을 복사하여 Firebase 콘솔에 입력한다.

 

방법 2: 명령어로 디버그 서명 인증서 SHA-1 확인 (keytool 사용)

  1. 명령어 실행:
    • 명령어를 통해 SHA-1 값을 확인 가능하다.
    • macOS 또는 Linux에서는 터미널, Windows에서는 명령 프롬프트 사용.
    keytool -list -v -keystore ~/.android/debug.keystore -alias androiddebugkey -storepass android -keypass android
     
  2. SHA-1 값 출력 확인:
    • 위 명령어를 실행하면 SHA-1 해시 값이 표시.
    SHA1: AA:BB:CC:DD:...
  3. SHA-1 값 복사:
    • SHA-1 값을 복사하여 Firebase 콘솔에 입력.

 

2:45:52 PM: Executing 'signingReport'...

Executing tasks: [signingReport] in project /Users/netcanis/projects4/TestWebview


> Task :app:signingReport
Variant: debug
Config: debug
Store: /Users/netcanis/.android/debug.keystore
Alias: AndroidDebugKey
MD5: B7:BA:15:3A:B7:E3:20:0A:5D:FE:9A:8C:21:6B:46:79
SHA1: 5D:D7:6C:1E:55:2E:20:59:15:23:81:43:F2:4D:BF:86:C7:E7:DF:2D
SHA-256: B2:A0:3A:51:2E:79:58:00:7B:C3:5A:84:F3:3B:C9:C0:75:08:94:F2:73:7C:33:6D:C6:D2:74:16:15:42:B8:BE
Valid until: Friday, June 6, 2053
----------
Variant: release
Config: null
Store: null
Alias: null
----------
Variant: debugAndroidTest
Config: debug
Store: /Users/netcanis/.android/debug.keystore
Alias: AndroidDebugKey
MD5: B7:BA:15:3A:B7:E3:20:0A:5D:FE:9A:8C:21:6B:46:79
SHA1: 5D:D7:6C:1E:55:2E:20:59:15:23:81:43:F2:4D:BF:86:C7:E7:DF:2D
SHA-256: B2:A0:3A:51:2E:79:58:00:7B:C3:5A:84:F3:3B:C9:C0:75:08:94:F2:73:7C:33:6D:C6:D2:74:16:15:42:B8:BE
Valid until: Friday, June 6, 2053
----------

BUILD SUCCESSFUL in 1s
1 actionable task: 1 executed

Build Analyzer results available
2:45:53 PM: Execution finished 'signingReport'.

 

 

 

 

반응형
블로그 이미지

SKY STORY

,