Is it possible for users of my Android Application to view the URLs/Post-Data of HTTP-Post Requests from this App? So they can manipulate it and also view it with their browser on a Desktop Computer?
You can use droidQuery to do this by using the beforeSend callback, and set it as a global ajax setting:
$.ajaxSetup(new AjaxOptions().beforeSend(new Function() {
#Override
public void invoke($ droidQuery, Object... params) {
AjaxOptions options = (AjaxOptions) params[0];
if (options.type().equalsIgnoreCase("post")) {
//here, show the data stored in the AjaxOptions object, such as the URL, data type, headers, etc.
}
}
}));
Calling this method in your onStart method will set it so that all HTTP POST requests made using Ajax that are set as global (default) will trigger the given function before sending the request. Inside the Function, you can view and manipulate the AjaxOptions Object.
Related
I'm implementing codes with jwt on Android.
At point of using refresh token, I'm not sure my code is correct way.
Here is sequene diagram of my flow.
Server issued access token and refresh token. These expire time is 1hour and 3 days. These token is saved to sharedpreferences.
Here is above diagram's description.
When access token is expired, http call will be failed with 401 error.
So I implemented getAccessToken() for re-newing access token.
(1) : One AsyncTask is used for this whole http call step.
- My AsyncTask is too big, I want to refactor it.
(2) : (1)'s AynsTask has a logic for re-getting access token.
- This logic was duplicated all my HTTP call functions.
(3) : After renewing access token, my app re-try to call /api/foo
- To retry it, AsyncTask's doBackground() function is call recursivly.
Here is my code snippet.
class ApplyCheck extends AsyncTask<String, Void, ResponseTypeEnum> {
private List<ApplyEntity> applyEntityList = null;
#Override
protected ResponseTypeEnum doInBackground(String... strings) {
try {
response = restManager.getApplyList(strings[0],"","",""); // call /api/foo
} catch (RestRuntimeException e) {
return ResponseTypeEnum.SERVER_ERROR;
}
switch (response.code()) {
case 200:
//set applyEntityList
....
return ResponseTypeEnum.SUCCESS;
case 401:
//<-- This routine is duplcated all my AsyncTasks
if(getAccessToken()) {
//<-- recursive call to re-call api
return doInBackground(strings);
} else {
return ResponseTypeEnum.TOKEN_EXPIRE;
}
}
}
//re-issue new access token
private boolean getAccessToken() {
Response response = restManager.getAccessToken(); // call /auth/issue-token
if(response.code() == 200) {
String tokens = response.body().string();
JSONObject jsonObject = new JSONObject(tokens);
sharedPreferences.edit().putString("accessToken", jsonObject.getString("accessToken"));
sharedPreferences.edit().putString("refreshToken", jsonObject.getString("refreshToken"));
return true;
} else {
return false;
}
My Questions
1. Is my approach correct? If not, please inform me good practice.
2. If yes, are any good practice for extracting common function for my duplicated AsyncTasks?
The process you have is fine IMHO. The only change is that I would not recursively call doInBackground. What you're doing is feasible, but it violates the intention of doInBackground. Rather modify your AsyncTask to cope with processing different responses in onPostExecute, (ie chaining your requests), and call the AsyncTask again with the relevant parameters for each use case. It will make it much easier to maintain as you can add specific methods to the AsyncTask to cope with each response type and can see how it's triggered in a linear way. If you need to update onProgressUpdate, you should also pass a progress value to the chained AsyncTask calls so it can maintain consistency on the progress. Otherwise it would keep restarting on each call.
I need to parse JSON content out of every page in my WebView, before it is shown to the user.
In order to do so, I need to parse the JSON element and only then I’m able to use the shouldOverrideUrlLoading method. I can’t use it before I’ve parsed the JSON object because I rely on that element as part of my implementation of that method.
I have created a variable called jsonParsed to indicate whether I have all needed information out of the JSON object.
At first, it is initialized to be false.
When I get a response from the server I know the object was parsed so I change the variable to be true in the onLoaded method, and then the code is ready to get the information and check it.
This is the wanted process:
Opening new page by the user
Entering automatically to shouldOverrideUrlLoading and then to the if statement(JSON wasn't parsed yet)
Getting the JSON response in OnResponse
Going back to shouldOverrideUrlLoading and entering the else statement (JSON is parsed)
As you can see, each process should go through both if and else statements, the if before the JSON was parsed, and the else after it was parsed.
The problem:
shouldOverrideUrlLoading is reached every step 1, but each time it goes into a different statement. The first time goes into the if (steps 2+3), and the next one goes into the else (step 4) and this process repeats itself...
I think the this line webView.loadUrl(loadingURL); doesn't call shouldOverrideUrlLoading for some reason.
Here is my code snippet:
#Override
public void onPageStarted(WebView view, String url, Bitmap favicon)
{
super.onPageStarted(view, url, favicon);
mProgressDialog.show();
}
#Override
public boolean shouldOverrideUrlLoading(WebView wView, String url){
loadingURL=url;
if (!jsonParsed){
/** JSON object is not parsed
* Some code for adding request
to requestQueue and than loading new url in onResponse method... */
}
else {
/** JSON object is parsed, starting checking process
* I need to check this URL and decide whether or not to override it*/
jsonParsed=false;
Root root = new Gson().fromJson(jsonResponse, Root.class);
for (Page page : root.query.pages.values()) {
firstParagraph=page.extract; //Parsing process, works fine
}
if (firstParagraph!=null) {
//If the webView isn't Wikipedia's article, it will be null
if (firstParagraph.contains(allowedContent)) {
//Passing URL to view
return true;
}
}
return false; //The URL leads to unallowed content
}
}
#Override
public void onPageFinished(WebView view, String url) {
CloseBlocksAndDisableEdit(view);
mProgressDialog.dismiss();
}
private final Response.Listener<String> onLoaded = new Response.Listener<String>() {
#Override
public void onResponse(String response) {
jsonResponse=response; //Getting response
jsonParsed=true; //Object was examined
webView.loadUrl(loadingURL);
}
};
What can be the cause of this problem?
If it's not possible in this way, I'd like to know which way is better...
I have found this answer:
https://stackoverflow.com/a/6739042/7483311
It is written in this answer:
After some research I conclude that despite what most of the tutorials
out there say, shouldOverrideUrlLoading() does not get called when:
You load a URL like:
loadUrl("http://www.google.com");
The browser redirects the user automatically via an HTTP Redirect.
This probably makes my code impposible.
In this line: webView.loadUrl(loadingURL);, I'm making an https request that was not made by the user in the WebView, and that's why it doesn't call shouldoverrideurlloading.
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.
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.
I'm writing a simple game. I included HTML pages + scrits into the apk file (I put them into assets folder and then loaded into a webview)
browser.loadUrl("file:///android_asset/home.html");
The prototype was only for one player and it was working fine till I needed to add authorization (to have the ability to play with a human:). I created a page for that and did a request:
$.mobile.showPageLoadingMsg();
$.ajax({
url: 'https://www.myhost.com/login',
data: {mail:'admin#mail.com', password: '123'},
datatype: 'html',
type: 'POST',
success:function(html){
$.mobile.hidePageLoadingMsg();
$("#message").html('SUCCESS');
},
error: function(jqXHR, textStatus, errorThrown) {
$("#message").html('FAILED');
$.mobile.hidePageLoadingMsg();
}
})
This call works fine. But... then I needed to add account info to all the game pages so the server can know who is doing what. So...I decided t create a bridge for that:
browser.addJavascriptInterface(bridge, "Bridge");
On the Java side I created a function that stores success login info in the Application class (something like a session).
#JavascriptInterface
public void storeAuthData(String callback, String user, String pass) {
WebGameApplication.setUser(user);
WebGameApplication.setPassword(pass);
webview.loadUrl("javascript:"+callback);
}
And it also works. But how can I add this params if I have POST requests? I googled a lot.
For GET requests it's possible to do it here:
#Override
public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
Log.i(TAG, "shouldInterceptRequest: " + url);
return super.shouldInterceptRequest(view, url);
}
But for POST I'm stuck. Maybe the solution I picked is incorrect? Of course I can extend the bridge by adding one extra method to retrive account info and then include this into each call whether it GET or POST.... but Really? There's no way of doing that?
Thanks in advance.
I'm afraid that POST requests are not passed through shouldInterceptRequest, only GET.
Could you set a cookie with the auth data rather than (or in addition to) using a JavaScript Bridge?
FYI, you should update your storeAuthData function such that it posts a task to the WebView, something like this:
#JavascriptInterface
public void storeAuthData(String callback, String user, String pass) {
...
webview.post(new Runnable() {
#Override
public void run() {
webview.loadUrl("javascript:"+callback);
}
});
}
The reason for this is important - WebView methods must be run on your applications UI thread, and JavaScript bridge callbacks are executed on a native background thread.