You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Android NFC支付应用未设为默认时无法优先调用问题咨询

解决Android HCE支付应用前台优先调用问题

看起来你已经把HCE服务的基础配置做对了——设为默认支付应用能正常工作,说明AID、服务权限这些核心配置都没问题。但要让打开的应用优先于默认支付应用,你还缺了关键的一步:给你的前台Activity配置NFC前台调度(Foreground Dispatch),因为HCE服务本身是后台组件,系统不会自动把前台应用和后台HCE服务关联起来抢占默认应用的优先级。

下面分步骤讲清楚怎么解决:

1. 为什么当前配置不行?

Android的“使用已打开应用替代默认支付应用”选项,本质是允许前台应用抢占NFC事件的处理权,但HCE支付场景比较特殊:默认支付应用的HCE服务是系统级优先级,除非你的前台Activity主动注册了NFC前台调度,否则系统还是会把支付事件派发给默认应用的HCE服务,哪怕你的应用是打开状态。

2. 添加前台NFC调度代码

你需要在应用的主Activity(就是你提前打开的那个页面)中,添加NFC前台调度的逻辑,确保应用在前台时能拦截NFC支付事件。示例代码如下:

import android.nfc.NfcAdapter;
import android.nfc.Tag;
import android.nfc.tech.IsoDep;
import android.content.Intent;
import android.content.IntentFilter;
import android.app.PendingIntent;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {
    private NfcAdapter mNfcAdapter;
    private PendingIntent mPendingIntent;
    private IntentFilter[] mIntentFilters;
    private String[][] mTechLists;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mNfcAdapter = NfcAdapter.getDefaultAdapter(this);
        if (mNfcAdapter == null) {
            // 设备不支持NFC,给用户提示
            return;
        }

        // 创建PendingIntent:NFC事件触发时,重新启动当前Activity(单例模式)
        mPendingIntent = PendingIntent.getActivity(
                this,
                0,
                new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP),
                PendingIntent.FLAG_MUTABLE // 适配Android 12+的权限要求
        );

        // 配置IntentFilter,过滤HCE相关的NFC事件
        IntentFilter hceFilter = new IntentFilter(NfcAdapter.ACTION_TECH_DISCOVERED);
        try {
            hceFilter.addDataType("application/vnd.android.nfc.cardemulation");
        } catch (IntentFilter.MalformedMimeTypeException e) {
            throw new RuntimeException("Invalid MIME type for HCE", e);
        }
        mIntentFilters = new IntentFilter[]{hceFilter};

        // 指定支持的NFC技术:HCE依赖ISO-DEP协议
        mTechLists = new String[][]{{IsoDep.class.getName()}};
    }

    @Override
    protected void onResume() {
        super.onResume();
        // 应用回到前台时,启用前台调度,抢占NFC事件处理权
        if (mNfcAdapter != null && mNfcAdapter.isEnabled()) {
            mNfcAdapter.enableForegroundDispatch(this, mPendingIntent, mIntentFilters, mTechLists);
        }
    }

    @Override
    protected void onPause() {
        super.onPause();
        // 应用退到后台时,禁用前台调度,避免干扰其他应用
        if (mNfcAdapter != null) {
            mNfcAdapter.disableForegroundDispatch(this);
        }
    }

    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        // 处理拦截到的NFC事件,这里可以把事件转发给你的HCE服务
        if (NfcAdapter.ACTION_TECH_DISCOVERED.equals(intent.getAction())) {
            Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
            if (tag != null) {
                // 这里可以根据需求处理APDU指令,或者直接交给HCE服务处理
                // 比如通过Intent启动你的HCE服务,传递Tag数据
            }
        }
    }
}

3. 补充必要的权限和配置

  • 确保你的Manifest中已经添加了NFC权限(如果还没加的话):
    <uses-permission android:name="android.permission.NFC" />
    <uses-feature android:name="android.hardware.nfc" android:required="true" />
    
  • 确认系统设置中NFC > 支付 > 使用已打开的应用选项已经开启,这个是前提条件。

4. 额外检查点

  • 确认你的apduservice.xml中的PPSE AID是正确的(标准PPSE AID是325041592E5359532E4444463031),如果你的@string/aid_number对应的值不对,可能导致支付终端无法识别你的应用。
  • 测试时,确保你的应用处于完全前台状态(没有被其他应用覆盖),后台状态下前台调度是不生效的。

这样配置后,当你提前打开应用并保持在前台时,系统就会优先把NFC支付事件派发给你的应用,而不是默认的Android Pay了。

内容的提问来源于stack exchange,提问作者Stepan Sanda

火山引擎 最新活动