NFC使用

使用NFC功能,芯片是NDEF格式的芯片,在4.4版本下的手机一直没有问题,新采购了一批4.4版本的手机,从此麻烦就来了。手机读取芯片时经常会发生卡机的状况,先找到了一部分的原因

4.4以下系统用onNewIntent(),4.4系统就要通过enableReaderMode()方法,如果4.4系统用onNewIntent()的话,会导致一直P2P,而不是卡与读卡器的关系。


public class ReadActivity extends Activity {

/** Called when the activity is first created. */
	private NfcAdapter mNfcAdapter;
	private PendingIntent mPendingIntent;
	private String[][] techList;
	private IntentFilter[] intentFilters;
	private Tag tag;
    private int sdkVersion;
    public static final String TXT_FILEPATH = Environment.getExternalStorageDirectory().getPath() + "/files/";
	/**
	 * 开始的生命周期:onCreate-->onStart-->OnResume
	 * 从此页面跳转至详细页面:onPause-->OnStop , OnRestart-->OnStart -->OnResume
	 * nfc onPause --> onNewIntent -- >onResume
	 * 从其他页面返回  onNewIntent-->OnRestart-->OnStart -->OnResume
	 */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		//屏幕变暗—>黑,但不锁屏
		//	getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
		getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
	
		setContentView(R.layout.activity_read_tag);
	
			// 支持nfc tag所有的标准
		techList = new String[][] { new String[] { android.nfc.tech.NfcV.class.getName() }, new String[] { android.nfc.tech.NfcF.class.getName() }, new String[] { android.nfc.tech.NfcA.class.getName() }, new String[] { android.nfc.tech.NfcB.class.getName() }, new String[] { android.nfc.tech.Ndef.class.getName() }, new String[] { android.nfc.tech.NdefFormatable.class.getName() }, new String[] { android.nfc.tech.MifareClassic.class.getName() }, new String[] { android.nfc.tech.MifareUltralight.class.getName() } };
		// 当任意tag被检测到时,你将收到TAG_DISCOVERED intent。因此请注意你应该只处理你想要的Intent。
		intentFilters = new IntentFilter[] { new IntentFilter(NfcAdapter.ACTION_TECH_DISCOVERED), new IntentFilter(NfcAdapter.ACTION_TAG_DISCOVERED), new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED) };
		mPendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);

		openNfcManager();
				
		sdkVersion = Build.VERSION.SDK_INT;

	}
	
	private void openNfcManager(){
		NfcManager manager = (NfcManager) getSystemService(Context.NFC_SERVICE);
		mNfcAdapter = manager.getDefaultAdapter();
		// 实例化NFC设备
	//	mNfcAdapter = NfcAdapter.getDefaultAdapter(this);
		if (mNfcAdapter == null) {
			Toast.makeText(this, "您的设备不支持NFC", Toast.LENGTH_SHORT).show();
		} else if (mNfcAdapter != null) {
			if (!mNfcAdapter.isEnabled()) {
				Toast.makeText(this, "请在系统设置中先启用NFC功能", Toast.LENGTH_SHORT).show();
				startActivity(new Intent(Settings.ACTION_NFC_SETTINGS));
			} else {
				Toast.makeText(this, "启动NFC注册成功......", Toast.LENGTH_SHORT).show();
			}
			
		}
	}

	
	// 当窗口的创建模式是singleTop或singleTask时调用,用于取代onCreate方法
	// 当NFC标签靠近手机,建立连接后调用
	@SuppressLint("NewApi")
	@Override
	public void onNewIntent( Intent intent) {
		
		//nfc标签靠近手机,建立连接后调用
		if(sdkVersion <  Build.VERSION_CODES.KITKAT){ //19 4.4
			tagShowMethod(intent);		
		}						
		
	}
	
	@Override
	public void onResume() {
		super.onResume();

		if(mNfcAdapter != null){
			// 使用前台发布系统
			mNfcAdapter.enableForegroundDispatch(this, mPendingIntent, intentFilters, techList);
			enableReaderMode();
		}

	}
	
	@TargetApi(19) 
	private void enableReaderMode() {
		if(sdkVersion < 19){return;}
    	 
    	if(sdkVersion >= Build.VERSION_CODES.KITKAT){ //19 4.4
			int READER_FLAGS = NfcAdapter.FLAG_READER_NFC_A | NfcAdapter.FLAG_READER_NO_PLATFORM_SOUNDS;
				//	| NfcAdapter.FLAG_READER_NO_PLATFORM_SOUNDS;
			Bundle options = new Bundle();
			options.putInt(NfcAdapter.EXTRA_READER_PRESENCE_CHECK_DELAY, 50);// 延迟对卡片的检测
			
			if (mNfcAdapter != null) {
				mNfcAdapter.enableReaderMode(ReadActivity.this, new ReaderCallback() {					
					@Override
					public void onTagDiscovered(Tag tag) {
						//这里不是主线程,不能直接让textview设置内容,
						//api19 不从onNewIntent走,而是直接跳到这个回调函数里
		
						tagShowMethodAPI19(tag);		
					}
				},READER_FLAGS, null);
			}			
		}
	}
	
	@Override
	protected void onStart() {
		super.onStart();
	}

	@Override
	protected void onRestart() {
		super.onRestart();
	}
	
	@Override
	protected void onPause() {
		super.onPause();
		if(mNfcAdapter != null){
			mNfcAdapter.disableForegroundDispatch(this);
			disableReaderMode();
		}
	}
	
	@TargetApi(19) 
	private void disableReaderMode() {
		
    	if(sdkVersion < 19){return;}
        mNfcAdapter.disableReaderMode(this);
	}
	
	@Override
	protected void onDestroy() {		
		super.onDestroy();
		mNfcAdapter = null;		
		this.finish();
		
	}
	
	@Override
	protected void onStop() {
		super.onStop();
	}
	
	private void tagShowMethod(final Intent intent){

			// 获取Tag对象后读取里面的信息
			String tagInfo = getTagInfo(intent);
			Log.e("nfc", "tagInfo =" + tagInfo);
			if (!TextUtils.isEmpty(tagInfo)) {

				Date curDate = new Date();
				String dateStr = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS", Locale.CHINA).format(curDate);
				writeToTxt(tagInfo, dateStr);		
		}				
	}

	private void tagShowMethodAPI19(final Tag tag){
			// 获取Tag对象后读取里面的信息
			String tagInfo = getTagInfoAPI19(tag);
			Log.e("nfc", "tagInfo === api19 ==" + tagInfo);
			if (!TextUtils.isEmpty(tagInfo)) {	
		
				Date curDate = new Date();
				String dateStr = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS", Locale.CHINA).format(curDate);
				writeToTxt(tagInfo, dateStr);
	
			}
	}
		

   private void writeToTxt( String recordNo,  String dateStr) {
		String fileNamePrefix = new SimpleDateFormat("yyyy-MM-dd", Locale.CHINA).format(new Date());
		String fileName = fileNamePrefix + ".txt";
		String s = recordNo + "," + dateStr.substring(11, dateStr.length());
		// 创建文件的对象,必须指向创建文件的路径
		FileOutputStream fos = null;
		try {
			File file = new File(TXT_FILEPATH + fileName);
			// 如果文件不存在,则创建文件
			if (!file.exists()) {
				if (!file.getParentFile().exists()) {
					file.getParentFile().mkdirs();
				}
				file.createNewFile();
			} else {
				// 文件中有内容写入前加入回车符
				// FileOutputStream无法写入回车
				s = "\r\n" + s;
			}
			fos = new FileOutputStream(file, true);
			byte[] usemms = s.getBytes();
			fos.write(usemms, 0, usemms.length);
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			try {
				fos.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
	
	private String getTagInfo(Intent intent) {
		tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
		String tagInfo = "";
		// nfc tag支持哪几种格式
		if (null != tag) {
			String[] techListStrings = tag.getTechList();

			for (String tech : techListStrings) {
				if (tech == android.nfc.tech.Ndef.class.getName()) {
					// 解析Ndef格式
					tagInfo = parseNDEFMsg(intent);
				} else if (tech == android.nfc.tech.NfcV.class.getName()) {
					// 解析NfcV格式
					tagInfo = parseNFCVMsg();
				} else if (tech == android.nfc.tech.NfcA.class.getName()) {
					// 解析NfcA格式
				} else if (tech == android.nfc.tech.MifareClassic.class.getName()) {
					// 解析MifareClassic格式
					tagInfo = parseMifareClassicMsg();
				}
			}			
			
		}
		return tagInfo;
	}

	private String getTagInfoAPI19(Tag tag) {
	//	tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
		String tagInfo = "";
		// nfc tag支持哪几种格式
		if (null != tag) {
			String[] techListStrings = tag.getTechList();
							
			for (String tech : techListStrings) {
				if (tech == android.nfc.tech.Ndef.class.getName()) {
					// 解析Ndef格式
					tagInfo = parseNDEFMsgAPI19(tag);
				} else if (tech == android.nfc.tech.NfcV.class.getName()) {
					// 解析NfcV格式
					tagInfo = parseNFCVMsg();
				} else if (tech == android.nfc.tech.NfcA.class.getName()) {
					// 解析NfcA格式
				} else if (tech == android.nfc.tech.MifareClassic.class.getName()) {
					// 解析MifareClassic格式
					tagInfo = parseMifareClassicMsg();
				}
			}						
		}
		return tagInfo;
	}
	
		
	private synchronized String parseNDEFMsg(Intent intent) {
				
		String tagText = "";
		Parcelable[] rawMsgs = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
		// 创建NdefMessage对象和NdefRecord对象
		if (rawMsgs != null && rawMsgs.length > 0) {
			NdefMessage ndefMessage = (NdefMessage) rawMsgs[0];
			NdefRecord mNdefRecord = null;
			if (null != ndefMessage) {
				mNdefRecord = ndefMessage.getRecords()[0];
			}
			if (null != mNdefRecord) {
				try {
					tagText = new String(mNdefRecord.getPayload(), "UTF-8").trim();
				} catch (UnsupportedEncodingException e) {
					e.printStackTrace();
				}
			}
		}
		return tagText;
	}

	private synchronized String parseNDEFMsgAPI19(Tag tag) {
		String tagText = "";
		Ndef ndef = Ndef.get(tag);
		
		try {
			if(ndef == null){
				return tagText;
			}
			ndef.connect();
			NdefMessage ndefMessage  = ndef.getNdefMessage();
			NdefRecord mNdefRecord = null;
			if (null != ndefMessage) {
				mNdefRecord = ndefMessage.getRecords()[0];
			}
			if (null != mNdefRecord) {
				tagText = new String(mNdefRecord.getPayload(), "UTF-8").trim();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			if(ndef != null){
				try {
					ndef.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		return tagText;
	}

	public void writeNdefTag(Intent in) {
		Tag tag = in.getParcelableExtra(NfcAdapter.EXTRA_TAG);
		Ndef ndef = Ndef.get(tag);
		try {
			// 这一句别丢了,读nfc标签的时候不需要这句,因为那时数据直接就在intent中。
			ndef.connect();
			// 构造一个合适的NdefMessage。你可以看到代码里用了NdefRecord数组,只不过这个数组里只有一个record
			NdefMessage ndefMsg = new NdefMessage(new NdefRecord[] { createTextRecord("Test-10112") });
			ndef.writeNdefMessage(ndefMsg);
		} catch (IOException e) {
			e.printStackTrace();
		} catch (FormatException e) {
			e.printStackTrace();
		}
	}

	// 创建一个封装要写入的文本的NdefRecord对象
	public NdefRecord createTextRecord(String text) {
		// 生成语言编码的字节数组,中文编码
		byte[] langBytes = Locale.CHINA.getLanguage().getBytes(Charset.forName("US-ASCII"));
		// 将要写入的文本以UTF_8格式进行编码
		Charset utfEncoding = Charset.forName("UTF-8");
		// 由于已经确定文本的格式编码为UTF-8,所以直接将payload的第1个字节的第7位设为0
		byte[] textBytes = text.getBytes(utfEncoding);
		int utfBit = 0;
		// 定义和初始化状态字节
		char status = (char) (utfBit + langBytes.length);
		// 创建存储payload的字节数组
		byte[] data = new byte[1 + langBytes.length + textBytes.length];
		// 设置状态字节
		data[0] = (byte) status;
		// 设置语言编码
		System.arraycopy(langBytes, 0, data, 1, langBytes.length);
		// 设置实际要写入的文本
		System.arraycopy(textBytes, 0, data, 1 + langBytes.length, textBytes.length);
		// 根据前面设置的payload创建NdefRecord对象
		NdefRecord record = new NdefRecord(NdefRecord.TNF_MIME_MEDIA, NdefRecord.RTD_TEXT, new byte[0], data);
		return record;
	}
	
	private String parseMifareClassicMsg() {
		String tagInfo = "";
		MifareClassic mc = MifareClassic.get(tag);// 通过intent拿到EXTRA_TAG并转化成MirareClassic格式。
		int bCount = 0;
		int bIndex = 0;
		try {
			mc.connect();
			
			// 1K: 16个分区(sector),每个分区4个块(block),每个块(block) 16个byte数据
			// 2K: 32个分区,每个分区4个块(block),每个块(block) 16个byte数据
			// 4K: 64个分区,每个分区4个块(block),每个块(block) 16个byte数据
			// 获得sector总数
			int sectorCount = mc.getSectorCount();
			System.out.println(sectorCount);
			for (int i = 0; i < sectorCount; i++) {
				// 尝试去获得每个sector的认证,只有认证通过才能访问
				boolean auth = mc.authenticateSectorWithKeyA(i, MifareClassic.KEY_DEFAULT);
				if (auth) {
					// 这句其实不是必须的,因为每个sector中本来就只有4个block
					bCount = mc.getBlockCountInSector(i);
					// 我们可以得到每一个sector中的第一个block的编号
					bIndex = mc.sectorToBlock(i);
					for (int j = 0; j < bCount; j++) {// 循环四次拿出一个sector中所有的block
						// 每次循环bIndex会去++,然后可以得出每一个block的数据。这些数据是字节码,所以你还有一个翻译的工作要做。
						byte[] data = mc.readBlock(bIndex);
						tagInfo += data.toString();
						System.out.println(tagInfo);
						bIndex++;
					}
				} else {
					System.out.println(i);
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		return tagInfo;
	}
}
AndroidManifest.xml 的配置
<activity
            android:name=".ReadActivity"
            android:label="@string/app_name"
            android:launchMode="singleTask"
            android:windowSoftInputMode="stateHidden|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" />

                <category android:name="android.intent.category.DEFAULT" />

                <data android:mimeType="text/plain" />
            </intent-filter>
            
            <intent-filter>
                <action android:name="android.nfc.action.TECH_DISCOVERED" />
            </intent-filter>

            <meta-data
                android:name="android.nfc.action.TECH_DISCOVERED"
                android:resource="@xml/nfc_tech_filter" />

            <intent-filter>
                <action android:name="android.nfc.action.TAG_DISCOVERED" />

                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
          
        </activity>


<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
   
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> 
	
	 <uses-permission android:name="android.permission.NFC" />
	<uses-feature  android:name="android.hardware.nfc"  android:required="true" />
	
nfc_tech_filter.xml 的内容

<?xml version="1.0" encoding="utf-8"?>
<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.NfcV</tech>
	</tech-list>
	
	<tech-list>
		<tech>android.nfc.tech.NfcF</tech>
	</tech-list>
	
	<tech-list>
		<tech>android.nfc.tech.NfcA</tech>
	</tech-list>
	
	<tech-list>
		<tech>android.nfc.tech.NfcB</tech>
	</tech-list>
	
	<tech-list>
		<tech>android.nfc.tech.Ndef</tech>
	</tech-list>
	
	<tech-list>
		<tech>android.nfc.tech.NdefFormatable</tech>
	</tech-list>
	
	<tech-list>
		<tech>android.nfc.tech.MifareClassic</tech>
	</tech-list>

	<tech-list>
		<tech>android.nfc.tech.MifareUltralight</tech>
	</tech-list>
</resources>



你可能感兴趣的:(NFC使用)