This is how I set up HCE: Manifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.NFC" />
<uses-feature android:name="android.hardware.nfc.hce" android:required="true"/>
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.NFCHCE"
tools:targetApi="33">
<activity
android:name=".MainActivity"
android:exported="true"
android:theme="@style/Theme.NFCHCE">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name=".MyHostApduService"
android:exported="true"
android:permission="android.permission.BIND_NFC_SERVICE">
<intent-filter>
<action android:name="android.nfc.cardemulation.action.HOST_APDU_SERVICE"/>
</intent-filter>
<meta-data
android:name="android.nfc.cardemulation.host_apdu_service"
android:resource="@xml/apduservice"/>
</service>
</application>
</manifest>
apduservice.xml
<?xml version="1.0" encoding="utf-8"?>
<host-apdu-service xmlns:android="http://schemas.android.com/apk/res/android"
android:description="@string/app_name"
android:requireDeviceUnlock="false">
<aid-group android:description="@string/app_name"
android:category="payment">
<aid-filter android:name="A0000000041010"/>
</aid-group>
</host-apdu-service>
MyHostApduService.kt
class MyHostApduService : HostApduService() {
override fun processCommandApdu(commandApdu: ByteArray?, extras: Bundle?): ByteArray {
Log.d("commandApdu Test", "commandApdu - $commandApdu")
commandApdu?.forEach {
Log.d("commandApdu Test", "connected - $it")
}
return byteArrayOf(0x90.toByte(), 0x00.toByte())
}
override fun onDeactivated(reason: Int) {
Log.d("commandApdu Test", "onDeactivated reason: $reason")
}
}
According to official docs. When setting up HCE in android device, if I set android:requireDeviceUnlock="false" processCommandApdu should get triggered whenever it is tapped to NFC reader. When I tested it I cannot use this feature. I can make it work only when devices screen is on. and also it works even app is cleared from recent apps.
Tested on Samsung A32 android ver. 13 and Xiaomi 12 Lite android ver. 14
There is a difference between unlocked and screen is on.
If you look at the doc
HostApduService_requireDeviceScreenOn
public static final int HostApduService_requireDeviceScreenOn
Whether the device must be screen on before routing data to this service. > The default is true.
May be a boolean value, such as "true" or "false".
As you have only set requireDeviceUnlock="false" and the default requireDeviceScreenOn="True" then this matches the behaviour you are seeing which the screen must be on but it does not need to be unlocked.
Set requireDeviceScreenOn="false"
in your xml and try again.