I need to create a custom capacitor plugin in order to connect an angular ionic app with native sdk. The app is going to run on a SUNMI P2 PRO POS, which doesn’t have support for builtin android nfc. The Sunmi uses its own SDK (Sunmi Pay SDK) to connect to the hardware, as the NFC module. I have never coded a capacitor plugin before neither an Android application in native Java code, so the logic here is all new, but I managed to get things rolling as for connection angular-plugin and connection to the PaySDK on App launch.
The problem now is to enable a “readMode” to read NFC cards (all I need at the moment is top receive the uuid of the card, so quite basic operation)
The SDK comes with some prepared functions, I followed the logic of the documentation (available on the SUNMI website) and used the checkCard() function, but the problem is that when the enableRead() of the plugin is called the checkCard function of the SDK seems to be exiting without executing anything or waiting for a card to be scanned with the sensor.
I thought that the problem could have been the capacitor call.resolve called right after the call to the sdk plugin, so I put the resolve inside the CheckCardCallback, but nothing really happens. Don’t know what to do, don’t know if it’s a problem with how Java handles async code or something different…
Below the java code (javascript code is only an async call to the plugin method, typical with Capacitor logic)
SunmiNfcPlugin.java
import com.getcapacitor.Plugin;
import com.getcapacitor.PluginCall;
import com.getcapacitor.PluginMethod;
import com.getcapacitor.annotation.CapacitorPlugin;
import com.getcapacitor.JSObject;
@CapacitorPlugin(name = "SunmiNfc")
public class SunmiNfcPlugin extends Plugin {
private SunmiNfc implementation;
@Override
public void load() {
implementation = new SunmiNfc(getActivity());
}
@PluginMethod()
public void test(PluginCall call) {
JSObject ret = new JSObject();
String type = "Hello world!";
ret.put("test", type);
call.resolve(ret);
}
@PluginMethod()
public void enableRFIDMode(PluginCall call) {
JSObject ret = new JSObject();
CardWrapper cardWrapper;
this.implementation.checkRFIDCard(call);
ret.put("sunminfc", "startedReadMode");
}
@PluginMethod()
public void disableRFIDMode(PluginCall call) {
this.implementation.cancelCheckRFIDCard();
call.resolve(new JSObject());
}
@Override
protected void handleOnDestroy() {
super.handleOnDestroy();
this.implementation.disconnectPayService();
}
}
SunmiNfc.java
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import androidx.appcompat.app.AppCompatActivity;
import com.getcapacitor.JSObject;
import com.getcapacitor.PluginCall;
import com.sunmi.pay.hardware.aidl.AidlConstants;
import com.sunmi.pay.hardware.aidlv2.AidlConstantsV2;
import com.sunmi.pay.hardware.aidlv2.emv.EMVOptV2;
import com.sunmi.pay.hardware.aidlv2.pinpad.PinPadOptV2;
import com.sunmi.pay.hardware.aidlv2.readcard.CheckCardCallbackV2;
import com.sunmi.pay.hardware.aidlv2.readcard.ReadCardOptV2;
import com.sunmi.pay.hardware.aidlv2.security.SecurityOptV2;
import com.sunmi.pay.hardware.aidlv2.system.BasicOptV2;
import plugins.SunmiNfc.utils.CheckCardCallbackV2Wrapper;
import sunmi.paylib.SunmiPayKernel;
public class SunmiNfc {
private static final String TAG = "SunmiNfcPlugin";
private SunmiPayKernel mSMPayKernel;
private boolean isDisconnectService = true;
public ReadCardOptV2 mReadCardOptV2; // Read card module
public EMVOptV2 mEMVOptV2; // EMV operations API
public PinPadOptV2 mPinPadOptV2;
public BasicOptV2 mBasicOptV2;
public SecurityOptV2 mSecurityOptV2;
private AppCompatActivity activity;
private PluginCall tmpCall;
public SunmiNfc(AppCompatActivity activity) {
this.activity = activity;
connectPayService();
}
private void connectPayService() {
mSMPayKernel = SunmiPayKernel.getInstance();
mSMPayKernel.initPaySDK(activity.getApplicationContext(), mConnectCallback);
}
private SunmiPayKernel.ConnectCallback mConnectCallback = new SunmiPayKernel.ConnectCallback() {
@Override
public void onConnectPaySDK() {
Log.d(TAG, "SUNMI Pay SDK Connected");
try {
mEMVOptV2 = mSMPayKernel.mEMVOptV2;
mReadCardOptV2 = mSMPayKernel.mReadCardOptV2;
mPinPadOptV2 = mSMPayKernel.mPinPadOptV2;
mBasicOptV2 = mSMPayKernel.mBasicOptV2;
mSecurityOptV2 = mSMPayKernel.mSecurityOptV2;
isDisconnectService = false;
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void onDisconnectPaySDK() {
Log.d(TAG, "SUNMI Pay SDK Disconnected");
isDisconnectService = true;
}
};
public void disconnectPayService() {
this.mSMPayKernel.destroyPaySDK();
mReadCardOptV2 = null;
mEMVOptV2 = null;
mPinPadOptV2 = null;
mBasicOptV2 = null;
mSecurityOptV2 = null;
isDisconnectService = true;
}
// Control green Led function - 1 to activate, 0 to deactivate
public void controlLed(int activate) {
try {
mBasicOptV2.ledStatusOnDeviceEx(1, (activate+1)&2, 1, 1);
} catch (Exception e) {
e.printStackTrace();
}
}
public void checkRFIDCard(PluginCall call) {
try {
int cardType = AidlConstants.CardType.NFC.getValue();
controlLed(1);
tmpCall = call;
mReadCardOptV2.checkCard(cardType, mCheckCardCallback, 60);
} catch (Exception e) {
e.printStackTrace();
call.reject("There was an error");
tmpCall = null;
}
}
public void cancelCheckRFIDCard() {
try {
mReadCardOptV2.cancelCheckCard();
} catch (Exception e) {
e.printStackTrace();
}
}
private CheckCardCallbackV2 mCheckCardCallback = new CheckCardCallbackV2Wrapper() {
@Override
public void findRFCard(String uuid) throws RemoteException {
super.findRFCard(uuid);
Log.i(TAG, "Type: NFC");
Log.i(TAG, "findRFCard:" + uuid);
JSObject ret = new JSObject();
ret.put("uuid", uuid);
tmpCall.resolve(ret);
tmpCall = null;
}
};
}
```tion in detail and share your code, configuration, and other relevant info.