์ฝ˜ํ…์ธ  ๋Œ€ํ‘œ ์ด๋ฏธ์ง€ - ๐Ÿ“ฑ NFC ํƒœ๊ทธ ์ฝ๊ธฐ/์“ฐ๊ธฐ ์‘์šฉ ์†Œ์Šค์ฝ”๋“œ ์™„๋ฒฝ ๊ฐ€์ด๋“œ - ์‹ค์ „ ์˜ˆ์ œ๋กœ ๋ฐฐ์šฐ๋Š” ๋ชจ๋ฐ”์ผ NFC ํ”„๋กœ๊ทธ๋ž˜๋ฐ

๐Ÿ“ฑ NFC ํƒœ๊ทธ ์ฝ๊ธฐ/์“ฐ๊ธฐ ์‘์šฉ ์†Œ์Šค์ฝ”๋“œ ์™„๋ฒฝ ๊ฐ€์ด๋“œ - ์‹ค์ „ ์˜ˆ์ œ๋กœ ๋ฐฐ์šฐ๋Š” ๋ชจ๋ฐ”์ผ NFC ํ”„๋กœ๊ทธ๋ž˜๋ฐ

์•ˆ๋“œ๋กœ์ด๋“œ NFC ๊ธฐ์ˆ ์„ ํ™œ์šฉํ•œ ์‹ค๋ฌด ๊ฐœ๋ฐœ ๋…ธํ•˜์šฐ ๋Œ€๊ณต๊ฐœ ๐Ÿš€

์š”์ฆ˜ ์Šค๋งˆํŠธํฐ์œผ๋กœ ๊ตํ†ต์นด๋“œ ์ฐ๊ณ , ๊ฒฐ์ œํ•˜๊ณ , ์ถœ์ž…๋ฌธ ์—ด๊ณ  ํ•˜๋Š” ๊ฑฐ ๋‹ค๋“ค ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ์“ฐ๊ณ  ์žˆ์ฃ ?ใ…‹ใ…‹ใ…‹ ์ด๊ฒŒ ๋‹ค NFC ๊ธฐ์ˆ  ๋•๋ถ„์ธ๋ฐ์š”! ๐Ÿ’ณ

๊ทผ๋ฐ ๋ง‰์ƒ ์ด๊ฑธ ์ง์ ‘ ๊ฐœ๋ฐœํ•˜๋ ค๊ณ  ํ•˜๋ฉด "์–ด? ์ƒ๊ฐ๋ณด๋‹ค ๋ณต์žกํ•œ๋ฐ?" ํ•˜๋Š” ๋ถ„๋“ค์ด ๋งŽ๋”๋ผ๊ณ ์š”. ํŠนํžˆ NFC ํƒœ๊ทธ ์ฝ๊ณ  ์“ฐ๋Š” ๊ธฐ๋Šฅ ๊ตฌํ˜„ํ•  ๋•Œ ๋ง์ด์ฃ .

์˜ค๋Š˜์€ ์‹ค์ œ๋กœ ๋™์ž‘ํ•˜๋Š” NFC ํƒœ๊ทธ ์ฝ๊ธฐ/์“ฐ๊ธฐ ์‘์šฉ ์†Œ์Šค์ฝ”๋“œ๋ฅผ ์™„์ „ ํŒŒํ—ค์ณ๋ณผ ๊ฑฐ์˜ˆ์š”! ์ด๋ก ๋งŒ ์ฃผ๊ตฌ์žฅ์ฐฝ ๋Š˜์–ด๋†“๋Š” ๊ฒŒ ์•„๋‹ˆ๋ผ, ์ง„์งœ ๋ณต๋ถ™ํ•ด์„œ ์“ธ ์ˆ˜ ์žˆ๋Š” ์‹ค์ „ ์ฝ”๋“œ ์œ„์ฃผ๋กœ ์„ค๋ช…๋“œ๋ฆด๊ฒŒ์š” ๐Ÿ˜Ž

์Šค๋งˆํŠธํฐ NFC ๋ฆฌ๋” ํƒœ๊ทธ ๊ฐ์ง€ ์ค‘... NFC ํƒœ๊ทธ ๋ฐ์ดํ„ฐ ์ €์žฅ๋จ ์ฝ๊ธฐ/์“ฐ๊ธฐ ๋ฐ์ดํ„ฐ ์ „์†ก โœจ 13.56MHz ํ†ต์‹  ๋น„์ ‘์ด‰ ๊ทผ๊ฑฐ๋ฆฌ ๋ฌด์„  ๊ธฐ์ˆ 
๐ŸŽฏ NFC ๊ธฐ์ˆ  ๊ธฐ๋ณธ ๊ฐœ๋…๋ถ€ํ„ฐ ์งš๊ณ  ๊ฐ€๊ธฐ

๋ณธ๊ฒฉ์ ์œผ๋กœ ์ฝ”๋“œ ๋“ค์–ด๊ฐ€๊ธฐ ์ „์— NFC๊ฐ€ ๋ญ”์ง€๋ถ€ํ„ฐ ๊ฐ„๋‹จํ•˜๊ฒŒ ์ •๋ฆฌํ•˜๊ณ  ๊ฐˆ๊ฒŒ์š”!ใ…‹ใ…‹

NFC(Near Field Communication)๋Š” ๋ง ๊ทธ๋Œ€๋กœ '๊ทผ๊ฑฐ๋ฆฌ ๋ฌด์„  ํ†ต์‹ ' ๊ธฐ์ˆ ์ด์—์š”. ๋ณดํ†ต 10cm ์ด๋‚ด์˜ ์งง์€ ๊ฑฐ๋ฆฌ์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์ฃผ๊ณ ๋ฐ›๋Š” ๋ฐฉ์‹์ธ๋ฐ, ๋ธ”๋ฃจํˆฌ์Šค๋‚˜ WiFi๋ณด๋‹ค ํ›จ์”ฌ ๊ฐ€๊นŒ์šด ๊ฑฐ๋ฆฌ์—์„œ๋งŒ ์ž‘๋™ํ•˜์ฃ .

์ด๊ฒŒ ์˜คํžˆ๋ ค ์žฅ์ ์ด์—์š”! ๋ณด์•ˆ์ด ์ข‹๊ณ , ๋น ๋ฅด๊ณ , ์ „๋ ฅ ์†Œ๋ชจ๋„ ์ ๊ฑฐ๋“ ์š” ๐Ÿ’ช

NFC๋Š” ํฌ๊ฒŒ ์„ธ ๊ฐ€์ง€ ๋ชจ๋“œ๋กœ ๋™์ž‘ํ•ด์š”:

๐Ÿ“– Reader/Writer ๋ชจ๋“œ ์Šค๋งˆํŠธํฐ์ด NFC ํƒœ๊ทธ๋ฅผ ์ฝ๊ฑฐ๋‚˜ ์“ฐ๋Š” ๋ชจ๋“œ์˜ˆ์š”. ์šฐ๋ฆฌ๊ฐ€ ์˜ค๋Š˜ ๋‹ค๋ฃฐ ํ•ต์‹ฌ ๊ธฐ๋Šฅ!

๐Ÿค P2P ๋ชจ๋“œ
๋‘ ๊ฐœ์˜ NFC ๊ธฐ๊ธฐ๋ผ๋ฆฌ ๋ฐ์ดํ„ฐ๋ฅผ ์ฃผ๊ณ ๋ฐ›๋Š” ๋ชจ๋“œ. Android Beam ๊ฐ™์€ ๊ธฐ๋Šฅ์ด ์—ฌ๊ธฐ ํ•ด๋‹น๋ผ์š”.

๐Ÿ’ณ Card Emulation ๋ชจ๋“œ
์Šค๋งˆํŠธํฐ์ด ์‹ ์šฉ์นด๋“œ๋‚˜ ๊ตํ†ต์นด๋“œ์ฒ˜๋Ÿผ ๋™์ž‘ํ•˜๋Š” ๋ชจ๋“œ. ์‚ผ์„ฑํŽ˜์ด, ๊ตฌ๊ธ€ํŽ˜์ด๊ฐ€ ์ด ๋ฐฉ์‹์ด์ฃ !

์šฐ๋ฆฌ๊ฐ€ ์ง‘์ค‘ํ•  ๊ฑด Reader/Writer ๋ชจ๋“œ์˜ˆ์š”. ์ด๊ฒŒ ๊ฐ€์žฅ ๊ธฐ๋ณธ์ด๋ฉด์„œ๋„ ํ™œ์šฉ๋„๊ฐ€ ๋†’๊ฑฐ๋“ ์š” ๐ŸŽจ

๐Ÿ› ๏ธ ๊ฐœ๋ฐœ ํ™˜๊ฒฝ ์„ธํŒ…ํ•˜๊ธฐ

์ž, ์ด์ œ ๋ณธ๊ฒฉ์ ์œผ๋กœ ๊ฐœ๋ฐœ ๋“ค์–ด๊ฐ€๋ณผ๊นŒ์š”? ๋จผ์ € ํ•„์š”ํ•œ ๊ฒƒ๋“ค๋ถ€ํ„ฐ ์ฒดํฌํ•ด๋ด…์‹œ๋‹ค!

ํ•„์ˆ˜ ์ค€๋น„๋ฌผ:
โœ… Android Studio (์ตœ์‹  ๋ฒ„์ „ ๊ถŒ์žฅ)
โœ… NFC ๊ธฐ๋Šฅ์ด ์žˆ๋Š” ์•ˆ๋“œ๋กœ์ด๋“œ ํฐ (ํ…Œ์ŠคํŠธ์šฉ)
โœ… NFC ํƒœ๊ทธ ๋ช‡ ๊ฐœ (๋‹ค์ด์†Œ๋‚˜ ์˜จ๋ผ์ธ์—์„œ ์ €๋ ดํ•˜๊ฒŒ ๊ตฌ์ž… ๊ฐ€๋Šฅใ…‹ใ…‹)
โœ… ์ตœ์†Œ SDK ๋ฒ„์ „: API 19 (Android 4.4) ์ด์ƒ

์š”์ฆ˜ ๋‚˜์˜ค๋Š” ์Šค๋งˆํŠธํฐ์€ ๊ฑฐ์˜ ๋‹ค NFC ์ง€์›ํ•˜๋‹ˆ๊นŒ ํฌ๊ฒŒ ๊ฑฑ์ • ์•ˆ ํ•ด๋„ ๋ผ์š”!

๐Ÿ’ก ๊ฟ€ํŒ! NFC ํƒœ๊ทธ๋Š” NTAG213, NTAG215, NTAG216 ๊ฐ™์€ ๋ชจ๋ธ์ด ๊ฐ€์žฅ ๋ฒ”์šฉ์ ์ด์—์š”. ์šฉ๋Ÿ‰์€ 144๋ฐ”์ดํŠธ~888๋ฐ”์ดํŠธ ์ •๋„์ธ๋ฐ, ๊ฐ„๋‹จํ•œ ํ…์ŠคํŠธ๋‚˜ URL ์ €์žฅํ•˜๊ธฐ์—” ์ถฉ๋ถ„ํ•ด์š”. ๊ฐ€๊ฒฉ๋„ ๊ฐœ๋‹น 500์›~1000์› ์ •๋„๋กœ ์ €๋ ดํ•˜๊ณ ์š” ๐Ÿ˜Š

๐Ÿ“ AndroidManifest.xml ์„ค์ •

๊ฐ€์žฅ ๋จผ์ € ํ•ด์•ผ ํ•  ๊ฑด ๋งค๋‹ˆํŽ˜์ŠคํŠธ ํŒŒ์ผ์— NFC ๊ถŒํ•œ๊ณผ ๊ธฐ๋Šฅ์„ ์„ ์–ธํ•˜๋Š” ๊ฑฐ์˜ˆ์š”. ์ด๊ฑฐ ์•ˆ ํ•˜๋ฉด ์•„๋ฌด๊ฒƒ๋„ ์•ˆ ๋ผ์š”ใ…‹ใ…‹ใ…‹

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.nfcapp">

    <!-- NFC ๊ถŒํ•œ ์„ ์–ธ -->
    <uses-permission android:name="android.permission.NFC" />
    
    <!-- NFC ๊ธฐ๋Šฅ ํ•„์ˆ˜ ์—ฌ๋ถ€ ์„ค์ • -->
    <uses-feature
        android:name="android.hardware.nfc"
        android:required="true" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme">
        
        <activity
            android:name=".MainActivity"
            android:launchMode="singleTop"
            android:exported="true">
            
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
            
            <!-- NFC ํƒœ๊ทธ ๊ฐ์ง€ ์ธํ…ํŠธ ํ•„ํ„ฐ -->
            <intent-filter>
                <action android:name="android.nfc.action.NDEF_DISCOVERED" />
                <category android:name="android.intent.category.DEFAULT" />
                <data android:mimeType="text/plain" />
            </intent-filter>
            
            <intent-filter>
                <action android:name="android.nfc.action.TAG_DISCOVERED" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
            
        </activity>
    </application>

</manifest>


์—ฌ๊ธฐ์„œ ์ค‘์š”ํ•œ ํฌ์ธํŠธ ๋ช‡ ๊ฐ€์ง€ ์งš๊ณ  ๋„˜์–ด๊ฐˆ๊ฒŒ์š”!

launchMode="singleTop" ์ด ๋ถ€๋ถ„ ์ง„์งœ ์ค‘์š”ํ•ด์š”! ์ด๊ฑฐ ์•ˆ ํ•˜๋ฉด NFC ํƒœ๊ทธ ์ฝ์„ ๋•Œ๋งˆ๋‹ค ์•กํ‹ฐ๋น„ํ‹ฐ๊ฐ€ ์ƒˆ๋กœ ์ƒ์„ฑ๋ผ์„œ ๋‚œ๋ฆฌ ๋‚˜๊ฑฐ๋“ ์š”ใ…‹ใ…‹ใ…‹

์ธํ…ํŠธ ํ•„ํ„ฐ๋Š” ๋‘ ๊ฐ€์ง€๋ฅผ ๋“ฑ๋กํ–ˆ์–ด์š”:
- NDEF_DISCOVERED: NDEF ํฌ๋งท์œผ๋กœ ์ €์žฅ๋œ ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ์„ ๋•Œ
- TAG_DISCOVERED: ํฌ๋งท๋˜์ง€ ์•Š์€ ํƒœ๊ทธ๋‚˜ ๋‹ค๋ฅธ ํ˜•์‹์˜ ํƒœ๊ทธ๋ฅผ ์ฝ์„ ๋•Œ

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ๊ฑฐ์˜ ๋ชจ๋“  NFC ํƒœ๊ทธ๋ฅผ ๊ฐ์ง€ํ•  ์ˆ˜ ์žˆ์–ด์š” ๐Ÿ‘

๐ŸŽจ ๋ ˆ์ด์•„์›ƒ XML ๊ตฌ์„ฑ

UI๋Š” ์‹ฌํ”Œํ•˜๊ฒŒ ๊ฐ€๋ณผ๊ฒŒ์š”. ์‹ค์ œ๋กœ๋Š” ๋” ์˜ˆ์˜๊ฒŒ ๊พธ๋ฏธ๊ฒ ์ง€๋งŒ, ๊ธฐ๋Šฅ ์ดํ•ด์— ์ง‘์ค‘ํ•˜๊ธฐ ์œ„ํ•ด ํ•„์ˆ˜ ์š”์†Œ๋งŒ ๋„ฃ์—ˆ์–ด์š”!

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="16dp"
    android:gravity="center_horizontal">

    <TextView
        android:id="@+id/tvStatus"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="NFC ํƒœ๊ทธ๋ฅผ ๊ฐ€๊นŒ์ด ๋Œ€์ฃผ์„ธ์š”"
        android:textSize="18sp"
        android:textStyle="bold"
        android:layout_marginTop="32dp"
        android:textColor="#558b2f" />

    <TextView
        android:id="@+id/tvTagInfo"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="ํƒœ๊ทธ ์ •๋ณด๊ฐ€ ์—ฌ๊ธฐ์— ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค"
        android:textSize="14sp"
        android:layout_marginTop="24dp"
        android:padding="16dp"
        android:background="#f5f5f5"
        android:minHeight="120dp" />

    <EditText
        android:id="@+id/etWriteData"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="ํƒœ๊ทธ์— ์“ธ ๋‚ด์šฉ์„ ์ž…๋ ฅํ•˜์„ธ์š”"
        android:layout_marginTop="24dp"
        android:padding="12dp"
        android:background="@android:drawable/edit_text" />

    <Button
        android:id="@+id/btnWrite"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="NFC ํƒœ๊ทธ์— ์“ฐ๊ธฐ"
        android:layout_marginTop="16dp"
        android:backgroundTint="#66bb6a"
        android:textColor="#ffffff" />

    <Button
        android:id="@+id/btnClear"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="ํ™”๋ฉด ์ง€์šฐ๊ธฐ"
        android:layout_marginTop="8dp"
        android:backgroundTint="#bdbdbd"
        android:textColor="#ffffff" />

</LinearLayout>


๊ฐ„๋‹จํ•˜์ฃ ? ์ƒํƒœ ํ‘œ์‹œ์šฉ ํ…์ŠคํŠธ๋ทฐ, ํƒœ๊ทธ ์ •๋ณด ํ‘œ์‹œ์šฉ ํ…์ŠคํŠธ๋ทฐ, ๋ฐ์ดํ„ฐ ์ž…๋ ฅ์šฉ ์—๋””ํŠธํ…์ŠคํŠธ, ๊ทธ๋ฆฌ๊ณ  ์“ฐ๊ธฐ/์ง€์šฐ๊ธฐ ๋ฒ„ํŠผ๋งŒ ์žˆ์œผ๋ฉด ๋ผ์š” โœจ

๐Ÿ’ป MainActivity.java - NFC ์ฝ๊ธฐ ๊ธฐ๋Šฅ ๊ตฌํ˜„

์ž, ์ด์ œ ์ง„์งœ ํ•ต์‹ฌ์ธ ๋ฉ”์ธ ์•กํ‹ฐ๋น„ํ‹ฐ ์ฝ”๋“œ๋ฅผ ๋ณผ ์ฐจ๋ก€์˜ˆ์š”! ๋จผ์ € NFC ํƒœ๊ทธ ์ฝ๊ธฐ ๊ธฐ๋Šฅ๋ถ€ํ„ฐ ๊ตฌํ˜„ํ•ด๋ณผ๊ฒŒ์š”.

์ฝ”๋“œ๊ฐ€ ์ข€ ๊ธธ์ง€๋งŒ ํ•˜๋‚˜ํ•˜๋‚˜ ์„ค๋ช…ํ•  ํ…Œ๋‹ˆ๊นŒ ์ฒœ์ฒœํžˆ ๋”ฐ๋ผ์˜ค์„ธ์š” ๐Ÿ˜Š

package com.example.nfcapp;

import android.app.PendingIntent;
import android.content.Intent;
import android.content.IntentFilter;
import android.nfc.NdefMessage;
import android.nfc.NdefRecord;
import android.nfc.NfcAdapter;
import android.nfc.Tag;
import android.nfc.tech.Ndef;
import android.nfc.tech.NdefFormatable;
import android.os.Bundle;
import android.os.Parcelable;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import java.io.IOException;
import java.nio.charset.Charset;

public class MainActivity extends AppCompatActivity {

    private NfcAdapter nfcAdapter;
    private PendingIntent pendingIntent;
    private IntentFilter[] intentFiltersArray;
    private String[][] techListsArray;
    
    private TextView tvStatus;
    private TextView tvTagInfo;
    private EditText etWriteData;
    private Button btnWrite;
    private Button btnClear;
    
    private boolean writeMode = false;
    private String dataToWrite = "";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        // UI ์š”์†Œ ์ดˆ๊ธฐํ™”
        initViews();
        
        // NFC ์–ด๋Œ‘ํ„ฐ ์ดˆ๊ธฐํ™”
        initNFC();
        
        // ๋ฒ„ํŠผ ๋ฆฌ์Šค๋„ˆ ์„ค์ •
        setupListeners();
        
        // ์ธํ…ํŠธ๋กœ ์ „๋‹ฌ๋œ NFC ํƒœ๊ทธ ์ฒ˜๋ฆฌ
        handleIntent(getIntent());
    }
    
    private void initViews() {
        tvStatus = findViewById(R.id.tvStatus);
        tvTagInfo = findViewById(R.id.tvTagInfo);
        etWriteData = findViewById(R.id.etWriteData);
        btnWrite = findViewById(R.id.btnWrite);
        btnClear = findViewById(R.id.btnClear);
    }
    
    private void initNFC() {
        // NFC ์–ด๋Œ‘ํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ
        nfcAdapter = NfcAdapter.getDefaultAdapter(this);
        
        if (nfcAdapter == null) {
            // ๊ธฐ๊ธฐ๊ฐ€ NFC๋ฅผ ์ง€์›ํ•˜์ง€ ์•Š์Œ
            tvStatus.setText("์ด ๊ธฐ๊ธฐ๋Š” NFC๋ฅผ ์ง€์›ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค ๐Ÿ˜ข");
            btnWrite.setEnabled(false);
            return;
        }
        
        if (!nfcAdapter.isEnabled()) {
            // NFC๊ฐ€ ๋น„ํ™œ์„ฑํ™”๋˜์–ด ์žˆ์Œ
            tvStatus.setText("NFC๊ฐ€ ๊บผ์ ธ์žˆ์–ด์š”! ์„ค์ •์—์„œ ์ผœ์ฃผ์„ธ์š” ๐Ÿ”ง");
        }
        
        // PendingIntent ์ƒ์„ฑ
        Intent intent = new Intent(this, getClass())
            .addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
        pendingIntent = PendingIntent.getActivity(
            this, 0, intent, PendingIntent.FLAG_MUTABLE);
        
        // IntentFilter ์„ค์ •
        IntentFilter ndefFilter = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED);
        try {
            ndefFilter.addDataType("text/plain");
        } catch (IntentFilter.MalformedMimeTypeException e) {
            throw new RuntimeException("MIME ํƒ€์ž… ์„ค์ • ์‹คํŒจ", e);
        }
        
        intentFiltersArray = new IntentFilter[] { ndefFilter };
        
        // Tech List ์„ค์ •
        techListsArray = new String[][] { 
            new String[] { Ndef.class.getName() },
            new String[] { NdefFormatable.class.getName() }
        };
    }
    
    private void setupListeners() {
        btnWrite.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String data = etWriteData.getText().toString().trim();
                if (data.isEmpty()) {
                    Toast.makeText(MainActivity.this, 
                        "์“ธ ๋‚ด์šฉ์„ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”!", Toast.LENGTH_SHORT).show();
                    return;
                }
                
                dataToWrite = data;
                writeMode = true;
                tvStatus.setText("์“ฐ๊ธฐ ๋ชจ๋“œ ํ™œ์„ฑํ™”! ํƒœ๊ทธ๋ฅผ ๊ฐ€๊นŒ์ด ๋Œ€์ฃผ์„ธ์š” โœ๏ธ");
                Toast.makeText(MainActivity.this, 
                    "์ด์ œ NFC ํƒœ๊ทธ๋ฅผ ๊ฐ€๊นŒ์ด ๋Œ€์ฃผ์„ธ์š”", Toast.LENGTH_LONG).show();
            }
        });
        
        btnClear.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                tvTagInfo.setText("ํƒœ๊ทธ ์ •๋ณด๊ฐ€ ์—ฌ๊ธฐ์— ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค");
                etWriteData.setText("");
                writeMode = false;
                tvStatus.setText("NFC ํƒœ๊ทธ๋ฅผ ๊ฐ€๊นŒ์ด ๋Œ€์ฃผ์„ธ์š”");
            }
        });
    }

    @Override
    protected void onResume() {
        super.onResume();
        if (nfcAdapter != null) {
            // Foreground Dispatch ํ™œ์„ฑํ™”
            nfcAdapter.enableForegroundDispatch(
                this, pendingIntent, intentFiltersArray, techListsArray);
        }
    }

    @Override
    protected void onPause() {
        super.onPause();
        if (nfcAdapter != null) {
            // Foreground Dispatch ๋น„ํ™œ์„ฑํ™”
            nfcAdapter.disableForegroundDispatch(this);
        }
    }

    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        handleIntent(intent);
    }
    
    private void handleIntent(Intent intent) {
        String action = intent.getAction();
        
        if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(action) ||
            NfcAdapter.ACTION_TAG_DISCOVERED.equals(action)) {
            
            Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
            
            if (writeMode) {
                // ์“ฐ๊ธฐ ๋ชจ๋“œ์ผ ๋•Œ
                writeToTag(tag, dataToWrite);
            } else {
                // ์ฝ๊ธฐ ๋ชจ๋“œ์ผ ๋•Œ
                readFromTag(intent, tag);
            }
        }
    }
    
    private void readFromTag(Intent intent, Tag tag) {
        // NDEF ๋ฉ”์‹œ์ง€ ์ฝ๊ธฐ
        Parcelable[] rawMessages = 
            intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
        
        StringBuilder tagInfo = new StringBuilder();
        tagInfo.append("๐Ÿ“ฑ ํƒœ๊ทธ ์ •๋ณด\n\n");
        
        // ํƒœ๊ทธ ID ํ‘œ์‹œ
        byte[] id = tag.getId();
        tagInfo.append("๐Ÿ†” ํƒœ๊ทธ ID: ").append(bytesToHex(id)).append("\n\n");
        
        // ์ง€์› ๊ธฐ์ˆ  ํ‘œ์‹œ
        String[] techList = tag.getTechList();
        tagInfo.append("๐Ÿ”ง ์ง€์› ๊ธฐ์ˆ :\n");
        for (String tech : techList) {
            String techName = tech.substring(tech.lastIndexOf(".") + 1);
            tagInfo.append("  โ€ข ").append(techName).append("\n");
        }
        tagInfo.append("\n");
        
        // NDEF ๋ฉ”์‹œ์ง€ ํŒŒ์‹ฑ
        if (rawMessages != null && rawMessages.length > 0) {
            NdefMessage[] messages = new NdefMessage[rawMessages.length];
            for (int i = 0; i < rawMessages.length; i++) {
                messages[i] = (NdefMessage) rawMessages[i];
            }
            
            tagInfo.append("๐Ÿ“ ์ €์žฅ๋œ ๋ฐ์ดํ„ฐ:\n\n");
            
            for (NdefMessage message : messages) {
                NdefRecord[] records = message.getRecords();
                for (NdefRecord record : records) {
                    String payload = parseNdefRecord(record);
                    if (payload != null && !payload.isEmpty()) {
                        tagInfo.append(payload).append("\n");
                    }
                }
            }
        } else {
            tagInfo.append("๐Ÿ“ญ ์ €์žฅ๋œ ๋ฐ์ดํ„ฐ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค\n");
        }
        
        tvTagInfo.setText(tagInfo.toString());
        tvStatus.setText("ํƒœ๊ทธ ์ฝ๊ธฐ ์™„๋ฃŒ! โœ…");
        
        Toast.makeText(this, "NFC ํƒœ๊ทธ๋ฅผ ์„ฑ๊ณต์ ์œผ๋กœ ์ฝ์—ˆ์–ด์š”!", 
            Toast.LENGTH_SHORT).show();
    }
    
    private String parseNdefRecord(NdefRecord record) {
        short tnf = record.getTnf();
        byte[] payload = record.getPayload();
        
        if (tnf == NdefRecord.TNF_WELL_KNOWN) {
            byte[] type = record.getType();
            
            if (java.util.Arrays.equals(type, NdefRecord.RTD_TEXT)) {
                // ํ…์ŠคํŠธ ๋ ˆ์ฝ”๋“œ ํŒŒ์‹ฑ
                try {
                    // ์ฒซ ๋ฐ”์ดํŠธ๋Š” ์–ธ์–ด ์ฝ”๋“œ ๊ธธ์ด
                    int languageCodeLength = payload[0] & 0x3F;
                    // ์‹ค์ œ ํ…์ŠคํŠธ ์ถ”์ถœ
                    String text = new String(payload, 
                        languageCodeLength + 1, 
                        payload.length - languageCodeLength - 1, 
                        Charset.forName("UTF-8"));
                    return text;
                } catch (Exception e) {
                    return "ํ…์ŠคํŠธ ํŒŒ์‹ฑ ์‹คํŒจ";
                }
            } else if (java.util.Arrays.equals(type, NdefRecord.RTD_URI)) {
                // URI ๋ ˆ์ฝ”๋“œ ํŒŒ์‹ฑ
                return parseUriRecord(payload);
            }
        }
        
        return "์•Œ ์ˆ˜ ์—†๋Š” ๋ฐ์ดํ„ฐ ํ˜•์‹";
    }
    
    private String parseUriRecord(byte[] payload) {
        // URI ์‹๋ณ„์ž ํ”„๋ฆฌํ”ฝ์Šค
        String[] uriPrefixes = {
            "", "http://www.", "https://www.", "http://", "https://",
            "tel:", "mailto:", "ftp://anonymous:anonymous@", "ftp://ftp.",
            "ftps://", "sftp://", "smb://", "nfs://", "ftp://", "dav://",
            "news:", "telnet://", "imap:", "rtsp://", "urn:", "pop:",
            "sip:", "sips:", "tftp:", "btspp://", "btl2cap://", "btgoep://",
            "tcpobex://", "irdaobex://", "file://", "urn:epc:id:",
            "urn:epc:tag:", "urn:epc:pat:", "urn:epc:raw:", "urn:epc:",
            "urn:nfc:"
        };
        
        byte prefixIndex = payload[0];
        String prefix = "";
        
        if (prefixIndex >= 0 && prefixIndex < uriPrefixes.length) {
            prefix = uriPrefixes[prefixIndex];
        }
        
        String uri = new String(payload, 1, payload.length - 1, 
            Charset.forName("UTF-8"));
        
        return prefix + uri;
    }
    
    private String bytesToHex(byte[] bytes) {
        StringBuilder sb = new StringBuilder();
        for (byte b : bytes) {
            sb.append(String.format("%02X", b));
        }
        return sb.toString();
    }
}


์™€... ์ฝ”๋“œ๊ฐ€ ์ข€ ๊ธธ์ฃ ?ใ…‹ใ…‹ใ…‹ ๊ทผ๋ฐ ํ•˜๋‚˜ํ•˜๋‚˜ ๋œฏ์–ด๋ณด๋ฉด ๋ณ„๊ฑฐ ์—†์–ด์š”!

ํ•ต์‹ฌ ํฌ์ธํŠธ๋งŒ ์ •๋ฆฌํ•ด๋ณผ๊ฒŒ์š”:

1๏ธโƒฃ Foreground Dispatch System onResume()์—์„œ enableForegroundDispatch()๋ฅผ ํ˜ธ์ถœํ•ด์„œ ์•ฑ์ด ํฌ๊ทธ๋ผ์šด๋“œ์— ์žˆ์„ ๋•Œ NFC ํƒœ๊ทธ๋ฅผ ์šฐ์„ ์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๋„๋ก ํ•ด์š”. ์ด๊ฑฐ ์•ˆ ํ•˜๋ฉด ๋‹ค๋ฅธ ์•ฑ์ด ํƒœ๊ทธ๋ฅผ ๊ฐ€๋กœ์ฑŒ ์ˆ˜ ์žˆ์–ด์š”!

2๏ธโƒฃ onNewIntent() ์ฒ˜๋ฆฌ
launchMode๊ฐ€ singleTop์ด๋ผ์„œ ์ƒˆ๋กœ์šด NFC ์ธํ…ํŠธ๊ฐ€ ๋“ค์–ด์˜ค๋ฉด onNewIntent()๊ฐ€ ํ˜ธ์ถœ๋ผ์š”. ์—ฌ๊ธฐ์„œ ํƒœ๊ทธ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ๊ฑฐ์ฃ .

3๏ธโƒฃ NDEF ๋ฉ”์‹œ์ง€ ํŒŒ์‹ฑ
NFC ํƒœ๊ทธ์— ์ €์žฅ๋œ ๋ฐ์ดํ„ฐ๋Š” NDEF(NFC Data Exchange Format) ํ˜•์‹์ด์—์š”. ์ด๊ฑธ ํŒŒ์‹ฑํ•ด์„œ ์‹ค์ œ ํ…์ŠคํŠธ๋‚˜ URI๋ฅผ ์ถ”์ถœํ•˜๋Š” ๊ฑฐ์˜ˆ์š”.

4๏ธโƒฃ ํƒœ๊ทธ ์ •๋ณด ํ‘œ์‹œ
ํƒœ๊ทธ ID, ์ง€์› ๊ธฐ์ˆ , ์ €์žฅ๋œ ๋ฐ์ดํ„ฐ ๋“ฑ์„ ๊น”๋”ํ•˜๊ฒŒ ์ •๋ฆฌํ•ด์„œ ๋ณด์—ฌ์ค˜์š” ๐Ÿ“Š

โœ๏ธ NFC ํƒœ๊ทธ ์“ฐ๊ธฐ ๊ธฐ๋Šฅ ๊ตฌํ˜„

์ด์ œ ํƒœ๊ทธ์— ๋ฐ์ดํ„ฐ๋ฅผ ์“ฐ๋Š” ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•ด๋ณผ๊ฒŒ์š”! ์œ„ MainActivity ํด๋ž˜์Šค์— ๋‹ค์Œ ๋ฉ”์„œ๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜๋ฉด ๋ผ์š”.

    private void writeToTag(Tag tag, String data) {
        try {
            // NDEF ๋ ˆ์ฝ”๋“œ ์ƒ์„ฑ
            NdefRecord record = createTextRecord(data);
            NdefMessage message = new NdefMessage(new NdefRecord[] { record });
            
            // Ndef ๊ธฐ์ˆ  ๊ฐ€์ ธ์˜ค๊ธฐ
            Ndef ndef = Ndef.get(tag);
            
            if (ndef != null) {
                // ์ด๋ฏธ ํฌ๋งท๋œ ํƒœ๊ทธ
                ndef.connect();
                
                // ์“ฐ๊ธฐ ๊ฐ€๋Šฅ ์—ฌ๋ถ€ ํ™•์ธ
                if (!ndef.isWritable()) {
                    tvStatus.setText("์ด ํƒœ๊ทธ๋Š” ์ฝ๊ธฐ ์ „์šฉ์ด์—์š” ๐Ÿ”’");
                    Toast.makeText(this, "์“ฐ๊ธฐ ๋ถˆ๊ฐ€๋Šฅํ•œ ํƒœ๊ทธ์ž…๋‹ˆ๋‹ค", 
                        Toast.LENGTH_SHORT).show();
                    ndef.close();
                    return;
                }
                
                // ์šฉ๋Ÿ‰ ํ™•์ธ
                int size = message.toByteArray().length;
                int maxSize = ndef.getMaxSize();
                
                if (size > maxSize) {
                    tvStatus.setText("๋ฐ์ดํ„ฐ๊ฐ€ ๋„ˆ๋ฌด ์ปค์š”! ๐Ÿ˜…");
                    Toast.makeText(this, 
                        String.format("์ตœ๋Œ€ %d๋ฐ”์ดํŠธ๊นŒ์ง€ ๊ฐ€๋Šฅํ•ด์š”", maxSize), 
                        Toast.LENGTH_SHORT).show();
                    ndef.close();
                    return;
                }
                
                // ๋ฐ์ดํ„ฐ ์“ฐ๊ธฐ
                ndef.writeNdefMessage(message);
                ndef.close();
                
                tvStatus.setText("์“ฐ๊ธฐ ์™„๋ฃŒ! โœ…");
                tvTagInfo.setText("โœ๏ธ ์“ด ๋‚ด์šฉ:\n\n" + data);
                Toast.makeText(this, "NFC ํƒœ๊ทธ์— ์„ฑ๊ณต์ ์œผ๋กœ ์ผ์–ด์š”!", 
                    Toast.LENGTH_SHORT).show();
                
                writeMode = false;
                etWriteData.setText("");
                
            } else {
                // ํฌ๋งท๋˜์ง€ ์•Š์€ ํƒœ๊ทธ
                NdefFormatable format = NdefFormatable.get(tag);
                
                if (format != null) {
                    try {
                        format.connect();
                        format.format(message);
                        format.close();
                        
                        tvStatus.setText("ํฌ๋งท ํ›„ ์“ฐ๊ธฐ ์™„๋ฃŒ! โœ…");
                        tvTagInfo.setText("โœ๏ธ ์“ด ๋‚ด์šฉ:\n\n" + data);
                        Toast.makeText(this, 
                            "ํƒœ๊ทธ๋ฅผ ํฌ๋งทํ•˜๊ณ  ๋ฐ์ดํ„ฐ๋ฅผ ์ผ์–ด์š”!", 
                            Toast.LENGTH_SHORT).show();
                        
                        writeMode = false;
                        etWriteData.setText("");
                        
                    } catch (IOException e) {
                        tvStatus.setText("ํฌ๋งท ์‹คํŒจ ๐Ÿ˜ข");
                        Toast.makeText(this, "ํƒœ๊ทธ ํฌ๋งท์— ์‹คํŒจํ–ˆ์–ด์š”", 
                            Toast.LENGTH_SHORT).show();
                    }
                } else {
                    tvStatus.setText("์ง€์›ํ•˜์ง€ ์•Š๋Š” ํƒœ๊ทธ์˜ˆ์š” โŒ");
                    Toast.makeText(this, "์ด ํƒœ๊ทธ๋Š” ์“ธ ์ˆ˜ ์—†์–ด์š”", 
                        Toast.LENGTH_SHORT).show();
                }
            }
            
        } catch (Exception e) {
            tvStatus.setText("์“ฐ๊ธฐ ์‹คํŒจ ๐Ÿ˜ข");
            Toast.makeText(this, "์˜ค๋ฅ˜: " + e.getMessage(), 
                Toast.LENGTH_SHORT).show();
            e.printStackTrace();
        }
    }
    
    private NdefRecord createTextRecord(String text) {
        // ์–ธ์–ด ์ฝ”๋“œ
        String lang = "en";
        byte[] langBytes = lang.getBytes(Charset.forName("US-ASCII"));
        
        // ํ…์ŠคํŠธ ๋ฐ”์ดํŠธ
        byte[] textBytes = text.getBytes(Charset.forName("UTF-8"));
        
        // ํŽ˜์ด๋กœ๋“œ ์ƒ์„ฑ
        int langLength = langBytes.length;
        int textLength = textBytes.length;
        byte[] payload = new byte[1 + langLength + textLength];
        
        // ์ฒซ ๋ฐ”์ดํŠธ: ์–ธ์–ด ์ฝ”๋“œ ๊ธธ์ด
        payload[0] = (byte) langLength;
        
        // ์–ธ์–ด ์ฝ”๋“œ ๋ณต์‚ฌ
        System.arraycopy(langBytes, 0, payload, 1, langLength);
        
        // ํ…์ŠคํŠธ ๋ณต์‚ฌ
        System.arraycopy(textBytes, 0, payload, 1 + langLength, textLength);
        
        // NDEF ๋ ˆ์ฝ”๋“œ ์ƒ์„ฑ
        return new NdefRecord(
            NdefRecord.TNF_WELL_KNOWN,
            NdefRecord.RTD_TEXT,
            new byte[0],
            payload
        );
    }
    
    // URI ๋ ˆ์ฝ”๋“œ ์ƒ์„ฑ ๋ฉ”์„œ๋“œ (์ถ”๊ฐ€ ๊ธฐ๋Šฅ)
    private NdefRecord createUriRecord(String uri) {
        byte[] uriBytes = uri.getBytes(Charset.forName("UTF-8"));
        byte[] payload = new byte[uriBytes.length + 1];
        
        // ํ”„๋ฆฌํ”ฝ์Šค ์—†์Œ
        payload[0] = 0x00;
        System.arraycopy(uriBytes, 0, payload, 1, uriBytes.length);
        
        return new NdefRecord(
            NdefRecord.TNF_WELL_KNOWN,
            NdefRecord.RTD_URI,
            new byte[0],
            payload
        );
    }


์“ฐ๊ธฐ ๊ธฐ๋Šฅ์˜ ํ•ต์‹ฌ ๋กœ์ง์„ ์„ค๋ช…ํ•ด๋ณผ๊ฒŒ์š”!

1. NDEF ๋ ˆ์ฝ”๋“œ ์ƒ์„ฑ
createTextRecord() ๋ฉ”์„œ๋“œ๋กœ ํ…์ŠคํŠธ๋ฅผ NDEF ํ˜•์‹์œผ๋กœ ๋ณ€ํ™˜ํ•ด์š”. ์–ธ์–ด ์ฝ”๋“œ์™€ ์‹ค์ œ ํ…์ŠคํŠธ๋ฅผ ์กฐํ•ฉํ•ด์„œ ํŽ˜์ด๋กœ๋“œ๋ฅผ ๋งŒ๋“œ๋Š” ๊ฑฐ์ฃ .

2. ํƒœ๊ทธ ์ƒํƒœ ํ™•์ธ
ํƒœ๊ทธ๊ฐ€ ์ด๋ฏธ ํฌ๋งท๋˜์–ด ์žˆ๋Š”์ง€, ์“ฐ๊ธฐ ๊ฐ€๋Šฅํ•œ์ง€, ์šฉ๋Ÿ‰์€ ์ถฉ๋ถ„ํ•œ์ง€ ์ฒดํฌํ•ด์š”. ์ด๊ฑฐ ์•ˆ ํ•˜๋ฉด ์—๋Ÿฌ ๋‚˜๊ธฐ ์‰ฌ์›Œ์š”ใ… ใ… 

3. ๋ฐ์ดํ„ฐ ์“ฐ๊ธฐ
ndef.writeNdefMessage()๋กœ ์‹ค์ œ ๋ฐ์ดํ„ฐ๋ฅผ ํƒœ๊ทธ์— ์จ์š”. ํฌ๋งท๋˜์ง€ ์•Š์€ ํƒœ๊ทธ๋Š” format.format()์œผ๋กœ ํฌ๋งทํ•˜๋ฉด์„œ ๋™์‹œ์— ๋ฐ์ดํ„ฐ๋ฅผ ์“ธ ์ˆ˜ ์žˆ์–ด์š”!

4. ์—๋Ÿฌ ์ฒ˜๋ฆฌ
๊ฐ ๋‹จ๊ณ„๋งˆ๋‹ค ์ ์ ˆํ•œ ์—๋Ÿฌ ๋ฉ”์‹œ์ง€๋ฅผ ํ‘œ์‹œํ•ด์„œ ์‚ฌ์šฉ์ž๊ฐ€ ๋ญ๊ฐ€ ๋ฌธ์ œ์ธ์ง€ ์•Œ ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค˜์š” ๐Ÿ’ฌ

NFC ํƒœ๊ทธ ์ฝ๊ธฐ/์“ฐ๊ธฐ ํ”Œ๋กœ์šฐ ์•ฑ ์‹œ์ž‘ NFC ์–ด๋Œ‘ํ„ฐ ์ดˆ๊ธฐํ™” ๊ธฐ๊ธฐ NFC ์ง€์› ํ™•์ธ Foreground Dispatch ํƒœ๊ทธ ๊ฐ์ง€ ๋Œ€๊ธฐ ์ฝ๊ธฐ ๋ชจ๋“œ ํƒœ๊ทธ ๋ฐ์ดํ„ฐ ํŒŒ์‹ฑ ํ™”๋ฉด์— ์ •๋ณด ํ‘œ์‹œ ์“ฐ๊ธฐ ๋ชจ๋“œ ๋ฐ์ดํ„ฐ NDEF ๋ณ€ํ™˜ ํƒœ๊ทธ์— ์“ฐ๊ธฐ ์‹คํ–‰ ์ฝ๊ธฐ ์“ฐ๊ธฐ โœ… ์ž‘์—… ์™„๋ฃŒ
๐Ÿ” ๋ณด์•ˆ ๊ณ ๋ ค์‚ฌํ•ญ

NFC ์•ฑ ๊ฐœ๋ฐœํ•  ๋•Œ ๋ณด์•ˆ๋„ ์‹ ๊ฒฝ ์จ์•ผ ํ•ด์š”! ํŠนํžˆ ๋ฏผ๊ฐํ•œ ์ •๋ณด๋ฅผ ๋‹ค๋ฃฌ๋‹ค๋ฉด ๋”๋”์šฑ์ด์š” ๐Ÿ”’

๋ช‡ ๊ฐ€์ง€ ์ค‘์š”ํ•œ ๋ณด์•ˆ ํŒ์„ ์•Œ๋ ค๋“œ๋ฆด๊ฒŒ์š”:

1. ๋ฐ์ดํ„ฐ ์•”ํ˜ธํ™” ์ค‘์š”ํ•œ ์ •๋ณด๋Š” ๋ฐ˜๋“œ์‹œ ์•”ํ˜ธํ™”ํ•ด์„œ ์ €์žฅํ•˜์„ธ์š”! AES ๊ฐ™์€ ๋Œ€์นญํ‚ค ์•”ํ˜ธํ™”๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ข‹์•„์š”.

2. ํƒœ๊ทธ ์ธ์ฆ
์ •ํ’ˆ ํƒœ๊ทธ์ธ์ง€ ํ™•์ธํ•˜๋Š” ๋กœ์ง์„ ์ถ”๊ฐ€ํ•˜์„ธ์š”. ํƒœ๊ทธ ID๋‚˜ ํŠน์ • ์„œ๋ช…์„ ๊ฒ€์ฆํ•˜๋Š” ๋ฐฉ์‹์ด ์žˆ์–ด์š”.

3. ์ž…๋ ฅ ๊ฒ€์ฆ
์‚ฌ์šฉ์ž๊ฐ€ ์ž…๋ ฅํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ํƒœ๊ทธ์— ์“ฐ๊ธฐ ์ „์— ๋ฐ˜๋“œ์‹œ ๊ฒ€์ฆํ•˜์„ธ์š”. SQL ์ธ์ ์…˜์ด๋‚˜ XSS ๊ฐ™์€ ๊ณต๊ฒฉ์„ ๋ง‰์„ ์ˆ˜ ์žˆ์–ด์š”.

4. ๊ถŒํ•œ ์ตœ์†Œํ™”
ํ•„์š”ํ•œ ๊ถŒํ•œ๋งŒ ์š”์ฒญํ•˜์„ธ์š”. NFC ๊ถŒํ•œ ์™ธ์— ๋ถˆํ•„์š”ํ•œ ๊ถŒํ•œ์€ ๋นผ๋Š” ๊ฒŒ ์ข‹์•„์š”.

5. HTTPS ํ†ต์‹ 
NFC ํƒœ๊ทธ์—์„œ ์ฝ์€ URL๋กœ ํ†ต์‹ ํ•  ๋•Œ๋Š” ๋ฐ˜๋“œ์‹œ HTTPS๋ฅผ ์‚ฌ์šฉํ•˜์„ธ์š”!


๊ฐ„๋‹จํ•œ ์•”ํ˜ธํ™” ์˜ˆ์ œ๋„ ๋ณด์—ฌ๋“œ๋ฆด๊ฒŒ์š”:

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import android.util.Base64;

public class NFCEncryption {
    
    private static final String ALGORITHM = "AES";
    private static final String KEY = "MySecretKey12345"; // ์‹ค์ œ๋กœ๋Š” ์•ˆ์ „ํ•˜๊ฒŒ ๊ด€๋ฆฌ!
    
    // ๋ฐ์ดํ„ฐ ์•”ํ˜ธํ™”
    public static String encrypt(String data) {
        try {
            SecretKeySpec key = new SecretKeySpec(KEY.getBytes(), ALGORITHM);
            Cipher cipher = Cipher.getInstance(ALGORITHM);
            cipher.init(Cipher.ENCRYPT_MODE, key);
            
            byte[] encryptedBytes = cipher.doFinal(data.getBytes());
            return Base64.encodeToString(encryptedBytes, Base64.DEFAULT);
            
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
    
    // ๋ฐ์ดํ„ฐ ๋ณตํ˜ธํ™”
    public static String decrypt(String encryptedData) {
        try {
            SecretKeySpec key = new SecretKeySpec(KEY.getBytes(), ALGORITHM);
            Cipher cipher = Cipher.getInstance(ALGORITHM);
            cipher.init(Cipher.DECRYPT_MODE, key);
            
            byte[] decodedBytes = Base64.decode(encryptedData, Base64.DEFAULT);
            byte[] decryptedBytes = cipher.doFinal(decodedBytes);
            
            return new String(decryptedBytes);
            
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}


์ด๋ ‡๊ฒŒ ์•”ํ˜ธํ™”ํ•ด์„œ ํƒœ๊ทธ์— ์ €์žฅํ•˜๋ฉด ํ›จ์”ฌ ์•ˆ์ „ํ•˜๊ฒ ์ฃ ? ๐Ÿ˜Š

๐ŸŽฏ ์‹ค์ „ ํ™œ์šฉ ์˜ˆ์ œ

์ด์ œ ์‹ค์ œ๋กœ ์–ด๋–ป๊ฒŒ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ๋ช‡ ๊ฐ€์ง€ ์˜ˆ์ œ๋ฅผ ๋ณด์—ฌ๋“œ๋ฆด๊ฒŒ์š”!

NFC ๊ธฐ์ˆ ์€ ์ •๋ง ๋‹ค์–‘ํ•œ ๋ถ„์•ผ์—์„œ ์“ธ ์ˆ˜ ์žˆ๊ฑฐ๋“ ์š” โœจ

๐Ÿ“ ์˜ˆ์ œ 1: ์Šค๋งˆํŠธ ๋ช…ํ•จ

NFC ํƒœ๊ทธ์— ์—ฐ๋ฝ์ฒ˜ ์ •๋ณด๋ฅผ ์ €์žฅํ•ด์„œ ์Šค๋งˆํŠธ ๋ช…ํ•จ์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ์–ด์š”!

private NdefRecord createVCardRecord(String name, String phone, String email) {
    String vCard = "BEGIN:VCARD\n" +
                   "VERSION:3.0\n" +
                   "FN:" + name + "\n" +
                   "TEL:" + phone + "\n" +
                   "EMAIL:" + email + "\n" +
                   "END:VCARD";
    
    byte[] vCardBytes = vCard.getBytes(Charset.forName("UTF-8"));
    
    return new NdefRecord(
        NdefRecord.TNF_MIME_MEDIA,
        "text/x-vcard".getBytes(),
        new byte[0],
        vCardBytes
    );
}

// ์‚ฌ์šฉ ์˜ˆ์‹œ
NdefRecord vCardRecord = createVCardRecord(
    "ํ™๊ธธ๋™", 
    "010-1234-5678", 
    "hong@example.com"
);
NdefMessage message = new NdefMessage(new NdefRecord[] { vCardRecord });
// ํƒœ๊ทธ์— ์“ฐ๊ธฐ...
๐Ÿ  ์˜ˆ์ œ 2: ์Šค๋งˆํŠธ ํ™ˆ ์ œ์–ด

NFC ํƒœ๊ทธ๋ฅผ ์ง‘์•ˆ ๊ณณ๊ณณ์— ๋ถ™์—ฌ์„œ ์Šค๋งˆํŠธ ํ™ˆ ๊ธฐ๊ธฐ๋ฅผ ์ œ์–ดํ•  ์ˆ˜ ์žˆ์–ด์š”!

private void handleSmartHomeTag(String command) {
    switch (command) {
        case "LIGHT_ON":
            // ์กฐ๋ช… ์ผœ๊ธฐ
            controlLight(true);
            Toast.makeText(this, "์กฐ๋ช…์„ ์ผฐ์–ด์š”! ๐Ÿ’ก", Toast.LENGTH_SHORT).show();
            break;
            
        case "LIGHT_OFF":
            // ์กฐ๋ช… ๋„๊ธฐ
            controlLight(false);
            Toast.makeText(this, "์กฐ๋ช…์„ ๊ป์–ด์š”! ๐ŸŒ™", Toast.LENGTH_SHORT).show();
            break;
            
        case "AC_ON":
            // ์—์–ด์ปจ ์ผœ๊ธฐ
            controlAirConditioner(true);
            Toast.makeText(this, "์—์–ด์ปจ์„ ์ผฐ์–ด์š”! โ„๏ธ", Toast.LENGTH_SHORT).show();
            break;
            
        case "GOODNIGHT":
            // ์ทจ์นจ ๋ชจ๋“œ
            controlLight(false);
            controlAirConditioner(true);
            setAlarm();
            Toast.makeText(this, "๊ตฟ๋‚˜์ž‡ ๋ชจ๋“œ ํ™œ์„ฑํ™”! ๐Ÿ˜ด", Toast.LENGTH_SHORT).show();
            break;
    }
}

private void controlLight(boolean on) {
    // ์‹ค์ œ๋กœ๋Š” ์Šค๋งˆํŠธ ํ™ˆ API ํ˜ธ์ถœ
    // ์˜ˆ: SmartHomeAPI.setLight(on);
}

private void controlAirConditioner(boolean on) {
    // ์—์–ด์ปจ ์ œ์–ด ๋กœ์ง
}
๐ŸŽซ ์˜ˆ์ œ 3: ์ถœ์ž… ๊ด€๋ฆฌ ์‹œ์Šคํ…œ

ํšŒ์‚ฌ๋‚˜ ํ•™๊ต ์ถœ์ž…์ฆ์œผ๋กœ๋„ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ์–ด์š”!

private void handleAccessControl(Tag tag) {
    String tagId = bytesToHex(tag.getId());
    
    // ์„œ๋ฒ„์— ์ธ์ฆ ์š”์ฒญ
    checkAccessPermission(tagId, new AccessCallback() {
        @Override
        public void onSuccess(UserInfo userInfo) {
            // ์ถœ์ž… ํ—ˆ๊ฐ€
            tvStatus.setText("ํ™˜์˜ํ•ฉ๋‹ˆ๋‹ค, " + userInfo.getName() + "๋‹˜! ๐ŸŽ‰");
            openDoor();
            logAccess(userInfo, true);
        }
        
        @Override
        public void onFailure(String reason) {
            // ์ถœ์ž… ๊ฑฐ๋ถ€
            tvStatus.setText("์ถœ์ž…์ด ๊ฑฐ๋ถ€๋˜์—ˆ์Šต๋‹ˆ๋‹ค โŒ");
            Toast.makeText(MainActivity.this, 
                "์‚ฌ์œ : " + reason, Toast.LENGTH_LONG).show();
            logAccess(null, false);
        }
    });
}

private void checkAccessPermission(String tagId, AccessCallback callback) {
    // ์‹ค์ œ๋กœ๋Š” ์„œ๋ฒ„ API ํ˜ธ์ถœ
    // ์˜ˆ์‹œ ์ฝ”๋“œ
    new Thread(() -> {
        try {
            // API ํ˜ธ์ถœ ๋กœ์ง
            // Response response = api.checkAccess(tagId);
            
            // ์ž„์‹œ ์˜ˆ์ œ
            UserInfo user = new UserInfo("ํ™๊ธธ๋™", "๊ฐœ๋ฐœํŒ€");
            runOnUiThread(() -> callback.onSuccess(user));
            
        } catch (Exception e) {
            runOnUiThread(() -> callback.onFailure(e.getMessage()));
        }
    }).start();
}

interface AccessCallback {
    void onSuccess(UserInfo userInfo);
    void onFailure(String reason);
}

class UserInfo {
    private String name;
    private String department;
    
    public UserInfo(String name, String department) {
        this.name = name;
        this.department = department;
    }
    
    public String getName() { return name; }
    public String getDepartment() { return department; }
}


์ด๋Ÿฐ ์‹์œผ๋กœ ๋‹ค์–‘ํ•˜๊ฒŒ ์‘์šฉํ•  ์ˆ˜ ์žˆ์–ด์š”! ์•„์ด๋””์–ด๋งŒ ์žˆ๋‹ค๋ฉด ๋ฌด๊ถ๋ฌด์ง„ํ•˜์ฃ  ๐Ÿš€

๐Ÿ› ์ž์ฃผ ๋ฐœ์ƒํ•˜๋Š” ์—๋Ÿฌ์™€ ํ•ด๊ฒฐ๋ฒ•

NFC ๊ฐœ๋ฐœํ•˜๋‹ค ๋ณด๋ฉด ์ž์ฃผ ๋งŒ๋‚˜๋Š” ์—๋Ÿฌ๋“ค์ด ์žˆ์–ด์š”. ๋ฏธ๋ฆฌ ์•Œ์•„๋‘๋ฉด ์‚ฝ์งˆ ์•ˆ ํ•ด๋„ ๋˜์ฃ ใ…‹ใ…‹ใ…‹

โŒ ์—๋Ÿฌ 1: "NFC adapter is null" ์›์ธ: ๊ธฐ๊ธฐ๊ฐ€ NFC๋ฅผ ์ง€์›ํ•˜์ง€ ์•Š๊ฑฐ๋‚˜ ์—๋ฎฌ๋ ˆ์ดํ„ฐ์—์„œ ์‹คํ–‰ ์ค‘
ํ•ด๊ฒฐ: ์‹ค์ œ NFC ์ง€์› ๊ธฐ๊ธฐ์—์„œ ํ…Œ์ŠคํŠธํ•˜๊ณ , null ์ฒดํฌ ๋กœ์ง ์ถ”๊ฐ€

โŒ ์—๋Ÿฌ 2: "Tag was lost"
์›์ธ: ํƒœ๊ทธ๋ฅผ ๋„ˆ๋ฌด ๋นจ๋ฆฌ ๋–ผ๊ฑฐ๋‚˜ ํ†ต์‹  ์ค‘ ์—ฐ๊ฒฐ์ด ๋Š๊น€
ํ•ด๊ฒฐ: ํƒœ๊ทธ๋ฅผ 3์ดˆ ์ •๋„ ๊ฐ€๊นŒ์ด ๋Œ€๊ณ  ์žˆ๋„๋ก ์•ˆ๋‚ด ๋ฉ”์‹œ์ง€ ์ถ”๊ฐ€

โŒ ์—๋Ÿฌ 3: "Tag is not NDEF formatted"
์›์ธ: ํƒœ๊ทธ๊ฐ€ NDEF ํฌ๋งท์ด ์•„๋‹˜
ํ•ด๊ฒฐ: NdefFormatable์œผ๋กœ ํฌ๋งท ํ›„ ์“ฐ๊ธฐ (์œ„ ์ฝ”๋“œ ์ฐธ๊ณ )

โŒ ์—๋Ÿฌ 4: "IOException: Transceive failed"
์›์ธ: ํƒœ๊ทธ์™€์˜ ํ†ต์‹  ์‹คํŒจ
ํ•ด๊ฒฐ: ์žฌ์‹œ๋„ ๋กœ์ง ์ถ”๊ฐ€, ํƒœ๊ทธ ํ’ˆ์งˆ ํ™•์ธ

โŒ ์—๋Ÿฌ 5: "SecurityException: Need NFC permission"
์›์ธ: ๋งค๋‹ˆํŽ˜์ŠคํŠธ์— ๊ถŒํ•œ ์„ ์–ธ ๋ˆ„๋ฝ
ํ•ด๊ฒฐ: AndroidManifest.xml์— NFC ๊ถŒํ•œ ์ถ”๊ฐ€


์—๋Ÿฌ ์ฒ˜๋ฆฌ ๊ฐ•ํ™” ๋ฒ„์ „ ์ฝ”๋“œ๋„ ๋ณด์—ฌ๋“œ๋ฆด๊ฒŒ์š”:

private void writeToTagWithRetry(Tag tag, String data, int retryCount) {
    int attempts = 0;
    boolean success = false;
    
    while (attempts < retryCount && !success) {
        try {
            attempts++;
            
            NdefRecord record = createTextRecord(data);
            NdefMessage message = new NdefMessage(new NdefRecord[] { record });
            
            Ndef ndef = Ndef.get(tag);
            
            if (ndef != null) {
                ndef.connect();
                
                if (!ndef.isWritable()) {
                    throw new IOException("Tag is read-only");
                }
                
                ndef.writeNdefMessage(message);
                ndef.close();
                success = true;
                
                tvStatus.setText("์“ฐ๊ธฐ ์™„๋ฃŒ! โœ…");
                Toast.makeText(this, "์„ฑ๊ณต!", Toast.LENGTH_SHORT).show();
                
            } else {
                throw new IOException("Tag is not NDEF formatted");
            }
            
        } catch (IOException e) {
            if (attempts >= retryCount) {
                tvStatus.setText("์“ฐ๊ธฐ ์‹คํŒจ ๐Ÿ˜ข");
                Toast.makeText(this, 
                    String.format("์‹คํŒจ (%d๋ฒˆ ์‹œ๋„): %s", attempts, e.getMessage()), 
                    Toast.LENGTH_LONG).show();
            } else {
                // ์žฌ์‹œ๋„
                try {
                    Thread.sleep(500); // 0.5์ดˆ ๋Œ€๊ธฐ
                } catch (InterruptedException ie) {
                    ie.printStackTrace();
                }
            }
        }
    }
}


์ด๋ ‡๊ฒŒ ์žฌ์‹œ๋„ ๋กœ์ง์„ ์ถ”๊ฐ€ํ•˜๋ฉด ํ›จ์”ฌ ์•ˆ์ •์ ์œผ๋กœ ๋™์ž‘ํ•ด์š”! ๐Ÿ’ช

โšก ์„ฑ๋Šฅ ์ตœ์ ํ™” ํŒ

NFC ์•ฑ์„ ๋” ๋น ๋ฅด๊ณ  ํšจ์œจ์ ์œผ๋กœ ๋งŒ๋“œ๋Š” ๋ฐฉ๋ฒ•๋“ค์ด์—์š”!

1๏ธโƒฃ ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์Šค๋ ˆ๋“œ ์‚ฌ์šฉ NFC ์ฝ๊ธฐ/์“ฐ๊ธฐ ์ž‘์—…์€ ๋ฉ”์ธ ์Šค๋ ˆ๋“œ๋ฅผ ๋ธ”๋กœํ‚นํ•  ์ˆ˜ ์žˆ์–ด์š”. AsyncTask๋‚˜ Coroutine์„ ์‚ฌ์šฉํ•˜์„ธ์š”!

2๏ธโƒฃ ์บ์‹ฑ ํ™œ์šฉ
์ž์ฃผ ์ฝ๋Š” ํƒœ๊ทธ ์ •๋ณด๋Š” ์บ์‹ฑํ•ด์„œ ์žฌ์‚ฌ์šฉํ•˜์„ธ์š”. SharedPreferences๋‚˜ Room DB๋ฅผ ํ™œ์šฉํ•˜๋ฉด ์ข‹์•„์š”.

3๏ธโƒฃ ๋ฐฐํ„ฐ๋ฆฌ ์ตœ์ ํ™”
Foreground Dispatch๋Š” onPause()์—์„œ ๋ฐ˜๋“œ์‹œ ๋น„ํ™œ์„ฑํ™”ํ•˜์„ธ์š”. ์•ˆ ๊ทธ๋Ÿฌ๋ฉด ๋ฐฐํ„ฐ๋ฆฌ๊ฐ€ ๋นจ๋ฆฌ ๋‹ณ์•„์š”!

4๏ธโƒฃ ๋ฐ์ดํ„ฐ ์••์ถ•
ํฐ ๋ฐ์ดํ„ฐ๋Š” ์••์ถ•ํ•ด์„œ ์ €์žฅํ•˜๋ฉด ํƒœ๊ทธ ์šฉ๋Ÿ‰์„ ์ ˆ์•ฝํ•  ์ˆ˜ ์žˆ์–ด์š”.

5๏ธโƒฃ ์—๋Ÿฌ ๋กœ๊น…
Firebase Crashlytics ๊ฐ™์€ ๋„๊ตฌ๋กœ ์—๋Ÿฌ๋ฅผ ์ถ”์ ํ•˜๋ฉด ๋””๋ฒ„๊น…์ด ํ›จ์”ฌ ์‰ฌ์›Œ์ ธ์š”!


AsyncTask ์˜ˆ์ œ๋„ ๋ณด์—ฌ๋“œ๋ฆด๊ฒŒ์š”:

private class WriteNFCTask extends AsyncTask<Void, Void, Boolean> {
    
    private Tag tag;
    private String data;
    private String errorMessage;
    
    public WriteNFCTask(Tag tag, String data) {
        this.tag = tag;
        this.data = data;
    }
    
    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        // UI ์—…๋ฐ์ดํŠธ (๋กœ๋”ฉ ํ‘œ์‹œ)
        tvStatus.setText("์“ฐ๋Š” ์ค‘... โณ");
        btnWrite.setEnabled(false);
    }
    
    @Override
    protected Boolean doInBackground(Void... voids) {
        try {
            NdefRecord record = createTextRecord(data);
            NdefMessage message = new NdefMessage(new NdefRecord[] { record });
            
            Ndef ndef = Ndef.get(tag);
            if (ndef != null) {
                ndef.connect();
                ndef.writeNdefMessage(message);
                ndef.close();
                return true;
            }
            
            errorMessage = "NDEF not supported";
            return false;
            
        } catch (Exception e) {
            errorMessage = e.getMessage();
            return false;
        }
    }
    
    @Override
    protected void onPostExecute(Boolean success) {
        super.onPostExecute(success);
        
        btnWrite.setEnabled(true);
        
        if (success) {
            tvStatus.setText("์“ฐ๊ธฐ ์™„๋ฃŒ! โœ…");
            Toast.makeText(MainActivity.this, 
                "์„ฑ๊ณต์ ์œผ๋กœ ์ผ์–ด์š”!", Toast.LENGTH_SHORT).show();
        } else {
            tvStatus.setText("์“ฐ๊ธฐ ์‹คํŒจ ๐Ÿ˜ข");
            Toast.makeText(MainActivity.this, 
                "์˜ค๋ฅ˜: " + errorMessage, Toast.LENGTH_SHORT).show();
        }
    }
}

// ์‚ฌ์šฉ
new WriteNFCTask(tag, dataToWrite).execute();


์š”์ฆ˜์€ Kotlin Coroutine์„ ๋” ๋งŽ์ด ์“ฐ๊ธด ํ•˜๋Š”๋ฐ, AsyncTask๋„ ์—ฌ์ „ํžˆ ์œ ์šฉํ•ด์š”!

๐ŸŽจ UI/UX ๊ฐœ์„  ์•„์ด๋””์–ด

๊ธฐ๋Šฅ๋„ ์ค‘์š”ํ•˜์ง€๋งŒ ์‚ฌ์šฉ์ž ๊ฒฝํ—˜๋„ ์—„์ฒญ ์ค‘์š”ํ•˜์ฃ ! ๋ช‡ ๊ฐ€์ง€ UI/UX ํŒ์„ ๋“œ๋ฆด๊ฒŒ์š” ๐Ÿ˜Š

๐Ÿ’ก ์‚ฌ์šฉ์ž ์นœํ™”์ ์ธ UI ๋งŒ๋“ค๊ธฐ 1. ์‹œ๊ฐ์  ํ”ผ๋“œ๋ฐฑ
ํƒœ๊ทธ๋ฅผ ๊ฐ์ง€ํ•˜๋ฉด ์ง„๋™์ด๋‚˜ ์†Œ๋ฆฌ๋กœ ์•Œ๋ ค์ฃผ์„ธ์š”. ์‚ฌ์šฉ์ž๊ฐ€ "์–ด? ๋๋‚˜?" ํ•˜๋Š” ๋ถˆ์•ˆ๊ฐ์„ ์—†์•จ ์ˆ˜ ์žˆ์–ด์š”!

2. ๋ช…ํ™•ํ•œ ์•ˆ๋‚ด
"ํƒœ๊ทธ๋ฅผ ํฐ ๋’ท๋ฉด ์ค‘์•™์— 3์ดˆ๊ฐ„ ๋Œ€์ฃผ์„ธ์š”" ๊ฐ™์€ ๊ตฌ์ฒด์ ์ธ ์•ˆ๋‚ด๋ฅผ ์ œ๊ณตํ•˜์„ธ์š”.

3. ์• ๋‹ˆ๋ฉ”์ด์…˜ ํšจ๊ณผ
NFC ๊ฐ์ง€ ์ค‘์ผ ๋•Œ ๋ฌผ๊ฒฐ ์• ๋‹ˆ๋ฉ”์ด์…˜ ๊ฐ™์€ ๊ฑธ ๋ณด์—ฌ์ฃผ๋ฉด ๋” ์ง๊ด€์ ์ด์—์š”!

4. ์—๋Ÿฌ ๋ฉ”์‹œ์ง€ ๊ฐœ์„ 
"์˜ค๋ฅ˜ ๋ฐœ์ƒ"๋ณด๋‹ค๋Š” "ํƒœ๊ทธ๋ฅผ ์กฐ๊ธˆ ๋” ๊ฐ€๊นŒ์ด ๋Œ€์ฃผ์„ธ์š”" ๊ฐ™์€ ์นœ์ ˆํ•œ ๋ฉ”์‹œ์ง€๊ฐ€ ์ข‹์•„์š”.

5. ํžˆ์Šคํ† ๋ฆฌ ๊ธฐ๋Šฅ
์ฝ์—ˆ๋˜ ํƒœ๊ทธ ๋ชฉ๋ก์„ ๋ณด์—ฌ์ฃผ๋ฉด ์‚ฌ์šฉ์ž๊ฐ€ ํŽธ๋ฆฌํ•˜๊ฒŒ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์–ด์š”!


์ง„๋™ ํ”ผ๋“œ๋ฐฑ ์ถ”๊ฐ€ํ•˜๋Š” ์ฝ”๋“œ์˜ˆ์š”:

import android.os.Vibrator;
import android.content.Context;

private void provideHapticFeedback() {
    Vibrator vibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
    if (vibrator != null && vibrator.hasVibrator()) {
        // ์งง์€ ์ง„๋™ (100ms)
        vibrator.vibrate(100);
    }
}

// NFC ํƒœ๊ทธ ๊ฐ์ง€ ์‹œ ํ˜ธ์ถœ
private void handleIntent(Intent intent) {
    String action = intent.getAction();
    
    if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(action) ||
        NfcAdapter.ACTION_TAG_DISCOVERED.equals(action)) {
        
        // ์ง„๋™ ํ”ผ๋“œ๋ฐฑ
        provideHapticFeedback();
        
        // ์†Œ๋ฆฌ ํ”ผ๋“œ๋ฐฑ (์„ ํƒ์‚ฌํ•ญ)
        playBeepSound();
        
        Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
        // ... ๋‚˜๋จธ์ง€ ์ฒ˜๋ฆฌ
    }
}

private void playBeepSound() {
    // ToneGenerator๋กœ ๋น„ํ”„์Œ ์žฌ์ƒ
    ToneGenerator toneGen = new ToneGenerator(AudioManager.STREAM_MUSIC, 100);
    toneGen.startTone(ToneGenerator.TONE_PROP_BEEP, 150);
}
๐ŸŒ ์žฌ๋Šฅ๋„ท์—์„œ NFC ๊ฐœ๋ฐœ ์žฌ๋Šฅ ๊ณต์œ ํ•˜๊ธฐ

์—ฌ๋Ÿฌ๋ถ„์ด ์ด ๊ธ€์„ ๋ณด๊ณ  NFC ๊ฐœ๋ฐœ ์‹ค๋ ฅ์„ ์Œ“์•˜๋‹ค๋ฉด, ์žฌ๋Šฅ๋„ท์—์„œ ๋‹ค๋ฅธ ์‚ฌ๋žŒ๋“ค๊ณผ ์žฌ๋Šฅ์„ ๊ณต์œ ํ•ด๋ณด๋Š” ๊ฑด ์–ด๋–จ๊นŒ์š”?

์žฌ๋Šฅ๋„ท(https://www.jaenung.net)์€ ๋‹ค์–‘ํ•œ IT ๊ฐœ๋ฐœ ์žฌ๋Šฅ์„ ๊ฑฐ๋ž˜ํ•  ์ˆ˜ ์žˆ๋Š” ํ”Œ๋žซํผ์ด์—์š”! ๐Ÿ’ผ

์˜ˆ๋ฅผ ๋“ค์–ด:
โœ… "NFC ์•ฑ ๊ฐœ๋ฐœ ์ปจ์„คํŒ…" ์žฌ๋Šฅ ๋“ฑ๋ก
โœ… "์Šค๋งˆํŠธ ๋ช…ํ•จ ์•ฑ ์ œ์ž‘" ์„œ๋น„์Šค ์ œ๊ณต
โœ… "์ถœ์ž… ๊ด€๋ฆฌ ์‹œ์Šคํ…œ ๊ตฌ์ถ•" ํ”„๋กœ์ ํŠธ ์ˆ˜์ฃผ
โœ… "NFC ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๊ณผ์™ธ" ๊ฐ•์˜

์ด๋Ÿฐ ์‹์œผ๋กœ ์—ฌ๋Ÿฌ๋ถ„์˜ ์ „๋ฌธ์„ฑ์„ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ์–ด์š”! ์‹ค์ œ๋กœ NFC ๊ธฐ์ˆ ์€ ์ˆ˜์š”๊ฐ€ ๊ฝค ์žˆ๋Š” ๋ถ„์•ผ๊ฑฐ๋“ ์š” ๐Ÿ˜Ž

๋˜ํ•œ ์žฌ๋Šฅ๋„ท์˜ ์ง€์‹์ธ์˜ ์ˆฒ ๊ฐ™์€ ๊ณณ์—์„œ ์—ฌ๋Ÿฌ๋ถ„์˜ ๋…ธํ•˜์šฐ๋ฅผ ๊ณต์œ ํ•˜๋ฉด์„œ ๋‹ค๋ฅธ ๊ฐœ๋ฐœ์ž๋“ค๊ณผ ์†Œํ†ตํ•  ์ˆ˜๋„ ์žˆ๊ณ ์š”!

๐Ÿ“š ์ถ”๊ฐ€ ํ•™์Šต ๋ฆฌ์†Œ์Šค

๋” ๊นŠ์ด ๊ณต๋ถ€ํ•˜๊ณ  ์‹ถ์€ ๋ถ„๋“ค์„ ์œ„ํ•œ ๋ฆฌ์†Œ์Šค๋“ค์ด์—์š”!

๐Ÿ“– ๊ณต์‹ ๋ฌธ์„œ โ€ข Android NFC ๊ฐ€์ด๋“œ: developer.android.com/guide/topics/connectivity/nfc
โ€ข NFC Forum ์ŠคํŽ™: nfc-forum.org/our-work/specifications-and-application-documents

๐ŸŽ“ ์˜จ๋ผ์ธ ๊ฐ•์˜
โ€ข Udemy: "Android NFC Development"
โ€ข Coursera: "Mobile Application Development"

๐Ÿ’ป ์˜คํ”ˆ์†Œ์Šค ํ”„๋กœ์ ํŠธ
โ€ข GitHub์—์„œ "android nfc" ๊ฒ€์ƒ‰ํ•˜๋ฉด ๋‹ค์–‘ํ•œ ์˜ˆ์ œ ํ”„๋กœ์ ํŠธ๋ฅผ ์ฐพ์„ ์ˆ˜ ์žˆ์–ด์š”!
โ€ข NFC Tools ์•ฑ ์†Œ์Šค์ฝ”๋“œ ๋ถ„์„๋„ ๋„์›€์ด ๋งŽ์ด ๋ผ์š”.

๐ŸŒ ์ปค๋ฎค๋‹ˆํ‹ฐ
โ€ข Stack Overflow์˜ [android-nfc] ํƒœ๊ทธ
โ€ข Reddit์˜ r/androiddev
โ€ข ํ•œ๊ตญ ์•ˆ๋“œ๋กœ์ด๋“œ ๊ฐœ๋ฐœ์ž ์ปค๋ฎค๋‹ˆํ‹ฐ

๐Ÿš€ ๋งˆ๋ฌด๋ฆฌํ•˜๋ฉฐ

์™€... ์—ฌ๊ธฐ๊นŒ์ง€ ์ •๋ง ๊ธด ์—ฌ์ •์ด์—ˆ๋„ค์š”!ใ…‹ใ…‹ใ…‹ ๊ณ ์ƒ ๋งŽ์œผ์…จ์–ด์š” ๐Ÿ‘

์˜ค๋Š˜ ๋‹ค๋ฃฌ ๋‚ด์šฉ์„ ์ •๋ฆฌํ•ด๋ณผ๊ฒŒ์š”:

โœ… NFC ๊ธฐ๋ณธ ๊ฐœ๋…๊ณผ ๋™์ž‘ ์›๋ฆฌ
โœ… ์•ˆ๋“œ๋กœ์ด๋“œ NFC ๊ฐœ๋ฐœ ํ™˜๊ฒฝ ์„ธํŒ…
โœ… NFC ํƒœ๊ทธ ์ฝ๊ธฐ ๊ธฐ๋Šฅ ๊ตฌํ˜„
โœ… NFC ํƒœ๊ทธ ์“ฐ๊ธฐ ๊ธฐ๋Šฅ ๊ตฌํ˜„
โœ… ๋ณด์•ˆ ๊ณ ๋ ค์‚ฌํ•ญ๊ณผ ์•”ํ˜ธํ™”
โœ… ์‹ค์ „ ํ™œ์šฉ ์˜ˆ์ œ๋“ค
โœ… ์—๋Ÿฌ ์ฒ˜๋ฆฌ์™€ ์„ฑ๋Šฅ ์ตœ์ ํ™”
โœ… UI/UX ๊ฐœ์„  ๋ฐฉ๋ฒ•

์ด ์ •๋„๋ฉด ๊ธฐ๋ณธ์ ์ธ NFC ์•ฑ์€ ์ถฉ๋ถ„ํžˆ ๋งŒ๋“ค ์ˆ˜ ์žˆ์„ ๊ฑฐ์˜ˆ์š”! ๐Ÿ’ช

๋ฌผ๋ก  ์ฒ˜์Œ์—” ์–ด๋ ค์šธ ์ˆ˜ ์žˆ์–ด์š”. ์ €๋„ ์ฒ˜์Œ NFC ๊ฐœ๋ฐœํ•  ๋•Œ ํƒœ๊ทธ๊ฐ€ ์•ˆ ์ฝํ˜€์„œ ๋ช‡ ์‹œ๊ฐ„ ๋™์•ˆ ์‚ฝ์งˆํ–ˆ๋˜ ๊ธฐ์–ต์ด ๋‚˜๋„ค์š”ใ…‹ใ…‹ใ…‹

ํ•˜์ง€๋งŒ ํฌ๊ธฐํ•˜์ง€ ๋ง๊ณ  ๊ณ„์† ์‹œ๋„ํ•ด๋ณด์„ธ์š”! ์‹ค์ œ ๊ธฐ๊ธฐ๋กœ ํ…Œ์ŠคํŠธํ•˜๋ฉด์„œ ํ•˜๋‚˜ํ•˜๋‚˜ ์ตํ˜€๊ฐ€๋‹ค ๋ณด๋ฉด ์–ด๋А์ƒˆ ์ „๋ฌธ๊ฐ€๊ฐ€ ๋˜์–ด ์žˆ์„ ๊ฑฐ์˜ˆ์š” ๐Ÿ˜Š

ํ•ต์‹ฌ์€ ์‹ค์Šต์ž…๋‹ˆ๋‹ค! ์ด๋ก ๋งŒ ๋ณด์ง€ ๋ง๊ณ  ์ง์ ‘ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๊ณ , ํƒœ๊ทธ๋ฅผ ์ฝ๊ณ  ์“ฐ๋ฉด์„œ ๊ฒฝํ—˜์„ ์Œ“์œผ์„ธ์š”.

๊ทธ๋ฆฌ๊ณ  ๋ง‰ํžˆ๋Š” ๋ถ€๋ถ„์ด ์žˆ์œผ๋ฉด ์ฃผ์ €ํ•˜์ง€ ๋ง๊ณ  ์ปค๋ฎค๋‹ˆํ‹ฐ์— ์งˆ๋ฌธํ•˜์„ธ์š”. ๊ฐœ๋ฐœ์ž๋“ค์€ ์„œ๋กœ ๋•๋Š” ๋ฌธํ™”๊ฐ€ ์žˆ์œผ๋‹ˆ๊นŒ์š”! ๐Ÿค

์—ฌ๋Ÿฌ๋ถ„์˜ NFC ์•ฑ ๊ฐœ๋ฐœ ์—ฌ์ •์— ์ด ๊ธ€์ด ๋„์›€์ด ๋˜์—ˆ์œผ๋ฉด ์ข‹๊ฒ ์–ด์š”. ๋ฉ‹์ง„ ์•ฑ ๋งŒ๋“ค์–ด์„œ ์žฌ๋Šฅ๋„ท์—๋„ ๊ณต์œ ํ•ด์ฃผ์‹œ๊ณ ์š”!

๊ทธ๋Ÿผ ์˜ค๋Š˜๋„ ์ฆ๊ฑฐ์šด ์ฝ”๋”ฉ ๋˜์„ธ์š”! ํ™”์ดํŒ…! ๐ŸŽ‰โœจ

๐ŸŽฏ Happy NFC Coding! ๐ŸŽฏ

์งˆ๋ฌธ์ด๋‚˜ ํ”ผ๋“œ๋ฐฑ์€ ์–ธ์ œ๋“  ํ™˜์˜์ด์—์š”! ๐Ÿ˜Š

๋Œ“๊ธ€ ์ž‘์„ฑ

์ด ๊ธ€์— ๋Œ€ํ•œ ์—ฌ๋Ÿฌ๋ถ„์˜ ์ƒ๊ฐ์„ ๋“ค๋ ค์ฃผ์„ธ์š”

๋Œ“๊ธ€ 0
๋Œ“๊ธ€์„ ๋ถˆ๋Ÿฌ์˜ค๋Š” ์ค‘์ž…๋‹ˆ๋‹ค.

์•„์ง ๋Œ“๊ธ€์ด ์—†์Šต๋‹ˆ๋‹ค.