我有一个捕捉NFC标签的应用程序。我过去遇到的问题是,用户以不稳定的方式悬停在标签上,导致NFC适配器触发两次。
我已经做了一些事情来应对这个问题。
显示:
<activity
android:name=".NfcActivity"
android:screenOrientation="portrait"
android:launchMode="singleTask"
android:noHistory="true"
android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|screenLayout|fontScale|uiMode|orientation">
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain" />
</intent-filter>
</activity>
这将NFC捕获活动设置为堆栈中的唯一实例,并且没有历史记录。我已经覆盖了所有可以停止并重新启动此活动的配置更改,后者可能会导致意向数据重新交付到该活动,使其看起来像是重复扫描。
在活动本身,我已经重写了onNewIntent,除了显示一个糟糕的扫描屏幕什么也不做。我也明白,从功能的角度来看,onNewIntent应该镜像oncreer,但是因为应用程序的前几个版本已经发送了2次扫描到下一个活动,我只希望NFC捕获代码在一个地方,在创建。
在创建中,我做了进一步的测试,以对抗悬停在标签上并创建错误的扫描。
该应用似乎运行良好,但在一款特定的手机(三星Galaxy Young 2)上,如果用户将手机放在标签上几秒钟,NFC适配器似乎会连续启动几次。
当这种情况发生时,原始扫描被取消。原因是oncreate处理标记,但当后续扫描发生时(通过悬停,意外),onPause-
上述问题并不严重,因为用户必须重新扫描标签。
我想发生的是:
当onCreate运行时,不管发生什么情况,都会处理标记,即使onNewintent执行。有没有办法在达到Wintent和onPause之前拦截意图?
也许我可以使用一个全局标志,首先可以检查它,说明onCreate仍在运行,而OnWintent不应该运行,或者更重要的是,onPause并不是让onCreate停止运行。
import java.util.List;
import java.util.concurrent.ExecutionException;
import org.ndeftools.Message;
import org.ndeftools.Record;
import android.app.Activity;
import android.app.PendingIntent;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.nfc.NdefMessage;
import android.nfc.NdefRecord;
import android.nfc.NfcAdapter;
import android.nfc.Tag;
import android.nfc.tech.Ndef;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Parcelable;
import android.os.Vibrator;
import android.util.Log;
import android.widget.Toast;
public class NfcActivity extends Activity {
private static final String TAG = NfcActivity.class.getName();
protected NfcAdapter nfcAdapter;
protected PendingIntent nfcPendingIntent;
Handler handler;
Runnable runnable;
Handler failHandler;
Runnable failRunnable;
Parcelable[] messages;
Intent i;
Tag tag;
String tagId;
boolean nfcConnected;
ProgressDialog progressDialog;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.nfcactivitylayout);
Log.e(TAG, "oncreate");
nfcConnected = false;
// initialize NFC
nfcAdapter = NfcAdapter.getDefaultAdapter(this);
nfcPendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, this.getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
tag = null;
tagId = null;
i = getIntent();
if ((i.getFlags() & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) != 0) {
//check to see if Android has previously killed the app and relaunched it from History
//and delivered the original intent.
//if it has do not process and launch the menu screen
Intent processPayloadIntent = new Intent(NfcActivity.this, NfcscannerActivity.class);
processPayloadIntent.setAction("QRCODE_ACTION");
processPayloadIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(processPayloadIntent);
}else{
tag = i.getParcelableExtra(NfcAdapter.EXTRA_TAG);
tagId = bytesToHexString(tag.getId());
Log.e(TAG, "tagID = " + tagId);
Log.e(TAG, "oncreate intent action = " + i.getAction());
//The activity has captured tag data, prove the user is not hovering over the tag and is doing a good scan
//hovering can trigger the html" target="_blank">adapter twice
AsyncNfcConnect asnc = new AsyncNfcConnect();
try {
asnc.execute().get();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Log.e(TAG, "nfcConnected!!!!!!!!!!!!!!!!!!!!!!!!! = " + nfcConnected);
if(nfcConnected == true){
int buildVersionSdk = Build.VERSION.SDK_INT;
int buildVersionCodes = Build.VERSION_CODES.GINGERBREAD;
Log.e(TAG, "buildVersionSdk = " + buildVersionSdk
+ "buildVersionCodes = " + buildVersionCodes);
int themeVersion;
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.GINGERBREAD) {
themeVersion = 2;
} else {
themeVersion = 1;
}
try{
progressDialog = new ProgressDialog(this, themeVersion);
progressDialog.setTitle("NFC Tag Scanned");
progressDialog.setMessage("Processing tag...");
progressDialog.setIndeterminate(true);
progressDialog.show();
}catch(Exception e){ }
if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(i.getAction()) || NfcAdapter.ACTION_TAG_DISCOVERED.equals(i.getAction())) {
if(NfcScannerApplication.isCanScanNfcTag()){
messages = i.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
if (messages != null) {
//setContentView(R.layout.successfulnfc);
NfcScannerApplication.startNfcTimer();
//Toast.makeText(this, "NFC timer set", Toast.LENGTH_LONG).show();
Log.e(TAG, "Found " + messages.length + " NDEF messages"); // is almost always just one
vibrate(); // signal found messages :-)
initHandler();
handler.postDelayed(runnable, 2000);
}else{
Toast.makeText(this, "Data on tag was not correct", Toast.LENGTH_LONG).show();
try{
handler.removeCallbacks(runnable);
Log.e(TAG, "just removed callback to runnable that reads nfc tag data");
}catch(Exception e){
}
initFailHandler();
failHandler.postDelayed(failRunnable, 1);
}
}else{
try{
handler.removeCallbacks(runnable);
Log.e(TAG, "just removed callback to runnable that reads nfc tag data");
}catch(Exception e){
}
initFailHandler();
failHandler.postDelayed(failRunnable, 1);
}
} else {
Toast.makeText(this, "Tag not recognized correctly", Toast.LENGTH_LONG).show();
try{
handler.removeCallbacks(runnable);
Log.e(TAG, "just removed callback to runnable that reads nfc tag data");
}catch(Exception e){
}
initFailHandler();
failHandler.postDelayed(failRunnable, 1);
}
}else{
try{
Toast.makeText(this, "Phone wasn't connected to Tag", Toast.LENGTH_LONG).show();
handler.removeCallbacks(runnable);
Log.e(TAG, "just removed callback to runnable that reads nfc tag data");
}catch(Exception e){
}
initFailHandler();
failHandler.postDelayed(failRunnable, 1);
}//end of NFC connect test
}//end of launched from history check
}//end of onCreate
@Override
protected void onStart() {
super.onStart();
Log.e(TAG, "onStart");
}
@Override
protected void onStop() {
super.onStop();
Log.e(TAG, "onStop");
}
@Override
public void onNewIntent(Intent intent) {
Log.e(TAG, "onNewIntent");
Toast.makeText(this, "Bad scan!!!", Toast.LENGTH_LONG).show();
initFailHandler();
failHandler.postDelayed(failRunnable, 1);
}//end of onNewIntent
public void enableForegroundMode() {
Log.e(TAG, "enableForegroundMode");
IntentFilter tagDetected = new IntentFilter(NfcAdapter.ACTION_TAG_DISCOVERED); // filter for all
IntentFilter[] writeTagFilters = new IntentFilter[] {tagDetected};
nfcAdapter.enableForegroundDispatch(this, nfcPendingIntent, writeTagFilters, null);
}
public void disableForegroundMode() {
Log.e(TAG, "disableForegroundMode");
nfcAdapter.disableForegroundDispatch(this);
}
@Override
protected void onResume() {
super.onResume();
Log.e(TAG, "onResume");
enableForegroundMode();
}
@Override
protected void onPause() {
Log.e(TAG, "onPause");
super.onPause();
disableForegroundMode();
if(handler != null){
handler.removeCallbacks(runnable);
}
}
private void vibrate() {
Log.e(TAG, "vibrate");
Vibrator vibe = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE) ;
vibe.vibrate(500);
}
public void initHandler(){
handler = new Handler();
runnable = new Runnable() {
public void run() {
processTag();
}
private void processTag() {
Log.e(TAG, "about to process tag");
try{
progressDialog.dismiss();
}catch(Exception e){
//do nothing
}
// parse to records
for (int i = 0; i < messages.length; i++) {
try {
List<Record> records = new Message((NdefMessage)messages[i]);
Log.e(TAG, "Found " + records.size() + " records in message " + i);
for(int k = 0; k < records.size(); k++) {
Log.e(TAG, " Record #" + k + " is of class " + records.get(k).getClass().getSimpleName());
Record record = records.get(k);
NdefRecord ndefRecord = record.getNdefRecord();
byte[] arr = ndefRecord.getPayload();
String payload = new String(arr);
if(payload.length() > 0){
payload = payload.substring(3, payload.length());
Log.e(TAG, "payload = " + payload);
String[] splitPayload = payload.split(",");
String tagType = splitPayload[0];
String tagCompany = splitPayload[1];
String tagClientID = splitPayload[2];
String tagClientName = splitPayload[3];
if(! tagClientID.equalsIgnoreCase("0") && tagClientID.length() > 0){
handler.post(new Runnable(){
public void run() {
setContentView(R.layout.successfulnfc);
}
});
Intent processPayloadIntent = new Intent(NfcActivity.this, NfcscannerActivity.class);
processPayloadIntent.putExtra("payload", payload);
processPayloadIntent.putExtra("tagid", tagId);
processPayloadIntent.setAction("NFC");
processPayloadIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
//processPayloadIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP|Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(processPayloadIntent);
finish();
overridePendingTransition(0, R.anim.activity_animation_zoom_in);
}else{
Toast.makeText(NfcActivity.this, "Tag data problem/Scan problem.", Toast.LENGTH_LONG).show();
initFailHandler();
failHandler.postDelayed(failRunnable, 1);
}
}else{
Toast.makeText(NfcActivity.this, "Tag data problem/Scan problem.", Toast.LENGTH_LONG).show();
initFailHandler();
failHandler.postDelayed(failRunnable, 1);
}
}
} catch (Exception e) {
Log.e(TAG, "Problem parsing message", e);
}
}
}
};
}
public void initFailHandler(){
failHandler = new Handler();
failRunnable = new Runnable() {
public void run() {
returnToMainMenu();
}
private void returnToMainMenu() {
//Log.e(TAG, "about to return to main menu");
try{
progressDialog.dismiss();
}catch(Exception e){
//do nothing
}
Toast.makeText(NfcActivity.this, "Please check your scanning technique.\nPlease do not hover over tag or swipe...", Toast.LENGTH_LONG).show();
failHandler.post(new Runnable(){
public void run() {
setContentView(R.layout.nfcfail);
}
});
//onBackPressed();
Intent processPayloadIntent = new Intent(NfcActivity.this, NfcscannerActivity.class);
processPayloadIntent.setAction("QRCODE_ACTION");
processPayloadIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(processPayloadIntent);
finish();
//overridePendingTransition(0, R.anim.activity_animation_zoom_in);
}
};
}
private String bytesToHexString(byte[] src) {
StringBuilder stringBuilder = new StringBuilder("0x");
if (src == null || src.length <= 0) {
return null;
}
char[] buffer = new char[2];
for (int i = 0; i < src.length; i++) {
buffer[0] = Character.forDigit((src[i] >>> 4) & 0x0F, 16);
buffer[1] = Character.forDigit(src[i] & 0x0F, 16);
System.out.println(buffer);
stringBuilder.append(buffer);
}
return stringBuilder.toString();
}
private class AsyncNfcConnect extends AsyncTask<String, Void, String> {
@Override
protected String doInBackground(String... params) {
NfcActivity.this.nfcConnected = false;
String result;
Ndef ndefTag = Ndef.get(tag);
try {
Log.e(TAG, "about to test connect()********************************************");
ndefTag.connect(); // this should already perform an IO operation and should therefore fail if there is no tag
Log.e(TAG, "Ndef.connect() connected!********************************************");
NdefMessage ndefMsg = ndefTag.getNdefMessage(); // this reads the current NDEF message from the tag and consequently causes an IO operation
NfcActivity.this.nfcConnected = true;
result = "OK";
return result;
} catch (Exception e) {
// there is no tag or communication with tag dropped
Log.e(TAG, "There a problem with connecting to the tag using Ndef.connect(");
NfcActivity.this.nfcConnected = false;
result = "NOTOK";
return result;
} finally {
try {
ndefTag.close();
} catch (Exception e) {
}
}
}
}//end of Async
}
你似乎坚持不在onNewIntent()
中处理NFC意图。我建议onCreate()
和onNewIntent()
都调用一个通用的过程来扫描标记。这样,两个入口点将遵循相同的代码路径。
你声称应用程序“跳出onCreate”可能只是一个比喻?发生的情况是,标记扫描asyncnfconnect
作为后台任务在一个单独的线程上运行(它应该这样做)。该任务在onCreate()
中创建,并在onCreate()
完成后继续运行(您可以在onCreate()
末尾添加Log
语句进行检查)。当与标记的连接以某种方式丢失并且标记被重新发现时,正如您所观察到的,将调用onNewIntent()
。
无论如何,没有办法阻止这种情况发生,所以你的应用程序必须能够处理它。要检测并处理此问题,可以在活动中设置一些标志,以指示后台任务正在运行或已运行。您还可以存储是否发生异常的信息,并在重新发现标记时尝试再次扫描它(这可能需要您实现我上面提出的建议)。如果你想让你的应用程序更能防故障,你还可以存储最后一次扫描的标签的ID,以便在成功扫描(或未扫描)后重新发现它时再次确认它。当同一标签持续出现异常时,您可以在一定次数后向用户指示his(例如,建议设备与标签位置不同)。
我一直在开发一个应用程序,它使用NFC标签做一些魔术。 一切都很好,直到最近,我改变了一些代码,这些代码与之前一直有效的NFC代码无关。 当我通过NFC点击启动我的应用程序时,所有的工作,当我点击应用程序运行时,我将在onNewIntent()中收到未来的NFCTag。 当我通过图标启动应用程序并在应用程序运行时尝试点击时,会调用onNewIntent()方法,但当我试图从intent中获取额外的
我有一个可以读取NFC标签的应用程序。到目前为止,这一切都很好——当NfcAdapter。行动_标记_发现意图被触发我的活动1开始。 现在我有一个Activity2,如果Activity2在前台,它应该读取NFC标签。所以我希望Activity2倾听NFC意图并拦截意图,这样Activity1就不会开始——Activity2已经处理了意图。 目前,Activity1在Android清单中分配了NF
问题内容: 我看到 一吨 的条目在我的Tomcat日志(样品粘贴下面)。这些在几个月前进行次要版本升级(Spring Security 4.2.4,IIRC)后开始出现在我的日志文件中,因此,这显然是默认情况下启用的Spring新安全功能。这里报告了类似的问题,但是我的问题专门涉及如何在控制器中拦截这些异常。有一个针对此问题的Spring Security错误记录(提供一种处理RequestRej
我在Tomcat日志中看到大量条目(示例粘贴在下面)。在几个月前的一次小版本升级(Spring Security 4.2.4,IIRC)后,这些功能开始出现在我的日志文件中,因此这显然是Spring中默认启用的一个新的安全特性。这里报告了一个类似的问题,但我的问题具体涉及如何在控制器中拦截这些异常。这个问题有一个Spring Securitybug(提供一种处理RequestRejectedExc
现在,当我到达spring-boot应用程序的endpoint时,它工作得很好 基本上,它根本不调用preandle。我错过了什么????
前端使用vue,后端使用springboot,前后端分离,且已解决跨域,登录采用jwt验证 想实现功能:如果用户通过url栏输入地址方式来访问某个页面(非登录页),对未登录用户自动跳转登录页面 请问拦截器是设置在后端还是设置在前端?另外对于静态页面能拦截吗