Android 全屏启动器应用来自后台后 NFC 读取失败

Android NFC read fails after fullscreen launcher app comes from background

我的应用程序是一个启动器,我在安装后立即将其设置为默认启动器,它确实在第一次启动时毫无问题地读取 NFC 标签,但如果我锁定 phone 并且他们将其解锁(此时我的应用程序已经在屏幕上并且调用了 onResume())应用程序停止读取标签(当 phone 读取标签时会播放不同的声音,我猜这是 NFC 失败的声音)和onNewIntent(Intent intent) 未被调用。

我已经尝试将我的过滤器和意图设置为 activity 范围而不是本地范围(从 setupForegroundDispatch 中删除),但仍然存在同样的问题。如果我重新打开应用程序(终止并重新启动),那么 NFC reader 确实读取正确。

下面是我的逻辑:

NfcAdapter nfcAdapter;

@Override
    protected void onResume() {
        super.onResume();

        if (nfcAdapter == null){
            nfcAdapter=NfcAdapter.getDefaultAdapter(this);
        }
        setupForegroundDispatch(this, nfcAdapter);
    }
public static void setupForegroundDispatch(Activity activity, NfcAdapter adapter) {
        final Intent intent = new Intent(activity.getApplicationContext(), activity.getClass());

        final PendingIntent pendingIntent = PendingIntent.getActivity(
                activity.getApplicationContext(), 0, intent, 0);

        IntentFilter[] filters = new IntentFilter[2];
        String[][] techList = new String[][]{};

        filters[0] = new IntentFilter();
        filters[0].addAction(NfcAdapter.ACTION_TAG_DISCOVERED);
        filters[1] = new IntentFilter();
        filters[1].addAction(NfcAdapter.ACTION_TECH_DISCOVERED);

        adapter.enableForegroundDispatch(activity, pendingIntent, filters, techList);
    }
@Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        String action = intent.getAction();
        if (NfcAdapter.ACTION_TAG_DISCOVERED.equals(action) ||
                NfcAdapter.ACTION_TECH_DISCOVERED.equals(action)) {
            Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
            if (tag != null) {
                 //do my logic here
            }
        }
    }
@Override
    protected void onPause() {
        super.onPause();
        nfcAdapter.disableForegroundDispatch(this);
    }

我的清单

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="br.org.company.app">

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.WRITE_INTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> 
    <uses-permission android:name="android.permission.SEND_SMS" />
    <uses-permission android:name="android.permission.READ_SMS" />
    <uses-permission android:name="android.permission.CALL_PHONE" />
    <uses-permission android:name="android.permission.CALL_PRIVILEGED" />
    <uses-permission android:name="android.permission.VIBRATE" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE" /> 
    <uses-permission android:name="android.permission.READ_PHONE_NUMBERS" />
    <uses-permission android:name="android.permission.STATUS_BAR" />
    <uses-permission android:name="android.permission.EXPAND_STATUS_BAR" />
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
    <uses-permission android:name="android.permission.PREVENT_POWER_KEY" />
    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
    <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
    <uses-permission android:name="android.permission.WRITE_SETTINGS" />
    <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
    <uses-permission android:name="android.permission.REORDER_TASKS" />
    <uses-permission android:name="android.permission.NFC" />

    <uses-feature
        android:name="android.hardware.nfc"
        android:required="true" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:sharedUserId="android.uid.system"
        android:supportsRtl="true"
        android:theme="@style/Theme.AppCompat.Light.NoActionBar"
        android:versionName="1.2.1xdk"
        android:usesCleartextTraffic="true">
        <meta-data
            android:name="com.google.android.actions"
            android:resource="@xml/actions" />

        <receiver android:name=".receivers.GpsLocationReceiver">
            <intent-filter>
                <action android:name="android.location.PROVIDERS_CHANGED" />

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

                <action android:name="android.location.LocationManager.KEY_LOCATION_CHANGED" />
            </intent-filter>
        </receiver>
        <receiver
            android:name=".receivers.PassiveLocationChangedReceiver"
            android:enabled="true">
            <intent-filter>
                <action android:name="android.location.LocationManager.KEY_LOCATION_CHANGED" />
            </intent-filter>
        </receiver>
        <receiver
            android:name=".receivers.BootReceiver"
            android:enabled="true"
            android:exported="false">
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED" />
                <action android:name="android.intent.action.BOOTUP_COMPLETE" />
                <action android:name="android.intent.action.QUICKBOOT_POWERON" />
            </intent-filter>
        </receiver>
        <receiver android:name=".receivers.MyWakefulReceiver" />
        <receiver android:name=".receivers.InternetConnectionReceiver">
            <intent-filter>
                <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
                <action android:name="android.net.wifi.WIFI_STATE_CHANGE" />
            </intent-filter>
        </receiver>
        <receiver android:name=".receivers.IncomingCall">
            <intent-filter>
                <action android:name="android.intent.action.PHONE_STATE" />
            </intent-filter>
        </receiver>

        <activity
            android:name=".FirstScreenActivity"
            android:configChanges="orientation|keyboardHidden|screenSize"
            android:label="@string/app_name"
            android:launchMode="singleTask"
            android:screenOrientation="portrait"
            android:sharedUserId="android.uid.system"
            android:soundEffectsEnabled="true"
            android:theme="@style/Theme.AppCompat.Light.NoActionBar">
            <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>
        <activity
            android:name=".FullscreenActivity"
            android:configChanges="orientation|keyboardHidden|screenSize"
            android:label="@string/app_name"
            android:launchMode="singleTask"
            android:screenOrientation="portrait"
            android:sharedUserId="android.uid.system"
            android:soundEffectsEnabled="true"
            android:theme="@style/Theme.AppCompat.Light.NoActionBar">
            <intent-filter>
                <action android:name="android.intent.action.CALL_BUTTON" />
            </intent-filter>
            <intent-filter>
                <action android:name="android.nfc.action.TAG_DISCOVERED" />
            </intent-filter>
            <intent-filter>
                <action android:name="android.nfc.action.NDEF_DISCOVERED" />

                <data android:mimeType="text/pg" />
            </intent-filter>

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

        <receiver
            android:name=".AppDeviceAdmin"
            android:description="@string/app_name"
            android:label="@string/app_name"
            android:permission="android.permission.BIND_DEVICE_ADMIN">
            <meta-data
                android:name="android.app.device_admin"
                android:resource="@xml/app_device_admin" />
            <intent-filter>
                <action android:name="android.app.action.PROFILE_PROVISIONING_COMPLETE" />
                <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
            </intent-filter>
        </receiver>

    </application>

</manifest>

在 logcat 上没有例外,看到 NFC 读取甚至没有传送到我的应用程序。 (在它从后台返回并且 phone 读取 NFC 后,我的应用程序甚至没有触发 onPause()、onResume())

到目前为止,这与我的应用程序是启动器有关,尽管我没有发现任何关于此限制的信息。

所以我找到了问题的答案;这个应用程序是一个全屏(公司内部应用程序)所以在我的 onCreate() 我有各种标志来保持应用程序在屏幕上并尽可能避免锁定屏幕上的键盘保护(以避免用户去其他应用程序) 这就是问题所在,我的应用有

WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD
WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON
WindowManager.LayoutParams.FLAG_FULLSCREEN

并且出于某种原因阻止键盘锁出现(运行 应用程序在锁定屏幕上)禁用 NFC 传送到应用程序(我猜是出于安全原因)。由于这是一个内部应用程序(并且所有 phone 都是由 I.T 团队预先设置的)解决方案是通过 phone 设置从锁定屏幕手动删除键盘锁并删除标志

WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD

所以每次用户锁定和解锁 phone 系统都会再次启用 NFC reader。