You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android OMAPI中SEService的OnConnectedListener未触发问题求助

问题描述

我正在开发一款使用OMAPI库向SIM卡传输APDU的应用,但SEService的OnConnectedListener始终未被调用。我参考谷歌CTS测试代码结构实现,等待30秒仍未触发该监听器,最终抛出超时异常:

throw new TimeoutException( "Service could not be connected after " + SERVICE_CONNECTION_TIME_OUT + "ms");

我的SIM卡包含ARA-M小程序及必要的SHA-1密钥,应用已获取运营商权限,且在另一款使用TelephonyManager库的应用中成功传输过APDU。请问是否存在操作错误?应用清单是否需要声明特殊权限?

以下是部分实现代码:

public class MainActivity extends AppCompatActivity [...]{
     /*FOR OMAPI*/
    private final Object serviceMutex = new Object();
    private SEService seService;
    private boolean connected = false;
    private Timer connectionTimer;
    private ServiceConnectionTimerTask mTimerTask = new ServiceConnectionTimerTask();
    private final long SERVICE_CONNECTION_TIME_OUT = 30000;
    //////////////////////////////////////////////////////////////////////////////


   @Override
    public void onCreate(Bundle savedInstanceState) {

      [...]
                setUp(getApplicationContext());

                try {
                    waitForConnection();
                } catch (TimeoutException e) {
                    throw new RuntimeException(e);
                }

                Reader[] readers = seService.getReaders();
                byte [] apdu = {(byte)0x80, (byte)0x02, (byte)0xfC, (byte)0x00};

                for (Reader reader : readers){

                    byte [] response = new byte[0];
                    try {
                        response = Util.internalTransmitAPDU(reader, apdu);
                    } catch (IOException e) {
                        throw new RuntimeException(e);
                    }
                    Log.i("response OMAPI", String.valueOf(response));
                }

   }


    public void setUp(Context context){

        seService = new SEService(context, new SynchronousExecutor(), mListener);
        connectionTimer = new Timer();
        connectionTimer.schedule(mTimerTask, SERVICE_CONNECTION_TIME_OUT);
    }

    static class SynchronousExecutor implements Executor {
        public void execute(Runnable r) {
            r.run();
        }
    }

    private final SEService.OnConnectedListener mListener = () -> {
        synchronized (serviceMutex){
            connected = true;
            serviceMutex.notify();
            Log.i("OMAPI", "EntraOnconnect");
        }


    private void waitForConnection() throws TimeoutException {
        synchronized (serviceMutex) {
            if (!connected) {
                try {
                    serviceMutex.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            if (!connected && !seService.isConnected()) {
                throw new TimeoutException(
                        "Service could not be connected after " + SERVICE_CONNECTION_TIME_OUT
                                + " ms");
            }
            if (connectionTimer != null) {
                connectionTimer.cancel();
            }
        }
    }
}

排查与解决建议

1. 代码中的致命问题

  • 主线程阻塞导致回调无法执行:你在onCreate(主线程)中调用waitForConnection(),该方法通过serviceMutex.wait()阻塞了主线程。而你的SynchronousExecutor是直接在当前线程(主线程)执行回调,主线程被阻塞后,OnConnectedListener的回调根本无法运行。
    解决:将OMAPI的连接逻辑和APDU传输放到后台线程(如Coroutine、Thread或ExecutorService),避免阻塞主线程。

  • 监听器代码未闭合:mListener的lambda表达式缺少闭合的};,这会导致编译或运行时异常,使得监听器无法正常注册。修正后的代码:

private final SEService.OnConnectedListener mListener = () -> {
    synchronized (serviceMutex){
        connected = true;
        serviceMutex.notify();
        Log.i("OMAPI", "EntraOnconnect");
    }
}; // 补充闭合符号
  • 未实现超时任务:ServiceConnectionTimerTask未实现,它应该在超时后设置connected = false并唤醒等待的线程,否则超时逻辑不完整。示例实现:
class ServiceConnectionTimerTask extends TimerTask {
    @Override
    public void run() {
        synchronized (serviceMutex) {
            connected = false;
            serviceMutex.notify();
        }
    }
}

2. 应用清单权限检查

必须在AndroidManifest.xml中声明以下权限:

  • 基础权限:
    <uses-permission android:name="android.permission.NFC" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    
  • 运营商/SE访问权限:
    如果你是运营商特权应用,需要声明:
    <uses-permission android:name="com.android.carrierapi.permission.CARRIER_PRIVILEGED" />
    
    另外,OMAPI访问SE需要系统级权限,需添加:
    <uses-permission android:name="com.android.se.permission.SECURE_ELEMENT_ACCESS" />
    
    注意:SECURE_ELEMENT_ACCESS是系统签名权限,你的应用需要有运营商或系统签名才能获取,需确保签名与权限要求匹配。

3. 其他注意事项

  • 避免在onCreate中直接执行耗时操作,将APDU传输等逻辑放到后台线程。
  • 确认设备支持OMAPI访问SIM卡SE:部分设备可能限制了OMAPI对SIM卡的访问,即使TelephonyManager可用,OMAPI可能需要额外的设备配置。
  • 管理SEService生命周期:在Activity销毁时调用seService.shutdown()释放资源,避免内存泄漏。

内容的提问来源于stack exchange,提问作者Dariel Reyes

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 03:35:32