我尝试按照此处的说明制作应用: https://developer.android.com/guide/topics/connectivity/nfc/nfc
但是当我编译代码并在手机上拿着卡时,我得到a weird sound
我的nfc已打开,并且我有一个运行Android 9的oneplus 6
当我检查logcat时,我看到一个错误:
56:27.888 7834-7850/com.appname D/DecorView: onWindowFocusChangedFromViewRoot hasFocus: true, DecorView@6302a6f[MainActivity]
2019-10-12 22:56:27.913 7834-7834/com.appname W/RenderThread: type=1400 audit(0.0:2504791): avc: denied { read } for name="u:object_r:vendor_default_prop:s0" dev="tmpfs" ino=21655 scontext=u:r:untrusted_app:s0:c16,c257,c512,c768 tcontext=u:object_r:vendor_default_prop:s0 tclass=file permissive=0
2019-10-12 22:56:27.928 7834-7880/com.appname E/libc: Access denied finding property "vendor.debug.egl.swapinterval"
为什么我收到此错误,而不是显示textview的nfc卡即时扫描信息(我尝试了多种nfc卡,但给出了相同的错误)
我发现某个人也有同样的问题。 they say,您应该点击链接,然后观看评论3。然后they say与安全问题有关,这与不允许写入tmp目录有关。
请帮助我解决此问题,这是我的MainActivity.java:
package com.packagename;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
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.renderscript.RenderScript;
import android.widget.TextView;
import android.widget.Toast;
import static android.nfc.NdefRecord.createMime;
public class MainActivity extends AppCompatActivity implements CreateNdefMessageCallback {
NfcAdapter nfcAdapter;
TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Check for available NFC Adapter
nfcAdapter = NfcAdapter.getDefaultAdapter(this);
if (nfcAdapter == null) {
Toast.makeText(this, "NFC is not available", Toast.LENGTH_LONG).show();
finish();
return;
}
// Register callback
nfcAdapter.setNdefPushMessageCallback(this, this);
}
@Override
public NdefMessage createNdefMessage(NfcEvent event) {
String text = ("Beam me up, Android!\n\n" +
"Beam Time: " + System.currentTimeMillis());
NdefMessage msg = new NdefMessage(
new NdefRecord[] { createMime(
"application/vnd.com.example.android.beam", text.getBytes())
/**
* The Android Application Record (AAR) is commented out. When a device
* receives a push with an AAR in it, the application specified in the AAR
* is guaranteed to run. The AAR overrides the tag dispatch system.
* You can add it back in to guarantee that this
* activity starts when receiving a beamed message. For now, this code
* uses the tag dispatch system.
*/
//,NdefRecord.createApplicationRecord("com.example.android.beam")
});
return msg;
}
@Override
public void onResume() {
super.onResume();
// Check to see that the Activity started due to an Android Beam
if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(getIntent().getAction())) {
processIntent(getIntent());
}
}
@Override
public void onNewIntent(Intent intent) {
// onResume gets called after this to handle the intent
setIntent(intent);
}
/**
* Parses the NDEF Message from the intent and prints to the TextView
*/
void processIntent(Intent intent) {
textView = findViewById(R.id.textView);
Parcelable[] rawMsgs = intent.getParcelableArrayExtra(
NfcAdapter.EXTRA_NDEF_MESSAGES);
// only one message sent during the beam
NdefMessage msg = (NdefMessage) rawMsgs[0];
// record 0 contains the MIME type, record 1 is the AAR, if present
textView.setText(new String(msg.getRecords()[0].getPayload()));
}
}
AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.packagename">
<uses-permission android:name="android.permission.NFC" />
<uses-feature android:name="android.hardware.nfc" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
谢谢!
答案 0 :(得分:1)
由于NFC读取由Android操作系统处理,因此在读取卡时始终会发出声音。
根据卡上NDEF记录的内容以及您的应用程序尝试执行的操作来确定操作系统对NFC数据的处理方式。
您可以下载https://play.google.com/store/apps/details?id=com.wakdev.wdnfc&hl=en_US之类的通用NFC应用程序来检查卡上的内容,并编写一些示例数据供应用程序读取。
您似乎正在尝试在2部手机上运行该应用程序,并使用不推荐使用的Android Beam功能https://developer.android.com/reference/android/nfc/NfcAdapter.CreateNdefMessageCallback(我发现它从来都不可靠-这就是为什么他们将其删除的原因)让他们进行交谈>
但是你说
为什么我会收到此错误,而不是在textview中显示 nfc卡即时扫描的信息
建议您尝试读取NFC卡,但所使用的方法不适用于此操作。
问题是您要使用NFC吗?
1)NFC卡是否使您的APP被Android OS启动?
然后以某种方式使用NFC上的数据。
如果是,那么您应该将正确的意图过滤器放入清单中,并像处理其他任何意图那样在MainActivity中处理它们,并从意图数据中解析NDEF消息。
有关一些非NFC的示例,请参见https://developer.android.com/guide/components/intents-filters#ExampleFilters,以了解您的应用如何向操作系统注册其可以处理的Intent类型。
2)在您的App中,有时会处理从NFC卡读取的信息
这似乎是您正在尝试做的事情(以及我的Apps所做的事情)
我在活动中使用以下类型的代码
public class ViewNFCCardsActivity extends AppCompatActivity {
private NfcAdapter mNfcAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_view_nfccards);
mNfcAdapter = NfcAdapter.getDefaultAdapter(this);
}
@Override
protected void onResume() {
super.onResume();
IntentFilter tagDetected = new IntentFilter(NfcAdapter.ACTION_TAG_DISCOVERED);
IntentFilter ndefDetected = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED);
IntentFilter techDetected = new IntentFilter(NfcAdapter.ACTION_TECH_DISCOVERED);
IntentFilter[] nfcIntentFilter = new IntentFilter[]{techDetected,tagDetected,ndefDetected};
try {
ndefDetected.addDataType("*/*");
} catch (IntentFilter.MalformedMimeTypeException e) {}
PendingIntent pendingIntent = PendingIntent.getActivity(
this, 0, new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
if(mNfcAdapter!= null)
mNfcAdapter.enableForegroundDispatch(this, pendingIntent, nfcIntentFilter, null);
}
@Override
protected void onPause() {
super.onPause();
if(mNfcAdapter!= null)
mNfcAdapter.disableForegroundDispatch(this);
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
TextView textView = (TextView) findViewById(R.id.MessageText);
// High level way to get Ndef records from what is already been read from the tag
if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(intent.getAction())) {
Parcelable[] rawMessages = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
if (rawMessages != null) {
// Only need the first message
NdefMessage msg = (NdefMessage) rawMessages[0];
// Only need the first record in message
String message = new String(msg.getRecords()[0].getPayload());
textView.setText(message);
}
}
}
onResume
告诉Android OS将所有NFC卡类型的消息发送到我的应用程序,并且onNewIntent
方法获取OS传递给它的Intent并处理消息(如果它是NDEF消息)
您还可以在onResume
中创建Foreground Dispatcher时,添加其他过滤器,例如
try {
ndefDetected.addDataType("custom/text");
} catch (IntentFilter.MalformedMimeTypeException e) {}
或删除非NDEF卡的过滤器(通常添加所有类型,因为我不希望其他类型的卡(例如非接触式银行卡)在我的应用处于前台时触发其他应用)