关于NFC P2P模式
来源:互联网 发布:农村淘宝 广告 编辑:程序博客网 时间:2024/06/05 09:34
P2P模式是NFC的三种工作模式之一,主要完成在两个NFC设备之间数据的传递,传输的一方同时也可以接收数据。P2P模式是在Android2.3.3+(API 10)中开始加入的,之后在Android4.0+(API 14)后又重新提供了一套新的API函数。
如上所述,在API 10以上的系统开发p2p功能时,Android系统提供两套API函数。在API 10到API 13之间提供的是enableForegroundNdefPush方法,在API 14之后提供的则是setNdefPushMessageCallback方法和setNdefPushMessage方法,本文中主要就是对这两种新的方法的介绍。
一. Android Beam功能
在Android API 14+后,将两个NFC设备之间通过p2p模式传输数据称为Beam,Android Beam功能允许设备把一个NDEF消息推送到物理上相互监听的另一个设备上。这种交互提供了比其他无线技术(如蓝牙)更容易的发送数据的方法。因为 NFC不需要手动的设备发现或配对要求。两个设备在接近到一定范围时会自动的连接。Android Beam通过一组NFC API来使用,以便应用程序能够在设备之间来传输信息。例如,通信录、浏览器以及YouTube等应用程序都使用Android Beam来跟其他设备共享通信录、网页和视频。
在两个NFC设备之间实现Beam功能必须满足以下条件:
1) 两台设备的Android系统设置里的Android beam必须打开;
2) 想要发送数据的应用程序必须是在前台;
3) 接收数据的设备必须不锁屏;
4) 当发射设备跟接收设备的距离足够近的时候,发射设备会显示”Touch to Beam(触摸发射)”的UI。然后,用户能够选择是否把消息发射给接收设备。
利用Android Beam功能,你可以传输NDEF消息给另一台设备。为了传输NDEF消息,必须要生成一个NDEF消息。而且如果发射设备上当前打开的应用程序没有实现Android Beam功能, 系统会自动发送一个默认的包含你这个app的URI的NDEFmessage给接收端。如果目标设备的API level在9到13之间,这台设备会提醒用户该app未打开。如果API level在14之上,设备就会自动跳转到Google Play中这个应用的下载链接页供用户下载。基于这个功能,用户同样可以和其他用户分享app而不需要在谷歌商店中搜索,这个功能适用于API level 14 或更高。
通过调用下列两个方法中的任意一个,就能够为你的应用程序启用Android Beam:
1) setNdefPushMessage():这个方法把接收到的NdefMessage对象作为一个消息 设置给Beam。当两个设备足够近的时候,就会自动的发送消息。
2) setNdefPushMessageCallback():接收包含createNdefMessage()方法的回调, 当设备在发射数据的范围内时,这个回调方法会被调用。回调会让你只在需要的时候创建NDEF消息。
一个Activity一次只能推送一条NDEF消息,因此如果同时使用了这两种方法,那么setNdefPushMessageCallback()方法的优先级要高于setNdefPushMessage()方法。 要使用Android Beam,通常必须满足以下条件:
1) 发射数据的Activity必须是在前台。两个设备的屏幕都必须没有被锁定;
2) 必须要把发射的数据封装到一个NdefMessage对象中;
3) 接收发射数据的NFC设备必须支持Android NDEF推送协议或是NFC论坛的SNEP协议(简单的NDEF交换协议)。在API Level9(Android2.3)到API Level 13(Android3.2)的设备上需要NDEF推送协议。在API Level 14(Android4.0)和以后的设备上NDEF推送协议和SNEP都需要。NDEF Push Protocol 是Android独有的协议,而SNEP是NFC论坛的标准,所以其他操作系统也支持。如果android设备有NFC功能,则两个协议支持。
注意:如果在前台的Activity 启用了Android Beam,那么标准的Intent调度系统就会被禁用,这时Android是不能扫描标签的。但是,如果该Activity还启用了前台调度,那么在前台调度系统中,它依然能够扫描到跟Intent过滤器匹配的NFC标签。
二、 发送数据-setNdefPushMessageCallback()方法
1. 启动Beam,发送NDEF message的步骤:
1) 在你的activity类对象中实现CreateNdefMessageCallback接口;
2) 调用setNdefPushMessageCallback(NfcAdapter.CreateNdefMessageCallback callback, Activity activity, Activity … activities)方法,当这个方法被调用,activity接收到一个回调而且如果一个要传输数据的设备被发现,方法creatNdefMessage(NfcEvent)会被自动调用。
3) 在creatNdefMessage方法中,创建一个NDEF消息并返回这个message。这个NDEF message会被传输到目标设备上。
setNdefPushMessageCallback()方法动态的生成NDEF消息。你可以在activity中的任意地方调用这个方法。当然最好是在activity中的onCreate方法中调用它。
当目标设备被发现后,creatNdefMessage方法会被调用,它会返回一个NDEF消息。而这个NDEF消息会被传输给目标设备。在这期间,Touch to Beam的UI会显示在你的activity之上,所以在这个方法中你不能得到任意用户的输入。因此只能生成你想要传输的NDEF消息,然后返回这个消息。
三、 发送数据-setNdefPushMessage()方法
1. 启动Beam,发送NDEF message的步骤:
1) 创建一个NDEF消息;
2) 调用setNdefPushMessage (NdefMessage message, Activity activity, Activity … activities)方法。当这个方法被调用时,activity会将接收到的NdefMessage参数作为一个NDEF消息发送出去。
其中,第2步中,setNdefPushMessage()中的NDEF消息的生成是静态的,即由用户选择生成然后作为参数进行传递。
四、 接收数据
两个NFC设备之间通过Beam实现数据传递时,数据接受端即接受Beam消息端。接受Beam消息的实现步骤如下:
1.在你的activity中实现onNewIntent(Intent)方法,该方法会调用setIntent(Intent),由Android生命周期描述可知,在调用onNewIntent方法后,onResume()方法会自动调用。
2.在activity的onResume()方法中,检测当前消息是否来自Beam,如果是,获取并处理该NDEF消息。
3.调用自己定义的消息解析函数,将获取的NDEF消息解析并获取Payload,再对Payload进行进一步UI操作。
代码如下
<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.nfcdemo" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="14" android:targetSdkVersion="21" /> <uses-permission android:name="android.permission.NFC" /> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name=".MainActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> <intent-filter> <action android:name="android.nfc.action.NDEF_DISCOVERED" /> <category android:name="android.intent.category.DEFAULT" /> <data android:host="*" android:pathPrefix="" android:scheme="http" /> </intent-filter> </activity> </application></manifest>
1) 实现NFC的beam功能需要在AndroidManifest.xml中添加NFC权限。
2) 中的 应用程序支持的最低的skd版本应该是14,因为本文的两种方法都是在API 14之后新提供的。
3) 在中添加应用程序要处理的intent类型
import java.nio.charset.Charset;import android.app.Activity;import android.content.ActivityNotFoundException;import android.content.Intent;import android.net.Uri;import android.nfc.NdefMessage;import android.nfc.NdefRecord;import android.nfc.NfcAdapter;import android.nfc.NfcAdapter.CreateNdefMessageCallback;import android.nfc.NfcEvent;import android.os.Bundle;import android.os.Parcelable;import android.util.Log;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;import android.widget.LinearLayout;import android.widget.TextView;/** * NFC test ClassName: MainActivity * @Description: TODO * @author fzq * @date 2017-11-25 */public class MainActivity extends Activity implements CreateNdefMessageCallback { private TextView messagetv; private NfcAdapter nfcAdapter; private String payload = ""; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); } private void initView() { messagetv = (TextView) findViewById(R.id.message_tv); nfcAdapter = NfcAdapter.getDefaultAdapter(this); if (nfcAdapter == null) { messagetv.setText("nfc error"); return; } messagetv.setText("touch another device to beam nfc"); nfcAdapter.setNdefPushMessageCallback(this, this, this); } @Override public void onPointerCaptureChanged(boolean hasCapture) { Log.e("fzq", "--hasCapture : "+hasCapture); } /** * 发送nfc message */ @Override public NdefMessage createNdefMessage(NfcEvent event) { byte[] uriFiled = "fengzhiqi say hello".getBytes(Charset .forName("US-ASCII")); byte[] payload = new byte[uriFiled.length + 1]; payload[0] = 0x01; System.arraycopy(uriFiled, 0, payload, 1, uriFiled.length); NdefRecord URIRecord = new NdefRecord(NdefRecord.TNF_WELL_KNOWN, NdefRecord.RTD_URI, new byte[0], payload); NdefMessage message = new NdefMessage(new NdefRecord[] { URIRecord }); return message; } /** * 接受nfc */ @Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); setIntent(intent); } @Override protected void onResume() { super.onResume(); if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(getIntent().getAction())) { ProcessIntenet(getIntent()); } } /** * 处理nfc消息 * * @Description: TODO * @param @param intent * @return void * @throws * @author fzq * @date 2017-11-25 */ private void ProcessIntenet(Intent intent) { NdefMessage[] messages = getNdefMessage(getIntent()); for (int i = 0; i < messages.length; i++) { for (int j = 0; j < messages[i].getRecords().length; j++) { NdefRecord record = messages[i].getRecords()[j]; payload = new String(record.getPayload(), 1, record.getPayload().length - 1, Charset.forName("UTF-8")); messagetv.setText(payload); } } LinearLayout.LayoutParams params = new LinearLayout.LayoutParams( LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT); Button button = new Button(this); this.addContentView(button, params); messagetv.setText(""); button.setText("OPEN LINK: " + payload); //点击跳转网页 button.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent(); intent.setAction(Intent.ACTION_VIEW); intent.setData(Uri.parse("http://www." + payload)); try { startActivity(intent); } catch (ActivityNotFoundException e) { } } }); } /** * 接受数据方法 * @Description: TODO * @param @param intent * @param @return * @return NdefMessage[] * @throws * @author fzq * @date 2017-11-25 */ private NdefMessage[] getNdefMessage(Intent intent) { NdefMessage[] msgs = null; if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(getIntent().getAction())) { 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 { 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 }; } } else { Log.e("fzq", "no message data"); } return msgs; }}
- 关于NFC P2P模式
- android nfc P2P模式
- NFC--P2P模式 java层源码码流程解析。
- 关于其他设备NFC与android手机p2p传输问题
- [NFC]P2P设备响应流程
- Android NFC P2P开发基础
- [NFC]P2P设备响应流程
- 关于NFC
- Android NFC P2P学习1 - API层
- Android NFC P2P学习2 - Service层
- NFC应用(三)点对点(P2P)通信
- NFC低功耗模式
- 关于NFC(近场通信)的三种响应模式(一)
- 关于NFC(近场通信)的三种响应模式(二)
- P2P服务模式
- 网络游戏的P2P模式?
- P2P通信模式
- NFC通信的模式选择
- 大数据挖掘:手把手教你分析头条小程序文章数据
- C#抽象类
- linux下使用crontab如何实现mysql数据库每天自动备份定时备份
- python基础-单例模式、__new__方法、利用new构造对象
- 土地经济学笔记第二部分
- 关于NFC P2P模式
- 自定义类型部分知识理解
- 解决phpmailer后的总结
- 'module' object has no attribute 'JSONField' Django REST framework
- Java
- 初学SpringMVC 小总结(有些术语说的不准确以后会加强,有些只是我个人理解,发现有问题可以告诉我)
- C#静态类
- laravel5.5 路由分割成不同文件
- iOS开发之UI篇(8)—— UITextField