博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
《Android NFC开发实战详解》——6.3节Android NFC P2P开发实例
阅读量:6758 次
发布时间:2019-06-26

本文共 45964 字,大约阅读时间需要 153 分钟。

本节书摘来自异步社区《Android NFC开发实战详解》一书中的第6章,第6.33节Android NFC P2P开发实例,作者 赵波,更多章节内容可以访问云栖社区“异步社区”公众号查看

6.3 Android NFC P2P开发实例

Android NFC开发实战详解
学习了Android NFC P2P开发的基础知识后,本节将以程序实例的形式对Android NFC P2P功能进行进一步阐述,其中包括setNdefPushMessageCallback、setNdefPushMessage、enableForeground NdefPush以及结合AAR功能的Beam功能的四个实例开发。通过本节的学习,读者可以根据具体场景实现自己的P2P功能的开发。

6.3.1 实例1:使用setNdefPushMessageCallback实现Android Beam

在Android NFC P2P实例1中,对setNdefPushMessageCallback ( )方法实现Android Beam功能进行了实例描述。该实例包括消息发送端和接收端两部分,既可以完成NDEF消息的Push,又可以完成NDEF的获取。

(1)BNM部分主要包括两个步骤,分别为:

① 在Activity中实现CreateNdefMessageCallback接口(implements);

② 在需要的地方调用setNdefPushMessageCallback();

③ 回调函数createNdefMessage(NfcEvent event)中实现Beam Data。

(2)RBM部分主要包括两个步骤,分别为:

① 在Activity中重载onNewIntent(Intent intent),并在其中做setIntent(intent);

② 在Activity中重载onResume(),在其中做消息判别;

③ 当消息判别为需要的Beam时,处理接收的数据。

具体参见实例代码中对应的注释,详细代码如下阐述。

主程序P2PDemo1.java文件的代码如下:

1. package skyseraph.nfc_demo.p2p.beam.app;   //声明包2. import java.nio.charset.Charset;   //导入相关类3. ……//该处省略了导入相关类的代码4. public class P2PDemo1 extends Activity implements CreateNdefMessageCallback5. { // BNM步骤1:在你的Activity中实现CreateNdefMessageCallback接口(implements)6.      private static final String Tag_ASSIST = "[P2PDemo1]-";7.      private TextView p2pMessage = null;8.      private Context mContext = null;9.      // NFC相关10.     private NfcAdapter mNfcAdapter = null;11. 12.     @Override13.  protected void onCreate(Bundle savedInstanceState)14.  {15.      // TODO Auto-generated method stub16.      super.onCreate(savedInstanceState);17.      setContentView(R.layout.p2p_demo1);18.      mContext = this;19.      LogUtil.i(MyConstant.Tag, Tag_ASSIST + "into onCreate");20.      p2pMessage = (TextView) this.findViewById(R.id.p2p_demo1_tv);21.      checkNFCFunction();22. 23.      p2pMessage.setText("Touch another mobile to Beam 'http://www.cnblogs.            com/skyseraph/'or to Rev the beam msg");24. 25.      // BNM步骤2: call setNdefPushMessageCallback anywhere your want26.      mNfcAdapter.setNdefPushMessageCallback(this, this);27.  }28. 29.  /*30.   * (non-Javadoc)31.   * 32.   * @see33.   * android.nfc.NfcAdapter.CreateNdefMessageCallback#createNdefMessage (android34.   * .nfc.NfcEvent)35.   */36.  // BNM步骤3:回调函数中实现Beam Data。37.  // 当发现有支持Beam的手机时,该回调接口会自动激活,你只需将你需要Beam的NDEF消息准备好    //并作为NdefMessage返回即可。本例中以RTD_URI为例。38.  @Override39.  public NdefMessage createNdefMessage(NfcEvent event)40.  {41.       // TODO Auto-generated method stub42.       LogUtil.i(MyConstant.Tag, Tag_ASSIST + "into createNdefMessage");43.       String uriFiledStr = "cnblogs.com/skyseraph/";44.       Byte identifierCode = 0x01;45.       NdefMessage message = BobNdefMessage.getNdefMsg_from_RTD_URI(uriFiledStr,             identifierCode, false);46.       return message;47.  }48. 49.  @Override50.  protected void onResume()51.  {52.        // TODO Auto-generated method stub53.        super.onResume();54.        LogUtil.i(MyConstant.Tag, Tag_ASSIST + "into onResume");55.        // RBM步骤2:消息判别56.        if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(getIntent().getAction()))57.       {58.             // RBM步骤3:处理接收的消息/数据59.             resolveIntent(getIntent());60.       }61.  }62. 63.  // RBM步骤1:onNewIntent setIntent(intent);64.  @Override65.  protected void onNewIntent(Intent intent)66.  {67.       // TODO Auto-generated method stub68.       // super.onNewIntent(intent);69.       LogUtil.i(MyConstant.Tag, Tag_ASSIST + "into onNewIntent");70.       setIntent(intent);71.  }72.      73. // RBM步骤3:处理接收的数据74.  /**75.   * @param intent76.   */77.  void resolveIntent(Intent intent)78.  {79.       LogUtil.i(MyConstant.Tag, Tag_ASSIST + "into resolveIntent");80.       String action = intent.getAction();81.       if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(action))82.      {83.            LogUtil.i(MyConstant.Tag, Tag_ASSIST + "ACTION_NDEF_DISCOVERED");84.            NdefMessage[] messages = null;85.            Parcelable[] rawMsgs = intent.getParcelableArrayExtra(NfcAdapter.                  EXTRA_NDEF_MESSAGES);86.            if (rawMsgs != null)87.            {88.                 messages = new NdefMessage[rawMsgs.length];89.                 for (int i = 0; i < rawMsgs.length; i++)90.                 {91.                      messages[i] = (NdefMessage) rawMsgs[i];92.                      LogUtil.i(MyConstant.Tag, Tag_ASSIST + "messages[i] = "                            + messages[i]);93.                  }94.         } else95.         {96.                  // Unknown tag type97.                  byte[] empty = new byte[]98.                  {};99.                  NdefRecord record = new NdefRecord(NdefRecord.TNF_UNKNOWN,                        empty, empty, empty);100.                 NdefMessage msg = new NdefMessage(new NdefRecord[]101.                 { record });102.                  messages = new NdefMessage[]103.                  { msg };104.          }105.          // Setup the views106.          setTitle(R.string.title_scanned_tag);107.          // process NDEF Msg108.          processNDEFMsg(messages);109.   } else if (NfcAdapter.ACTION_TECH_DISCOVERED.equals(intent.getAction()))110.   {111.    LogUtil.i(MyConstant.Tag, Tag_ASSIST + "ACTION_TECH_DISCOVERED");112.   } else if (NfcAdapter.ACTION_Tag_DISCOVERED.equals(intent.getAction()))113.   {114.    LogUtil.i(MyConstant.Tag, Tag_ASSIST + "ACTION_Tag_DISCOVERED");115.   } else116.   {117.         LogUtil.e(MyConstant.Tag, Tag_ASSIST + "Unknown intent " + intent);118.         finish();119.         return;120.   }121.  }122. 123.  /**124.   * 获取NdefMessage125.   *  @param messages126.   */127.  void processNDEFMsg(NdefMessage[] messages)128.  {129.       LogUtil.i(MyConstant.Tag, Tag_ASSIST + "into processNDEFMsg");130.       if (messages == null || messages.length == 0)131.   {132.       LogUtil.e(MyConstant.Tag, Tag_ASSIST +"NdefMessage is null");133.       return;134.   }135.       for (int i = 0; i < messages.length; i++)136.   {137.       int length = messages[i].getRecords().length;138.       LogUtil.i(MyConstant.Tag, Tag_ASSIST + "Message " + (i + 1) + ","               + "length=" + length);139.       NdefRecord[] records = messages[i].getRecords();140.       for (int j = 0; j < length; j++) // 几个记录141.       {142.            for (NdefRecord record : records)143.            {144.                 if (isUri(record))145.                 {146.                      parseUriRecord(record);147.                 }148.            }149.       }150.    }151.  }152. 153.  /**154.   * 解析NdefMessage155.   *  @param record156.   */157.  private void parseUriRecord(NdefRecord record)158.  {159.       // TODO Auto-generated method stub160.       LogUtil.i(MyConstant.Tag, Tag_ASSIST + "into parseUriRecord");161.       short tnf = record.getTnf();162.       if (tnf == NdefRecord.TNF_WELL_KNOWN)163.       {164.             parseWellKnownUriRecord(record);165.        } else if (tnf == NdefRecord.TNF_ABSOLUTE_URI)166.        {167.              parseAbsoluteUriRecord(record);168.        } else169.       {170.              LogUtil.e(MyConstant.Tag, Tag_ASSIST + "Unknown TNF " + tnf);171.       }172.  }173. 174.  private void parseAbsoluteUriRecord(NdefRecord record)175.  {176.       // TODO Auto-generated method stub177.       LogUtil.i(MyConstant.Tag, Tag_ASSIST + "into parseAbsolute");178.       byte[] payload = record.getPayload();179.       Uri uri = Uri.parse(new String(payload, Charset.forName("UTF-8")));180.       LogUtil.i(MyConstant.Tag, Tag_ASSIST + "the Record Tnf: " + record.getTnf()       +         "\n");// 1181.       LogUtil.i(MyConstant.Tag, Tag_ASSIST + "the Record type: " + new      String(record.getType()) + "\n");// T182.       LogUtil.i(MyConstant.Tag, Tag_ASSIST + "the Record id: " + new      String(record.getId()) + "\n");183.       LogUtil.i(MyConstant.Tag, Tag_ASSIST + "the Record payload: " + uri + "\n");184.       uiControl(uri);185.  }186. 187.  /**188.   * @param record189.   * 190.   *            payload[0] contains the URI Identifier Code, per the NFC Forum191.   *            "URI Record Type Definition" section 3.2.2.192.   * 193.   *            payload[1]...payload[payload.length - 1] contains the rest of194.   *            the URI.195.   */196.  private void parseWellKnownUriRecord(NdefRecord record)197.  {198.        // TODO Auto-generated method stub199.        LogUtil.i(MyConstant.Tag, Tag_ASSIST + "into parseWellKnown");200.        Preconditions.checkArgument(Arrays.equals(record.getType(), NdefRecord.                  RTD_URI));   201.        byte[] payload = record.getPayload();202. 203.        String prefix = URI_PREFIX_MAP.get(payload[0]);204.        LogUtil.i(MyConstant.Tag, Tag_ASSIST + "the prefix: " + prefix + "\n");//205.        byte[] fullUri = Bytes.concat(prefix.getBytes(Charset.forName("UTF-8")),206.                   Arrays.copyOfRange(payload, 1, payload.length));207.       Uri uri = Uri.parse(new String(fullUri, Charset.forName("UTF-8")));208.       LogUtil.i(MyConstant.Tag, Tag_ASSIST + "the Record Tnf: " + record.getTnf()                + "\n");//  209.       LogUtil.i(MyConstant.Tag, Tag_ASSIST + "the Record type: " + new String               (record.getType()) + "\n");//210.       LogUtil.i(MyConstant.Tag, Tag_ASSIST + "the Record id: " + new String               (record.getId()) + "\n");211.       LogUtil.i(MyConstant.Tag, Tag_ASSIST + "the Record payload: " + uri + "\n");212.       uiControl(uri);213.  }214. 215.  /**216.   * UI操控217.   * 218.   * @param uri219.   */220.  private void uiControl(final Uri uri)221.  {222.       // TODO Auto-generated method stub223.       LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(Linear              Layout.LayoutParams.WRAP_CONTENT,224.       LinearLayout.LayoutParams.WRAP_CONTENT);225.       Button button = new Button(this);226.       this.addContentView(button, params);227.       p2pMessage.setText("Rev MSG : " + "\n" + " " + uri);228.       button.setText("Open Link : " + uri);229.       button.setOnClickListener(new View.OnClickListener()230.       {231.            public void onClick(View view)232.            {233.                   Intent data = new Intent();234.                  data.setAction(Intent.ACTION_VIEW);235.                  data.setData(uri);236.                  try237.                  {238.                       startActivity(data);239.            } catch (ActivityNotFoundException e)240.            {241.                 return;242.            }243.      }244.   });245.  }246. 247.  /**248.   * @param record249.   * @return250.   */251.  public static boolean isUri(NdefRecord record)252.  {253.       if (record.getTnf() == NdefRecord.TNF_WELL_KNOWN)254.       {255.             if (Arrays.equals(record.getType(), NdefRecord.RTD_URI))256.             {257.                   return true;258.             } else259.             {260.                   return false;261.             }262.      } else if (record.getTnf() == NdefRecord.TNF_ABSOLUTE_URI)263.     {264.            return true;265.     } else266.     {267.         return false;268.      }269.  }270. 271.  /**272.   * NFC Forum "URI Record Type Definition"273.   * 274.   * This is a mapping of "URI Identifier Codes" to URI string prefixes, per275.   * section 3.2.2 of the NFC Forum URI Record Type Definition document.276.   */277.  private static final BiMap
URI_PREFIX_MAP = ImmutableBiMap.
builder()278. .put((byte) 0x00, "").put((byte) 0x01, "http://www.").put((byte) 0x02, "https://www.")279. .put((byte) 0x03, "http://").put((byte) 0x04, "https://").put((byte) 0x05, "tel:")280. .put((byte) 0x06, "mailto:").put((byte) 0x07, "ftp://anonymous: anonymous@").put((byte) 0x08, "ftp://ftp.")281. .put((byte) 0x09, "ftps://").put((byte) 0x0A, "sftp://").put((byte) 0x0B, "smb://")282. .put((byte) 0x0C, "nfs://").put((byte) 0x0D, "ftp://").put((byte) 0x0E, "dav://").put((byte) 0x0F, "news:")283. .put((byte) 0x10, "telnet://").put((byte) 0x11, "imap:").put((byte) 0x12, "rtsp://")284. .put((byte) 0x13, "urn:").put((byte) 0x14, "pop:").put((byte) 0x15, "sip:").put((byte) 0x16, "sips:")285. .put((byte) 0x17, "tftp:").put((byte) 0x18, "btspp://").put((byte) 0x19, "btl2cap://")286. .put((byte) 0x1A, "btgoep://").put((byte) 0x1B, "tcpobex://").put ((byte) 0x1C, "irdaobex://")287. .put((byte) 0x1D, "file://").put((byte) 0x1E, "urn:epc:id:").put ((byte) 0x1F, "urn:epc:tag:")288. .put((byte) 0x20, "urn:epc:pat:").put((byte) 0x21, "urn:epc:raw:"). put((byte) 0x22, "urn:epc:")289. .put((byte) 0x23, "urn:nfc:").build();290. 291. /**292. * NFC Function Check By skyseraph 2013-2293. */294. private void checkNFCFunction()295. {296. // TODO Auto-generated method stub297. mNfcAdapter = NfcAdapter.getDefaultAdapter(this);298. if (mNfcAdapter == null)299. {300. p2pMessage.setText("NFC apdater is not available");301. Dialog dialog = null;302. CustomDialog.Builder customBuilder = new CustomDialog.Builder (mContext);303. customBuilder.setTitle(getString(R.string.inquire)).setMessage (getString(R.string.nfc_notice2))304. .setIcon(R.drawable.dialog_icon2)305. .setNegativeButton(getString(R.string.no), new Dialog Interface.OnClickListener()306. {307. public void onClick(DialogInterface dialog, int which)308. {309. dialog.dismiss();310. finish();311. }312. }).setPositiveButton(getString(R.string.yes), new Dialog Interface.OnClickListener()313. {314. public void onClick(DialogInterface dialog, int which)315. {316. dialog.dismiss();317. finish();318. }319. });320. dialog = customBuilder.create();321. dialog.setCancelable(false);// back322. dialog.setCanceledOnTouchOutside(false);323. SetDialogWidth(dialog).show();324. return;325. } else326. {327. if (!mNfcAdapter.isEnabled())328. {329. Dialog dialog = null;330. CustomDialog.Builder customBuilder = new CustomDialog.Builder (mContext);331. customBuilder.setTitle(getString(R.string.inquire)).setMessage(getString(R.strin g.nfc_notice3)) 332. .setIcon(R.drawable.dialog_icon2)333. .setNegativeButton(getString(R.string.no), new DialogInterface.OnClickListener()334. {335. public void onClick(DialogInterface dialog, int which)336. {337. dialog.dismiss();338. finish();339. }340. }).setPositiveButton(getString(R.string.yes), new DialogInterface.OnClickListener()341. {342. public void onClick(DialogInterface dialog, int which)343. {344. dialog.dismiss();345. Intent setnfc = new Intent(Settings. ACTION_WIRELESS_SETTINGS);346. // Intent setnfc = new347. // Intent(Settings.ACTION_NFC_SETTINGS);348. startActivity(setnfc);349. }350. });351. dialog = customBuilder.create();352. dialog.setCancelable(false);// back353. dialog.setCanceledOnTouchOutside(false);354. SetDialogWidth(dialog).show();355. return;356. } else if (!mNfcAdapter.isNdefPushEnabled())357. {358. Intent setnfc = new Intent(Settings.ACTION_NFCSHARING_ SETTINGS);359. startActivity(setnfc);360. return;361. }362. }363. }364. 365. /**366. * @param dialog367. * @return368. */369. private Dialog SetDialogWidth(Dialog dialog)370. {371. DisplayMetrics dm = new DisplayMetrics();372. // 取得窗口属性373. getWindowManager().getDefaultDisplay().getMetrics(dm);374. // 窗口的宽度375. int screenWidth = dm.widthPixels;376. // 窗口高度377. int screenHeight = dm.heightPixels;378. WindowManager.LayoutParams params = dialog.getWindow().getAttributes();379. if (screenWidth > screenHeight)380. {381. params.width = (int) (((float) screenHeight) * 0.875);382. 383. } else384. {385. params.width = (int) (((float) screenWidth) * 0.875);386. }387. dialog.getWindow().setAttributes(params);388. 389. return dialog;390. }391. }

第4行为BNM步骤1阶段,即实现CreateNdefMessageCallback接口。实现该接口后,在该Activity中需重载createNdefMessage (NfcEvent event)函数,在该函数中返回需要的Beam数据。

第21行为实现NFC功能的检测,在使用Android Beam功能前需要确保设备支持NFC功能。NFC功能可用,且Android Beam功能是enable,具体可通过isEnabled() 和 isNdefPushEnabled()函数实现,参考代码第291~363行checkNFCFunction()函数。
第26行为BNM步骤2阶段,即调用setNdefPushMessageCallback(this, this),实现该接口后,当发现有其他设备Beam数据,该Activity中会接收一个回调,createNdefMessage (NfcEvent event)函数会自动激活。
第29~47行为BNM步骤3阶段,即在回调函数createNdefMessage (NfcEvent event)中实现Beam Data。在createNdefMessage (NfcEvent event)函数中,其通过调用setNdefPushMessageCallback (this, this) 后自动激活,其中,可以创建需要的NDEF消息并将其返回。
第45行为通过调用BobNdefMessage.getNdefMsg_from_RTD_URI(String uriFiledStr, byte identifierCode, boolean flagAddAAR)方法生成RTD-URI类型的NDEF消息,也可以创建其他类型的NDEF消息。关于BobNdefMessage类可参考第5章。
第63~71行为RBM步骤1阶段,即在Activity中重载onNewIntent(Intent intent),并在其中setIntent(intent)。
第49~61行为RBM步骤2阶段,即在Activity中重载onResume(),并在其中做消息判别。
第59行为RBM步骤3阶段,即当消息判别为需要的Beam时,调用resolveIntent(Intent intent)函数处理接收的数据,resolveIntent(Intent intent)函数可参考第73~121行所示。
第73~121行为resolveIntent(Intent intent)函数,处理接收到的NDEF消息。其中,第85行通过intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES)获取具体的消息数据,然后在第86行判断该消息是否为空。不为空时,将其依次保存到定义的NdefMessage[]中;为空时,NdefMessage[]消息中保存一个默认的NdefRecord.TNF_UNKNOWN记录类型。
第108行为处理resolveIntent(Intent intent)中得到的NdefMessage[]消息,具体函数参考第123~151所示。其中,首先检测NdefMessage[]消息是否为空,再依次处理每个消息(第135行)和每个消息中的每个记录(第140~142行)。第144行isUri(NdefRecord record)函数主要完成判别当前记录是否为URI类型,具体见第247~269行所述。第146行parseUriRecord(NdefRecord record)为解析获取的消息记录,具体见第153~172行所述。
第247~269行为isUri(NdefRecord record)函数,完成判别当前记录是否为URI类型。由于NFC消息记录中定义的URI类型有两种,即NdefRecord.TNF_WELL_KNOW(第253行)N和NdefRecord.TNF_ABSOLUTE_URI(第262行),因此此处分别作了判断。其中,记录格式和类型的分别通过record.getTnf()和record.getType()得到。
第153~172行为parseUriRecord(NdefRecord record)函数,完成对当前获取的记录进行解析得到最终的数据(Payload)。如上所述,此处也分两种情况,通过getTnf()得到记录格式(第161行),然后再针对NdefRecord.TNFWELL_KNOWN和NdefRecord.TNF_ABSOLUTE URI分别解析以获取Payload。两者的解析分别参考第174~185行和第187~213行的parseAbsoluteUriRecord (NdefRecord record)和parseWellKnownUriRecord(NdefRecord record)函数,具体解析过程需参考NFC论坛定义URI相关协议,在第5章已描述,此处省略。
第215~245行为uiControl(final Uri uri)函数,主要完成对解析完后的NDEF消息的Payload(即URI)进行UI映射。此处通过一个文本控件显示该URI内容,同时增添一个按钮控件并添加点击响应函数。当用户点击该按钮时,跳转到文本控件中显示的URI链接主页上,如图6-5(c)所示。
第271~289行为利用Google Collections Library BiMap 定义的URI_PREFIX_MAP,用于parseWellKnownUriRecord(NdefRecord record)函数中(第187~213行)中URI的前缀的判别。具体根据NFC论坛定义的协议文档“URI Record Type Definition”所述。
BobNdefMessage为自定义NdefMessage辅助类,具体代码可参考第5章的5.3.2节,此处省略。

LogUtil为自定义调试类,主要是为方便APP在发布正式版本时一次性关闭所有调试Log信息,具体代码可参考第5章的5.2.2小节,此处省略。

MyConstant为自定义常量类,具体代码可参考第5章的5.2.2小节,此处省略。

在布局文件中,p2p_demo1.xml包含了一个按钮控件和一个文本控件,并修改了相关属性,代码如下:

1. 
2.
7. 8.
15. 16.
23.

第8~14行为按钮控件,此处的按钮控件只是起提示作用。

第16~23行为文本控件,文本控件主要显示需要Beam的数据以及接收到的Beam数据。
在AndroidManifest.xml中声明Activity,并添加NFC权限,其代码如下:

1. 
2.
5.
6.
7.
8.
9.
10.
11.
12.
13.
17.
18.

第1行为APP添加NFC权限。

第10~17行增加一个RTD-URI过滤器,以便能够接受任何来自其他NFC设备的Scheme为http的URI。
Beam文件传输实例1的具体效果如图6-3至图6-5所示,其中,图6-3所示为两台准备了Beam的手机。打开本实例APP,然后将两台手机触屏,如图6-4(a)所示。Push成功后,作为RBM的手机将显示刚刚输入的信息,如图6-4(b)和图6-5(a)所示。点击RBM端接收到的URI链接信息,此时将实现跳转。当用户手机中存在多个可以打开URI链接的APP时,系统会提示用户进行选择,如图6-5(b)所示。若用户手机只有唯一一个能打开URI链接的APP,将直接进行跳转,跳转的结果如图6-5(c)所示。

e3a6a67a04e8763bc026f99859e36ebaa477e054

54310d853670816f20060a7e1a893dccdb7b978d

6.3.2 实例2:使用setNdefPushMessage实现Android Beam

在Android NFC P2P实例2中,本书对setNdefPushMessage ( )方法实现Android Beam功能进行了实例描述。该实例包括消息发送端和接收端两部分,既可以完成NDEF消息的Push,又可以完成NDEF的获取。详细代码如下。

(1)BNM部分主要包括两个步骤,分别为:

① 创建NDEF消息;

② 在需要的地方调用setNdefPushMessage( )方法。

(2)RBM部分主要包括两个步骤,分别为:

① 在Activity中重载onNewIntent(Intent intent),并在其中做setIntent(intent);

② 在Activity中重载onResume(),在其中做消息判别;

③ 当消息判别为需要的Beam时,处理接收的数据。

具体参见实例代码中对应的注释,详细代码如下阐述。

主程序P2PDemo2.java文件代码如下:

1. package skyseraph.nfc_demo.p2p.beam.app;   //声明包2. import java.nio.charset.Charset;   //导入相关类3. ……//该处省略了导入相关类的代码4. public class P2PDemo2 extends Activity5. {6.  private static final String Tag_ASSIST = "[P2PDemo2]-";7.  private Context mContext = null;8.  // UI相关9.  private TextView mTextView = null;10.  private EditText mEditText = null;11.  private Button mButton = null;12.  private String inputText = null;13.  // NFC相关14.  private NfcAdapter mNfcAdapter = null;15. 16.  @Override17.  protected void onCreate(Bundle savedInstanceState)18.  {19.   // TODO Auto-generated method stub20.   super.onCreate(savedInstanceState);21.   setContentView(R.layout.p2p_demo2);22.   mContext = this;23.   LogUtil.i(MyConstant.Tag, Tag_ASSIST + "into onCreate");24.   initUI();25.   checkNFCFunction();26.   initFunction();27.  }28. 29.  private void initUI()30.  {31.   // TODO Auto-generated method stub32.   mTextView = (TextView) this.findViewById(R.id.p2p_demo2_tv);33.   mEditText = (EditText) this.findViewById(R.id.p2p_demo2_et);34.   mButton = (Button) this.findViewById(R.id.p2p_demo2_btn);35.  }36. 37.  private void initFunction()38.  {39.   // TODO Auto-generated method stub40.   mButton.setOnClickListener(new OnClickListener()41.   {42.    @Override43.    public void onClick(View v)44.    {45.     // TODO Auto-generated method stub46.     // BNM步骤1: Create NDEF Msg47.     // get the input message your want to push48.     getInputMessage();49.     if (inputText == null || inputText.isEmpty())50.     {51.      inputText = "This is an RTD_TEXT from P2PDemo2";52.      LogUtil.w(MyConstant.Tag, Tag_ASSIST + "inputText is null");53.     }54.     // change the message to NDEF to Push55.     NdefMessage message = BobNdefMessage.getNdefMsg_from_RTD_        TEXT(inputText, false, false);56. 57.     // BNM步骤2:call setNdefPushMessage anywhere your want58.     mNfcAdapter.setNdefPushMessage(message, P2PDemo2.this);59.     Toast.makeText(mContext, "Touch another mobile to share the        message:" + inputText, Toast.LENGTH_SHORT)60.       .show();61.    }62.   });63.  }64. 65.  /**66.   * getInputMessage()67.   */68.  private void getInputMessage()69.  {70.   // TODO Auto-generated method stub71.   inputText = mEditText.getText().toString();72.  }73.  74.  @Override75.  protected void onResume()76.  {77.   // TODO Auto-generated method stub78.   super.onResume();79.   LogUtil.i(MyConstant.Tag, Tag_ASSIST + "into onResume");80.   // RBM步骤2:消息判别81.   if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(getIntent().getAction()))82.   {83.    // RBM步骤3:处理接收的消息/数据84.    resolveIntent(getIntent());85.   }86.  }87. 88.  // RBM步骤1:onNewIntent setIntent(intent);89.  @Override90.  protected void onNewIntent(Intent intent)91.  {92.   // TODO Auto-generated method stub93.   // super.onNewIntent(intent);94.   LogUtil.i(MyConstant.Tag, Tag_ASSIST + "into onNewIntent");95.   setIntent(intent);96.  }97. 98.  /**99.   * RBM步骤3:处理接收的数据* 100.   * @param intent101.   */102.  void resolveIntent(Intent intent)103.  {104.   // Android NFC P2P实例1中的resolveIntent(Intent intent)函数,该处省略105.  }106. 107.  /**108.   * 获取NdefMessage109.   * 110.   * @param messages111.   */112.  void processNDEFMsg(NdefMessage[] messages)113.  {114.   LogUtil.i(MyConstant.Tag, Tag_ASSIST + "into processNDEFMsg");115.   if (messages == null || messages.length == 0)116.   {117.    LogUtil.e(MyConstant.Tag, Tag_ASSIST + "NdefMessage is null");118.    return;119.   }120.   for (int i = 0; i < messages.length; i++)121.   {122.    int length = messages[i].getRecords().length;123.    LogUtil.i(MyConstant.Tag, Tag_ASSIST + "Message " + (i + 1) + ","       + "length=" + length);124.    NdefRecord[] records = messages[i].getRecords();125.    for (int j = 0; j < length; j++) // 几个记录126.    {127.     for (NdefRecord record : records)128.     {129.      if (isTextRecord(record))130.      {131.       parseRTD_TEXTRecord(record);132.      }133.     }134.    }135.   }136.  }137. 138.  /**139.   * @param record140.   * @return141.   */142.  public static boolean isTextRecord(NdefRecord record)143.  {144.   if (record.getTnf() == NdefRecord.TNF_WELL_KNOWN)145.   {146.    if (Arrays.equals(record.getType(), NdefRecord.RTD_TEXT))147.    {148.     return true;149.    } else150.    {151.     return false;152.    }153.   } else154.   {155.    return false;156.   }157.  }158. 159.  160.  /**161.   * @param record162.   *            payload[0] contains the "Status Byte Encodings" field, per the163.   *            NFC Forum "Text Record Type Definition" section 3.2.1.164.   * 165.   *            bit7 is the Text Encoding Field.166.   * 167.   *            if (Bit_7 == 0): The text is encoded in UTF-8 if (Bit_7 == 1):168.   *            The text is encoded in UTF16169.   * 170.   *            Bit_6 is reserved for future use and must be set to zero.171.   * 172.   *            Bits 5 to 0 are the length of the IANA language code.173.   */174.  void parseRTD_TEXTRecord(NdefRecord record)175.  {176.   LogUtil.i(MyConstant.Tag, Tag_ASSIST + "into parseRTD_TEXTRecord");177.   // 记录格式验证178.   Preconditions.checkArgument(record.getTnf() == NdefRecord.TNF_WELL_KNOWN);179.   // 记录类型验证180.   Preconditions.checkArgument(Arrays.equals(record.getType(), NdefRecord.          RTD_TEXT));    181. 182.   String payloadStr = "";183.   byte[] payload = record.getPayload(); // 获取记录payload内容184.   Byte statusByte = record.getPayload()[0];// 获取记录payload第1个字节185. 186.   String textEncoding = ((statusByte & 0200) == 0) ? "UTF-8" : "UTF-16";     // 0x80=0200 ,获取状态字节编码187.   LogUtil.i(MyConstant.Tag, Tag_ASSIST + "textEncoding = " + textEncoding);188.   int languageCodeLength = statusByte & 0077; // & 0x3F=0077(bit 5 to 0)189.              // 获取语言码长度190.   String languageCode = new String(payload, 1, languageCodeLength,      Charset.forName("UTF-8")); // 获取语言码191.   LogUtil.i(MyConstant.Tag, Tag_ASSIST + "languageCodeLength = " +      languageCodeLength + ",languageCode = "+ languageCode);192.     193.   try194.   {195.    payloadStr = new String(payload, languageCodeLength + 1, payload.       length - languageCodeLength - 1, textEncoding); // 获取payload实际数据196.      197.   } catch (UnsupportedEncodingException e)198.   {199.    // TODO Auto-generated catch block200.    e.printStackTrace();// 异常信息201.   }202. 203.   LogUtil.i(MyConstant.Tag, Tag_ASSIST + "the Record Tnf: " + record.getTnf()+      "\n");// 1204.                        // ,状态字节编码信息205.   LogUtil.i(MyConstant.Tag, Tag_ASSIST + "the Record type: " + new String      (record.getType()) + "\n");// T,语言码信息206.   LogUtil.i(MyConstant.Tag, Tag_ASSIST + "the Record id: " + new String      (record.getId()) + "\n");// 记录ID信息207.   LogUtil.i(MyConstant.Tag, Tag_ASSIST + "the Record payload: " + payloadStr      + "\n");// 解析获取到的payload实际数据208.   mTextView.setText("New Msg Rev(Text): " + payloadStr);209.  }210. 211.  /**212.   * NFC Function Check By skyseraph 2013-2213.   */214.  private void checkNFCFunction()215.  {216.   // Android NFC P2P实例1中的checkNFCFunction ()函数,该处省略217.  }218. 219.  /**220.   * @param dialog221.   * @return222.   */223.  private Dialog SetDialogWidth(Dialog dialog)224.  {225.   // Android NFC P2P实例1中的SetDialogWidth ()函数,该处省略226.  }227. }

第24行为UI初始化阶段,主要通过findViewById完成UI控件的初始化(第29~35行)。

第25行为实现NFC功能的检测,在使用Android Beam功能前需要确保设备支持NFC功能、NFC功能可用,且Android Beam功能是enable。具体可通过isEnabled() 和 isNdefPushEnabled()函数实现,参考代码第211~217行checkNFCFunction()函数。
第26行为调用按钮控件事件响应函数,函数中完成按钮控件的事件监听(第37~63行)。
第46~55行为BNM步骤1阶段,即创建NDEF消息阶段。创建消息前先通过第65~72行的getInputMessage()函数获取来自编辑框用户输入的待Beam to Share的信息。如果用户未输入,程序会自动添加一个默认值(第49~53行),得到需要用户待Beam的信息后,再调用getNdefMsg_from_RTD_TEXT(String RTD_TEXT, boolean encodeInUtf8, boolean flagAddAAR)方法(第55行)生成RTD-Text类型的NDEF消息。关于BobNdefMessage类可参考第5章。
第58行为BNM步骤2阶段,即调用setNdefPushMessage (message, P2PDemo2.this),在该函数中静态的传入需要Beam的NDEF消息。
第88~96行为RBM步骤1阶段,即在Activity中重载onNewIntent(Intent intent),并在其中做setIntent(intent)。
第74~86行为RBM步骤2阶段,即在Activity中重载onResume(),并在其中做消息判别。
第84行为RBM步骤3阶段,即当消息判别为需要的Beam时,调用resolveIntent(Intent intent)函数处理接收的数据,resolveIntent(Intent intent)函数可参考第98~105行所示。
第98~105行为resolveIntent(Intent intent)函数。该函数与Android NFC P2P实例1中的resolveIntent(Intent intent)函数相同,具体可参考对应内容。
第107~136行为处理resolveIntent(Intent intent)中得到的NdefMessage[]消息的函数。其中,首先检测NdefMessage[]消息是否为空,然后再依次处理每个消息(第120行)和每个消息中的每个记录(第125~128行)。第129行调用的isTextRecord(record)函数主要完成判别当前记录是否为Text类型,具体见第138~157行所述,然后在第131行调用的parseRTD_TEXTRecord(record)函数来解析获取的消息记录,具体见第160~209行所述。
第138~157行为isTextRecord(NdefRecord record)函数,完成判别当前记录是否为Text类型。当为Text类型时,返回true,反之返回false。其中,记录格式和类型的分别获取通过record.getTnf()和record.getType()得到。
第160~209行为parseRTD_TEXTRecord(NdefRecord record)函数,完成对当前获取的记录进行解析得到最终的数据(Payload)。详细的解析过程参考代码中的注释信息,同时参考NFC论坛定义URI相关协议(在第5章已描述,此处省略)。
BobNdefMessage为自定义NdefMessage辅助类,具体代码可参考第5章的5.3.2节,此处省略。

LogUtil为自定义调试类,主要是为方便APP在发布正式版本时一次性关闭所有调试Log信息。具体代码可参考第5章的5.2.2节,此处省略。

MyConstant为自定义常量类,具体代码可参考第5章的5.2.2节,此处省略。

布局文件p2p_demo2.xml中包含了一个按钮控件、一个输入编辑框控件和一个文本控件,并修改了相关属性,代码如下:

1.  
2.
6. 7.
13. 14.
22.
23. 24. 25.
32. 33.

第7~12行为文本控件,主要显示需要Beam的数据以及接收到的Beam数据。

第14~23行为编辑框控件,作为Beam to Share文本的输入。
第25~31行为按钮控件,按住开始Beam数据。
AndroidManifest.xml中声明Activity,并添加NFC权限,其代码如下:
``

  1. android:name="skyseraph.nfc_demo.p2p.beam.app.P2PDemo2"
  2. android:label="NFC_Demo_P2P-2" >
  3. ``

第1行为APP添加NFC权限。

第10~15行增加一个RTD-Text过滤器,以便能够接受任何来自其他NFC设备的Text数据。
Beam文件传输实例1的具体效果如图6-6~图6-8所示。其中,图6-8所示为两台准备了Beam的手机。打开本实例APP,其中要作为BNM端的手机中输入待前台Push的消息,点击NDEF Msg Push By setNdefPushMessage按钮,如图6-7(a)所示,然后将两台手机触屏,如图6.7(b)所示。同时触摸BNM实现发送,如图6.7(c)所示。Push成功后,作为RBM的手机将显示你刚刚输入的信息,如图6-8所示。

44e0b00ccf21ff7fcc7b9ba752695901e8758e1c

397b74e036bafd39b75452cffeacb63b443135b3

e485bc101890eee53a6c0887df0442eaefd13d1d

6.3.3 实例3:使用enableForegroundNdefPush实现Android Beam

在Android NFC P2P实例3中,本书对enableForegroundNdef Push( )方法实现Android Beam功能进行了实例描述。该实例包括消息发送端和接收端两部分,既可以完成NDEF消息的Push,又可以完成NDEF的获取,详细代码如下。

主程序P2PDemo3.java文件代码如下:

``

  1. package skyseraph.nfc_demo.p2p.beam.app; //声明包
  2. import java.nio.charset.Charset; //导入相关类
  3. ……//该处省略了导入相关类的代码
  4. public class P2PDemo3 extends Activity
  5. {
  6. private static final String Tag_ASSIST = "[P2PDemo3]-";
  7. private Context mContext = null;
  8. // UI相关
  9. private TextView mTextView = null;
  10. private EditText mEditText = null;
  11. private Button mButton = null;
  12. private String inputText = null;
  13. // NFC相关
  14. private NfcAdapter mNfcAdapter = null;
  15. @Override
  16. protected void onCreate(Bundle savedInstanceState)
  17. {
  18. // TODO Auto-generated method stub
  19. super.onCreate(savedInstanceState);
  20. setContentView(R.layout.p2p_demo3);
  21. mContext = this;
  22. LogUtil.i(MyConstant.Tag, Tag_ASSIST + "into onCreate");
  23. initUI();
  24. checkNFCFunction();
  25. initFunction();
  26. }
  27. private void initUI()
  28. {
  29. // TODO Auto-generated method stub
  30. mTextView = (TextView) findViewById(R.id.p2p_demo3_tv);
  31. mEditText = (EditText) findViewById(R.id.p2p_demo3_et);
  32. mButton = (Button) findViewById(R.id.p2p_demo3_bt);
  33. }
  34. private void initFunction()
  35. {
  36. // TODO Auto-generated method stub
  37. mButton.setOnClickListener(new OnClickListener()
  38. {
  39. @Override
  40. public void onClick(View v)
  41. {
  42. // TODO Auto-generated method stub
  43. // BNM步骤1:准备NDEF数据
  44. // get the input message your want to push
  45. getInputMessage();
  46. if (inputText == null || inputText.isEmpty())
  47. {
  48. inputText = "This is an RTD_TEXT from P2PDemo3";
  49. LogUtil.w(MyConstant.Tag, Tag_ASSIST + "inputText is null");
  50. }
  51. // change the message to NDEF to Push
  52. mNdefMessage = BobNdefMessage.getNdefMsg_from_RTD_TEXT(input
    Text,false,false);
  53. // BNM步骤2:enableForegroundNdefPush
  54. if (null != mNdefMessage)
  55. {
  56. mNfcAdapter.enableForegroundNdefPush(P2PDemo3.this,
    mNdefMessage);
  57. Toast.makeText(P2PDemo3.this, "Touch another NFC device
    to share this message", Toast.LENGTH_SHORT).show();
  58. }
  59. }
  60. });
  61. }
  62. /**
    • getInputMessage()
  63. */
  64. private void getInputMessage()
  65. {
  66. // TODO Auto-generated method stub
  67. inputText = mEditText.getText().toString();
  68. }
  69. @Override
  70. protected void onResume()
  71. {
  72. // TODO Auto-generated method stub
  73. super.onResume();
  74. // RBM步骤2:消息判别
  75. if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(getIntent().getAction()))
  76. {
  77. resolveIntent(getIntent());
  78. } else
  79. {
  80. // BNM步骤4:enableForegroundNdefPush
  81. mNfcAdapter.enableForegroundNdefPush(this, BobNdefMessage.getNdef
    Msg_from_RTD_TEXT("",false,false));
  82. }
  83. }
  84. @Override
  85. protected void onPause()
  86. {
  87. // TODO Auto-generated method stub
  88. super.onPause();
  89. // BNM步骤3:disableForegroundNdefPush
  90. if (null != mNfcAdapter)
  91. mNfcAdapter.disableForegroundNdefPush(this);
  92. }
  93. // RBM步骤1:onNewIntent setIntent(intent);
  94. @Override
  95. protected void onNewIntent(Intent intent)
  96. {
  97. // TODO Auto-generated method stub
  98. // super.onNewIntent(intent);
  99. setIntent(intent);
  100. }
  101. /**
    • RBM步骤3:处理接收的数据*
    • @param intent
  102. */
  103. void resolveIntent(Intent intent)
  104. {
  105. // Android NFC P2P实例1中的resolveIntent(Intent intent)函数,该处省略
  106. }
  107. /**
    • 获取NdefMessage
    • @param messages
  108. */
  109. void processNDEFMsg(NdefMessage[] messages)
  110. {
  111. // Android NFC P2P实例2中的processNDEFMsg (NdefMessage[] messages)函数,该处省略
  112. }
  113. /**
    • @param record
    • @return
  114. */
  115. public static boolean isTextRecord(NdefRecord record)
  116. {
  117. // Android NFC P2P实例2中的isTextRecord (NdefRecord record)函数,该处省略
  118. }
  119. /**
    • @param record,另一种方法
  120. */void parseRTD_TEXTRecord(NdefRecord record)
  121. {
  122. LogUtil.i(MyConstant.Tag, Tag_ASSIST + "into parseRTD_TEXTRecord2");
  123. String payload = "";
  124. String recordType = new String(record.getType()); // Byte to
  125. // String
  126. LogUtil.i(MyConstant.Tag, Tag_ASSIST + "recordType:" + recordType); // String
  127. // compare!
  128. if (!recordType.equals("T"))
  129. {
  130. LogUtil.e(MyConstant.Tag, Tag_ASSIST + "not RTD-Text,return!");
  131. return;
  132. }
  133. Byte statusByte = record.getPayload()[0];
  134. int languageCodeLength = statusByte & 0x3F;
  135. LogUtil.i(MyConstant.Tag, Tag_ASSIST + "Language Code Length:" + language
    CodeLength + "n");// 2
  136. String languageCode = new String(record.getPayload(), 1, languageCode
    Length, Charset.forName("UTF-8"));
  137. LogUtil.i(MyConstant.Tag, Tag_ASSIST + "Language Code:" + languageCode

    • "n"); // en
  138. int isUTF8 = statusByte - languageCodeLength;
  139. if (isUTF8 == 0x00)
  140. {
  141. LogUtil.i(MyConstant.Tag, Tag_ASSIST + "the Record is UTF-8n");//
  142. payload = new String(record.getPayload(), 1 + languageCodeLength,
    record.getPayload().length - 1
    • languageCodeLength, Charset.forName("UTF-8"));
  143. } else if (isUTF8 == -0x80)
  144. {
  145. LogUtil.i(MyConstant.Tag, Tag_ASSIST + "the Record is UTF-16n");
  146. payload = new String(record.getPayload(), 1 + languageCodeLength,
    record.getPayload().length - 1
    • languageCodeLength, Charset.forName("UTF-16"));
  147. }
  148. LogUtil.i(MyConstant.Tag, Tag_ASSIST + "the Record Tnf: " + record.getTnf()+
    "n");// 1
  149. LogUtil.i(MyConstant.Tag, Tag_ASSIST + "the Record type: " + new String
    (record.getType()) + "n");// T
  150. LogUtil.i(MyConstant.Tag, Tag_ASSIST + "the Record id: " + new String
    (record.getId()) + "n");
  151. LogUtil.i(MyConstant.Tag, Tag_ASSIST + "the Record payload: " + payload

    • "n");
  152. mTextView.setText("New Msg Rev(Text): " + payload);
  153. }
  154. /**
    • NFC Function Check By skyseraph 2013-2
  155. */
  156. private void checkNFCFunction()
  157. {
  158. // Android NFC P2P实例1中的checkNFCFunction ()函数,该处省略
  159. }
  160. /**
    • @param dialog
    • @return
  161. */
  162. private Dialog SetDialogWidth(Dialog dialog)
  163. {
  164. // Android NFC P2P实例1中的SetDialogWidth ()函数,该处省略
  165. }
  166. }
    ``

第24行为UI初始化阶段,主要通过findViewById完成UI控件的初始化(第29~35行)。

第25行为实现NFC功能的检测,在使用Android Beam功能前需要确保设备支持NFC功能、NFC功能可用,且Android Beam功能是enable。具体可通过isEnabled() 和 isNdefPushEnabled()函数实现,参考代码第174~180行checkNFCFunction()函数。
第26行为调用按钮控件事件响应函数,函数中完成按钮控件的事件监听(第36~64行)。
第46~54行为BNM步骤1阶段,即准备NDEF消息阶段。创建NDEF消息前先通过第65~72行的getInputMessage()函数获取来自编辑框用户输入的待Beam to Share的信息。如果用户未输入,程序会自动添加一个默认值(第48~52行),得到需要用户待Beam的信息后,再调用getNdefMsg_from_RTD_TEXT(String RTD_TEXT, boolean encodeInUtf8, boolean flagAddAAR)方法(第54行),生成RTD-Text类型的NDEF消息。关于BobNdefMessage类可参考第5章的5.3.2节。
第58行为BNM步骤2阶段,即调用enableForegroundNdefPush (P2PDemo3.this, mNdefMessage),在该函数中的传入需要Push的NDEF消息。该方法创建后,message处于挂起状态,一旦系统检测到RBM设备,该message就会通过Beam传输给接收端。
第90~98行为BNM步骤3阶段,即在onPause( )方法中,调用disableForegroundNdef Push(this)方法。由于这是一种前台推送方法,因此,一旦Activity不出于前台,就需要Foreground NDEF Push立即停止。
第85~86行为BNM步骤4阶段,即在onResume ( )方法中,调用enableForegroundNdefPush (this)方法。当应用再次处于前台时,可以通过该方法首次或再次启用Foreground NDEF Push推送。
第100~107行为RBM步骤1阶段,即在Activity中重载onNewIntent(Intent intent),并在其中做setIntent(intent)。
第80行为RBM步骤2阶段,即在Activity中重载onResume(),并在其中做消息判别。
第82行为RBM步骤3阶段,即当消息判别为需要的Beam时,调用resolveIntent(Intent intent)函数处理接收的数据。关于resolveIntent(Intent intent)函数可参考第108~115行所示。
第108~115行为resolveIntent(Intent intent)函数。该函数与Android NFC P2P实例1中的resolveIntent(Intent intent)函数相同,具体可参考对应内容。
第122~125行为处理resolveIntent(Intent intent)中得到的NdefMessage[]消息的函数。该函数与Android NFC P2P实例2中的processNDEFMsg (NdefMessage[] messages)函数相同,具体可参考对应内容。
第131~134行为isTextRecord(NdefRecord record)函数,完成判别当前记录是否为Text类型。该函数与Android NFC P2P实例2中的isTextRecord (NdefRecord record)函数相同,具体可参考对应内容。
第138~173行为parseRTD_TEXTRecord(NdefRecord record)函数,完成对当前获取的记录进行解析得到最终的数据(Payload)。详细的解析过程参考代码中的注释信息,同时参考NFC论坛定义URI相关协议(在第5章已描述,此处省略)。
BobNdefMessage为自定义NdefMessage辅助类,具体代码可参考第5章的5.3.2节,此处省略。

LogUtil为自定义调试类,主要是为方便APP在发布正式版本时一次性关闭所有调试Log信息,具体代码可参考第5章的5.2.2节,此处省略。

MyConstant为自定义常量类,具体代码可参考第5章的5.2.2节,此处省略。

布局文件p2p_demo3.xml中包含了一个按钮控件、一个输入编辑框控件和一个文本控件,并修改了相关属性,代码如下:

``

  1. <?xml version="1.0" encoding="utf-8"?>
  2. android:layout_width="fill_parent"
  3. android:layout_height="fill_parent"
  4. android:orientation="vertical" >
  5. android:id="@+id/p2p_demo3_tv"
  6. android:layout_width="match_parent"
  7. android:layout_height="wrap_content"
  8. android:paddingTop="20dp" />
  9. android:id="@+id/p2p_demo3_et"
  10. android:layout_width="match_parent"
  11. android:layout_height="wrap_content"
  12. android:ems="12"
  13. android:inputType="text"
  14. android:paddingTop="20dp" >
  15. android:id="@+id/p2p_demo3_bt"
  16. android:layout_width="wrap_content"
  17. android:layout_height="wrap_content"
  18. android:layout_gravity="center"
  19. android:paddingTop="20dp"
  20. android:text="Foreground NDEF Msg Push" />
  21. 第7~11行为文本控件,主要显示需要Push NDEF的数据以及接收到的Push数据。

第13~21行为编辑框控件,作为Foreground NDEF Push文本的输入。

第23~30行为按钮控件,按住开始Push NDEF数据。
AndroidManifest.xml中声明Activity,并添加NFC权限,其代码如下:

  1. android:name="skyseraph.nfc_demo.p2p.beam.app.P2PDemo3"
  2. android:label="NFC_Demo_P2P-3" >
第1行为APP添加NFC权限。第10~15行增加一个RTD-Text过滤器,以便能够接受任何来自其他NFC设备Text数据。Beam文件传输实例1的具体效果如图6.9~图6.11所示。其中,图6.9所示为两台准备了Beam的手机。打开本实例APP,其中,要作为BNM端的手机中输入待前台Push的消息,点击Foreground NDEF Msg Push按钮,如图6.10(a)所示。然后将两台手机触屏如图6.10(b)所示。Push成功后,作为RBM的手机将显示刚刚输入的信息,如图6.11所示。
**6.3.4 实例4:结合AAR实现Android Beam**在第4章中详细介绍了AAR相关知识。Android NFC P2P实例4 中结合了AAR和 setNdefPush MessageCallback(Android NFC P2P实例1)来实现Android Beam,同时还增加了对BNM后的结果进行了处理。主要代码与实例1相似,详细代码如下:
  1. package skyseraph.nfc_demo.p2p.beam.app; //声明包
  2. import java.nio.charset.Charset; //导入相关类
  3. ……//该处省略了导入相关类的代码
  4. public class P2PDemo4 extends Activity implements CreateNdefMessageCallback,
    OnNdefPushCompleteCallback
  5. { // BNM步骤1:在你的Activity中实现CreateNdefMessageCallback接口(implements)
  6. private static final String Tag_ASSIST = "[P2PDemo4]-";
  7. private Context mContext = null;
  8. // UI相关
  9. private TextView mTextView = null;
  10. // NFC相关
  11. private NfcAdapter mNfcAdapter = null;
  12. private static final int MESSAGE_SENT = 1;
  13. @Override
  14. protected void onCreate(Bundle savedInstanceState)
  15. {
  16. // TODO Auto-generated method stub
  17. super.onCreate(savedInstanceState);
  18. setContentView(R.layout.p2p_demo4);
  19. mContext = this;
  20. LogUtil.i(MyConstant.Tag, Tag_ASSIST + "into onCreate");
  21. mTextView = (TextView) this.findViewById(R.id.p2p_demo4_tv);
  22. checkNFCFunction();
  23. mTextView
  24. .setText("Touch another mobile to Beam '
    com/skyseraph/' or to Rev the beam msg with AAR");
  25. // BNM步骤2: call setNdefPushMessageCallback anywhere your want
  26. mNfcAdapter.setNdefPushMessageCallback(this, this);// Register callback
    to set NDEF message
  27. // BNM步骤4:获取Beam发送状态
  28. mNfcAdapter.setOnNdefPushCompleteCallback(this, this);// Register callback
    to listen for message-sent success
  29. }
  30. /*
    • (non-Javadoc)
    • @see
    • android.nfc.NfcAdapter.OnNdefPushCompleteCallback#onNdefPushComplete(
    • android.nfc.NfcEvent)
  31. */
  32. // BNM步骤4:获取Beam发送状态(API 14)
  33. @Override
  34. public void onNdefPushComplete(NfcEvent event)
  35. {
  36. // TODO Auto-generated method stub
  37. LogUtil.w(MyConstant.Tag, Tag_ASSIST + "into onNdefPushComplete");
  38. mHandler.obtainMessage(MESSAGE_SENT).sendToTarget();
  39. }
  40. /*
    • (non-Javadoc)
    • @see
    • android.nfc.NfcAdapter.CreateNdefMessageCallback#createNdefMessage(android
    • .nfc.NfcEvent)
  41. */
  42. // BNM步骤3:回调函数中实现Beam Data。
  43. // 当发现有支持Beam的手机时,该回调接口会自动激活,你只需将你需要Beam的NDEF消息准备好
    // 并作为NdefMessage返回即可。
  44. // 本例中以RTD_URI为例。
  45. @Override
  46. public NdefMessage createNdefMessage(NfcEvent event)
  47. {
  48. // TODO Auto-generated method stub
  49. LogUtil.i(MyConstant.Tag, Tag_ASSIST + "into createNdefMessage");
  50. String uriFiledStr = "cnblogs.com/skyseraph/";
  51. Byte identifierCode = 0x01;
  52. NdefMessage message = BobNdefMessage.getNdefMsg_from_RTD_URI(uriFiled
    Str, identifierCode, true);// AAR设置为true
  53. return message;
  54. }
  55. @Override
  56. protected void onResume()
  57. {
  58. // Android NFC P2P实例1中的onResume()函数,该处省略
  59. }
  60. // RBM步骤1:onNewIntent setIntent(intent);
  61. @Override
  62. protected void onNewIntent(Intent intent)
  63. {
  64. // Android NFC P2P实例1中的onNewIntent(Intent intent)函数,该处省略
  65. }
  66. /**
    • RBM步骤3:处理接收的数据
    • @param intent
  67. */
  68. void resolveIntent(Intent intent)
  69. {
  70. // Android NFC P2P实例1中的resolveIntent(Intent intent)函数,该处省略
  71. }
  72. /**
    • 获取NdefMessage
    • @param messages
  73. */
  74. void processNDEFMsg(NdefMessage[] messages)
  75. {
  76. // Android NFC P2P实例1中的processNDEFMsg(NdefMessage[] messages)函数,该处省略
  77. }
  78. /**
    • 解析NdefMessage
    • @param record
  79. */
  80. private void parseUriRecord(NdefRecord record)
  81. {
  82. // Android NFC P2P实例1中的parseUriRecord(NdefRecord record)函数,该处省略
  83. }
  84. private void parseAbsoluteUriRecord(NdefRecord record)
  85. {
  86. // Android NFC P2P实例1中的parseAbsoluteUriRecord(NdefRecord record)函数,该处省略
  87. }
  88. /**
    • @param record
    • payload[0] contains the URI Identifier Code, per the NFC Forum
    • "URI Record Type Definition" section 3.2.2.
    • payload[1]...payload[payload.length - 1] contains the rest of
    • the URI.
  89. */
  90. private void parseWellKnownUriRecord(NdefRecord record)
  91. {
  92. // Android NFC P2P实例1中的parseWellKnownUriRecord(NdefRecord record)函数,该处省略
  93. }
  94. /**
    • UI操控
    • @param uri
  95. */
  96. private void uiControl(final Uri uri)
  97. {
  98. // Android NFC P2P实例1中的uiControl(final Uri uri)函数,该处省略
  99. }
  100. /**
    • @param record
    • @return
  101. */
  102. public static boolean isUri(NdefRecord record)
  103. {
  104. // Android NFC P2P实例1中的isUri(NdefRecord record)函数,该处省略 }
  105. /**
    • NFC Forum "URI Record Type Definition"
    • This is a mapping of "URI Identifier Codes" to URI string prefixes, per
    • section 3.2.2 of the NFC Forum URI Record Type Definition document.
  106. */
  107. private static final BiMap URI_PREFIX_MAP = ImmutableBiMap. String> builder()
  108. // Android NFC P2P实例1中的URI_PREFIX_MAP,该处省略
  109. /**
    • This handler receives a message from onNdefPushComplete
  110. */
  111. private final Handler mHandler = new Handler()
  112. {
  113. @Override
  114. public void handleMessage(Message msg)
  115. {
  116. switch (msg.what)
  117. {
  118. case MESSAGE_SENT:
  119. Toast.makeText(getApplicationContext(), "Message sent!",
    Toast.LENGTH_LONG).show();
  120. break;
  121. }
  122. }
  123. };
  124. /**
    • NFC Function Check By skyseraph 2013-2
  125. */
  126. private void checkNFCFunction()
  127. {
  128. // Android NFC P2P实例1中的checkNFCFunction()函数,该处省略
  129. }
  130. /**
    • @param dialog
    • @return
  131. */
  132. private Dialog SetDialogWidth(Dialog dialog)
  133. {
  134. // Android NFC P2P实例1中的SetDialogWidth ()函数,该处省略
  135. }
  136. }
第4行为BNM步骤1阶段,即实现CreateNdefMessageCallback接口。实现该接口后,该Activity中需重载createNdefMessage (NfcEvent event)函数,在该函数中返回需要的Beam数据。第23行为实现NFC功能的检测,在使用Android Beam功能前需要确保设备支持NFC功能、NFC功能可用,且Android Beam功能是enable。具体可通过isEnabled() 和 isNdefPushEnabled()函数实现,参考代码第180~183行checkNFCFunction()函数。第28行为BNM步骤2阶段,即调用setNdefPushMessageCallback(this, this)。实现该接口后,当发现有其他设备的Beam数据,该Activity中会接收一个回调,createNdefMessage (NfcEvent event)函数会自动激活。第61~69行为BNM步骤3阶段,即在回调函数createNdefMessage (NfcEvent event)中实现Beam Data。在createNdefMessage (NfcEvent event)函数中,其通过调用setNdefPushMessageCallback (this, this) 后自动激活,其中,可以创建自己需要的NDEF消息并将其返回。第67行为通过调用BobNdefMessage.getNdefMsg_from_RTD_URI(String uriFiledStr, byte identifierCode, boolean flagAddAAR)方法生成RTD-URI类型的NDEF消息,也可以创建其他类型的NDEF消息。关于BobNdefMessage类可参考第5章的5.3.2节。其中,此处flagAddAAR参数为true,表示增加AAR。第31行为BNM步骤4阶段,即调用setOnNdefPushCompleteCallback(this, this)。实现该接口后,当成功将消息Beam to其他设备后,该Activity中会接收一个回调,onNdefPushComplete (NfcEvent event)函数会自动激活。第79~82行为onNdefPushComplete(NfcEvent event)回调函数。在该函数里,以消息发送的机制处理Beam数据推送成功后的操作。第72~75行为RBM步骤1阶段,该函数与Android NFC P2P实例1中的onResume()函数中相同,具体可参考对应内容。第77~82行为RBM步骤2阶段,该函数与Android NFC P2P实例1中的onNewIntent(Intent intent)函数中相同,具体可参考对应内容。第89~95行为RBM步骤3阶段,该函数与Android NFC P2P实例1中的resolveIntent(Intent intent)函数相同,具体可参考对应内容。其他函数与Android NFC P2P实例1中对应的函数相同,此处不再赘述,具体可参考实例1中对应的内容。第163~175行为通过Handler处理接收到的来自onNdef PushComplete(NfcEvent event)发送的消息,此处仅仅是Toast提示(如图6.12所示),读者可以在这里加入自己需要的功能。1.setOnNdefPushCompleteCallback方法的原型public void setOnNdefPushCompleteCallback (NfcAdapter.OnNdef PushCompleteCallback callback, Activity activity, Activity... activities):其中,callback为回调接口;activity为当前调用该方法的activity,即NDEF Push的Activity; activities为附加activity选项,强烈建议该方法在每个activity中只注册一次。
使用setOnNdefPushCompleteCallback()方法时注意以下几点:(1)该方法可以在Activity中任何位置调用(onDestroy()之前)。因为callback只有Activity在前台状态(resume()状态)下才发生,所以Android的官方建议在OnCreate()中调用该方法,同时该方法并不阻塞线程,因此可以在UI主线程中使用。(2)使用该方法时,如果callback为null,则调用该方法的Activity setOnNdefPushComplete Callback功能将会disable。(3)关于该方法的使用,官方提供的使用范例如下(关于更详细的使用方法,读者可以参考实例4中的具体代码)。

protected void onCreate(Bundle savedInstanceState)

{

super.onCreate(savedInstanceState);   NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(this);   if (nfcAdapter == null) return;  // NFC not available on this device  nfcAdapter.setOnNdefPushCompleteCallback(callback, this);

}

(4)使用该方法需要在AndroidManifest.xml中添加NFC权限。(5)使用该方法需要在Android API 14+以上的系统中进行。2.OnNdefPushCompleteCallback方法的原型abstract void onNdefPushComplete(NfcEvent event):其中,event为通过Android Beam发送一个或多个动态生成的Uri(s)的回调接口;activity为当前调用该方法的activity,即push Uri(s)的Activity。使用onNdefPushComplete()方法时应注意以下几点:(1)使用该方法需要在AndroidManifest.xml中添加NFC权限。(2)使用该方法需要在Android API 14+以上的系统中进行。

转载地址:http://ehzeo.baihongyu.com/

你可能感兴趣的文章
quartus ii 中文注释乱码解决办法
查看>>
Linux网卡配置与绑定
查看>>
java学习之路--String类方法的应用
查看>>
auto,register,static分析
查看>>
百度BAE JAVA环境项目部署和调试
查看>>
CSS盒模型
查看>>
Log4Net 添加自定义字段并保存到数据库
查看>>
Redis集群(三)Cluster集群
查看>>
NSURLSession
查看>>
JFinal学习 & Gradle配置续 & Tomcat配置
查看>>
CSS进度条
查看>>
android的color值
查看>>
对于linux下system()函数的深度理解(整理)
查看>>
软件设计和开发准备
查看>>
ROS + Kinect2 跑ORB_SLAM2 安装步骤记录
查看>>
纯CSS实现垂直居中的几种方法
查看>>
win7注册表常用设置
查看>>
amazeui学习笔记--css(常用组件3)--按钮组Button-group
查看>>
Spring简介
查看>>
new Function()
查看>>