Android Nfc讀寫標(biāo)簽

??文章介紹NDEFMifareClassic兩種格式數(shù)據(jù)讀寫標(biāo)簽的方法扇商。 在進行Nfc的讀寫之前巩割,了解卡片的存儲結(jié)構(gòu)是非常重要的(非常重要广鳍,尤其對理解MifareClassic數(shù)據(jù)格式)说莫。
卡片常用的數(shù)據(jù)格式:
MifareClassic數(shù)據(jù)格式就是NfcA。
IsoDep:各種交通卡膝蜈。如:北京市政交通卡锅移。
NfcB:二代身份證。
NfcF:Felica用的是饱搏。
NfcV:德州儀器的VicinityCard卡用的是帆啃。
Ndef:安卓主推的傳輸數(shù)據(jù)格式。

一窍帝、Nfc卡片存儲結(jié)構(gòu)

M1卡:容量1K努潘。16個扇區(qū)(sector),每個扇區(qū)4個塊(block)坤学,每個塊(block) 16個byte數(shù)據(jù)
每個扇區(qū)的前三個塊疯坤,可用于存貯數(shù)據(jù)。
第0扇區(qū)的第一個塊除外深浮,它用于存放廠商數(shù)據(jù)压怠,已經(jīng)固化,不可更改飞苇。
每個扇區(qū)的第四個塊為控制塊菌瘫,用于控制該扇形區(qū)的訪問權(quán)限。它的前6個字節(jié)為KeyA布卡,后6個字節(jié)為KeyB雨让,中間的4個字節(jié)為存取控制。KeyA和KeyB記錄了兩種加密方式忿等,存取控制里記錄了該扇區(qū)的讀寫權(quán)限支持KeyA驗證還是KeyB驗證栖忠。

扇形區(qū) 塊中的數(shù)據(jù)
扇區(qū) 0(sectorIndex 0) 塊 0(blockIndex 0) 廠家數(shù)據(jù)不可修改
扇區(qū) 0(sectorIndex 0) 塊 1(blockIndex 1) 0........................15 (byte)
扇區(qū) 0(sectorIndex 0) 塊 2(blockIndex 2) 0........................15 (byte)
扇區(qū) 0(sectorIndex 0) 塊 3(blockIndex 3) 密碼A?存取控制?密碼B
: : :
: : :
扇區(qū) 15(sectorIndex 15) 塊 60(blockIndex 60) 0........................15 (byte)
扇區(qū) 15(sectorIndex 15) 塊 61(blockIndex 61) 0........................15 (byte)
扇區(qū) 15(sectorIndex 15) 塊 62(blockIndex 62) 0........................15 (byte)
扇區(qū) 15(sectorIndex 15) 塊 63(blockIndex 63) 密碼A?存取控制?密碼B
數(shù)據(jù)塊.png

二、NFC數(shù)據(jù)過濾器

NFC有三種過濾器:ACTION_NDEF_DISCOVERED贸街,ACTION_TECH_DISCOVERED庵寞,ACTION_TAG_DISCOVERED。

1薛匪、過濾器介紹

ACTION_NDEF_DISCOVERED
當(dāng)卡片中包含NDEF格式的數(shù)據(jù)捐川,將使用該模式啟動Activity。
ACTION_TECH_DISCOVERED
當(dāng)卡片中包含非NDEF格式的數(shù)據(jù)(如:MifareClassic)將使用該模式啟動Activity逸尖。
ACTION_TAG_DISCOVERED
過濾規(guī)則是最不嚴格的古沥,只要符合NFC規(guī)范中的任一種則都會響應(yīng)。

優(yōu)先級順序冷溶,上面三種規(guī)則依次遞減

  1. 如果卡片是Ndef格式的數(shù)據(jù)
    如果activity注冊了ACTION_NDEF_DISCOVERED红碑,會優(yōu)先響應(yīng)ACTION_NDEF_DISCOVERED彪置。
    如果activity沒有注冊ACTION_NDEF_DISCOVERED电抚,會優(yōu)先響應(yīng)ACTION_TECH_DISCOVERED任岸。
    如果activity沒有注冊ACTION_NDEF_DISCOVERED和ACTION_TECH_DISCOVERED,會響應(yīng)ACTION_TAG_DISCOVERED苗胀。
  2. 如果卡片是非Ndef格式的數(shù)據(jù)
    即使activity注冊了ACTION_NDEF_DISCOVERED襟诸,也不會響應(yīng)ACTION_NDEF_DISCOVERED瓦堵。
    如果activity注冊了ACTION_TECH_DISCOVERED,會優(yōu)先響應(yīng)ACTION_TECH_DISCOVERED歌亲。
    如果activity沒有注冊ACTION_TECH_DISCOVERED菇用,會響應(yīng)ACTION_TAG_DISCOVERED。

ACTION_TAG_DISCOVERED的優(yōu)先級是最低陷揪,activity無法獲得更詳細的一些信息惋鸥,所以不會一開始就選擇TAG_DISCOVERED來響應(yīng)。

2悍缠、過濾器注冊

靜態(tài)注冊
在AndroidMainfest.xml中聲明卦绣。在需要處理NFC讀卡的Activity標(biāo)簽里聲明過濾器。當(dāng)在桌面刷卡的時候飞蚓,手機系統(tǒng)會彈窗出現(xiàn)可以處理該Intent的APP滤港。

<activity
            android:name=".activity.InspectionsActivity"
            android:configChanges="orientation|keyboardHidden|screenSize"
            android:label="@string/inspection"
            android:screenOrientation="portrait"
            android:windowSoftInputMode="stateHidden|adjustPan">
            <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.TECH_DISCOVERED" />
            </intent-filter>
            <meta-data
                android:name="android.nfc.action.TECH_DISCOVERED"
                android:resource="@xml/nfc_tech_filter" />
        </activity>

篩選NFC卡片的類型。

<meta-data
    android:name="android.nfc.action.TECH_DISCOVERED"
    android:resource="@xml/nfc_tech_filter"/>

在res>xml目錄下添加nfc_tech_filter.xml

<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <tech-list>
        <tech>android.nfc.tech.NfcA</tech>
    </tech-list>
    <tech-list>
        <tech>android.nfc.tech.NfcB</tech>
    </tech-list>
    <tech-list>
        <tech>android.nfc.tech.NfcF</tech>
    </tech-list>
    <tech-list>
        <tech>android.nfc.tech.NfcV</tech>
    </tech-list>
    <tech-list>
        <tech>android.nfc.tech.Ndef</tech>
    </tech-list>
    <tech-list>
        <tech>android.nfc.tech.NdefFormatable</tech>
    </tech-list>
    <tech-list>
        <tech>android.nfc.tech.IsoDep</tech>
    </tech-list>
    <tech-list>
        <tech>android.nfc.tech.MifareClassic</tech>
    </tech-list>
    <tech-list>
        <tech>android.nfc.tech.MifareUltralight</tech>
    </tech-list>
</resources>

動態(tài)注冊
在代碼里聲明過濾器趴拧,在桌面刷卡的時候溅漾,不會彈出可響應(yīng)APP的彈窗。

Intent intent = new Intent(activity, activity.getClass());
        intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
        mPendingIntent = PendingIntent.getActivity(activity, 0, intent, 0);
        //intentFilter過濾----ndef
        IntentFilter ndefFilter = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED);
        try {
            //文本類型
            ndefFilter.addDataType("text/plain");
        } catch (IntentFilter.MalformedMimeTypeException e) {
            e.printStackTrace();
        }
        //intentFilter過濾----非ndef
        IntentFilter techFilter = new IntentFilter(NfcAdapter.ACTION_TECH_DISCOVERED);
        //intentFilter過濾器列表
        mIntentFilter = new IntentFilter[]{ndefFilter, techFilter};
        //匹配的數(shù)據(jù)格式列表
        mTechList = new String[][]{
                {MifareClassic.class.getName()},
                {NfcA.class.getName()},
                {Ndef.class.getName()},
                {NdefFormatable.class.getName()}};

三著榴、NFC的工具類

1添履、初始化

 mNfcAdapter = NfcAdapter.getDefaultAdapter(activity);
        if (mNfcAdapter == null) {
            ToastUtils.showShort("設(shè)備不支持NFC功能!");
        } else {
            if (!mNfcAdapter.isEnabled()) {
                showSettingDailog();
            } else {
                Logger.e(TAG, "NFC功能已打開!");
                init();
            }
        }

2、啟動

 /**
     * Nfc監(jiān)聽intent
     */
    public void enableForegroundDispatch() {
        if (mNfcAdapter != null && mNfcAdapter.isEnabled()) {
            mNfcAdapter.enableForegroundDispatch(activity, mPendingIntent, mIntentFilter, mTechList);
        }
    }

2兄渺、關(guān)閉

/**
     * 取消監(jiān)聽Nfc
     */
    public void disableForegroundDispatch() {
        if (mNfcAdapter != null && mNfcAdapter.isEnabled()) {
            mNfcAdapter.disableForegroundDispatch(activity);
        }
    }

3缝龄、讀取NDEF格式

/**
     * 讀取Ndef的數(shù)據(jù)
     *
     * @return
     */
    private String readNdef(Intent intent) {
        String info = "";
        Parcelable[] rawMsgs = intent.getParcelableArrayExtra(
                NfcAdapter.EXTRA_NDEF_MESSAGES);
        NdefMessage msgs[] = null;
        if (rawMsgs != null) {
            msgs = new NdefMessage[rawMsgs.length];
            for (int i = 0; i < rawMsgs.length; i++) {
                msgs[i] = (NdefMessage) rawMsgs[i];
            }
            NdefRecord record = msgs[0].getRecords()[0];
            if (record != null) {
                byte[] payload = record.getPayload();
                //下面代碼分析payload:狀態(tài)字節(jié)+ISO語言編碼(ASCLL)+文本數(shù)據(jù)(UTF_8/UTF_16)
                //其中payload[0]放置狀態(tài)字節(jié):如果bit7為0,文本數(shù)據(jù)以UTF_8格式編碼挂谍,如果為1則以UTF_16編碼
                //bit6是保留位,默認為0
                /*
                 * payload[0] contains the "Status Byte Encodings" field, per the
                 * NFC Forum "Text Record Type Definition" section 3.2.1.
                 *
                 * bit7 is the Text Encoding Field.
                 *
                 * if (Bit_7 == 0): The text is encoded in UTF-8 if (Bit_7 == 1):
                 * The text is encoded in UTF16
                 *
                 * Bit_6 is reserved for future use and must be set to zero.
                 *
                 * Bits 5 to 0 are the length of the IANA language code.
                 */
                String textEncoding = ((payload[0] & 0x80) == 0) ? "UTF-8"
                        : "UTF-16";
                //處理bit5-0瞎饲。bit5-0表示語言編碼長度(字節(jié)數(shù))
                int languageCodeLength = payload[0] & 0x3f;
                //獲取語言編碼(從payload的第2個字節(jié)讀取languageCodeLength個字節(jié)作為語言編碼)
                try {
                    String languageCode = new String(payload, 1, languageCodeLength,
                            "US-ASCII");
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                }
                //解析出實際的文本數(shù)據(jù)
                try {
                    info = new String(payload, languageCodeLength + 1,
                            payload.length - languageCodeLength - 1, textEncoding);
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                }
            }
        }
        return info;
    }

5口叙、寫NDEF格式

 /**
     * 往nfc寫入數(shù)據(jù)
     */
    public void writeNFCToTag(String text, Intent intent) throws IOException, FormatException {
        Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
        //生成語言編碼的字節(jié)數(shù)組,中文編碼
        byte[] langBytes = Locale.CHINA.getLanguage().getBytes(
                Charset.forName("US-ASCII"));
        //將要寫入的文本以UTF_8格式進行編碼
        Charset utfEncoding = Charset.forName("UTF-8");
        //由于已經(jīng)確定文本的格式編碼為UTF_8嗅战,所以直接將payload的第1個字節(jié)的第7位設(shè)為0
        byte[] textBytes = text.getBytes(utfEncoding);
        int utfBit = 0;
        //定義和初始化狀態(tài)字節(jié)
        char status = (char) (utfBit + langBytes.length);
        //創(chuàng)建存儲payload的字節(jié)數(shù)組
        byte[] data = new byte[1 + langBytes.length + textBytes.length];
        //設(shè)置狀態(tài)字節(jié)
        data[0] = (byte) status;
        //設(shè)置語言編碼
        System.arraycopy(langBytes, 0, data, 1, langBytes.length);
        //設(shè)置實際要寫入的文本
        System.arraycopy(textBytes, 0, data, 1 + langBytes.length,
                textBytes.length);
        NdefRecord record = new NdefRecord(NdefRecord.TNF_WELL_KNOWN,
                NdefRecord.RTD_TEXT, new byte[0], data);
        NdefMessage ndefMessage = new NdefMessage(new NdefRecord[]{record});
        //轉(zhuǎn)換成字節(jié)獲得大小
        int size = ndefMessage.toByteArray().length;
        //2.判斷NFC標(biāo)簽的數(shù)據(jù)類型(通過Ndef.get方法)
        Ndef ndef = Ndef.get(tag);
        //判斷是否為NDEF標(biāo)簽
        if (ndef != null) {
            ndef.connect();
            //判斷是否支持可寫
            if (!ndef.isWritable()) {
                return;
            }
            //判斷標(biāo)簽的容量是否夠用
            if (ndef.getMaxSize() < size) {
                return;
            }
            //3.寫入數(shù)據(jù)
            ndef.writeNdefMessage(ndefMessage);
            Logger.e(TAG, "寫入NDEF成功");
        } else {
            //當(dāng)我們買回來的NFC標(biāo)簽是沒有格式化的妄田,或者沒有分區(qū)的執(zhí)行此步
            //Ndef格式類
            NdefFormatable format = NdefFormatable.get(tag);
            //判斷是否獲得了NdefFormatable對象,有一些標(biāo)簽是只讀的或者不允許格式化的
            if (format != null) {
                //連接
                format.connect();
                //格式化并將信息寫入標(biāo)簽
                format.format(ndefMessage);
                Logger.e(TAG, "格式化并寫入NDEF成功");
            } else {
                Logger.e(TAG, "格式化并寫入NDEF失敗");
            }
        }
    }

6驮捍、讀取MifareClassic格式

private String readMifareClassic(Intent intent) {
        String info = "";
        List<byte[]> list = new ArrayList<>();
        boolean auth = false;
        //讀取TAG
        MifareClassic mfc = MifareClassic.get(getNFCTag(intent));
        try {
            mfc.connect();
            if (mfc.isConnected()) {
                int sectorCount = mfc.getSectorCount();//獲取TAG中包含的扇區(qū)數(shù)
                for (int j = 0; j < sectorCount; j++) {
                    auth = mfc.authenticateSectorWithKeyA(j,
                            MifareClassic.KEY_NFC_FORUM);
                    int bCount;
                    int bIndex;
                    if (auth) {
                        // 讀取扇區(qū)中的塊
                        bCount = mfc.getBlockCountInSector(j);
                        bIndex = mfc.sectorToBlock(j);
                        for (int i = 0; i < bCount; i++) {
                            byte[] data = mfc.readBlock(bIndex);
                            if (i < bCount - 1) {
                                if (!bytesToHexString(data).equals("0x00000000000000000000000000000000")) {
                                    list.add(data);
                                }
                            }
                            bIndex++;
                        }
                    }
                }
                if (list.size() > 0) {
                    byte[] aa = new byte[list.size() * list.get(0).length];
                    for (int i = 0; i < list.size(); i++) {
                        byte[] bytes = list.get(i);
                        System.arraycopy(bytes, 0, aa, bytes.length * i, bytes.length);
                    }
                    info = new String(trim(aa), Charset.forName("utf-8"));
                }
            }
        } catch (Exception e) {
            Logger.e(TAG, e);
        } finally {
            try {
                mfc.close();
            } catch (IOException e) {
                Logger.e(TAG, e);
            }
        }
        return info;
    }

7疟呐、寫MifareClassic格式

public void writeMifareClassic(String data, Intent intent) throws IOException {
        Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
        MifareClassic mfc = MifareClassic.get(tag);
        try {
            mfc.connect();
            int sectorCount = mfc.getSectorCount();//獲取TAG中包含的扇區(qū)數(shù)
            for (int j = 0; j < sectorCount; j++) {
                if (mfc.authenticateSectorWithKeyA(j,
                        MifareClassic.KEY_NFC_FORUM)) {
                    // 讀取扇區(qū)中的塊
                    int bCount = mfc.getBlockCountInSector(j);
                    int bIndex = mfc.sectorToBlock(j);
                    for (int i = 0; i < bCount - 1; i++) {
                        if (!bytesToHexString(mfc.readBlock(bIndex + i)).equals("0x00000000000000000000000000000000")) {
                            mfc.writeBlock(bIndex + i, new byte[16]);
                        }
                    }
                }
            }
            byte[] bytes = new byte[16];
            System.arraycopy(data.getBytes(), 0, bytes, 0, data.getBytes().length);
            if (mfc.authenticateSectorWithKeyA(1,
                    MifareClassic.KEY_NFC_FORUM)) {
                mfc.writeBlock(4, bytes);
            }
            Logger.e(TAG, "寫入MifareClassic成功");
        } finally {
            try {
                mfc.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

8、清空數(shù)據(jù)

public boolean clear(Intent intent) throws IOException {
        boolean result = false;
        Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
        MifareClassic mfc = MifareClassic.get(tag);
        try {
            mfc.connect();
            int sectorCount = mfc.getSectorCount();//獲取TAG中包含的扇區(qū)數(shù)
            for (int j = 0; j < sectorCount; j++) {
                if (mfc.authenticateSectorWithKeyA(j,
                        MifareClassic.KEY_NFC_FORUM)) {
                    // 讀取扇區(qū)中的塊
                    int bCount = mfc.getBlockCountInSector(j);
                    int bIndex = mfc.sectorToBlock(j);
                    for (int i = 0; i < bCount - 1; i++) {
                        if (!bytesToHexString(mfc.readBlock(bIndex + i)).equals("0x00000000000000000000000000000000")) {
                            mfc.writeBlock(bIndex + i, new byte[16]);
                        }
                    }
                }
            }
            result = true;
            Logger.e(TAG, "清空成功");
        } finally {
            try {
                mfc.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return result;
    }

四东且、NFC調(diào)用

1启具、重寫onNewIntent()方法

 @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        String id = nfcUtils.readNFCId(nfcUtils.getNFCTag(intent));
        Logger.e(TAG, "nfcID:" + id);
        String message = nfcUtils.readMessage(intent);
        Logger.e(TAG, "nfcMessage:" + message); 
    }

2、啟動和關(guān)閉

 @Override
    protected void onResume() {
        super.onResume();
        Logger.e(TAG, "onResume");
        nfcUtils.enableForegroundDispatch();
    }

    @Override
    protected void onPause() {
        super.onPause();
        Logger.e(TAG, "onPause");
        nfcUtils.disableForegroundDispatch();
    }

代碼太多了珊泳,懶的粘了

第一次寫文章歡迎大家指教

附上GitHub地址:

https://github.com/yaogoodgoodde/SimpleNfc.git

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末鲁冯,一起剝皮案震驚了整個濱河市拷沸,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌薯演,老刑警劉巖撞芍,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異跨扮,居然都是意外死亡序无,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進店門衡创,熙熙樓的掌柜王于貴愁眉苦臉地迎上來帝嗡,“玉大人,你說我怎么就攤上這事钧汹≌商剑” “怎么了?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵拔莱,是天一觀的道長碗降。 經(jīng)常有香客問我,道長塘秦,這世上最難降的妖魔是什么讼渊? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮尊剔,結(jié)果婚禮上爪幻,老公的妹妹穿的比我還像新娘。我一直安慰自己须误,他們只是感情好挨稿,可當(dāng)我...
    茶點故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著京痢,像睡著了一般奶甘。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上祭椰,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天臭家,我揣著相機與錄音,去河邊找鬼方淤。 笑死钉赁,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的携茂。 我是一名探鬼主播你踩,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了姓蜂?” 一聲冷哼從身側(cè)響起按厘,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎钱慢,沒想到半個月后逮京,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡束莫,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年懒棉,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片览绿。...
    茶點故事閱讀 38,018評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡策严,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出饿敲,到底是詐尸還是另有隱情妻导,我是刑警寧澤,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布怀各,位于F島的核電站倔韭,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏瓢对。R本人自食惡果不足惜寿酌,卻給世界環(huán)境...
    茶點故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望硕蛹。 院中可真熱鬧醇疼,春花似錦、人聲如沸法焰。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽埃仪。三九已至辰如,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間贵试,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工凯正, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留毙玻,地道東北人。 一個月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓廊散,卻偏偏與公主長得像桑滩,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子允睹,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,762評論 2 345

推薦閱讀更多精彩內(nèi)容