I want to open a website in Kotlin and login programmatically to it. Then I want to open different pages of that website programmatically and read their information using JavaScript and save them in some variables in Kotlin.
So far, I have used web-view and I can login to website programmatically using following code:
var webview = WebView(this)
webview.settings.javaScriptEnabled = true
webview.settings.domStorageEnabled = true
webview.webViewClient = object: WebViewClient() {
override fun onPageFinished(view: WebView, url: String) {
webview.loadUrl("javascript: {" +
"document.getElementById('TXT_UserName').value = '" + password + "';" +
"document.getElementById('TXT_Password').value = '" + password + "';" +
"var frms = document.getElementById('btn_Login').click(); };")
}
})
}
}
webview.loadUrl("http://10.104.24.64/")
I know by using onPageFinished function,I can understand when the first page is loaded completely. But I don't know when other pages are loaded completely. This is important to me because before completely loading, I can't read their information and JavaScript returns null. Also I don't know exactly how to open a link to other page from the first page programmatically. Following code is executed in JavaScript successfully, but in Kotlin returns null.
val script = "var t= document. getElementById ('ContentPlaceHold');"
+"t.name"
webview. evaluateJavascript(script, object : ValueCallback<String> {
override fun onReceiveValue(value: String) {
//to save JavaScript variables in to Kotlin variables here
}
})
I think it's reason is that in Kotlin codes are executed asynchronously.
Can anyone help me?
Thanks in advance.
Related
I want to use variable defined in inAppBrowser of cordova and use it in in executeScript method?
ref = cordova.InAppBrowser.open(env,'_blank','clearcache=no,location=no,
clearsessioncache=no, footer=no,zoom=no' );
var variable_needed = 1;
ref.addEventListener("loadstop", function(e) { ref.executeScript({
code: "console.log(variable_needed);"})
});
When I am trying to access varible_in executescript, it gives NULL.
I know they are different javascript bundle. Is there any way to achieve this?
The value passed via the code key of executeScript() is passed as a string to the Java layer which injects it into the Webview of the Inappbrowser and eval()'s it.
As such, there is no direct "connection" between the Cordova app Webview and the InappBrowser Webview that would allow Javascript entities to be directly shared.
Since the data is passed as a string, only stringifiable Javascript data can be passed (i.e. not functions).
In your case above, the variable value should simply be inlined in the code string:
ref = cordova.InAppBrowser.open(env,'_blank','clearcache=no,location=no, clearsessioncache=no, footer=no,zoom=no' );
var variable_needed = 1;
ref.addEventListener("loadstop", function(e) {
ref.executeScript({
code: "console.log("+variable_needed+");"
});
});
However if you want to send a more complex object structure you would need to stringify it, for example:
ref = cordova.InAppBrowser.open(env,'_blank','clearcache=no,location=no, clearsessioncache=no, footer=no,zoom=no' );
var myObj = {
foo: "bar"
};
var s_myObj = JSON.stringify(myObj);
ref.addEventListener("loadstop", function(e) {
ref.executeScript({
code: "var myObj = JSON.parse('"+s_myObj+"'); console.dir(myObj);"
});
});
I need to post data to Webview.
I found from some of the links the below code:
WebView webview = new WebView(this);
setContentView(webview);
String url = "http://www.example.com";
String postData = username=my_username&password=my_password";
webview.postUrl(url",EncodingUtils.getBytes(postData, "BASE64"));
But in my android studio I see EncodingUtils as deprecated
Can anyone help me what is the alternative for EncodingUtils to post data to Android WebView?
Try like below...
Java:
WebView webview = new WebView(this);
setContentView(webview);
String url = "http://www.example.com";
String postData = "username=" + URLEncoder.encode(my_username, "UTF-8") + "&password=" + URLEncoder.encode(my_password, "UTF-8");
webview.postUrl(url,postData.getBytes());
Kotlin:
val webview = WebView(this)
setContentView(webview)
val url = "http://www.example.com"
val postData = "username=${URLEncoder.encode(my_username, "UTF-8")}" +
"&password=${URLEncoder.encode(my_password, "UTF-8")}"
webview.postUrl(url, postData.toByteArray())
This is a simple workaround.
String html = "<!DOCTYPE html>" +
"<html>" +
"<body onload='document.frm1.submit()'>" +
"<form action='http://www.yoursite.com/postreceiver' method='post' name='frm1'>" +
" <input type='hidden' name='foo' value='12345'><br>" +
" <input type='hidden' name='bar' value='23456'><br>" +
"</form>" +
"</body>" +
"</html>";
webview.loadData(html, "text/html", "UTF-8");
I know this is not the best method but this works.
I would like to add a few things to the answer as I had to work on same and found some info could help complete the answer to this question.
First thing is the need for such a scenario. My need was that I am
creating a payment gateway client for native applications in android.
Second thing is that the URL you are opening needs to perform some
operations right. Hence you must enable your webView to enable
such operations or else things might not work. For example if your
URL is executing some java script, than you must enable java script
for your webview. This can be done as shown below :
val set = webview.settings
set.javaScriptEnabled = true
Normally this will enable trivial things such as timers, returning results etc on your webview.
Third thing is a case when your webView needs to call methods of your android app. This can be done by adding some JavaScript Interface as shown below :
webview.addJavascriptInterface(WebAppInterface(), "Android")
Where WebAppInterface() is a simple class which atleast one method annotated with #JavascriptInterface as shown below :
class WebAppInterface() {
#JavascriptInterface
fun showToast(status: String) {
//show toast here or handle status
}
}
The name Android will be the one which will be injected into your URL as a variable and you can call the methods of your android WebAppInterace from that URL as shown below:
Android.showToast("From WebPage")
Last thing is your postURL method which is somewhat like :
webview.postUrl(actionUrl, params.toByteArray(Charsets.UTF_8))
This method has couple of things that it takes as default. First is that request type is taken as default POST as the name suggest.
Header content-type can be default taken as application/x-www-form-urlencoded and
most important params it takes as & separated key value pairs as shown :
val params = "MERCHANT_ADDR=" + addr + "&CHANNEL=android"
We must pass byteArray of this string which is shown in post URL callback.
Now after your API is hit and it in some cases loads a callback url, from that call back URL using the JavaScript Interface, you can return result to your application and close the webview.
I hope it helps people.
try this:
You need to URL-encode the parameter value before sending it.
String postData = "fileContents=" + URLEncoder.encode(fileCon, "UTF-8");
For those who came here by trying to put a html body as a postData and not working,
try to put your string body as something below:
val htmlCode = "https://ramdom.user.me"
val postData = "{\n" +
"\t\"token\": \"963966f649\"\n" + "}"
webview.postUrl(htmlCode, postData.toByteArray())
I hope to save someone`s life. :-)
I want to load a webpage on android Webview. Is there a way to override some CSS component of the web page in my android webView?
Upload your customized css somewhere. You can apply your new css using Javascript. You can inject following javascript after the WebView is finished loading:
var link = document.createElement("link");
link.href = "http://example.com/mystyle.css";
link.type = "text/css";
link.rel = "stylesheet";
document.getElementsByTagName("head")[0].appendChild(link);
So your final Java code will look something like this:
String jsToInject = "var link=document.createElement('link');link.href='http://example.com/mystyle.css';link.type ='text/css'; link.rel ='stylesheet';document.getElementsByTagName('head')[0].appendChild(link);"
myWebView.loadUrl("javascript:" + jsToInject);
I am working on an app where i need to pass parameters to url while loading html file in webview from assets folder. If I am passing parameters webview was not loading & If not it's working good. The following code is working in 2.1 & 2.3 versions but coming to 4.0 version it's not working.
code:
webview.loadUrl("file:///android_asset/index.html"); //this is working
webview.loadUrl("file:///android_asset/index.html?" + parameters); //this is not working
//to pass parameters I am adding "?" at the end & it's not working.
Can anyone please help me with any alternative code for passing parameters to the following url.
Could you add a JavaScript method to your HTML and pass the parameters in via that function after loading the page? Something like ...
<script type="text/javascript">
function receiveParameters(p) {
// Do something with p
}
</script>
webview.loadUrl("file:///android_asset/index.html");
webview.evaluateJavascript("receiveParameters(" + parameters + ");", null);
I have solved it...
String filePath = "/data/user/0/~/files/public";
//launchUrl = String.format("%s/index.html?id=test", filePath);
//-->
launchUrl = String.format("file://%s/index.html?id=test", filePath);
webview.loadUrl(launchUrl);
You can use shouldInterceptRequest to remove the query before assetLoader seek for the file:
webview.webViewClient = object : WebViewClient() {
override fun shouldInterceptRequest(
view: WebView,
request: WebResourceRequest
): WebResourceResponse? {
if (request.url.host == "appassets.androidplatform.net") {
// Do any logic you want to remove disturb parmeters
var url = request.url
if (request.url.queryParameterNames.contains("yourparam")) {
url = Uri.parse(request.url.toString().split("?")[0])
}
return assetLoader.shouldInterceptRequest(url)
}
}
}
Now your html will be available to handle the parameters. But the assets loader do not care.
I am trying to use Google OAuth2 for Google Drive authentication on both Android and iOS. I had a solution working on Android using ChildBrowser, but it did not work on iOS. PhoneGap Build support suggested I use InAppBrowser because ChildBrowser is depreciated.
I can get iOS and Android both to prompt my user for ID/PW then it shows "Allow Access" button all in InAppBrowser to give Googl Drive access. On Android tapping Allow Access button gives page not available error with correct code and OAuth token in the url. When using childbrowser it was this change event that allowed you to check for code 4 and get the token. InAppBrowser only has LoadStart, LoadStop and Exit events.
How can I check the Google return URL for success/failure and if success grab the token?
Thanks for any and all help!
Here's how I use InAppBrowser to do Facebook auth. Since you're just trying to grab a value out of the url, it should work the same way:
var fb = {
id: '...'
,secret: '...'
,namespace: '...'
,redirect: '...'
,display: 'touch'
,scope: ['publish_actions']
,windowRef: null
,code: null
,onLoadEvent: function(event){
var url = event.url;
console.log(url);
//once we've been redirected to this domain, fb's job is done
if (/my.domain.com/.test(url)){
if (/code=/.test(url)){
//auth done
var code = url.match(/code=([^\&]+)/)
if (code) code = code[1];
window.fb.code = code;
window.fb.windowRef.close();
}else if (/error_description=/.test(url)){
//login unsuccessful
var error = url.match(/error_description=([^\&]+)/);
if (error) error = error[1].replace(/[^A-Z0-9 ]/gi, " ");
console.error("facebook login failed: " + error);
window.fb.code = null;
window.fb.windowRef.close();
}
}
}
};
var authUrl = "https://graph.facebook.com/oauth/authorize?"
+ "client_id=" + fb.id
+ "&redirect_uri=" + encodeURI(fb.redirect)
+ "&display=" + fb.display
+ "&scope=" + fb.scope.join('%2C');
fb.windowRef = window.open(authUrl, '_blank', loginPopupOptions);
//no reason we can't use the same function twice...
fb.windowRef.addEventListener('loadstart', fb.onLoadEvent);
fb.windowRef.addEventListener('loadstop', fb.onLoadEvent);
I tried to pull only the relevant bits out of our structure so hopefully it makes sense this way...