NFC framework introduce(二)

  

5.2 大數據量的傳送

大數據量的傳送,是指圖片等數據量比較大的資源,需要通過NFC啓動藍牙的匹配,通過藍牙來傳送數據。

5.2.1 讀寫流程圖

5.2.2 發送端發送藍牙請求和發送數據流程
5.2.2.1時序圖


   大數據量的寫操作跟小數據量的類似,我們這裏主要關注差異的部分,我們從P2pLinkManager.doSenpProtocol()開始。前面部分的時序圖,請查看5.1.2.1小數據量寫操作的時序圖.

5.2.2.2 代碼分析

在看P2pLinkManager.doSenpProtocol()之前,我們先看看發送數據的Apk是如何設置數據的吧。

mNfcAdapter =NfcAdapter.getDefaultAdapter(mActivity.getAndroidContext());

mNfcAdapter.setBeamPushUris(newUri[]{manager.getContentUri(path)},Activity);

以上代碼是在Gallery2中設置圖片資源的代碼,將圖片的路徑封裝在Uri數組中,並調用NfcAdapter. setBeamPushUris()進行設置。這個跟小數據量的設置類似,是將數據保存在NfcActivityState. Uris變量中。P2pLinkManager將回調NfcActivityManager.getUris()獲取到該數據。我們看看代碼吧:

void prepareMessageToSend(){

   ……

           if (mCallbackNdef != null) {

               try {

                   mMessageToSend = mCallbackNdef.createMessage();

                   mUrisToSend =mCallbackNdef.getUris();

                   return;

               } catch (RemoteException e) {

               }

           }

       }

   }

P2pLinkManager. prepareMessageToSend()方法相信已經不再陌生,前面也見到過,這裏就是通過Binder回調了NfcActivityManager.getUris()方法,讀取數據,並暫存在mUrisToSend變量中。

好了,經過簡單的介紹,那麼現在我們可以從P2pLinkManager. doSenpProtocol()開始了,代碼如下:

static intdoSnepProtocol(HandoverManager handoverManager,

           NdefMessage msg, Uri[] uris) throws IOException {

       SnepClient snepClient = new SnepClient();//創建新的客戶端

       try {

           snepClient.connect();//socket連接

       } catch (IOException e) {

       }

       try {

           if (uris != null) {//說明有大數據量要發送

               NdefMessage response = null;

               //封裝藍牙標誌的請求信息在NdefMessage

               NdefMessagerequest = handoverManager.createHandoverRequestMessage();

               if (request != null) {

                   SnepMessage snepResponse= snepClient.get(request);//發送藍牙請求,並讀取另外設備迴應數據保存在snepResponse

                   response =snepResponse.getNdefMessage();//SnepMessage數據轉換成NdefMessage

               } // else, handover not supported

               if (response != null) {//有相應,可以發送數據

                   handoverManager.doHandoverUri(uris,response);//通過藍牙發送數據

               } else if(msg != null) {

                   snepClient.put(msg);

               } else {

                   return SNEP_HANDOVER_UNSUPPORTED;

               }

           } ……

   }

在大數據量傳送流程圖中也說到,發送端要發送圖片之前,需要創建標準的藍牙請求信息,然後將信息封裝在Ndefmessage中,發送給接收端,當收到接收端迴應之後才能發送真正的圖片數據。

下面我們來看看標準藍牙請求數據的創建代碼如下:

HandoverManager.createHandoverRequestMessage()

public NdefMessagecreateHandoverRequestMessage() {

       if (mBluetoothAdapter == null) return null;//是否支持藍牙設備

       return new NdefMessage(createHandoverRequestRecord(),createBluetoothOobDataRecord());//將數據封裝在NdefMessage

   }

當然,需要設備有藍牙的支持,否則面談,接着調用兩個接口創建兩個NdefRecord,封裝在NdefMessage中。

先看看HandoverManager.createHandoverRequestRecord()方法,藍牙請求數據:

   NdefRecord createHandoverRequestRecord() {

       NdefMessage nestedMessage = newNdefMessage(createCollisionRecord(),

               createBluetoothAlternateCarrierRecord(false));

       byte[] nestedPayload = nestedMessage.toByteArray();

 

       ByteBuffer payload = ByteBuffer.allocate(nestedPayload.length +1);

       payload.put((byte)0x12);  // connection handoverv1.2

       payload.put(nestedMessage.toByteArray());

 

       byte[] payloadBytes = new byte[payload.position()];

       payload.position(0);

       payload.get(payloadBytes);

       return new NdefRecord(NdefRecord.TNF_WELL_KNOWN,NdefRecord.RTD_HANDOVER_REQUEST, null,

               payloadBytes);

   }

接着看HandoverManager.createBluetoothOobDataRecord(),創建當前設備藍牙地址數據:

   NdefRecord createBluetoothOobDataRecord() {

       byte[] payload = new byte[8];

       payload[0] = 0;

       payload[1] = (byte)payload.length;

 

       synchronized (HandoverManager.this) {

           if (mLocalBluetoothAddress == null) {

               mLocalBluetoothAddress =mBluetoothAdapter.getAddress();//獲取當前設備藍牙地址

           }

 

           byte[]addressBytes =addressToReverseBytes(mLocalBluetoothAddress);

           System.arraycopy(addressBytes, 0,payload, 2, 6);//地址數據拷貝

       }

 

       return new NdefRecord(NdefRecord.TNF_MIME_MEDIA, TYPE_BT_OOB, newbyte[]{'b'},payload);//將地址封裝在NdefRecord

   }

上面兩個方法,創建了兩個NdefRecord,一個是藍牙請求數據,另一個是當前藍牙地址數據。好了,將量數據封裝在NdefMessage中返回。我們回頭繼續看doSnepProtocol()方法。createHandoverRequestMessage()之後就到SnepClient.get(request)發送請求了:

  publicSnepMessage get(NdefMessage msg) throws IOException {

       SnepMessenger messenger;

       synchronized (this) {

           messenger = mMessenger;

       }

 

       synchronized (mTransmissionLock) {

           try {

               messenger.sendMessage(SnepMessage.getGetRequest(mAcceptableLength,msg));//發送請求

               returnmessenger.getMessage();//獲取迴應

           } catch (SnepException e) {

               throw new IOException(e);

           }

       }

   }

在發送數據之前,先調用SnepMessage.getGetRequest(mAcceptableLength,msg)NdefMessage數據轉換成SnepMessage數據,然後調用SnepMessenger.sendMessage開始發送數據,SnepMessenger中包含了Socket的端口。

發送數據之後直接調用SnepMessenger.getMessage();獲取另一設備的迴應信息。這裏有個疑問,一直不明白,發送完數據之後立刻獲取迴應,這樣是怎麼做到同步的呢?求解釋…....

到此,我們繼續回到P2pLinkManager.doSnepProtocol()中,SnepClient.get()get請求有了迴應,迴應的信息還是封裝在SnepMessage中,接着調用SnepMessage的方法getNdefMessage()將回應的數據轉換成NdefMessage數據。

有了迴應,說明藍牙可以匹配,調用HandoverManager.doHandoverUri(uris,response),開始通過藍牙發送Uri

  // Thisstarts sending an Uri over BT

   public void doHandoverUri(Uri[] uris, NdefMessage m) {

       if (mBluetoothAdapter == null) return;

 

       BluetoothHandoverDatadata = parse(m);//解析迴應出藍也數據

       if (data != null && data.valid){

           // Register a new handover transfer object

           getOrCreateHandoverTransfer(data.device.getAddress(), false,true);//創建藍牙轉換器

           BluetoothOppHandover handover = new BluetoothOppHandover(mContext,data.device,

               uris, mHandoverPowerManager, data.carrierActivating);

           handover.start();//開始發送數據

       }

   }

首先需要調用HandoverManager.parse()將回應數據解析爲藍牙數據,裏面當然包含了接收設備的藍牙地址,接着創建了一個BluetoothOppHandover()實例,這樣,該實例就包含了接收設備的藍牙地址,Uris數據,然後就調用其start()開始傳送數據了。

下面就需要看看接收端是怎麼迴應藍牙請求了的。

5.2.3 接收端迴應藍牙請求流程
5.2.3.1時序圖

5.2.3.2 代碼分析

SnepServer我們這裏也不陌生了的,裏面有ConnectionThread線程讀取收到的數據,在run方法中調用SnepServer.handleRequest()處理請求數據:

   static boolean handleRequest(SnepMessenger messenger, Callbackcallback) throws IOException {

       SnepMessage request;

       try {

           request =messenger.getMessage();//讀取收到的數據

       } catch (SnepException e) {

          ……

       }

       if (((request.getVersion() & 0xF0)>> 4) != SnepMessage.VERSION_MAJOR){

           ……

       } else if (request.getField() == SnepMessage.REQUEST_GET){//get請求

           messenger.sendMessage(callback.doGet(request.getAcceptableLength(),

                   request.getNdefMessage()));

       } else if (request.getField() == SnepMessage.REQUEST_PUT){//put請求

           if (DBG) Log.d(TAG, "putting message " +request.toString());

           messenger.sendMessage(callback.doPut(request.getNdefMessage()));

       } else {

       ……

       }

       return true;

   }

SnepMessenger.getMessage()這裏也不陌生了,是用來讀取收到的數據的,將數據保存在SnepMessage中。

要清楚的是,我們這裏是要回應藍牙的請求,所以這裏我們滿足了條件request.getField() ==SnepMessage.REQUEST_GET,即get請求,意思是,接收到得到的數據是其他設備的請求信息,當前設備作爲接收端,需要解析其請求數據,滿足條件後,將發送迴應信息的請求端。

callback.doGet()就是去處理請求的信息,然後返回迴應的信息,通過SnepMessenger. sendMessage()迴應發送給請求端。

先來看看callback.doGet()。這個前面也見到過,Callback接口在P2pLinkManager被實現了:

  finalSnepServer.Callback mDefaultSnepCallback = newSnepServer.Callback() {

       @Override

       public SnepMessage doPut(NdefMessage msg) {

           onReceiveComplete(msg);

           returnSnepMessage.getMessage(SnepMessage.RESPONSE_SUCCESS);

       }

 

       @Override

       public SnepMessagedoGet(intacceptableLength, NdefMessage msg) {//處理請求信息

           NdefMessageresponse =mHandoverManager.tryHandoverRequest(msg);//嘗試處理請求信息,並返回迴應信息。

if (response != null){

               onReceiveHandover();

               returnSnepMessage.getSuccessResponse(response);返回響應信息給SnepServer

              }else {

               returnSnepMessage.getMessage(SnepMessage.RESPONSE_NOT_FOUND);

           }

       }

};

代碼簡單,我們只需要關注HandoverManager.tryHandoverRequest(),參數類型是NdefMessage

public NdefMessagetryHandoverRequest(NdefMessage m) {

       NdefRecord r = m.getRecords()[0];

       //判斷數據是否是藍牙請求數據

       if (r.getTnf() != NdefRecord.TNF_WELL_KNOWN) return null;

       if (!Arrays.equals(r.getType(), NdefRecord.RTD_HANDOVER_REQUEST)) return null;

       BluetoothHandoverData bluetoothData = null;

       for (NdefRecord oob : m.getRecords()) {

           if (oob.getTnf() == NdefRecord.TNF_MIME_MEDIA&&

                   Arrays.equals(oob.getType(), TYPE_BT_OOB)) {

               bluetoothData =parseBtOob(ByteBuffer.wrap(oob.getPayload()));//解析藍牙數據,當然包含了發送端的藍牙地址

               break;

           }

       }

 

       synchronized(HandoverManager.this) {

           if (!mHandoverPowerManager.isBluetoothEnabled()) {

               if (!mHandoverPowerManager.enableBluetooth()) {//啓用當前設備的藍牙

                   return null;

               }

           }

           // Create the initial transfer object

           HandoverTransfer transfer =getOrCreateHandoverTransfer(//創建藍牙轉換器

                   bluetoothData.device.getAddress(), true, true);

           transfer.updateNotification();//發送通知準備接收圖片數據,狀態欄看到了進度條

       }

 

       // BT OOB found, whitelist it for incoming OPP data

       whitelistOppDevice(bluetoothData.device);//將藍牙請求端設備添加到列表中

 

       // return BT OOB record so they can perform handover

       return(createHandoverSelectMessage(bluetoothActivating));創建並返回響應的數據

   }

該方法的參數是NdefMessage,第一步需要判斷數據是否是藍牙請求數據。

第二步,符合標準之後,讀取出藍牙地址數據bluetoothData

第三步,啓用當前設備的藍牙。

第四步,將獲取到的藍牙請求端的藍牙地址數據,創建藍牙轉換器

第五步,發送通知準備接收圖片數據,這時候狀態欄那裏就可以看到進圖條了。

第六步,將藍牙請求端設備添加到列表中。

第七步,創建並返回響應的數據。這裏跟請求端創建請求數據類似,裏面也包含了當前藍牙設備的地址和迴應數據。都封裝在NdefMessage中。

Ok,接收端藍牙就開始等待接收數據了。HandoverManager.tryHandoverRequest()方法,就是完成兩件事情,第一件事情就是第一到第六步,完成接收端藍牙的匹配工作,第二件事情就是第七步,創建響應信息,並返回創建的迴應信息給到doGet()方法中,在doGet()中,將NdefMessage轉換成SnepMessage,然後返回到SnepServer中的handleRequest()方法中:

 messenger.sendMessage(callback.doGet(request.getAcceptableLength(),

                   request.getNdefMessage()));

接着調用SnepMessenger.sendMessage(SnepMessage),發送響應數據給請求端。

請求端接收到相應數據後,就開始通過匹配藍牙發送圖片等大數據量的數據了。簡單吧。

 

6 Tag設備讀寫流程

6.1 Tag設備讀寫流程圖


6.2 時序圖



6.2 代碼分析

4.2中,NFC的啓動將調用NativeNfcManager.enableDiscovery(),然後將調用到JNI方法com_android_nfc_NfcManager_enableDiscovery()掃描tagP2p設備。在該方法中,調用phLibNfc_RemoteDev_NtfRegister()方法註冊回調函數nfc_jni_Discovery_notification_callback()。當掃面到tagP2p的時候將回調該方法。下面看看JNI鍾開始NFC設備掃描的方法com_android_nfc_NfcManager_enableDiscovery():

static voidcom_android_nfc_NfcManager_enableDiscovery(JNIEnv *e, jobject o){

   NFCSTATUS ret;

   struct nfc_jni_native_data *nat;

   CONCURRENCY_LOCK();

    nat= nfc_jni_get_nat(e, o);

  

  REENTRANCE_LOCK();

   ret = phLibNfc_RemoteDev_NtfRegister(&nat->registry_info,nfc_jni_Discovery_notification_callback, (void *)nat);//註冊回調函數

  REENTRANCE_UNLOCK();

   ……

   nfc_jni_start_discovery_locked(nat,false);//開始掃描

clean_and_return:

   CONCURRENCY_UNLOCK();

}

   我們這裏主要看到其註冊回調函數,然後就開始掃描NFC設備了,當發現有NFC設備的時候,將會回調nfc_jni_Discovery_notification_callback()方法,代碼如下:

static voidnfc_jni_Discovery_notification_callback(void *pContext,

  phLibNfc_RemoteDevList_t *psRemoteDevList,

   uint8_t uNofRemoteDev,NFCSTATUS status)

{

 

 

       

     TRACE("Notify Nfc Service");

     if((remDevInfo->RemDevType ==phNfc_eNfcIP1_Initiator)

         || (remDevInfo->RemDevType ==phNfc_eNfcIP1_Target))

     {

        

        hLlcpHandle = remDevHandle;

        

        

        e->CallVoidMethod(nat->manager,cached_NfcManager_notifyLlcpLinkActivation, tag);

       ……  

     }

     else

     {

        

        e->CallVoidMethod(nat->manager,cached_NfcManager_notifyNdefMessageListeners,tag);

      …… 

     }

     e->DeleteLocalRef(tag);

   }

}

前面也介紹過了,發現NFC設備分爲兩種,一種是Tag設備,即公交卡等卡類,另一種是手機、平板等設備,完成點對點(P2p)的數據交換。在以上方法中,分別對這兩類型的NFC設備做不同的處理。

當發現P2P設備的時候,回調了java層的NativeNfcManager.notifyLlcpLinkActivation(),當發現一個新的tag的時候,回調了java層的NativeNfcManager.notifyNdefMessageListeners().這裏我們主要關注發現新的tag,消息是如何傳送的呢?

NativeNfcManager.notifyNdefMessageListeners()代碼如下:

 

   private void notifyNdefMessageListeners(NativeNfcTag tag){

       mListener.onRemoteEndpointDiscovered(tag);

   }

mListener其實就是NfcService的實例,調用了其onRemoteEndpointDiscovered()方法,代碼如下:

@Override

   public void onRemoteEndpointDiscovered(TagEndpoint tag){

       sendMessage(NfcService.MSG_NDEF_TAG,tag);

   }

這裏是發送了MSG_NDEF_TAGHandler消息到NfcServiceHandler,是NfcService的子類。在其handleMessage()方法中處理:

case MSG_NDEF_TAG:

                   TagEndpoint tag = (TagEndpoint) msg.obj;

                   playSound(SOUND_START);

                   NdefMessage ndefMsg =tag.findAndReadNdef();

                   if(ndefMsg != null) {

                       tag.startPresenceChecking();

                       dispatchTagEndpoint(tag);

                   } else {

                         if(tag.reconnect()) {

                           tag.startPresenceChecking();

                           dispatchTagEndpoint(tag);

                          }else {

                           ……

                       }

                   }

                   break;

這裏的tag,其實是NativeNfcTag的實例,調用了其findAndReadNdef()方法讀取NDEF信息,在這個方法中,調用NativeNfcTag. readNdef(),讀取消息。接着調用JNI方法,doRead()JNI中讀取消息,然後返回給NdefMessage。因爲這裏發現的是TAG設備,所以,返回了ndefMgs=null

接下來看tag消息的傳送。

NfcServiceHandler.dispatchTagEndPoint()

private voiddispatchTagEndpoint(TagEndpoint tagEndpoint) {

           Tag tag = new Tag(tagEndpoint.getUid(),tagEndpoint.getTechList(),

                   tagEndpoint.getTechExtras(), tagEndpoint.getHandle(),mNfcTagService);

           registerTagObject(tagEndpoint);

           if (!mNfcDispatcher.dispatchTag(tag)) {

               unregisterObject(tagEndpoint.getHandle());

               playSound(SOUND_ERROR);

           } else {

               playSound(SOUND_END);

           }

       }

這裏面將NativeNfcTag消息用於構造一個TagtagEndpoint.getTechList()取出該Tag設備支持的technologymNfcDispatcherNfcDispatcher的實例,用於向Activity派發消息的。然後調用mNfcDispatcher.dispatchTag派發Tag消息。代碼如下:

 

   public boolean dispatchTag(Tag tag) {

       NdefMessage message = null;

       Ndef ndef = Ndef.get(tag);

      ……

       PendingIntent overrideIntent;

       IntentFilter[] overrideFilters;

       String[][] overrideTechLists;

 

       DispatchInfo dispatch = newDispatchInfo(mContext, tag, message);

       synchronized (this) {

           overrideFilters= mOverrideFilters;

           overrideIntent = mOverrideIntent;

           overrideTechLists = mOverrideTechLists;

       }

       ……

       if (tryTech(dispatch, tag)) {

           return true;

       }

 

 

   }

這個方法已經不再陌生了,前面也看到過了的。因爲我們這裏發現的是Tag設備,所以將選擇調用了NfcDispatcher.tryTech()方法,代碼如下:

boolean tryTech(DispatchInfodispatch, Tag tag) {

       dispatch.setTechIntent();//設置IntentActionACTION_TECH_DISCOVERED

       String[] tagTechs = tag.getTechList();//獲取Tag設備支持的technology

       Arrays.sort(tagTechs);

 

       // Standard tech dispatch path

       ArrayList<ResolveInfo> matches = newArrayList<ResolveInfo>();

       List<ComponentInfo> registered =mTechListFilters.getComponents();//獲取ActionACTION_TECH_DISCOVEREDActivity列表

 

       // Check each registered activity to see if it matches

       for (ComponentInfo info : registered) {

           // Don't allow wild card matching

           if (filterMatch(tagTechs, info.techs)&&//Activity支持解析該technology

                   isComponentEnabled(mPackageManager,info.resolveInfo)) {

               // Add the activity as a match if it's not already in thelist

               if (!matches.contains(info.resolveInfo)) {

                   matches.add(info.resolveInfo);//滿足條件,添加到列表中

               }

           }

       }

 

       if (matches.size() == 1) {//只有一個Activity滿足條件

           // Single match, launch directly

           ResolveInfo info = matches.get(0);

           dispatch.intent.setClassName(info.activityInfo.packageName,info.activityInfo.name);

           if(dispatch.tryStartActivity()) {

               if (DBG) Log.i(TAG, "matched single TECH");

               return true;

           }

           dispatch.intent.setClassName((String)null, null);

       } else if (matches.size()> 1) {//多個Activity滿足條件

           // Multiple matches, show a custom activity chooserdialog

           Intent intent = new Intent(mContext,TechListChooserActivity.class);

           intent.putExtra(Intent.EXTRA_INTENT, dispatch.intent);

           intent.putParcelableArrayListExtra(TechListChooserActivity.EXTRA_RESOLVE_INFOS,

                   matches);

           if (dispatch.tryStartActivity(intent)){

               if (DBG) Log.i(TAG, "matched multiple TECH");

               returntrue;

           }

       }

       return false;

   }

第一步,還是需要設置IntentActionACTION_TECH_DISCOVERED

第二步,獲取該Tag設備支持的technology

第三步,讀取系統中ActionACTION_TECH_DISCOVEREDActivity列表,並獲取該Apk支持解析的technology列表,這個是在apkXml文件中定義的:

<?xmlversion="1.0" encoding="utf-8"?>

<resourcesxmlns: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>

</resources>

第四步,做一個匹配,將支持解析該Tag設備technologyApk添加到matches列表中

第五步,如果只有一個Activity滿足條件,直接啓動該Activity

第六步,如果有多個Activity滿足條件,發送Intent消息供用戶選擇啓動哪裏Activity

 

到此,Tag消息就已經傳送到Activity了。那麼接下來就需要在Activity中,發起對Tag設備的讀寫了。

6.3Activity中發起對Tag設備讀寫

6.3.1 三個Intent啓動Activity

當設備掃描發現有tagP2p設備的時候,將數據封裝好後發送Intent啓動Activity處理數據,有三類型Intent

n        ACTION_NDEF_DISCOVERED:處理NDEF數據,包含MIMEURI數據類型

n        ACTION_TECH_DISCOVERED:處理非NDEF數據或者NDEF數據但不能映射爲MIMEURI數據類型

n        ACTION_TAG_DISCOVERED:如果沒有Activity相應上面兩個Intent,就由該Intent處理

官網上調度圖如下:



6.3.2 Activity中對Tag設備讀寫

經過前面一大串的分析,對於Tag設備,首先需要獲取Tag信息,也說過,Tag信息包含了支持的technology類型。獲取方式如下:

Tag tagFromIntent =intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);

我們以MifareUltralighttechnology類型爲例子,根據Tag構造MifareUltralight

MifareUltralight.get(tagFromIntent);

看看MifareUltralight.get()接口吧:

   public staticMifareUltralight get(Tag tag) {

       if(!tag.hasTech(TagTechnology.MIFARE_ULTRALIGHT)) returnnull;//判斷該Tag是否支持

       try {

           return new MifareUltralight(tag);

       } catch (RemoteException e) {

           returnnull;

       }

   }

get()方法中,需要判斷Tag設備是否支持MifareUltralight類型的technology,如果支持,那麼就真正的構造它。

得到了MifareUltralight實例後,就可以開始完成讀寫操作了。

public void writeTag(Tagtag, String tagText) {

       MifareUltralight ultralight = MifareUltralight.get(tag);

       try {

           ultralight.connect();

           ultralight.writePage(4,"abcd".getBytes(Charset.forName("US-ASCII")));

           ultralight.writePage(5,"efgh".getBytes(Charset.forName("US-ASCII")));

           ultralight.writePage(6,"ijkl".getBytes(Charset.forName("US-ASCII")));

           ultralight.writePage(7,"mnop".getBytes(Charset.forName("US-ASCII")));

       } catch (IOException e) {

           Log.e(TAG, "IOException while closing MifareUltralight...",e);

       } finally {

           try {

               ultralight.close();

           } catch (IOException e) {

               Log.e(TAG, "IOException while closing MifareUltralight...",e);

           }

       }

   }

 

   public String readTag(Tag tag) {

       MifareUltralight mifare = MifareUltralight.get(tag);

       try {

           mifare.connect();

           byte[] payload = mifare.readPages(4);

           return new String(payload, Charset.forName("US-ASCII"));

       } catch (IOException e) {

           Log.e(TAG, "IOException while writing MifareUltralight

           message...", e);

       } finally {

           if (mifare != null) {

              try {

                  mifare.close();

              }

              catch (IOException e) {

                  Log.e(TAG,"Error closing tag...", e);

              }

           }

       }

       return null;

   }

 

不管是read還是write,都會調用到TagService中,然後是NativeNfcTag,最終到JNI中。詳細代碼就不分析了,感興趣就自己看。

 

 

 

 

 

 

 

 

 

參考:

http://www.eoeandroid.com/thread-173822-1-1.html

http://www.cnblogs.com/doandroid/archive/2011/11/29/2267404.html

http://blog.csdn.net/wchinaw/article/details/6542831

http://leave001.blog.163.com/blog/static/16269129320122283648327/

http://wiki.eoeandroid.com/index.php?title=NFC_Basics&diff=4589&oldid=4580

http://doandroid.info/android中nfc功能解析及代碼演示/

P2p設備http://blog.csdn.net/karen2lotus/article/details/7922948

NFC理解很好:http://www.360doc.com/content/11/0524/13/474846_119019554.shtml

發佈了36 篇原創文章 · 獲贊 6 · 訪問量 9萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章