I need help regarding SSL trust. I am loading a payment gateway page in WebView. It is a POST request and I am passing a payload.
This is happening successfully till now.(Shown below)
mWebView = (Android.Webkit.WebView)Control;
string payload = "myPayload";
byte[] valTest = Encoding.UTF8.GetBytes(payload.ToCharArray(0, payload.Length));
mWebView.Settings.JavaScriptEnabled = true;
mWebView.Settings.DomStorageEnabled=true;
mWebView.SetWebViewClient(new MyWebViewClient(this));
mWebView.SetWebChromeClient(new ChromeClient());
mWebView.PostUrl("https://mypage", valTest);
After filling up the form and submit I am getting a callback in the OnReceivedSslError method of the WebViewClient class. Here I ask it to proceed (as per various forums). Once this is done I am not getting any success callback. I need to be able to read javascript values once I get a response from the webview. I do not know how this is to be achieved.
Shown below is the OnSSLErrorReceived Callback method.
public override void OnReceivedSslError(Android.Webkit.WebView view, SslErrorHandler handler, Android.Net.Http.SslError error)
{
base.OnReceivedSslError(view, handler, error);
handler.Proceed();
}
}
Expectations-
1. On submitting the form it should be trusted(it is a self-signed certificate).
2. Once this above step is done we are expecting a response from the webpage. We need to read javascript values from the page. How can I achieve this?
I do not see any SuccessCallback or ResponseCallback.
I use the below to read the JS values.But this is not working.
view.EvaluateJavascript("document.getElementById('test').value", new MyCallbackClass());
The above issue has been resolved. Calling handler.Proceed in OnSSLError method was fine but the issue was with calling the base inside this callback. Once I removed base.OnSSLError my code worked fine.
After the page finishes I am able to read JS values in the OnPageFinished callback method.
Also the evaluate JS function is also working and I get callbacks.
Related
I have a Xamarin.Forms 5.0 application (for both iOS and Android). I am not sure if this is a Xamarin issue or just Android. On iOS it is working fine.
In the app I use a webview to display single page webapplication. Inside that spa I have a login page with a "remember me" checkbox. When this is checked, the backend creates persistent cookie instead of a sessioncookie. The login is done with a XHR request to the backend.
Seems all working fine, but when the app is restarted, it doesn't know the cookie anymore and the user has to login again.
When I do a full reload of the page in the webview (after login), it looks like the cookie is persisted. After restarting the app, the user is logged in automatically, so the cookie is available.
So the problem seems to be that new cookies in the response of XHR requests are not persisted, while the response cookies of a normal page request are.
Anybody any ideas about this?
Added some code
I created a simple Xamarin.Forms project with an Android app.
Added this in the MainPage.xaml:
<StackLayout>
<Button Clicked="Button_Clicked" Text="(Re)Load"></Button>
<WebView x:Name="wv"
WidthRequest="1000"
HeightRequest="1000"
></WebView>
</StackLayout>
And in the codebehind:
private void Button_Clicked(object sender, EventArgs e)
{
wv.Source = "https://---.---.nl/portal";
}
This loads a SPA webapplication. Not much code to show.
As i know, UWP and iOS would share their cookie containers automatically between the WebView and native http client, however Android does not.
The WebView could use CookieManager to handle cookies. If you want to share cookies between the two, you will have to manually process the information. You need to know the Uri of the domain for these cookies.
private void CopyCookies(HttpResponseMessage result, Uri uri)
{
foreach (var header in result.Headers)
if (header.Key.ToLower() == "set-cookie")
foreach (var value in header.Value)
_cookieManager.SetCookie($"{uri.Scheme}://{uri.Host}", value);
foreach (var cookie in GetAllCookies(_cookieContainer))
_cookieManager.SetCookie(cookie.Domain, cookie.ToString());
}
public void ReverseCopyCookies(Uri uri)
{
var cookie = _cookieManager.GetCookie($"{uri.Scheme}://{uri.Host}");
if (!string.IsNullOrEmpty(cookie))
_cookieContainer.SetCookies(new Uri($"{uri.Scheme}://{uri.Host}"), cookie);
}
It is not very clear, at least for me, when the WebView flushes the cookies and when not.
The simple solution for me was to flush the cookies everytime the onPause lifecycle event of the activity containing the webview is called. This occurs when another activity is started, or the user switches to another app or closes the app.
protected override void OnPause()
{
base.OnPause();
Android.Webkit.CookieManager.Instance.Flush();
}
I want to intercept POST requests from a custom page, which is impossible from the callback client interface (unlike to GET one, you have no access to the POST request body). So, I have implemented a service worker based solution, which wrapping POST request into a GET one with the same data, that I can handle in shouldInterceptRequest().
So, once the service worker is registered and active:
function subscribeToSWMessages()
{
navigator.serviceWorker.onmessage = function (event)
{
if (event.data.command == 'activeSW')
{
// !! Only from now we can post requests !!
}
};
}
Only after that it's safe to post request from the page. So, how to properly inject my JS code, to be sure no requests are posted until the message is received? Can the page be totally custom, or I should ask its developer to do something on their side?
My question looks stupid at first glance and all my searches pointed out window.location and other JS stuff or the externalWebPage plugin. That's not what I'm looking for.
From the JAVA code, when I catch one specific exception during execution of a custom plugin, I want to force the page to move to "logout.html". I don't want to execute callback.error() or to deal with the error inside code in my webpage in any ways. I only want my transaction to be cancel and a web resource to be loaded in the current web UI.
Is there any way to do that?
Thanks in advance.
The CordovaWebView offers a showWebPage function to load any url from the native code.
From the plugin you should be able to do
this.webView.showWebPage("logout.html", false, true, null);
Also offers loadUrl
this.webView.loadUrl("file:///android_asset/www/logout.html");
And you can also use loadUrl to execute javascript so you can run the window.location from there without a callback.
this.webView.loadUrl("javascript:window.location.href='logout.html'");
You will either need to add it to your main.js interface so that you can callup page changed () and handle it in your angular code.
This can be a simple onPageNeedsChanged Handler call where you retain the context on page change context and just call it whenever you need.
Or you can call the onError callback from the caller, if it is a consistent error callback context to move you there, but sounds like you don't want to do this route.
So the easiest answer then is to just launch your own Activity with a preloaded web url and a web view. You already have access to the activity, so just make your own native activity with a full web view in it, hard coded url and then launch your activity on error.
i.e. I do it for sending an email, but it could be your own activity
cordova.getActivity().startActivity(Intent.createChooser(emailIntent, "Send mail..."));
You may even be able to get a reference to the Cordova web view, but not positive on that, but I assume you could through the tree of objects.
Does that work for you needs?
If not can you elaborate on your hesitation to handle in the onerror callback. It's fairly straight forward. Maybe I can help you there as an alternative? Retaining the callingContext and just using callingContext.error(withkey or instructions or object) is not too bad.
A35ble.writeValueToPodCharacteristic(this.device.macAddress, true, this.bytesToSend,
function (response) {
console.log("Success: " + response);
callbackContext.device.notificationReceivedFromPod(callbackContext.device.arrayBufferToString(response));
},
function (response) {
console.log("ERROR: " + response);
alert("Error Sending NSM Message: " + response);
}
);
For example I made a cordova plugin called A35ble that manages my bluetooth stuff and in this response I just show alert.
Have a little program with a WebView loading e.g. "www.google.com". I have tried to start searching automatic without ENTER by user, after scanning a barcode, like this:
final String scanedCode = "123456";
runOnUiThread(new Runnable() {
#Override
public void run() {
dispatchKeyEvent(new KeyEvent(100, scanedCode, 1, 0));
dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENTER));
}
);
The number "123456" will displayed in google search field, but the ENTER, or rather the automatic search is not started.
Have tried many ways and searched here, but I still cannot get these simple thing. Could someone give me some tips?
A more robust approach will be to inject your own javascript code directly into the WebView. This injection does not care which URL is loaded inside, so you can do it to any site.
It sounds like a big security hole but this really isn't. The browser is inside your app which means you are the browser therefore you can do anything you want while parsing the HTML code of the websites you're showing.
Here is a code example which loads some JS into a google hosted page:
final WebView webview = (WebView)findViewById(R.id.browser);
/* JavaScript must be enabled if you want it to work, obviously */
webview.getSettings().setJavaScriptEnabled(true);
/* WebViewClient must be set BEFORE calling loadUrl! */
webview.setWebViewClient(new WebViewClient() {
#Override
public void onPageFinished(WebView view, String url)
{
webview.loadUrl("javascript:(function() { " +
"document.getElementsByTagName('body')[0].style.color = 'red'; " +
"})()");
}
});
webview.loadUrl("http://code.google.com/android");
If you can run your own JS you can pretty much do anything you want - including traversing the DOM directly, accessing the search-box itself and making sure it has focus.
In order to figure out which JS code you want to inject, use Google Chrome on your PC and open google.com inside Chrome Developer Tools. Then try to type JS commands in the console until you get the required result. Typing JS lines in the console = injecting JS code into the page.
I am new to sencha touch and i want to consume soap web service in sencha touch.I have written code for this cause, but the problem is that I am getting just plain HTML content as response not the soap object. And I dont know how to call a specific method from web service to sencha touch.
Here's my code :-
Ext.Ajax.request({
method: 'get',
url: 'http://192.168.1.15:80/himanshu/helloworldwebservice.asmx',
success: function (response, request) {
alert('Working!')
alert(response.responseText)
console.log('Response:-'+response.responseText)
},
failure: function (response, request) {
alert('Not working!')
console.log('Response Status:- '+response.status)
}
});
EDIT:- Ok i got the idea to call a specific method from web service from here.Like i have HelloWorld() method which only returns a single string and my url is http://192.168.1.15:80/himanshu/helloworldwebservice.asmx.
I can call HelloWorld() method by setting my url like this :- http://192.168.1.15:80/himanshu/helloworldwebservice.asmx/HelloWorld
But its not working for me.Every time i run the program 'Not Working' alert generates and 500 is the response stats i gets.Please make me understand that how can i call methods from webservice.Thanx in advance.
You will not be able to consume your SOAP webservice in this way, since performing a GET request on the asmx url will just return you the HTML content for the page listing your webservice methods.
Consuming SOAP webservices relies on POST requests and need that you send a correct XML SOAP request. I may suggest you to use something like http://archive.plugins.jquery.com/project/jqSOAPClient to execute your SOAP calls and retrieve your data and then pass them back to your Ext code.
Hope this helps
Nacef
Your code is absolutely fine. I think you are sending HTML data from the server side. Do check the response in Chrome/Safari Developer Tools. Also, use console.log() function instead of alert() function for a better view.
Also, open this url: "http://192.168.1.15:80/himanshu/helloworldwebservice.asmx" in browser and "View source" of the page - you will see what exactly you are sending.
You can make use of : SOAP Data Proxy
http://www.sencha.com/blog/taking-a-look-at-the-new-sencha-soap-data-proxy