我有一个在Kiosk模式下启动的应用程序,应该读取NFCTag并对之做出反应。它正在使用enableReaderMode
中NFCAdapter
上的onResume
开始读取它们。如果应用程序例如(重新)在开发过程中开始。但是,如果我重新启动设备(活动自动开始),则有时仅将活动置于正确的模式,但通常仅播放NFC系统声音,而不会调用我的handleTag
。
根据我的记录,在任何情况下都可以正确调用我拥有的NFCAdapter安装代码
我也尝试过enableForegroundDispatch
,但效果相同。我也尝试过定期召回enableReaderMode
,但它也有相同的效果。
任何人都知道发生了什么事吗?
更新
[尝试在失败的情况下尝试设置阅读器模式时,我在日志中看到此错误消息
NfcService: setReaderMode: Caller is not in foreground and is not system process.
尽管该活动在前者中清晰可见。
电话是Google Pixel 3
该应用程序是设备所有者,通过
adb shell dpm set-device-owner ...
应用程序清单
<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"
android:testOnly="true">
<!-- snip DeviceAdminReceiver -->
<activity
android:name=".FullscreenActivity"
android:screenOrientation="reverseLandscape"
android:configChanges="orientation|keyboardHidden|screenSize"
android:label="@string/app_name"
android:theme="@style/FullscreenTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.HOME" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
<uses-permission android:name="android.permission.NFC" />
<uses-feature android:name="android.hardware.nfc" />
应该处理NFC标签的FullscreenActivity
public class FullscreenActivity extends AppCompatActivity {
NfcAdapter mAdapter;
private DevicePolicyManager mDevicePolicyManager;
private ComponentName mAdminComponentName;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mDevicePolicyManager = (DevicePolicyManager) getSystemService(
Context.DEVICE_POLICY_SERVICE);
if (mDevicePolicyManager.isDeviceOwnerApp(getPackageName())) {
mAdminComponentName = MyDeviceAdminReceiver.getComponentName(this);
IntentFilter intentFilter = new IntentFilter(Intent.ACTION_MAIN);
intentFilter.addCategory(Intent.CATEGORY_HOME);
intentFilter.addCategory(Intent.CATEGORY_DEFAULT);
mDevicePolicyManager.addPersistentPreferredActivity(
mAdminComponentName, intentFilter,
new ComponentName(getPackageName(),
FullscreenActivity.class.getName()));
mDevicePolicyManager.setLockTaskPackages(mAdminComponentName,
new String[]{getPackageName()});
mDevicePolicyManager.setKeyguardDisabled(mAdminComponentName, true);
}
startLockTask();
}
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if (hasFocus) {
setFullscreenFlags();
}
}
private void setFullscreenFlags() {
getWindow().getDecorView()
.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
}
@Override
protected void onResume() {
super.onResume();
setFullscreenFlags();
mAdapter = NfcAdapter.getDefaultAdapter(this);
setupNfcAdapter();
}
private void setupNfcAdapter() {
if (mAdapter == null) return;
Bundle options = new Bundle();
// No sure this is needed
options.putInt(NfcAdapter.EXTRA_READER_PRESENCE_CHECK_DELAY, 50000);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
new Intent(this, getClass())
.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
mAdapter.enableReaderMode(this, this::handleTag,
NfcAdapter.FLAG_READER_NO_PLATFORM_SOUNDS |
NfcAdapter.FLAG_READER_NFC_A |
NfcAdapter.FLAG_READER_NFC_B |
NfcAdapter.FLAG_READER_NFC_F |
NfcAdapter.FLAG_READER_NFC_V, options);
}
@Override
protected void onPause() {
super.onPause();
if (mAdapter != null) {
mAdapter.disableReaderMode(this);
}
}
private void handleTag(Tag tag) {
Log.d("NFCADAPTER", "tag detected");
}
}
更新:可能是另一个系统应用程序正在您的应用程序中启动并占据前台。
我认为您可以在启用阅读器模式之前将您的应用强制到Foreground吗?例如https://stackoverflow.com/a/10019332/2373819
不知道发生了什么,除了认为这是时间问题。
但有两点可能会有所帮助。
尝试检查NfcAdapter.isEnabled()
是否为真,以帮助您在尝试enableReaderMode
之前确定NFC硬件是否实际可用
设置广播者接收器以记录NFC服务状态,并在就绪时以及在enableReaderMode
中记录onResume
。]
这应该比轮询更可靠,以便以后查看适配器是否可用。
这可以通过以下代码完成:-
protected void onCreate(Bundle savedInstanceState) {
// All the normal onCreate Stuff
// Listen for changes NFC settings
IntentFilter filter = new IntentFilter(NfcAdapter.ACTION_ADAPTER_STATE_CHANGED);
this.registerReceiver(mReceiver, filter);
}
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (action != null && action.equals(NfcAdapter.ACTION_ADAPTER_STATE_CHANGED)) {
final int state = intent.getIntExtra(NfcAdapter.EXTRA_ADAPTER_STATE,
NfcAdapter.STATE_OFF);
switch (state) {
case NfcAdapter.STATE_OFF:
Log.d("NFCADAPTER", "Adapter Off");
break;
case NfcAdapter.STATE_TURNING_OFF:
Log.d("NFCADAPTER", "Adapter Turning Off");
break;
case NfcAdapter.STATE_TURNING_ON:
Log.d("NFCADAPTER", "Adapter Turning On");
break;
case NfcAdapter.STATE_ON:
Log.d("NFCADAPTER", "Adapter On");
setupNfcAdapter();
break;
}
}
}
};