Android平臺中,NFC應用的類型和NFC三種運行模式有關,我們先來看一個使用NFCR/W模式讀取NFC Tag的示例。
**1、NFC R/W模式示例**
根據前文對NFC基礎知識的介紹可知,和R/W模式相關的應用場景就是使用者利用NFC手機(充當NFC Reader的角色)來讀取目標NFC Tag中的信息。Android平臺為NFC R/W模式設計了“Tag分發系統”(Tag Dispatch System)的機制,描述了NFC系統模塊如何向應用進程分發與目標NFC Tag相關的Intent(該Intent中包含了Tag中的數據或是一個代表目標NFC Tag的Tag對象)。
**①、NFC Tag分發系統**
Tag分發系統的工作機制如圖8-27所示。
:-: 
圖8-27 Tag分發系統的工作機制
Tag分發系統的工作機制如下。
1. 當本機掃描到一個NFC Tag后,NFC系統模塊將首先嘗試直接讀取該Tag中的數據。
2. 如果這些數據封裝在NDEF消息中并且能映射成Android系統直接支持的數據類型(目前僅支持MIME和URI這兩大類數據類型,詳情見表8-11),則NFC系統模塊將發送一個ACTION_NDEF_DISCOVERED的Intent給那些注冊了對ACTION_NDEF_DISCOVERED通知感興趣的Activity。如果找到目標Activity,則將此Intent(攜帶Tag中的NDEF消息和一個代表該NFC Tag的Tag對象)派發給它。如果NFC系統模塊沒有找到目標Activity,則將嘗試發送一個ACTION_TECH_DISCOVERED的Intent(包含一個代表目標NFC Tag的Tag對象)。
3. 如果NFC Tag中的數據不能轉換成系統直接支持的類型,或者NFC Tag中的數據沒有使用NDEF消息格式或者沒有目標Activity對ACTION_NDEF_DISCOVERED通知感興趣,則NFC系統模塊將發送一個ACTION_TECH_DISCOVERED的Intent(包含一個Tag對象)。如果找到對該Intent感興趣的Activity,則此Intent將派發給它。
4. 如果沒有Activity對ACTION_TECH_DISCOVERED感興趣,則NFC系統模塊將最后嘗試發送一個ACTION_TAG_DICOVERED的Intent(包含一個Tag對象)。如果有對ACTION_TAG_DISCOVERED感興趣的Activity,則此Intent將派發給它。
上述的Tag分發系統看起來很復雜,實際上其核心內容可概況成三個步驟。
* **步驟1** 如果目標NFC Tag包含了系統支持的NDEF消息,則NFC系統模塊將直接把這個NDEF消息分發給感興趣的Activity。如果有目標Activity,則直接分發給它,否則轉步驟2。分支轉換的判斷標準是NFC Tag是否包含了系統支持的NDEF消息以及同時是否有目標Activity注冊了ACTION_NDEF_DISCOVERED通知。
* **步驟2** 如果目標NFC Tag包含了系統不支持的NDEF消息或者步驟1中沒有目標Activity,則NFC系統模塊將嘗試分發一個ACTION_TECH_DISCOVERED通知。NFC系統模塊在分發此通知時,將首先分析目標NFC Tag所支持的Tag Technology(它代表目標NFC Tag所使用的技術,詳情見下文分析),然后尋找注冊了支持這些Tag Technology的目標Activity并將Intent分發給它。如果沒有合適的目標Activity,則轉入步驟3。
* **步驟3** NFC系統模塊將分發ACTION_TAG_DISCOVERED通知給注冊了對該通知感興趣的目標Activity。
除了Tag分發系統外,Android系統還有一個“前臺分發系統”(Foreground Dispatch System)。其規則和Tag分發系統類似,二者區別主要集中在選擇目標Activity上。
* Tag分發系統中,Activity在其AndroidManifest.xml中設置Intent分發條件,即設置對應的IntentFilter。在這種分發系統中,不考慮目標Activity是否在前臺還是后臺。只要找到目標Activity,NFC系統就會啟動它。
* 前臺分發系統中,當前活躍(即所謂的前臺)的Activity在其啟動過程中設置Intent分發條件。如果NFC Tag滿足前臺Activity設置的分發條件,NFC系統模塊首先會把Intent分發給前臺這個Activity。當該Activity退到后臺時,它需要取消前臺分發功能,即它不再是目標Activity。
簡而言之,前臺分發系統只檢查當前顯示的Activity是否滿足分發條件,而Tag分發系統則會搜索系統內所有滿足條件的Activity。
**②、Tag分發通知**
下面我們分別來看看這三個不同作用的Tag分發通知。
* **1)ACTION_NDEF_DISCOVERED**:由上文可知,NFC系統模塊首先嘗試將NFC Tag中的數據映射成系統直接支持的數據格式。表8-11列舉了Android系統直接支持的NFC Forum數據格式。
:-: 
由表8-11可知,如果NFC Tag中數據格式能映射成功,則NFC系統模塊將發送一個ACTION_NDEF_DISCOVERED Intent給目前Activity,而該Intent將包含此NFC Tag中的NDEF消息。
除了NFC Forum定義的數據類型外,Android還新增了一個名為AAR(Android Application Record)的數據類型,它其實是在一個NDEF的消息中封裝了某個應用的package名。對AAR來說,分發系統的工作流程如下。
* 分發系統首先嘗試使用IntentFilter來尋找目標Activity。如果和IntentFilter匹配的Activity同時和AAR匹配(即二者的package名一樣),就啟動該Activity。
* 如果Activity跟AAR不匹配,或者是有多個Activity能夠處理該Intent,或者是沒有能夠處理該Intent的Activity,NFC系統模塊將啟動由AAR指定的應用程序。
* 如果系統中沒有安裝該AAR對應的應用程序,NFC系統模塊將從Google Play下載該應用程序。
AAR的好處是能讓某個公司部署的NFC標簽只能由該公司開發的客戶端(通過在NDEF中設置AAR)來處理。后文代碼分析時候讀者還將看到上述AAR的工作流程。
* **2)ACTION_TECH_DISCOVERED**:如果系統不能映射NFC Tag中的數據,我們該如何處理呢?
>[info] 提示 ACTION_TECH_DISCOVERED觸發的另一個原因是沒有Activity對ACTION_NDEF_DISCOVERED感興趣。
該問題的直觀答案就是應用程序自己去讀取并解析Tag中的數據。不過,由于NFC Tag的類型有四種之多,甚至同一個廠商還生產了基于不同底層協議的NFC Tag,導致Android系統無法提供一種通用的接口來操作所有種類的NFC Tag。為了解決此問題,Android提供了一個名為"android.nfc.tech"的Java包來幫助應用程序操作對應的NFC Tag。表8-12為android.nfc.tech包
中的幾個重要成員類。
:-: 
NFC系統模塊將在ACTION_TECH_DISCOVERED Intent中攜帶一個Tag對象,應用程序可調用該Tag對象的getTechList來獲取該Tag所使用的Technology。注意,一個Tag可能同時支持表8-12中多種Technology。例如圖8-28所示為筆者測試北京市公交卡時所得到的Tag Technology信息。
:-: 
圖8-28 北京市公交卡Tag Technology示例
由圖8-28可知,北京市公交卡同時支持MifareClassic、NfcA和NdefFormatable這三種類型的Tag Technology。應用程序接著可根據目標NFC Tag所支持的Tag Technology來創建表8-12中的對象來和NFC Tag交互。
>[info] 特別注意 嚴格來說,表8-12中所列的類不僅僅是用來讀寫對應類型的NFC Tag,它還支持一些控制操作以至于能在NFC Tag上實現一些特定的協議。以北京市公交卡為例,其內部肯定有一個相關的協議使得應用程序可通過這些協議來完成公交卡充值,付費等操作。“小木公交”軟件即可讀取多個城市公交卡的信息,讀者不妨下載試試。
* **3)ACTION_TAG_DISCOVERED**:如果目標NFC Tag不屬于表8-12中的一種,則NFC系統模塊將發送ACTION_TAG_DISCOVERED Intent并攜帶一個Tag對象傳遞給感興趣的Activity。Activity將根據Tag的ID(調用Tag的getId函數)或該Tag使用的技術(調用Tag的getTechList)來創建合適的處理對象。
下面通過一個示例來了解上述三種通知的用法。
**③、示例分析**
本節將通過一個前臺分發示例來看看應用程序如何處理上述三種Intent。
**ForegroundDispatch.java::onCreate**
~~~
public class ForegroundDispatch extends Activity {// ForegroundDispatch是一個Activity
......// 定義一些成員變量
public void onCreate(Bundle savedState) {
super.onCreate(savedState);
// NFC客戶端必須調用下面這個函數以獲得一個NfcAdapter對象,該對象用于和NFC系統模塊交互
mAdapter = NfcAdapter.getDefaultAdapter(this);
// 構造一個PendingIntent供NFC系統模塊派發
mPendingIntent = PendingIntent.getActivity(this, 0,
new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
// 監聽ACTION_NDEF_DISOVERED通知,并且設置MIME類型為“*/*”
// 對任何MIME類型的NDEF消息都感興趣
IntentFilter ndef = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED);
ndef.addDataType("*/*");
// 我們同時還監聽ACTION_TECH_DISSCOVERED和ACTION_TAG_DISCOVERED通知
mFilters = new IntentFilter[] {
ndef,
new IntentFilter(NfcAdapter.ACTION_TECH_DISCOVERED),
new IntentFilter(NfcAdapter.ACTION_TAG_DISCOVERED),
};
// 對ACTION_TECH_DISCOVERED通知來說,還需要注冊對哪些Tag Technology感興趣
mTechLists = new String[][] {
new String[] { NfcF.class.getName() },// 假設本例支持NfcF
new String[]{MifareClassic.class.getName()}
};// 假設本例支持MifareClassic
}
}
~~~
在上述onCreate函數中,同時監聽了三種Tag Intent通知,最終效果如下。
* 如果目標Tag中包含MIME類型的NDEF消息,則Tag分發系統將給我們傳遞一個ACTION_NDEF_DISCOVERED Intent。
* 如果目標Tag使用的Tag Technolog為NfcF或MifareClass,則Tag分發系統將給我們傳遞一個ACTION_TECH_DISCOVERED Intent。
* 最后,Tag分發系統將不滿足上述條件的其他所有Tag通過ACTION_TAG_DISCOVEREDIntent傳遞給我們。
接下來,由于本例使用了NFC的前臺分發系統,故需要將onCreate中設置的配置信息傳遞給NFC系統模塊,相關代碼如下所示。
**ForegroundDispatch.java::onResume**
~~~
public void onResume() {
super.onResume();
// 調用NfcAdapter的enableForegroundDispatch函數啟動前臺分發系統
// 同時需要將分發條件傳遞給NFC系統模塊
mAdapter.enableForegroundDispatch(this, mPendingIntent, mFilters,mTechLists);
}
~~~
當NFC系統模塊掃描到一個NFC Tag時,前臺分發系統通過將觸發ForegroundDispatch這個Activity的onNewIntent函數,該函數的代碼如下所示。
**ForegroundDispatch.java::onNewIntent**
~~~
public void onNewIntent(Intent intent) {
String action = intent.getAction();
// 處理ACTION_NDEF_DISCOVERED消息
if(action.equals(NfcAdapter.ACTION_NDEF_DISCOVERED)){
NdefMessage[] ndefMsgs = null;
// 獲取該Intent中的NdefMessage數組。絕大部分情況下該數組的長度為1
NdefMessage[] ndefMsgs = (NdefMessage[])intent.
getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
} // 處理ACTION_TECH_DISCOVERED通知
else if (action.equals(NfcAdapter.ACTION_TECH_DISCOVERED)){
// 獲取該Intent中的Tag對象
Tag detectedTag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
String[] techList = detectedTag. getTechList();// 獲取該Tag使用的Technology
for(String tech: techList){
if(tech.equals(NfcF.class.getName())){// 假設該Tag支持NfcF
// 創建NfcF對象和該Tag交互
NfcF nfcF = NfcF.get(detectedTag);
nfcF.connect();// 向目標Tag發起I/O操作前需要先連接上它
......// 調用NfcF類的其他函數,例如transceive向NFC Tag發送命令
nfcF.close();// 關閉連接
}......
}
} // 處理ACTION_TAG_DISCOVERED通知
else if(action.equals(NfcAdapter.ACTION_TAG_DISCOVERED)){
Tag tag = (Tag)intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
String[] arry = tag.getTechList();
......// 根據Tag使用的Technology來構造相應的處理對象
}
}
~~~
當ForegroundActivity退出時,需要在onPause函數中停止使用前臺分發系統,相關代碼如下所示。
~~~
public void onPause() {
super.onPause();
mAdapter.disableForegroundDispatch(this);// 停止前臺分發系統
}
~~~
通過上述介紹可知,在R/W模式中:
* 如果應用程序僅用于讀取NFC Tag中所包含的數據,則應盡量通過注冊ACTION_NDEF_DISCOVERED通知來獲取自己感興趣的數據。
* 如果應用程序希望能和NFC Tag交互以實現自己的一套協議或者希望能直接讀寫NFCTag,則可通過注冊ACTION_TECH_DISCOVERED通知來獲得代表NFC Tag的Tag對象。應用程序接著要根據該Tag使用的Technology來構造對應的TagTechnology對象來操作此NFC Tag。
* 如果應用程序處理的NFC Tag不滿足表8-12中的一種,則需要監聽ACTION_TAG_DISCOVERED通知,然后再構造自己的TagTechnology對象來操作此NFC Tag。
>[info] 提示 關于Android中NFC的分發系統,請讀者閱讀Android SDK關于NFC的介紹,相關資料位于http://developer.android.com/guide/topics/connectivity/nfc/nfc.html。
**2、NFC P2P模式示例**
Android平臺中的NFC P2P模式使用了前文介紹的SNEP協議。在SNEP協議基礎上,Android設計了"Android Beam"技術架構,該架構使得NFC客戶端程序能非常容易得在兩個NFC設備間傳遞NDEF消息。
>[info] 提示 除了SNEP外,Android還定義了一個與之類似的NPP(Ndef Push Protocol),該協議對應的服務端SAP為0x10,服務名為"com.android.npp"。Android Beam中,系統首先使用SNEP進行傳輸。如果一些老舊的設備不支持SNEP,則系統將使用NPP。
和R/W模式一樣,Android Beam的使用也需要綁定到一個Activity中,下面我們直接通過一例子來看看如何使用Android Beam。
**①、發送端處理**
**Beam.java::onCreate**
~~~
public class Beam extends Activity implements CreateNdefMessageCallback,// 用于從源Activity中得到需要傳遞的NDEF消息
OnNdefPushCompleteCallback // 用于通知NDEF消息傳送完畢
{
NfcAdapter mNfcAdapter;
TextView mInfoText;
private static final int MESSAGE_SENT = 1;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mInfoText = (TextView) findViewById(R.id.textView);
// 得到一個NfcAdapter對象,用于和NFC系統模塊交互
mNfcAdapter = NfcAdapter.getDefaultAdapter(this);
/*
下面這兩個函數調用非常重要。
setNdefPushMessageCallback:設置一個回調對象。如果該回調對象不為空,則NFC系統模塊將
為Beam這個Activity啟用Android Beam。該回調對象的作用是:當NFC系統模塊通過SNEP協議
發現另外一個NFC設備時,系統會彈出如圖8-29所示的“數據發送通知框”。如果用戶選擇本機發送數據,
則NFC系統模塊將通過這個回調對象獲取需要發送的數據。
setOnNdefPushCompleteCallback:設置一個數據發送完畢通知回調對象,當NFC系統模塊發送完
本Activity所設置的NDEF消息時,該回調對象對應的函數將被調用。
*/
mNfcAdapter.setNdefPushMessageCallback(this, this);
mNfcAdapter.setOnNdefPushCompleteCallback(this, this);
}
}
~~~
如圖8-29所示,左圖為數據發送通知框。在Android平臺中,兩個互相靠近的NFC設備都會彈出類似左圖這樣的數據發送通知框。至于最終是誰來發送數據則需要用戶點擊觸摸屏來決定。當對端設備收到示例Beam所發送的NDEF消息后,對端設備的NFC系統模塊將解析該NDEF消息然后通過Tag分發系統或前臺分發系統找到目標Activity。圖8-29右圖即為對端設備收到本例中Beam發送的數據后的處理結果。
:-: 
圖8-29 Beam示例截圖
下面來看createNdefMessage函數,它實現了CreateNdefMessageCallback接口類。當用戶在圖8-29左圖中點擊觸摸屏后,NFC系統模塊將通過該函數獲取應用程序需要發送的NDEF消息,其代碼如下所示。
**Beam.java::createNdefMessage**
~~~
public NdefMessage createNdefMessage(NfcEvent event) {
Time time = new Time();
time.setToNow();
// 設置一些信息
String text = ("Beam me up!\n\n" +"Beam Time: " + time.format("%H:%M:%S"));
// 構造一個MIME Type的NDEF消息
NdefMessage msg = new NdefMessage(NdefRecord.createMime(
"application/com.example.android.beam", text.getBytes()));
return msg;
}
~~~
當本機NFC系統模塊成功發送了NDEF消息后,onNdefPushComplete將被調用以通知數據發送的情況。在Beam示例中,該函數的代碼如下所示。
**Beam.java::onNdefPushComplete**
~~~
public void onNdefPushComplete(NfcEvent arg0) {
// 發送一個MESSAGE_SENT消息。注意,onNdefPushComplete運行在Binder線程
mHandler.obtainMessage(MESSAGE_SENT).sendToTarget();
}
~~~
**②、接收端處理**
當對端NFC設備接收到此NDEF消息時,將通過Tag分發系統來處理它。Beam示例在其AndroidManifest.xml設置了如圖8-30所示的IntentFilter。
:-: 
圖8-30 Beam設置的IntentFilter
根據前文對Tag分發系統的介紹,對端設備的Beam將被啟動。啟動過程中幾個重要函數的代碼如下所示。
**Beam.java::onNewIntent/onResume/processIntent**
~~~
public void onNewIntent(Intent intent) {
setIntent(intent);// Beam使用了SINGLE_TOP啟動模式。setIntent用于保存Intent
} // Beam啟動時,onResume將被調用
public void onResume() {
super.onResume();
if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(getIntent().getAction())) {
processIntent(getIntent());// getIntent獲取setIntent設置的那個Intent對象
}
}
// 處理ACTION_NDEF_DISCOVERED通知
void processIntent(Intent intent) {
// 取出對端Beam發送的NDEF消息
Parcelable[] rawMsgs =
intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
NdefMessage msg = (NdefMessage) rawMsgs[0];
// 設置Text控件,最終結果如圖8-29右圖所示
mInfoText.setText(new String(msg.getRecords()[0].getPayload()));
}
~~~
至此,通過一個示例展示了NFC客戶端程序如何使用Android Beam技術。Android Beam的本質是利用NFC P2P模式的SNEP協議在兩個NFC設備間傳遞NDEF消息。除了NfcAdapter的setOnNdefPushCompleteCallback函數外,NfcAdapter還有其他方式能發送NDEF消息。關于這部分內容,請讀者務必閱讀SDK中的介紹
(http://developer.android.com/guide/topics/connectivity/nfc/nfc.html#p2p)。
另外,Android Beam除了能發送NDEF消息外,它還支持發送URI Scheme為"file"或"content"類型的數據,也就是文件或數據庫中的內容。這些數據的量可能比較大,所以Android Beam將使用Handover并選擇藍牙來傳輸它們。
**3、NFC CE模式示例**
在Android平臺中,NFC CE的使用比較特殊,主要體現在兩點。
* Android SDK沒有直接提供Card Emulation相關的API,但Android系統內部提供了一個名為"com.android.nfc_extras.jar"的Java動態庫。在這個動態庫中,Android封裝了和CE相關的API。應用程序需要主動加載這個nfc_extras庫才能使用CE模式。
* 由于CE通常用于支付等方面的工作,所以Android系統在nfc_extras動態庫的使用上有著非常嚴格的權限管理。
下面介紹相關知識。
**①、nfc_extras和nfcee_access.xml**
根據上文所述,應用程序如何才能使用CE模式呢?我們先來看看如何在應用程序中使用nfc_extras動態庫。圖8-31所示的AndroidManifest.xml指明了必要的做法。
:-: 
圖8-31 AndroidManifest.xml設置
使用NFC CE的應用必須通過<uses-permission>標簽申明"android.permission.NFC"權限。同時還需通過<uses-library>申明使用動態庫"com.android.nfc_extras"。這樣,當應用程序運行時,系統會為它加載com.android.nfc_extras.jar包。該包對應的文件位于/system/framework目錄下。
接著,客戶端在需要使用nfc_extras API的Java類文件中通過import語句導入相關的類,如圖8-32所示。
:-: 
圖8-32 nfc_extras動態庫相關類
nfc_extras主要包含三個類,其用法將留待下節的示例代碼中再來介紹。
客戶端導入相關類后,下一步要解決的問題就是編譯。由于Android SDK沒有提供這些類,故需要手動解決編譯問題。目前有兩種方法解決。
一種方法是為應用程序編寫Android.mk,然后添加以下內容。
~~~
LOCAL_JAVA_LIBRARIES:=com.android.nfc_extras
~~~
該方法要求在Android源碼下編譯此應用程序。
另外一種方式是在Eclipse中為應用程序手動添加一個編譯路徑,如圖8-33所示。
:-: 
圖8-33 Eclipse設置編譯路徑
圖8-33中,筆者在測試示例中添加了nfc_extras動態庫(即classes-full-debug.jar,它是Android系統編譯nfc_extras時生成的中間JAR文件包)。
>[info] 注意 無論哪種方法,都需要有Android系統的源碼。
通過上述步驟,應用程序可編譯成功,但它此時依然沒有權限操作NFC CE。這是因為在Android系統中,除了"android.permission.NFC"權限外,NFC系統模塊針對NFC CE這種重要運行模式還需要檢查另外一個權限,即客戶端程序的簽名信息。只有擁有系統指定簽名的應用程序才能使用NFC CE模式。
Android系統所指定的簽名信息都保存在/etc/nfcee_access.xml文件中,圖8-34所示為Galaxy Note 2中該文件的內容。
:-: 
圖8-34 nfcee_access.xml示例
圖8-34中所示nfcee_access.xml包含三個簽名(由signer標簽指定,圖中由黑框標示)。
* 第一個簽名為Google Wallet相關應用擁有。
* 第二個簽名為Samsung Wallet相關應用擁有。
* 第三個簽名為筆者測試時用的簽名信息。
簽名信息檢查的工作流程如下。
1. 客戶端程序開展CE相關操作前,必須先獲得一個NfcAdapterExtras對象。
2. 在獲取該對象時,NFC系統模塊先檢查應用程序是否擁有"android.permission.NFC"權限,接著檢查該應用程序的簽名信息。只有調用程序的簽名信息在nfcee_access.xml有記錄,該應用才能得到一個NfcAdapterExtras對象。
>[info] 提示 顯然,nfcee_access.xml要么由手機廠商在出廠前設置,要么在root的手機上修改。了解上述知識后,通過一個示例來介紹nfc_extras相關的API及使用方法。
**②、示例分析**
本節使用的示例通過修改AndroidBeamDemo而來。
**示例**
~~~
class NfcEEActivity extends Activity{
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
try {// 先從PackageManager那獲取自己的簽名信息
PackageManager pm = getPackageManager();
PackageInfo info = pm.getPackageInfo("com.example.android.beam",
PackageManager.GET_SIGNATURES);
// 將簽名信息打印出來,開發者需要將此簽名信息保存到/etc/nfcee_access.xml中
Log.e("NfcEE", "signature = " + info.signatures[0].toCharsString());
mContext = this;
// 調用NfcAdatperExtras.get函數獲取一個NfcAdapterExtras對象
mAdapterExtras = NfcAdapterExtras.get(NfcAdapter.getDefaultAdapter(
mContext));
/*
獲取與NFC芯片中Execution Environment模塊交互的對象。注意:此處的EE一般情況下就是指
Secure Element。以圖8-21 NXP pn65芯片模塊圖為例,SE可以是其內部的SmartMX模塊,
也可以是外部的UICC。對UICC來說,不是所有手機都支持將UICC連接到NFC芯片。除此之外,
通過NFC操作UICC還需要相關驅動的支持。
mEe的類型為NfcExecutionEnvironment,通過它可以和SE交互。
*/
mEe = mAdapterExtras.getEmbeddedExecutionEnvironment();
}......
// 創建一個新的線程,相關測試工作放在此線程中進行
Thread testThread = new Thread(){
public void run() {
/*
使用CE模式前需要先設置Route,系統目前有ROUTE_ON_WHEN_SCREEN_ON(屏幕打開
時啟用CE)和ROUTE_OFF(關閉CE)這兩種選項。
*/
mAdapterExtras.setCardEmulationRoute(
new CardEmulationRoute(CardEmulationRoute.ROUTE_ON_WHEN_SCREEN_ON, mEe));
// 創建和SE交互的通道。該通道創建后,NFC其他功能將被禁止(如R/W或P2P)
mEe.open();
/*
發送命令給EE去執行。SELECT_CARD_MANAGER_COMMAND存儲了相關的命令信息。
注意:EE命令的格式遵循ISO 7816-4規范。不同應用需要具體芯片的情況使用對應的命令,這部分是
CE模式的難點。
*/
byte[] out = mEe.transceive(SELECT_CARD_MANAGER_COMMAND);
......
mEe.close();// 關閉與SE交互的通道
// 關閉Card Emulation功能
mAdapterExtras.setCardEmulationRoute(
new CardEmulationRoute(CardEmulationRoute.ROUTE_OFF, null));
}
};
testThread.start(); // 啟動工作線程
}
......// 其他代碼
}
~~~
從上述示例代碼來看,nfc_extras的API似乎比較簡單。但對一個實際應用程序而言,其最大難度卻在于處理相關命令上。由于不同NFC芯片以及所使用的SE不同,其定義的命令也不盡相同。關于SE命令的格式,讀者可參考ISO 7816-4規范。
至此,我們對NFC CE進行了一些簡單介紹,并圍繞nfc_extras動態庫的使用進行了相關討論。根據筆者的研究,CE模式的內容遠比R/W及P2P模式復雜。為此,強烈建議讀者繼續閱讀參考資料[23]、[24]和[25]。
- 前言
- 第1章 準備工作
- 1.1 Android系統架構
- 1.2 工具使用
- 1.2.1 Source Insight的使用
- 1.2.2 Eclipse的使用
- 1.2.3 BusyBox的使用
- 1.3 本書資源下載說明
- 第2章 深入理解Netd
- 2.1 概述
- 2.2 Netd工作流程
- 2.2.1 main函數分析
- 2.2.2 NetlinkManager分析
- 2.2.3 CommandListener分析
- 2.2.4 DnsProxyListener分析
- 2.2.5 MDnsSdListener分析
- 2.3 CommandListener中的命令
- 2.3.1 iptables、tc和ip命令
- 2.3.2 CommandListener構造函數和測試工具ndc
- 2.3.3 InterfaceCmd命令
- 2.3.4 IpFwd和FirewallCmd命令
- 2.3.5 ListTtysCmd和PppdCmd命令
- 2.3.6 BandwidthControlCmd和IdletimerControlCmd命令
- 2.3.7 NatCmd命令
- 2.3.8 TetherCmd和SoftapCmd命令
- 2.3.9 ResolverCmd命令
- 2.4 NetworkManagementService介紹
- 2.4.1 create函數詳解
- 2.4.2 systemReady函數詳解
- 2.5 本章總結和參考資料說明
- 2.5.1 本章總結
- 2.5.2 參考資料說明
- 第3章 Wi-Fi基礎知識
- 3.1 概述
- 3.2 無線電頻譜和802.11協議的發展歷程
- 3.2.1 無線電頻譜知識
- 3.2.2 IEEE 802.11發展歷程
- 3.3 802.11無線網絡技術
- 3.3.1 OSI基本參考模型及相關基本概念
- 3.3.2 802.11知識點導讀
- 3.3.3 802.11組件
- 3.3.4 802.11 Service介紹
- 3.3.5 802.11 MAC服務和幀
- 3.3.6 802.11 MAC管理實體
- 3.3.7 無線網絡安全技術知識點
- 3.4 Linux Wi-Fi編程API介紹
- 3.4.1 Linux Wireless Extensions介紹
- 3.4.2 nl80211介紹
- 3.5 本章總結和參考資料說明
- 3.5.1 本章總結
- 3.5.2 參考資料說明
- 第4章 深入理解wpa_supplicant
- 4.1 概述
- 4.2 初識wpa_supplicant
- 4.2.1 wpa_supplicant架構
- 4.2.2 wpa_supplicant編譯配置
- 4.2.3 wpa_supplicant命令和控制API
- 4.2.4 git的使用
- 4.3 wpa_supplicant初始化流程
- 4.3.1 main函數分析
- 4.3.2 wpa_supplicant_init函數分析
- 4.3.3 wpa_supplicant_add_iface函數分析
- 4.3.4 wpa_supplicant_init_iface函數分析
- 4.4 EAP和EAPOL模塊
- 4.4.1 EAP模塊分析
- 4.4.2 EAPOL模塊分析
- 4.5 wpa_supplicant連接無線網絡分析
- 4.5.1 ADD_NETWORK命令處理
- 4.5.2 SET_NETWORK命令處理
- 4.5.3 ENABLE_NETWORK命令處理
- 4.6 本章總結和參考資料說明
- 4.6.1 本章總結
- 4.6.2 參考資料說明
- 第5章 深入理解WifiService
- 5.1 概述
- 5.2 WifiService的創建及初始化
- 5.2.1 HSM和AsyncChannel介紹
- 5.2.2 WifiService構造函數分析
- 5.2.3 WifiStateMachine介紹
- 5.3 加入無線網絡分析
- 5.3.1 Settings操作Wi-Fi分析
- 5.3.2 WifiService操作Wi-Fi分析
- 5.4 WifiWatchdogStateMachine介紹
- 5.5 Captive Portal Check介紹
- 5.6 本章總結和參考資料說明
- 5.6.1 本章總結
- 5.6.2 參考資料說明
- 第6章 深入理解Wi-Fi Simple Configuration
- 6.1 概述
- 6.2 WSC基礎知識
- 6.2.1 WSC應用場景
- 6.2.2 WSC核心組件及接口
- 6.3 Registration Protocol詳解
- 6.3.1 WSC IE和Attribute介紹
- 6.3.2 802.11管理幀WSC IE設置
- 6.3.3 EAP-WSC介紹
- 6.4 WSC代碼分析
- 6.4.1 Settings中的WSC處理
- 6.4.2 WifiStateMachine的處理
- 6.4.3 wpa_supplicant中的WSC處理
- 6.4.4 EAP-WSC處理流程分析
- 6.5 本章總結和參考資料說明
- 6.5.1 本章總結
- 6.5.2 參考資料說明
- 第7章 深入理解Wi-Fi P2P
- 7.1 概述
- 7.2 P2P基礎知識
- 7.2.1 P2P架構
- 7.2.2 P2P Discovery技術
- 7.2.3 P2P工作流程
- 7.3 WifiP2pSettings和WifiP2pService介紹
- 7.3.1 WifiP2pSettings工作流程
- 7.3.2 WifiP2pService工作流程
- 7.4 wpa_supplicant中的P2P
- 7.4.1 P2P模塊初始化
- 7.4.2 P2P Device Discovery流程分析
- 7.4.3 Provision Discovery流程分析
- 7.4.4 GO Negotiation流程分析
- 7.5 本章總結和參考資料說明
- 7.5.1 本章總結
- 7.5.2 參考資料說明
- 第8章 深入理解NFC
- 8.1 概述
- 8.2 NFC基礎知識
- 8.2.1 NFC概述
- 8.2.2 NFC R/W運行模式
- 8.2.3 NFC P2P運行模式
- 8.2.4 NFC CE運行模式
- 8.2.5 NCI原理
- 8.2.6 NFC相關規范
- 8.3 Android中的NFC
- 8.3.1 NFC應用示例
- 8.3.2 NFC系統模塊
- 8.4 NFC HAL層討論
- 8.5 本章總結和參考資料說明
- 8.5.1 本章總結
- 8.5.2 參考資料說明
- 第9章 深入理解GPS
- 9.1 概述
- 9.2 GPS基礎知識
- 9.2.1 衛星導航基本原理
- 9.2.2 GPS系統組成及原理
- 9.2.3 OMA-SUPL協議
- 9.3 Android中的位置管理
- 9.3.1 LocationManager架構
- 9.3.2 LocationManager應用示例
- 9.3.3 LocationManager系統模塊
- 9.4 本章總結和參考資料說明
- 9.4.1 本章總結
- 9.4.2 參考資料說明
- 附錄