Presentation is loading. Please wait.

Presentation is loading. Please wait.

Android + NFC 建國科技大學 資管系 饒瑞佶 2017/3 v1.

Similar presentations


Presentation on theme: "Android + NFC 建國科技大學 資管系 饒瑞佶 2017/3 v1."— Presentation transcript:

1 Android + NFC 建國科技大學 資管系 饒瑞佶 2017/3 v1

2 Android 2.3.3 (API Level 10)才有支援完整的NFC功能 只要NFC相容都讀的到(NFC或Mifare)
讀取Tag UUID Android (API Level 10)才有支援完整的NFC功能 只要NFC相容都讀的到(NFC或Mifare)

3 建立新專案 修改AndroidManifest.xml
加入<intent-filter>,如果有NFC Tag進入感測範圍,本App也會變 成可處理的App選項之一

4 <intent-filter>
<action android:name="android.nfc.action.TAG_DISCOVERED" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter>

5 繼續修改AndroidManifest.xml 加入<uses-permission>與<uses-feature>
<uses-permission android:name="android.permission.NFC" /> <uses-feature android:name="android.hardware.nfc" android:required="true" />

6 設計layout 使用預設的activity_main.xml,加入1個TextView,用來顯示UUID 資訊
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android=" xmlns:tools=" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:padding="16dp" tools:context=".MainActivity"> <TextView android:layout_height="wrap_content" /> </LinearLayout>

7 修改MainActivity.java onCreate中加入 檢查裝置是否支援 NFC NfcAdapter物件,用 以對應裝置上NFC

8 private NfcAdapter nfcAdapter;
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); nfcAdapter = NfcAdapter.getDefaultAdapter(this); // 對應裝置上NFC if (nfcAdapter == null) { //透過是否對應到裝置NFC,檢查裝置是否支援NFC Toast.makeText(this, "本裝置不支援NFC!", Toast.LENGTH_LONG).show(); finish(); } else if (!nfcAdapter.isEnabled()) { "NFC功能尚未開啟", }

9 修改MainActivity.java 加入TextView對應

10 修改MainActivity.java 加入onResume事件
偵測是否有發生AndroidManifest.xml中設定的 Intent=ACTION_TAG_DISCOVERED? 如果有,可以透過 intent.getParcelableExtra(NfcAdapter.EXTRA_TAG)取得UUID 等相關資訊

11 onResume事件 首先取得Intent發生的動作 @Override protected void onResume() {
super.onResume(); // 取得Intent動作 Intent intent = getIntent(); String action = intent.getAction(); }

12 onResume事件 處理 ACTION_TAG_DIS COVERED

13 // 取得Intent動作 Intent intent = getIntent(); String action = intent.getAction(); // 如果發生ACTION_TAG_DISCOVERED if (NfcAdapter.ACTION_TAG_DISCOVERED.equals(action)) { Toast.makeText(this, "發生 - ACTION_TAG_DISCOVERED", Toast.LENGTH_SHORT).show(); // 取得tag資訊 Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG); if(tag == null){ nfcInfo.setText("沒有偵測到tag"); }else{ } // 非ACTION_TAG_DISCOVERED "發生動作 : " + action,

14 onResume事件 顯示TAG資訊

15 if (tag == null) { nfcInfo.setText("沒有偵測到tag"); } else { // 顯示TAG資料 String tagInfo = tag.toString() + "\n"; tagInfo += "\nTag UUID: \n"; byte[] tagId = tag.getId(); tagInfo += "長度 = " + tagId.length + "\n"; for (int i = 0; i < tagId.length; i++) { tagInfo += Integer.toHexString(tagId[i] & 0xFF) + " "; } tagInfo += "\n"; // 顯示TAG其他技術規範資料 String[] techList = tag.getTechList(); tagInfo += "\n技術規範資料\n"; tagInfo += "長度 = " + techList.length + "\n"; for (int i = 0; i < techList.length; i++) { tagInfo += techList[i] + "\n "; nfcInfo.setText(tagInfo);

16 執行 確認NFC有啟動

17 執行

18 Read & Write NDEF

19 修改AndroidManifest.xml 加入NDEF偵測之Intent 原Tag偵測

20 <intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED" /> <category android:name="android.intent.category.DEFAULT" /> <data android:mimeType="text/plain" /> </intent-filter>

21 新增layout ndef.xml <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android=" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <TextView android:layout_height="wrap_content" android:text="請靠近標籤讀取資料"/> <Button android:layout_width="wrap_content" android:text="寫入資料到標籤"></Button> <EditText android:layout_width="fill_parent" android:layout_height="388dp" android:gravity="top" android:text=""></EditText> </LinearLayout> 新增layout ndef.xml

22 新增NDEF.java 加入nfcAdapter與 必要的宣告 gResumed與gWriteMode決定寫入或讀取模式

23 public class NDEF extends AppCompatActivity {
private NfcAdapter nfcAdapter; // 判斷目前是否在Resume狀態 private boolean gResumed = false; // 判斷目前是否在可寫入的模式 private boolean gWriteMode = false; // 對應layout輸入框 EditText gNote; // 處理Intent PendingIntent gNfcPendingIntent; IntentFilter[] gNdefExchangeFilters; IntentFilter[] gWriteTagFilters; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.ndef); nfcAdapter = NfcAdapter.getDefaultAdapter(this); // 對應裝置上NFC if (nfcAdapter == null) { //透過是否對應到裝置NFC,檢查裝置是否支援NFC Toast.makeText(this, "本裝置不支援NFC!", Toast.LENGTH_LONG).show(); finish(); } else if (!nfcAdapter.isEnabled()) { "NFC功能尚未開啟", }

24 註冊物件與事件 當App在背景,偵測到Tag時會自動跳出到前景

25 // 取得EditText與Button,並註冊對應的事件
findViewById(R.id.write_tag).setOnClickListener(this.gTagWriter); gNote = (EditText) findViewById(R.id.note); gNote.addTextChangedListener(gTextWatcher); // 註冊本Activity負責處理所有接收到的NFC Intents gNfcPendingIntent = PendingIntent.getActivity(this, 0, // 指定本Activity為應用程式中的最上層Activity new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0); // 建立要處理的Intent Filter負責處理來自Tag或p2p交換的資料 IntentFilter ndefDetected = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED); try { ndefDetected.addDataType("text/plain"); } catch (IntentFilter.MalformedMimeTypeException e) { } gNdefExchangeFilters = new IntentFilter[]{ndefDetected};

26 加入按鈕事件

27 // 按鈕事件 private View.OnClickListener gTagWriter = new View.OnClickListener() { @Override public void onClick(View v) { // 先停止接收任何的Intent,準備寫入資料至tag disableNdefExchangeMode(); // 啟動寫入Tag模式,監測是否有Tag進入 enableTagWriteMode(); // 顯示對話框,告知將Tag或手機靠近本機的NFC感應區 new AlertDialog.Builder(NDEF.this) .setTitle("請將標籤靠近,以便寫入資料") .setOnCancelListener(new DialogInterface.OnCancelListener() { public void onCancel(DialogInterface dialog) { // 在取消模式下,先關閉監偵有Tag準備寫入的模式,再啟動等待資料交換的模式 // 停止寫入Tag模式,代表已有Tag進入 disableTagWriteMode(); // 啟動資料交換 enableNdefExchangeMode(); } }).create().show(); };

28 加入輸入框change事件

29 // 輸入框輸入文字後change事件 private TextWatcher gTextWatcher = new TextWatcher() { @Override public void onTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) { } public void beforeTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) { public void afterTextChanged(Editable arg0) { // 如果是在Resume的狀態下,當編輯完後,啟動前景發佈訊息的功能 if (gResumed) { nfcAdapter.enableForegroundNdefPush(NDEF.this, getNoteAsNdef()); };

30 啟動與取消NDEF資料存取

31 // 啟動NDEF交換資料模式 private void enableNdefExchangeMode() { // 讓NfcAdatper啟動前景Push資料至Tag或應用程式 nfcAdapter.enableForegroundNdefPush(NDEF.this, getNoteAsNdef()); // 讓NfcAdapter啟動能夠在前景模式下進行intent filter的dispatch nfcAdapter.enableForegroundDispatch(this, gNfcPendingIntent, gNdefExchangeFilters, null); } // 取消NDEF交換資料模式 private void disableNdefExchangeMode() { nfcAdapter.disableForegroundNdefPush(this); nfcAdapter.disableForegroundDispatch(this);

32 啟動與取消Tag寫入模式

33 // 啟動Tag寫入模式,註冊對應的Intent Filter來前景模式監聽是否有Tag進入的訊息
private void enableTagWriteMode() { gWriteMode = true; IntentFilter tagDetected = new IntentFilter(NfcAdapter.ACTION_TAG_DISCOVERED); gWriteTagFilters = new IntentFilter[]{tagDetected}; nfcAdapter.enableForegroundDispatch(this, gNfcPendingIntent, gWriteTagFilters, null); } // 停止Tag寫入模式,取消前景模式的監測 private void disableTagWriteMode() { gWriteMode = false; nfcAdapter.disableForegroundDispatch(this);

34 將輸入的內容轉成NdefMessage // 將輸入的內容轉成NdefMessage
private NdefMessage getNoteAsNdef() { byte[] textBytes = gNote.getText().toString().getBytes(); NdefRecord textRecord = new NdefRecord(NdefRecord.TNF_MIME_MEDIA, "text/plain".getBytes(), new byte[]{}, textBytes); return new NdefMessage(new NdefRecord[]{textRecord}); }

35 onResume & onPause @Override protected void onResume() {
super.onResume(); gResumed = true; // 處理由Android系統送出的intent filter內容 if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(getIntent().getAction())) { // 取得NdefMessage NdefMessage[] messages = getNdefMessages(getIntent()); // 取得實際的內容 byte[] payload = messages[0].getRecords()[0].getPayload(); //設定寫入的內容 setNoteBody(new String(payload)); // 往下送出該intent給其他的處理對象 setIntent(new Intent()); } // 啟動前景模式支持Nfc intent處理 enableNdefExchangeMode(); protected void onPause() { super.onPause(); gResumed = false; // 由於NfcAdapter啟動前景模式將相對花費更多的電力,要記得關閉。 nfcAdapter.disableForegroundNdefPush(this);

36 取得Intent中放入的NdefMessage
NdefMessage[] getNdefMessages(Intent intent) { // 解析intent內容 NdefMessage[] msgs = null; String action = intent.getAction(); if (NfcAdapter.ACTION_TAG_DISCOVERED.equals(action) || NfcAdapter.ACTION_NDEF_DISCOVERED.equals(action)) { Parcelable[] rawMsgs = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES); if (rawMsgs != null) { msgs = new NdefMessage[rawMsgs.length]; for (int i = 0; i < rawMsgs.length; i++) { msgs[i] = (NdefMessage) rawMsgs[i]; } } else { // 未知的tag type byte[] empty = new byte[]{}; NdefRecord record = new NdefRecord(NdefRecord.TNF_UNKNOWN, empty, empty, empty); NdefMessage msg = new NdefMessage(new NdefRecord[]{record}); msgs = new NdefMessage[]{msg}; finish(); return msgs;

37 從輸入框取出要寫入Tag的內容 // 從輸入框取出要寫入Tag的內容
private void setNoteBody(String body) { Editable text = gNote.getText(); text.clear(); text.append(body); }

38 設定真正要處理動作的Intent // 真正要處理動作的Intent @Override
protected void onNewIntent(Intent intent) { // NDEF exchange mode (讀取資料) if (!gWriteMode && NfcAdapter.ACTION_NDEF_DISCOVERED.equals(intent.getAction())) { NdefMessage[] msgs = getNdefMessages(intent); promptForContent(msgs[0]); // 讀取資料 } // 監測到有指定ACTION進入,代表要寫入資料至Tag中。 // Tag writing mode if (gWriteMode && NfcAdapter.ACTION_TAG_DISCOVERED.equals(intent.getAction())) { Tag detectedTag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG); writeTag(getNoteAsNdef(), detectedTag); // 寫入資料

39 讀取Tag內容 // 提示讀取出內容會覆蓋textbox目前內容
private void promptForContent(final NdefMessage msg) { new AlertDialog.Builder(this).setTitle("是否取代現在TextBox的內容?").setPositiveButton("是", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface arg0, int arg1) { String body = new String(msg.getRecords()[0].getPayload()); setNoteBody(body); } }).setNegativeButton("否", new DialogInterface.OnClickListener() { }).show();

40 寫入Tag // 寫入Tag boolean writeTag(NdefMessage message, Tag tag) {
int size = message.toByteArray().length; try { Ndef ndef = Ndef.get(tag); if (ndef != null) { ndef.connect(); if (!ndef.isWritable()) { toast("這是唯讀標籤"); return false; } if (ndef.getMaxSize() < size) { toast("標籤容量為 " + ndef.getMaxSize() + " bytes, message大小是 " + size + " bytes."); ndef.writeNdefMessage(message); toast("資料成功寫入已格式化標籤"); return true; } else {

41 NdefFormatable format = NdefFormatable.get(tag);
if (format != null) { try { format.connect(); format.format(message); toast("成功格式化標籤與寫入資料"); return true; } catch (IOException e) { toast("無法格式化標籤"); return false; } } else { toast("標籤不支援NDEF."); } catch (Exception e) { toast("寫入失敗"); private void toast(String text) { Toast.makeText(this, text, Toast.LENGTH_SHORT).show();

42 執行 中文ok

43 兩個裝置透過NFC交換資料 android-nfc.html

44 其他

45

46

47

48

49

50

51

52

53

54


Download ppt "Android + NFC 建國科技大學 資管系 饒瑞佶 2017/3 v1."

Similar presentations


Ads by Google