NFC--近距离无线通信技术(Near Field Communication,NFC),是由飞利浦公司和索尼公司共同开发的一种非接触式识别和互联技术,可以在移动设备、消费类电子产品、PC和智能设备间进行近距离无线通信。NFC提供了一种简单的、非触控式的解决方案,可以让消费者简单直观地交换信息、访问内容与服务。NFC整合了非接触式读卡器、非接触式智能卡和点对点(Peer-to—Peer)通信功能,为消费者开创了全新的便捷生活方式。手机和NFC技术的结合,将会给消费者提供极大的生活便利,例如移动支付、位置服务信息、公共交通卡等应用。安卓开发,需要了解NFC终端有3种工作模式:
1)主动模式,NFC终端作为一个读卡器,主动发出自己的射频场去识别和读,写别的NFC设备;
2)被动模式,NFC终端可以模拟成一个智能卡被读,写,它只在其他设备发出的射频场中被动响应;
3)双向模式,双方都主动发出射频场来建立点对点的通信”
Android.nfc package包含顶层类用来与本地NFC适配器交互. 这些类可以表示被检测到的tags和用NDEF数据格式。
class | Description |
一个NFC adapter的管理器,可以列出所有此android设备支持的NFC adapter.只不过大部分android 设备只有一个NFC adapter,所以你大部分情况下可以直接用静态方法 getDefaultAdapter(context)来取适配器。 | |
表示本设备的NFC adapter,可以定义Intent来请求将系统检测到tags的提醒发送到你的Activity.并提供方法去注册前台tag提醒发布和前台NDEF推送。 前台NDEF推送是当前android版本唯一支持的p2p NFC通信方式。 | |
NDEF是NFC论坛定义的数据结构,用来有效的存数据到NFC tags.比如文本,URL,和其他MIME类型。一个NdefMessage扮演一个容器,这个容器存哪些发送和读到的数据。一个NdefMessage对象包含0或多个NdefRecord,每个NDEF record有一个类型,比如文本,URL,智慧型海报/广告,或其他MIME数据。在NDEFMessage里的第一个NfcRecord的类型用来发送tag到一个android设备上的activity. | |
标示一个被动的NFC目标,比如tag,card,钥匙挂扣,甚至是一个电话模拟的的NFC卡. 当一个tag被检测到,一个tag对象将被创建并且封装到一个Intent里,然后NFC 发布系统将这个Intent用startActivity发送到注册了接受这种Intent的activity里。你可以用getTechList()方法来得到这个tag支持的技术细节和创建一个android.nfc.tech提供的相应的TagTechnology对象。 |
注册清单设置:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.demo.xnfc"
android:versionCode="15"
android:versionName="2.3" >
<uses-sdk
android:minSdkVersion="10"
android:targetSdkVersion="19" />
<uses-permission android:name="android.permission.NFC" />
<uses-feature
android:name="android.hardware.nfc"
android:required="true" />
<application
android:name=".ThisApplication"
android:allowBackup="false"
android:hardwareAccelerated="true"
android:icon="@drawable/nfcard"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<meta-data
android:name="android.nfc.disable_beam_default"
android:value="true" />
<activity
android:name="com.demo.xnfc.MainActivity"
android:alwaysRetainTaskState="false"
android:configChanges="orientation|screenSize"
android:label="@string/app_name"
android:launchMode="singleTask"
android:windowSoftInputMode="adjustUnspecified|stateAlwaysHidden" >
<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" /> <!-- NDEF_DISCOVERED过滤 -->
<action android:name="android.nfc.action.TECH_DISCOVERED" /> <!-- TECH_DISCOVERED过滤 -->
<action android:name="android.nfc.action.TAG_DISCOVERED" /> <!-- TAG_DISCOVERED过滤 -->
</intent-filter>
<meta-data
android:name="android.nfc.action.TECH_DISCOVERED"
android:resource="@xml/nfc_tech_filter" /> <!-- 自定义res/xml/nfc_techfilter。xml-->
</activity>
</application>
</manifest>
<?xml version="1.0" encoding="utf-8"?> <!-- 自定义res/xml/nfc_techfilter。xml-->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<tech-list>
<tech>android.nfc.tech.IsoDep</tech>
</tech-list>
<tech-list>
<tech>android.nfc.tech.NfcF</tech>
</tech-list>
</resources>
主要代码: NfcAdapter.getDefaultAdapter(this);
import android.app.Activity;
import android.content.Intent;
import android.graphics.Typeface;
import android.os.Bundle;
import android.text.method.LinkMovementMethod;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.ViewSwitcher;
import com.demo.xnfc.R;
import com.sinpo.xnfc.nfc.NfcManager;
import com.sinpo.xnfc.ui.AboutPage;
import com.sinpo.xnfc.ui.MainPage;
import com.sinpo.xnfc.ui.NfcPage;
import com.sinpo.xnfc.ui.Toolbar;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initViews();
nfc = new NfcManager(this);
onNewIntent(getIntent());
}
@Override
public void onBackPressed() {
if (isCurrentPage(SPEC.PAGE.ABOUT))
loadDefaultPage();
else if (safeExit)
super.onBackPressed();
}
@Override
public void setIntent(Intent intent) {
if (NfcPage.isSendByMe(intent))
loadNfcPage(intent);
else if (AboutPage.isSendByMe(intent))
loadAboutPage();
else
super.setIntent(intent);
}
@Override
protected void onPause() {
super.onPause();
nfc.onPause();
}
@Override
protected void onResume() {
super.onResume();
nfc.onResume();
}
@Override
public void onWindowFocusChanged(boolean hasFocus) {
if (hasFocus) {
if (nfc.updateStatus())
loadDefaultPage();
// 有些ROM将关闭系统状态下拉面板的BACK事件发给最顶层窗口
// 这里加入一个延迟避免意外退出
board.postDelayed(new Runnable() {
public void run() {
safeExit = true;
}
}, 800);
} else {
safeExit = false;
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
loadDefaultPage();
}
@Override
protected void onNewIntent(Intent intent) {
if (!nfc.readCard(intent, new NfcPage(this)))
loadDefaultPage();
}
public void onSwitch2DefaultPage(View view) {
if (!isCurrentPage(SPEC.PAGE.DEFAULT))
loadDefaultPage();
}
public void onSwitch2AboutPage(View view) {
if (!isCurrentPage(SPEC.PAGE.ABOUT))
loadAboutPage();
}
public void onCopyPageContent(View view) {
toolbar.copyPageContent(getFrontPage());
}
public void onSharePageContent(View view) {
toolbar.sharePageContent(getFrontPage());
}
private void loadDefaultPage() {
toolbar.show(null);
TextView ta = getBackPage();
resetTextArea(ta, SPEC.PAGE.DEFAULT, Gravity.CENTER);
ta.setText(MainPage.getContent(this));
board.showNext();
}
private void loadAboutPage() {
toolbar.show(R.id.btnBack);
TextView ta = getBackPage();
resetTextArea(ta, SPEC.PAGE.ABOUT, Gravity.LEFT);
ta.setText(AboutPage.getContent(this));
board.showNext();
}
private void loadNfcPage(Intent intent) {
final CharSequence info = NfcPage.getContent(this, intent);
TextView ta = getBackPage();
if (NfcPage.isNormalInfo(intent)) {
toolbar.show(R.id.btnCopy, R.id.btnShare, R.id.btnReset);
resetTextArea(ta, SPEC.PAGE.INFO, Gravity.LEFT);
} else {
toolbar.show(R.id.btnBack);
resetTextArea(ta, SPEC.PAGE.INFO, Gravity.CENTER);
}
ta.setText(info);
board.showNext();
}
private boolean isCurrentPage(SPEC.PAGE which) {
Object obj = getFrontPage().getTag();
if (obj == null)
return which.equals(SPEC.PAGE.DEFAULT);
return which.equals(obj);
}
private void resetTextArea(TextView textArea, SPEC.PAGE type, int gravity) {
((View) textArea.getParent()).scrollTo(0, 0);
textArea.setTag(type);
textArea.setGravity(gravity);
}
private TextView getFrontPage() {
return (TextView) ((ViewGroup) board.getCurrentView()).getChildAt(0);
}
private TextView getBackPage() {
return (TextView) ((ViewGroup) board.getNextView()).getChildAt(0);
}
private void initViews() {
board = (ViewSwitcher) findViewById(R.id.switcher);
Typeface tf = ThisApplication.getFontResource(R.string.font_oem1);
TextView tv = (TextView) findViewById(R.id.txtAppName);
tv.setTypeface(tf);
tf = ThisApplication.getFontResource(R.string.font_oem2);
tv = getFrontPage();
tv.setMovementMethod(LinkMovementMethod.getInstance());
tv.setTypeface(tf);
tv = getBackPage();
tv.setMovementMethod(LinkMovementMethod.getInstance());
tv.setTypeface(tf);
toolbar = new Toolbar((ViewGroup) findViewById(R.id.toolbar));
}
private ViewSwitcher board;
private Toolbar toolbar;
private NfcManager nfc;
private boolean safeExit;
}
github demo例子: