I'm got a custom webview setup which is working pretty well, but I'd like to be able to either:
1, change the url hash without the webview reloading the page (it would lose the state of my js app)
2, call some js that sits within my web page from within android. I can't change any JS within the site, unfortunately, so can't custom write any js to put on the site especially for the job, the only stuff I have control over is the Android app.
Can anyone think of a way of doing either of these?
Thanks in advance.
M
Or if you just want to change the hash, you can use:
view.loadUrl("javascript:location.hash=\"#" +fragment+"\"");
For #2, your Activity can invoke JavaScript methods. All you have to do is call the loadUrl method with the appropriate JavaScript call:
mWebView.loadUrl("javascript:wave()");
From:
http://developer.android.com/resources/articles/using-webviews.html
I know this question is old but this is what works for me in Android 4.4:
String fragment = "#test"
mWebView.evaluateJavascript("location.hash=\"" + fragment + "\";", new ValueCallback<String>() {
#Override
public void onReceiveValue(String value) {
// Yes, I like to log data :-)
Log.d("MyApp", "onReceiveValue(value): " + value);
}
});
Related
Is it possible to load a web page in c++ and get the rendered DOM? Not just the HTTP response, but the rendered DOM that occurs after java-script runs (maybe after letting it run for some amount of time). Specifically the dynamic HTML that may have changed over time? Is there a library for this?
Or if not c++, do you know of any other language which this can be done in?
Edit here's an example to illustrate better why one might want to do this:
Imagine you want to crawl a website written in angular. You can't just make an http request and use the HTTP response, because most of the DOM is rendered after javascript/dynamic html manipulates the DOM. The initial http response for an angular site probably doesn't have all the contents, its requested and rendered later through javascript/AJAX/dyanmic html.
Since DOM is something implemented differently by each browser, how you use that from C++ will be different with each browser.
I'll give an example for IE. You can use the WebBrowser ActiveX control which exposes the IWebBrowser2 interface. From there you can call IWebBrowser2::get_Document to get an IHTMLDocument2 object, which is the root of the DOM.
#include "StdAfx.h"
using namespace ATL;
using namespace std;
void ThrowIfFailed(HRESULT hr)
{
if (FAILED(hr))
throw CAtlException(hr);
}
int main()
{
::CoInitialize(nullptr);
try
{
CComPtr<IWebBrowser2> pWebBrowser;
HRESULT hr = ::CoCreateInstance(CLSID_InternetExplorer, nullptr, CLSCTX_LOCAL_SERVER, IID_PPV_ARGS(&pWebBrowser));
ThrowIfFailed(hr);
hr = pWebBrowser->put_Visible(VARIANT_TRUE);
ThrowIfFailed(hr);
hr = pWebBrowser->GoHome();
ThrowIfFailed(hr);
CComPtr<IDispatch> pDispatch;
hr = pWebBrowser->get_Document(&pDispatch);
ThrowIfFailed(hr);
CComPtr<IHTMLDocument2> pDocument;
hr = pDispatch->QueryInterface(&pDocument);
ThrowIfFailed(hr);
CComBSTR bstrTitle;
hr = pDocument->get_title(&bstrTitle);
ThrowIfFailed(hr);
wcout << bstrTitle.m_str << endl;
}
catch (const CAtlException& e)
{
wcout << L"Error (" << hex << e.m_hr << L")" << endl;
}
::CoUninitialize();
return 0;
}
This code just opens an IE window, navigates to the home page, and writes the title of the page to the console. You can also control whether the IE window becomes visible by removing the call to IWebBrowser2::put_Visible.
As I am understanding, you are asking:
"How to manipulate DOM of already rendered HTML Page through C++?"
If that's what you wanted to ask, here is my answer:
Technically, you can do it through C++. However, you need a right tool/lib/framework/ ... for doing this.
Normally, we manipulate DOM by Javascript.
In my experience, mobile developer have built-in control for load the page, usually called "webview". Android (Java) and iOS (Objective-C) have it. Then they manipulate DOM like this manner: "webview.evaluteScript("your javascript").
If you want to do it with C++. I think you can read these link:
How to embed WebKit into my C/C++/Win32 application?
How do I embed WebKit in a window?
I feel pretty stupid for having to ask this but I can't for the life of me get it to work.
So I've searched around and found lots of help, guides, and etc for using the onPageFinished function in WebViewClient and my code is largely based on these.
Basically I have a function that is supposed to load a web page and then hides certain elements on that page with the onPageFinished. Instead of actually doing this though it hides the entire page and the webview displays the text "none".
When I comment out the onPageFinished function the webview loads the page just fine which leads me to believe that it has to be the javascript but according to the w3c site my javascript is correct for what I want to do...
So my question is this, Does anyone see the problem with the below code and/or anyone have a suggestion for something else that might accomplish my above stated goals?
Any help in getting this to work would be greatly appreciated.
Code:
public class MainActivity extends AppCompatActivity{
private WebView browser;
private String url = "https://www.google.com";
< onCreate calls cleanPage and other stuff >
public void cleanPage() {
browser = (WebView) findViewById(R.id.webview);
browser.getSettings().setJavaScriptEnabled(true);
browser.setWebViewClient(new WebViewClient() {
#Override
public void onPageFinished(WebView view, String url) {
browser.loadUrl("javascript:document.getElementById('lga').style.display='none';");
}
});
browser.loadUrl(url);
}
}
Notes:
-The above uses google as an example, lga is the id of the google banner div.
-browser and url are global because once I get cleanPage working I will add in other functions that will alter them as needed.
You need to add void(0); at the end of your javascript: URL. Otherwise, WebView replaces your current page with the result of the JS evaluation (in your case, that is the string "none").
So change this:
browser.loadUrl("javascript:document.getElementById('lga').style.display='none';");
to:
browser.loadUrl("javascript:document.getElementById('lga').style.display='none';void(0);");
i know that to run a javascript function in webview we need to load it in loadUrl(). In my program everything works fine javascript gets called when i use it in loadUrl, but instead of running javascript on the same page, loadUrl("javascript:function()") vanishes my previous page and run this javascript "function()" in a totally new blank page..
for eg. i tried to fill a form automatically using command:
view.loadUrl("javascript:document.getElementById('password').value = 'my_passoword'");
what happens is, the page which consists of ID-'password' vanishes and a new blank page generates consisting of 'my_password' only
where is the problem?
Using loadUrl to run javascript loads different page
anonymous self-invoking function works fine.. i.e.
view.loadUrl("javascript:(function(){document.getElementById('password').value = 'sb14november';})()");
and as a loop around i think Bojan Kseneman answer will work too..
thanks to all!! :)
EDIT: This library is only for evaluating JavaScript and it created a new WebView instead of using an existing one :/
You can also try js evaluator library
jsEvaluator.evaluate("put your JavaScript code", new JsCallback() {
#Override
public void onResult(final String result) {
// you get the result here (optional)
}
});
I have a webview with HTML webpage which is downloaded from server and i populate dynamic data and add rows of information to this webpage. I have used the following code on that webpage to enable javascript:
class JSClass {
Context jsContext;
JSClass(Context c){
jsContext = c;
}
public void getHTMLContent(String info)
{
Log.i(TAG, "Info: "+info);
}
}
WebView webview = (WebView) findViewById(R.id.webView);
webview.loadDataWithBaseURL("", htmlcontent, "text/html", "utf-8", "");
webview.getSettings().setJavaScriptEnabled(true);
webview.setWebChromeClient(new WebChromeClient());
webview.addJavascriptInterface(new JSClass(this), "Android");
webview.loadUrl("javascript:"+
"var rows = document.getElementsByClassName('info');"+
"if(rows !== null){"+
"for(var i=0;i<rows.length;i++){"+
"rows[i].onclick = function(){"+
"var workId = 0;"+
"workId = parseInt(this.cells[0].innerHTML);"+
"window.Android.getHTMLContent(workId);"+
"}}}"
);
when i click on any row, i cal an intent to download images from the server depending on the row data. It works fine on first click, but the second time i click, the application closes without any error. I don't understand the reason. Please help. Thanks in advance
I think you need to use loadDataWithBaseURL again instead of just loadUrl.
See this link. There is a section explaining loadData that says:
Note that JavaScript's same origin policy means that script running in a page loaded using this method will be unable to access content loaded using any scheme other than 'data', including 'http(s)'. To avoid this restriction, use loadDataWithBaseURL() with an appropriate base URL.
FINALLY!! fixed it.. the adapter was holding previously downloaded images as well as the images downloaded during second click and i don't understand why the application was closing without giving any memory leaks as well.. anyways its working fine now after using
adapter.clear();
or re-initializing the adapter to null after all the image thumbs are downloaded(i do not know if this is very efficient). After the adapter is cleared, use
adapter.notifyDataSetChanged();
I have been able to get content out of WebView using javascript and loadUrl() method having specified an interface thats called from javascript string that is injected into WebView.The problem is that this only works for me when the loadUrl() method is present in onPageFinished() method in the WebView client. What I want to do is I want to get the content out of the WebView (with the content already loaded). The WebView is in an activity instrumentation test case and I can for instance use findAll() method and that works fine. For some reason I can not use loadUrl() and get the desired behaviour (which is injecting javascript and getting content out of the WebView with a help of an interface).
PLease help.
Thanks
Pawel
EDIT:
Just adding code to show what I am doing exactly:
Yes I understand that but my problem is that I am trying to do it within a test case this way:
public void testWebView() throws Exception {
solo.sleep(3000); // wait for views to load on the screen
WebView a=null;
ArrayList<View> views = solo.getCurrentViews(); // I am using solo object to get views for the screen currently loaded
for(View s:views)
{
if (s instanceof WebView)
{
a = (WebView)s; // this is where I get my WebView
}
}
Instrumentation inst = getInstrumentation();
inst.runOnMainSync(new Runnable()
{
public void run()
{
int d =a.findAll("something"); // this method runs fine on the object and i get the desired result
WebSettings settings = a.getSettings();
settings.setJavaScriptEnabled(true);
a.loadUrl("javascript:document.location = document.getElementById('google').getAttribute('href')"); // this javascript is never executed and that is my problem
}
});
}
You can inject javascript in a loaded page much the same way you can do it in desktop browsers - via inline javascript entered into navigation bar.
Bind some Java object so that it can be called from Javascript with WebView:
addJavascriptInterface(javaObjectExposed, "JSname")
Force execute javascript within an existing page by
WebView.loadUrl("javascript:window.JSname.passData("some data from page");");