React native: Callback in Native Module not being called? - android

I'm facing a issue in an app I'm developing that someone may be able to help me with.
I'm working on an app for payment machines that use Android (7.1), with it you are able to pay with credit card. The company that developed these machines offer a java sdk. Since this app is using React Native, I wrote a Native Module to connect with it. The SDK is really simple.
After the app is authenticated (done just once), All I have to do is call the doAsyncPayment method with the right parameters, and once its done, it will call the onSuccess or onError method of the listener.
When either of these methods is called, I call the callback parameter I got from the React Native side. In theory it's supposed to work, and it does, most of the time. Every once in a while, something happens that these callbacks are not called, so the client stays on the loading payment screen forever. No error is reported on sentry.
The only thing I'm thinking is that somehow the bridge is losing it? Maybe because these method runs asyncronously in the native side (another thread?), the connection is maybe lost?
I haven't been able to reproduce it, because it happens rarely and at random (I suppose).
I don't know much of Native Android, so any help is appreciated.
Here is a resumed piece of code of what's happening:
Native method being called:
#ReactMethod
public void startPayment(...other params,
Callback onErrorCallback, Callback onSuccessCallback) {
setPlugPag();
PlugPagPaymentData paymentData = new PlugPagPaymentData(paymentType, amountCents,
installmentType, installments, userReference, printReceipt);
PlugPagInitializationResult initResult = plugPag.initializeAndActivatePinpad(new
PlugPagActivationData(activationCode));
if(initResult.getResult() == PlugPag.RET_OK) {
plugPag.doAsyncPayment(paymentData, new PlugPagPaymentListener() {
PlugPagPrintResult printResult;
#Override
public void onSuccess(#NonNull PlugPagTransactionResult plugPagTransactionResult) {
if(printResult != null) {
WritableMap printResultMap = Arguments.createMap();
printResultMap.putInt("result", printResult.getResult());
printResultMap.putString("message", printResult.getMessage());
printResultMap.putString("errorCode", printResult.getErrorCode());
onSuccessCallback.invoke(TransactionResult.toRNWritableMap(plugPagTransactionResult), printResultMap);
}else {
onSuccessCallback.invoke(TransactionResult.toRNWritableMap(plugPagTransactionResult));
}
}
#Override
public void onError(#NonNull PlugPagTransactionResult plugPagTransactionResult) {
onErrorCallback.invoke(TransactionResult.toRNWritableMap(plugPagTransactionResult));
}
#Override
public void onPaymentProgress(#NonNull PlugPagEventData plugPagEventData) {
WritableMap eventDataMap = Arguments.createMap();
eventDataMap.putString("customMessage", plugPagEventData.getCustomMessage());
eventDataMap.putInt("eventCode", plugPagEventData.getEventCode());
sendEvent(Constants.EVENT_PLUG_PAG_PAYMENT_PROGRESS_CHANGED, eventDataMap);
}
#Override
public void onPrinterSuccess(#NonNull PlugPagPrintResult plugPagPrintResult) {
}
#Override
public void onPrinterError(#NonNull PlugPagPrintResult plugPagPrintResult) {
}
});
}else {
onErrorCallback.invoke(String.valueOf(initResult.getResult()));
}
}
on React native side, I just call:
startPayment(...other params, errorCallback, successCallback);
Maybe because the way the listener is instantiated?
Thanks in advance.

Related

Incomings Call with Android Sip stack in Embarcadero C++ builder

I'm trying to receive calls on my SIP application at Embarcadero with C++ builder
and I'm not able to get it. My situation is as follows:
I've made an Asterisk server, I've created several accounts to be able to do the
tests and I've downloaded the Zoiper application for both Windows and Android.
In my designed application, I'm able to make calls to those accounts registered
in Zoiper, although not through events, it seems that the listener does not
listen, and I've done it through the status changes in the call.
The Java code is like this:
SipAudioCall.Listener listener = new SipAudioCall.Listener() {
#Override
public void onCallEstablished(SipAudioCall call) {
call.startAudio();
call.setSpeakerMode(true);
call.toggleMute();
Log.d("on call established", "on call established");
}
#Override
public void onCallEnded(SipAudioCall call) {
finish();
}
};
In Embarcadero C++ builder I think it would be like this (it doesn't work)
Compiles and executes but the event never occurs:
//The Manifest counts as the necessary permissions for Android, Internet and Sip.
_di_JSipAudioCall_Listener audioCall_Listener;
_di_JSipSession_Listener sessionListener;
_di_JSipSession session;
_di_JSipManager;
_di_JSipAudioCall audioCall;
_di_JSipProfile profile;
_di_JString uri;
_di_JString uri_llamada;
void onCallEstablished2(SipAudioCall call);
//The process of profile creation and instantiation of SipManager are programmed
//and compiled and do not give any problem.
audioCall_listener = TJSipAudioCall_Listener::JavaClass->init();
audioCall_listener->onCallEstablished = onCallEstablished2;
sessionListener = TJSipSession_Listener::JavaClass->init();
session = manager->createSipSession(profile,sessionListener);
audioCall = manager->makeAudioCall(uri,uri_llamada,audioCall_listener,15);
void onCallEstablished2(SipAudioCall call)
{
audioCall->startAudio();
audioCall->setSpeakerMode(true);
}
The code made in Embarcadero C++ builder that works:
//The Manifest counts as the necessary permissions for Android, Internet and Sip.
_di_JSipAudioCall_Listener audioCall_Listener;
_di_JSipSession_Listener sessionListener;
_di_JSipSession session;
_di_JSipManager;
_di_JSipAudioCall audioCall;
_di_JSipProfile profile;
_di_JString uri;
_di_JString uri_llamada;
//The process of profile creation and instantiation of SipManager are programmed
//and compiled and do not give any problem.
audioCall_listener = TJSipAudioCall_Listener::JavaClass->init();
audioCall_listener->onCallEstablished = onCallEstablished2;
sessionListener = TJSipSession_Listener::JavaClass->init();
session = manager->createSipSession(profile,sessionListener);
audioCall = manager->makeAudioCall(uri,uri_llamada,audioCall_listener,15);
Timer1->Enabled = true;
void __fastcall TMainForm::Timer1Timer(TObject *Sender)
{
if (audioCall->getState() == 8)
{
audioCall->startAudio();
audioCall->setSpeakerMode(true);
}
if(audioCall->getState() == 0)
{
audioCall->endCall();
}
}
As for the Java code for receiving calls, I have found examples here
No ringing event on incoming calls
and here
Android Sip incoming Call using Service with Broadcast Receiver,
but they are all event based, which doesn't seem to work for me.
I have also tried to do the IncomingReceiver class, which extends from
BroadcastReceiver and at the Embarcadero gives me problems.
Class made in Embarcadero with C++ builder (not compiles):
class IncomingReceiver: public JBroadcastReceiver{
public:
__fastcall IncomingReceiver();
_di_JSipAudioCall incomingCall;
void onReceive(_di_JContext contexto, _di_JIntent intento);
void accept();
void showIncomingCallGui(_di_JIntent intento, _di_JContext contexto);
};
So, my questions are:
Why don't events work for me?
Can I receive calls without events?
If so, what would it be like without events?
What do I do if I can't get the IncomingReceiver class?
I found a page (in spanish): http://lfgonzalez.visiblogs.com/cbuilder-10-2-tokyo-jni-broadcastreceiver-android/ in which it is explained the use of BroadcastReceiver in Embarcadero C++ Builder. Maybe with this information you can get the events working in order to receive calls.

LibGDX http request not working

I want to send a String message to database when user presses a specific button in the LibGDX game I am designing for android. How do I go about doing that? Following is the code I tried. But it does not work.
Net.HttpRequest httpRequest = new Net.HttpRequest();
httpRequest.setMethod("POST");
httpRequest.setUrl("URL is here");
httpRequest.setContent("INSERT INTO `game_table` (`Button`) VALUES ('Button 1 Pressed')");
Net.HttpResponseListener httpResponseListener = new Net.HttpResponseListener() {
#Override
public void handleHttpResponse(Net.HttpResponse httpResponse) {
Gdx.app.log("Log httpResponse", httpResponse.getResultAsString());
}
#Override
public void failed(Throwable t) {
}
#Override
public void cancelled() {
}
};
Gdx.net.sendHttpRequest(httpRequest,httpResponseListener);
Log does not provide anything in android monitor. I also tried using AsyncTask and without AsyncTask to implement this code. But neither works.
Am I missing something? If so could you give me small code snippet that will work?
You don't need to use an AsyncTask, libGDX' HTTPRequest is async out of the box.
You did not log anything if the request fails or is cancelled so probably that's the case.

React Native - Module Lifecycle - Dispose resources on "Reload"

I am using a react native module (https://github.com/rusel1989/react-native-bluetooth-serial) for Bluetooth communication with an Arduino.
Eveything works just fine. But when I press "Reload" or the application reloads due to Live Reload being enabled, the onDestroy method of the module is not called. Because of that, the sockets (and streams) are no correctly disposed.
When the reload is finished, I can no longer open a bluetooth socket. It requires me to disable and enable bluetooth, or to restart the application.
Is there ant callback or method I could implement that would correctly dispose these sockets when I reload my application?
Ok after spending time in react-native code I found the answer to this:
On iOS:
You'll have to implement a method called invalidate in your RCTBridgeModule implementation:
That will run whenever the context is destroyed (the app is reloaded) and it will look like this:
- (void)invalidate
{
// disconnect bluetooth here
}
Here's an example of how I did it on iOS.
On Android:
you'll have to implement the onCatalystInstanceDestroy method inside your ReactContextBaseJavaModule and it will look like this:
#Override
public void onCatalystInstanceDestroy() {
// disconnect bluetooth here
}
Here's an example of how I did it on Android.
It seems we can use #Override public void onCatalystInstanceDestroy() {} without the need of implementing anything.
That method will be called before the current JS bundle is destroyed.
on iOS
- (instancetype)init
{
self = [super init];
NSLog(#"whatever you want");
return self;
}
- (void)dealloc
{
// by the way, you do not need the following line because of ARC
// [super dealloc];
NSLog(#"whatever you want");
}
I prefer use dealloc rather than invalidate
because react-native api may change in the future...
on android
import com.facebook.react.bridge.LifecycleEventListener;
import android.util.Log;
public class YourModule extends ReactContextBaseJavaModule implements LifecycleEventListener {
...
YourModule(ReactApplicationContext reactContext) {
super(reactContext);
reactContext.addLifecycleEventListener(this);
this.reactContext = reactContext;
Log.d("YourModuleLog", "whatever you want");
}
#Override
public void onHostResume() {}
#Override
public void onHostPause() {}
#Override
public void onHostDestroy() {
Log.d("YourModuleLog", "not trigger after fast reload");
}
#Override
public void onCatalystInstanceDestroy() {
Log.d("YourModuleLog", "whatever you want");
}
}
only override onCatalystInstanceDestroy does not work for me
unless I also add LifecycleEventListener.

Particular overload of Azure Mobile Service invokeApi is not working while calling custom API

Where is the documentation/sample for all overloads of invokeApi function for Azure Mobile Service client SDK for Android?
I found this article and tried following code, which does not work. There are no compile time or run time errors, invokeApi gets called, but it does not come back to onSuccess or onFailure. If I call invokeApi without order object, everything works as expected
PizzaOrder order = new PizzaOrder();
order.Size = "Large";
order.Flavor = "Four cheeses";
order.UserPhone = "555-555-1234";
ListenableFuture<PizzaOrderResponse> testresult = mClient.invokeApi("bookservice", order, PizzaOrderResponse.class);
Futures.addCallback(testresult, new FutureCallback<PizzaOrderResponse>() {
#Override
public void onFailure(Throwable exc) {
// failure handling code here
}
#Override
public void onSuccess(PizzaOrderResponse testresult) {
// success handling code here
}
});
One of the properties in the data object being returned by the custom API had incorrect data type. I am still not sure where the good documentation is and why custom API call did not fail but at least it is working now.

How would you write a test for this method using Mockito?

Please assist in this. I can't seem to create a suitable test for this method:
protected void startInterfacing() {
mLiveAuthClient.login(mView.context(), Arrays.asList(SCOPES), new LiveAuthListener() {
#Override
public void onAuthComplete(final LiveStatus liveStatus, final LiveConnectSession liveConnectSession,
Object o) {
// Login successful and user consented, now retrieve user ID and connect with backend server
getUserIdAndConnectWithBackendServer(liveConnectSession, mLiveAuthClient);
}
#Override
public void onAuthError(LiveAuthException e, Object o) {
// We failed to authenticate with auth service... show error
if (e.getError().equals("access_denied") ||
e.getMessage().equals("The user cancelled the login operation.")) {
// When user cancels in either the login or consent page, we need to log the user out to enable
// the login screen again when trying to connect later on
logUserOut(mLiveAuthClient, false);
} else {
onErrorOccured();
}
}
});
}
I'll explain abit what goes on here:
I'm trying to authenticate my client and log into OneDrive.
The method starts with a call to the Live SDK's login method. That SDK object is given to me from outside this class. So I can basically mock it.
Here's what I'm struggling with:
I do not need to test the call to the login method because it is not mine. I do need to test the call to getUserIdAndConnectWithBackendServer() inside onAuthComplete. But this method requires a liveConnectSession object. How do I provide that? It is given to me on the onAuthComplete method.
How do I mock the calls to onAuthComplete and onAuthError? I read about ArgumentCaptor but when I use that, I need to provide the arguments to those methods when I call the actual method.
For instance, argument.getValue().onAuthComplete() requires me to add arguments to this call. What do I actually provide here?
Here is the next method which is roughly the same but has its own issues:
protected void getUserIdAndConnectWithBackendServer(final LiveConnectSession liveConnectSession, final LiveAuthClient
authClient) {
final LiveConnectClient connectClient = new LiveConnectClient(liveConnectSession);
connectClient.getAsync("me", new LiveOperationListener() {
#Override
public void onComplete(LiveOperation liveOperation) {
// We got a result. Check for errors...
JSONObject result = liveOperation.getResult();
if (result.has(ERROR)) {
JSONObject error = result.optJSONObject(ERROR);
String code = error.optString(CODE);
String message = error.optString(MESSAGE);
onErrorOccured();
} else {
connectWithBackend(result, liveConnectSession, authClient);
}
}
#Override
public void onError(LiveOperationException e, LiveOperation liveOperation) {
// We failed to retrieve user information.... show error
onErrorOccured();
logUserOut(authClient, false);
}
});
}
In here I would like to mock the JSONObject for instance. But how do I call the onComplete method, or the onError method. And what would I provide as the arguments the methods provide me with. LiveOperation for instance?
Thank you!!
The solution I eventually used was to use mockito's doAnswer() structure.
This enabled me to get the callback argument and call one of its methods.
Another solution was to use an ArgumentCator.

Categories

Resources