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

Slides:



Advertisements
Similar presentations
第13章 繪圖與多媒體 13-1 顯示圖檔-行動相簿 13-2 音樂播放-音樂播放器 13-3 影片播放-視訊播放器
Advertisements

實驗五:多媒體播放器選單介面.
Part 2 開發Android應用程式的流程
位置與地圖應用 此投影片為講解Android如何取得定位經緯度和使用Google Map地圖.
Android + BLE 建國科技大學 資管系 饒瑞佶 2017/3 v1.
Android + Web Service 建國科技大學 資管系 饒瑞佶 2017/3 V1.
ArrayAdapter & Spinner
手持式裝置之隨身照護應用 Android開發環境設定 鐘國家 老師.
手持式裝置之隨身照護應用 Android開發環境設定 鐘國家 老師.
建立Android新專案 建國科技大學 資管系 饒瑞佶 2010/10.
厦门大学数据库实验室 报告人:谢荣东 导师:林子雨 2014年8月30日
實驗四:單位轉換程式.
Chapter 13 Android 實戰演練.
Android + JUnit 單元測試 建國科技大學資管系 饒瑞佶 2012/8/19V4.
實驗十三:顯示目前經緯度位置.
Ch06 再談選單元件 物件導向系統實務.
JAVA vs. SQL Server 建國科技大學 資管系 饒瑞佶 2013/4 V1.
使用Android控制Arduino 史先强
第10章 App微信分享的实现 倚动实验室.
Android資料庫處理 Android智慧型手機程式設計 程式設計與應用班 建國科技大學 資管系 饒瑞佶 2012/4 V1
第一个Android程序 本讲大纲: 1、创建Android应用程序 2、Android项目结构说明 3、运行Android应用程序
第8章 Android内容提供者(ContentProvider)应用
Chapter 6 Advanced UI Design.
Android智慧型手機程式設計實務應用班
Ch5 Android應用程式的主要組成.
Chapter 7 Android應用元件 Android應用元件可以幫助我們獲得系統資源訊息(ActivityManager)、提供系統服務(Service)、搜尋系統服務(SearchManager)、監聽Intent訊息(Broadcast Receiver)以及資料共享(ContentProvider和ContentResolver)。
Android介面設計 Android智慧型手機程式設計 建國科技大學 資管系 饒瑞佶 2012/4 V1 2012/8 V2
Android基本程式設計 建國科技大學 資管系 饒瑞佶.
CH10 對話框與分頁.
Working with Databases (II) 靜宜大學資管系 楊子青
Chapter 6 進階UI設計.
第4章 Android生命周期.
第9章 使用意圖啟動活動與內建應用程式 9-1 意圖的基礎 9-2 使用意圖啟動活動
CH7 佈局、按鈕與文字編輯元件.
Android + Service 建國科技大學 資管系 饒瑞佶.
實驗十四:顯示與控制地圖.
第2讲 移动应用开发基础知识(二) 宋婕
RecyclerView and CardView
建立Android新專案 Android智慧型手機程式設計 程式設計與應用班 建國科技大學 資管系 饒瑞佶 2012/4 V1
NFC教學 哈哈哈哈哈!!.
第6章 建立Android使用介面 6-1 介面元件的基礎 6-2 Android的事件處理 6-3 按鈕元件 6-4 文字元件
Part16 開發NFC程式 單元80 NFC程式設計 單元81 把資料寫入NFC tag 單元82 NFC的進階用法 2.
生活智慧王 樹德科技大學 資訊工程系 指導教授 : 陳毓璋 教授 小組成員: 劉上緯 翁維廷 洪文財.
實驗十一:待辦事項程式 (儲存在手機上).
主编:钟元生 赵圣鲁.
Android Application Component
Chapter 5 Basic UI Design.
讓Emulator可以 使用Android Market
Android視窗介面 建國科技大學 資管系 饒瑞佶 2010/10.
實驗九:延續實驗八, 製作一個完整音樂播放器
Location Based Services - LBS
IIS Internet Information Services
補間動畫 (Tween Animation) 靜宜大學資管系 楊子青
第二章 Java语法基础.
Android視窗介面 建國科技大學 資管系 饒瑞佶 2010/10.
第二章 Java基本语法 讲师:复凡.
進階UI元件:ListView元件以及複選 靜宜大學資管系 楊子青
RecyclerView and CardView
Android Speech To Text(STT)
Activity的生命週期: 播放音樂與影片 靜宜大學資管系 楊子青
用Intent啟動程式中的其他Activity、運用WebView顯示網頁 靜宜大學資管系 楊子青
第2章 Java语言基础.
第9章 BroadcastReceiver的使用
多國語系 建國科技大學 資管系 饒瑞佶.
讀取網路資料及JSON開放資料 靜宜大學資管系 楊子青
加速感測器 靜宜大學資管系 楊子青.
NFC (近場通訊, Near Field Communication) 靜宜大學資管系 楊子青
SQLite資料庫 靜宜大學資管系 楊子青.
Part 8 Broadcast Receiver、Service和App Widget
InputStreamReader Console Scanner
Presentation transcript:

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

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

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

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

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

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

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

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功能尚未開啟", }

修改MainActivity.java 加入TextView對應

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

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

onResume事件 處理 ACTION_TAG_DIS COVERED

// 取得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,

onResume事件 顯示TAG資訊

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);

執行 確認NFC有啟動

執行

Read & Write NDEF

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

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

新增layout ndef.xml <?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"> <TextView android:id="@+id/info" android:layout_height="wrap_content" android:text="請靠近標籤讀取資料"/> <Button android:id="@+id/write_tag" android:layout_width="wrap_content" android:text="寫入資料到標籤"></Button> <EditText android:id="@+id/note" android:layout_width="fill_parent" android:layout_height="388dp" android:gravity="top" android:text=""></EditText> </LinearLayout> 新增layout ndef.xml

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

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功能尚未開啟", }

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

// 取得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};

加入按鈕事件

// 按鈕事件 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(); };

加入輸入框change事件

// 輸入框輸入文字後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()); };

啟動與取消NDEF資料存取

// 啟動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);

啟動與取消Tag寫入模式

// 啟動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);

將輸入的內容轉成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}); }

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);

取得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;

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

設定真正要處理動作的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); // 寫入資料

讀取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();

寫入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 {

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();

執行 中文ok

兩個裝置透過NFC交換資料 http://android-er.blogspot.tw/2014/04/example-of-programming- android-nfc.html

其他 http://android-er.blogspot.tw/search?q=NFC