retrofit enqueue stop and exit suddenly - android

I'm using Retrofit enqueue to call CodeIgniter Restful API and get subscription message then move to next screen.
inside subscription API method I'm calling SMS and Email services.
if I use only SMS or Email during subscription then program works fine and enqueue OnResponse method being executed. BUT if I use both SMS and Email in same subscription function then enqueue call will exit without executing OnResponse or OnFailure.
I have tried to increase max_execution_time and max_input_time but without success. I don't know what the reason cause my application to exit without executing OnResponse/ OnFailure methods.
also I couldn't trace logs to know the issue because OnFailure is not executed.
I'm using Centos 8 and Apache as web server.
here is the code in CodeIgniter Restful API that insert user to database, then send SMS & email:
$data['user_name']='essa';
$mobnumber = $this->trim_number($data["phone"]);
$data['otp'] = $this->random_number();
$data['otp_status'] = '0';
$this->services_model->insert_data('subscribers',$data);
$id = $this->db->insert_id();
$this->sendsms($mobnumber ,$data['otp']);
$template_data['user_name'] = $data['username'];
$template_data['userid'] = base64_encode($id);
$em_message = $this->parser->parse("subscription.html", $template_data, TRUE);
$email_result = send_mail($data['email'],'registration',$em_message);
$result = ["status"=>1,"message"=>'Registration successful'];
$this->response($result,REST_Controller::HTTP_OK);
and here is my Retrofit.enqueue code:
retrofitCall .enqueue(new Callback<JsonElement>() {
#Override
public void onResponse(Call<JsonElement> call, Response<JsonElement> response)
{
if (response.isSuccessful())
{
try {
JSONObject jsonObject = new JSONObject(response.body().toString());
int status = jsonObject.getInt("status");
String message = jsonObject.getString("message");
showToast(message);
Intent i = new Intent(Welcome.this, Welcome.class);
i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_CLEAR_TASK);
i.putExtra("message",message);
startActivity(i);
} catch (Exception e) {
e.printStackTrace();
}
}
}
#Override
public void onFailure(Call<JsonElement> call, Throwable t) {
Log.e("retrofiError",t.toString());
}
});

Related

Android: SafetyNet Attest Device Verification Response Network Error

I'm calling SafetyNet Api using Google Client but it not responding the correct response.
SafetyNet.SafetyNetApi.attest(mGoogleApiClient, generateNonce())
.setResultCallback(new ResultCallback<SafetyNetApi.AttestationResult>() {
#Override
public void onResult(SafetyNetApi.AttestationResult result) {
Status status = result.getStatus();
String data = decodeJws(result.getJwsResult());
if (status.isSuccess()) {
// Indicates communication with the service was successful.
// Use result.getJwsResult() to get the result data.
} else {
// An error occurred while communicating with the service.
}
}
});
I'm getting below error message in result method.
Status{statusCode=NETWORK_ERROR, resolution=null}
Any kind of help would be highly appreciated.
This doesn't work because you are using SafetyNetApi, which is no longer supported.
Starting with Google Play Services 11.0.0, you should now get an API key, and use SafetyNetClient instead.
You may also want to take a look at 10 things you might be doing wrong when using the SafetyNet Attestation API.
First you have to generate nonce by following method
private static byte[] getRequestNonce() {
String data = String.valueOf(System.currentTimeMillis());
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
byte[] bytes = new byte[24];
Random random = new Random();
random.nextBytes(bytes);
try {
byteStream.write(bytes);
byteStream.write(data.getBytes());
}catch (IOException e) {
return null;
}
return byteStream.toByteArray();
}
Afterwords use safety net client attestation api
SafetyNet.getClient(context).attest(nonce, <API KEY>).addOnSuccessListener(new OnSuccessListener<SafetyNetApi.AttestationResponse>() {
#Override
public void onSuccess(SafetyNetApi.AttestationResponse attestationResponse) {
// parse response
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
// An error occurred while communicating with the service.
}
});
}
Reference: Sample Code Offline verification
Sample Code Online verification using google api

PendingResult.setResultCallback() always returns the statusCode success

if i connect my google watch with a mobile device successfully, and then disable the bluetooth connection (for test reasons) and make a google api client call to my mobile device, the pending result always returns the status code success, even if its not successfull because there is no more connection
async task for the request
class DataTask extends AsyncTask<Node, Void, Void> {
#Override
protected Void doInBackground(Node... nodes) {
Gson gson = new Gson();
Request requestObject = new Request();
requestObject.setType(Constants.REQUEST_TYPE);
String jsonString = gson.toJson(requestObject);
PutDataMapRequest dataMap = PutDataMapRequest.create(Constants.PATH_REQUEST);
dataMap.setUrgent();
dataMap.getDataMap().putString(Constants.KEY_REQUEST, jsonString);
PutDataRequest request = dataMap.asPutDataRequest();
DataApi.DataItemResult dataItemResult = Wearable.DataApi
.putDataItem(googleApiClient, request).await();
boolean connected = googleApiClient.isConnected();
PendingResult<DataApi.DataItemResult> pendingResult = Wearable.DataApi.putDataItem(googleApiClient, request);
pendingResult.setResultCallback(new ResultCallback<DataApi.DataItemResult>() {
#Override
public void onResult(#NonNull DataApi.DataItemResult dataItemResult) {
com.google.android.gms.common.api.Status status = dataItemResult.getStatus();
DataItem dataItem = dataItemResult.getDataItem();
boolean dataValid = dataItemResult.getDataItem().isDataValid();
boolean canceled = status.isCanceled();
boolean interrupted = status.isInterrupted();
float statusCode = status.getStatusCode();
if(status.isSuccess()){ // expected to be false because there is no bluetooth connection anymore
Log.d(TAG, "Success");
}else{
Log.d(TAG, "Failure");
}
}
});
return null;
}
}
why do i not get a false for status.isSuccess?
the only solution i found is to write following code inside the AsyncTask:
Wearable.NodeApi.getConnectedNodes(googleApiClient).await().getNodes();
if(connectedNodes.size() == 0){
// no connection
}
is it not possible to check if the request was successfully inside the ResultCallback?
I believe that the getStatus() call for DataItemResult is only indicating whether the call was successfully passed off to the Data API, not whether it was successfully relayed to another node. The Data API is asynchronous - it's a "store and forward" architecture - so it's not reasonable to expect it to notify you immediately of successful delivery.
In fact, I don't think that there is a way to determine from the Data API when your DataItem has been delivered at all. Your getConnectedNodes technique is only telling you that the watch is connected, not that the data has been delivered. If you need proof of delivery, you'll probably have to implement that yourself, perhaps using the Message API.
One other note: given you've wrapped your code in an AsyncTask, there's no need to use PendingResult.setResultCallback. You can simply await the result inline: http://developer.android.com/training/wearables/data-layer/events.html#sync-waiting

SignalR HTTP status 400 multiple clients

I'm running an application with SignalR 2.2.0 on server side and signalr-java-client (self compiled, last GitHub version) on Android as client.
Currently, there are 4 clients connected to my hub. From time to time, it happens, that all 4 clients simultaneously receive the HTTP status 400 with the message "The connection id is in the incorrect format" (the clients were connected before). I analyzed this multiple times and am not able to find any information/pattern when or why this happens.
The connecten is secured via JWT, the token is definitely valid. When retrieving a new token, the connection is stopped and started again. Apart from this, it is very unlikely that the error is device-related, because the error is thrown at all 4 clients the same time.
I know, this error can occur when the client's Identity changes, but an Identity change for 4 clients the same time seems very unlikely to me.
This is the server-code used for authentication (Deepak asked).
The following method gets called in my Startup.cs:
public static void ConfigureOAuth(IAppBuilder app, string audienceID, string sharedSecret)
{
byte[] secret = TextEncodings.Base64Url.Decode(sharedSecret);
app.UseJwtBearerAuthentication(
new JwtBearerAuthenticationOptions
{
Provider = new MyOAuthBearerAuthenticationProvider(),
AuthenticationMode = AuthenticationMode.Active,
AllowedAudiences = new[] { audienceID },
IssuerSecurityTokenProviders = new IIssuerSecurityTokenProvider[]
{
new SymmetricKeyIssuerSecurityTokenProvider(Issuer, secret)
}
});
}
Here's the code of MyOAuthBearerAuthenticationProvider class:
class MyOAuthBearerAuthenticationProvider : OAuthBearerAuthenticationProvider
{
/// <summary>
/// Get's a JWT from querysting and puts it to context
/// </summary>
public override Task RequestToken(OAuthRequestTokenContext context)
{
if (context.Token == null)
{
string value = context.Request.Query.Get("auth_token");
if (!string.IsNullOrEmpty(value)) //token from queryString
{
context.Token = value;
}
}
return Task.FromResult<object>(null);
}
}
I have to retrieve the token from query string, because additionally to the java-client, a javascript client is used, which is not able to set headers.
Lastly, I secure my hub and some of it's methods with the Authorization attribute:
[Authorize(Roles = "MyExampleRole")]
This is the client-code for connection:
public boolean connect(String url, String token) {
if (connected) {
return true;
}
try {
this.hubConnection = new HubConnection(url, "auth_token=" + token, true, logger);
this.hubProxy = hubConnection.createHubProxy("MyHub");
this.hubProxy.subscribe(this.signalRMethodProvider);
this.hubConnection.stateChanged(stateChangedCallback);
SignalRFuture<Void> awaitConnection = this.hubConnection.start();
awaitConnection.get(10000, TimeUnit.MILLISECONDS);
return true;
}
catch (InterruptedException | TimeoutException | ExecutionException e) {
log.error("connect", e);
return false;
}
}
Does anybody have an Idea, how to fix this problem or where I may receive further information?
Thank you very much
-Lukas
seems fine...
possible alteration you can do is change
awaitConnection.get(10000, TimeUnit.MILLISECONDS);
to
awaitConnection.done(new Action<Void>() {
#Override
public void run(Void obj) throws Exception {
Log.d(TAG, "Hub Connected");
}
}).onError(new ErrorCallback() {
#Override
public void onError(Throwable error) {
error.printStackTrace();
Log.d(TAG, "SignalRServiceHub Cancelled");
}
}).onCancelled(new Runnable() {
#Override
public void run() {
Log.d(TAG, "SignalRServiceHub Cancelled");
}
});

How to stream real time data using Retrofit

I want to observer changes from server in my android app.
So I'm using this interface for open stream with server.
public interface Service {
#GET("/n/{id}/streaming")
void streamThreads(#Path("name_space_id") String Id, #QueryMap Map<String, String> options,#Query("exclude_types") String type, Callback<Object> callback);
}
and this is my method where I can get response in my activity
server.streamThreads(accountInfo.getId(), map, "thread", new Callback<Object>() {
#Override
public void success(Object o, Response response) {
String json = (String) o;
Log.i(TAG,json);
}
#Override
public void failure(RetrofitError error) {
Response r = error.getResponse();
if (r != null)
Log.e(TAG, "error: " + r.getReason());
}
});
So I tested method in web browser and life stream works.
But response comes in my mobile app every 30 minutes. I'm using one activity and call method onCreate().
Thanks
Retrofit provides an #Streaming annotation.
The unread byteStream can then be obtained from the raw OkHttp ResponseBody.

How do I get response from Azure Mobile Service to confirm sending?

i'm currently building a simple android app that sends info to Azure mobile services. I'm using the below example code of the tutorial.
mSClient = new MobileServiceClient(URL, KEY, context);
mSClient = getMSClient();
mSClient.getTable(MyClass.class).insert(form, new TableOperationCallback<MyClass>() {
public void onCompleted(MyClass entity, Exception exception, ServiceFilterResponse response) {
if (exception != null) {
Log.e("MSG", exception.getLocalizedMessage());
}
if (response != null) {
Log.e("MSG", response.getContent());
}
}
});
Now, how do I get the response from ServiceFilterResponse in onComplete method that takes a while to get and the MobileServiceClient have done its work already.
How do I wait to flag my info on sqlite as sent?
When the callback is invoked, it means that the insertion operation already finished at the server side. If you want to flag something between the moment you send the 'insert' request (which is basically a HTTP POST request) to the moment the operation is complete: right
mSClient = new MobileServiceClient(URL, KEY, context);
mSClient = getMSClient();
mSClient.getTable(MyClass.class).insert(form, new TableOperationCallback<MyClass>() {
public void onCompleted(MyClass entity, Exception exception, ServiceFilterResponse response) {
if (exception != null) {
// here: tell sqlite that the insert request failed
Log.e("MSG", exception.getLocalizedMessage());
} else {
// here: tell sqlite that the insert request succeeded
Log.e("MSG", response.getContent());
}
}
});
// here: tell sqlite that the insert request was sent

Categories

Resources