I want to pull some stuff from a webpage in Android. I know there are libraries to parse HTML, but I thought maybe I could cheat a little bit.
Here's what I'm doing..
- Programmatically create a WebView using the application context so it doesn't have to be displayed in the UI.
- Load the web page
- Attach the JS Interface
- Inject some Javascript to interact with the host application
Here's some code...
public void getLatestVersion(){
Log.e("Testing", "getLatestVersion called...");
WebView webview = new WebView(context.getApplicationContext());
webview.loadUrl("https://example.com");
webview.addJavascriptInterface(new jsInterface(), "Droid");
webview.loadUrl("javascript: window.onload=function(){ Droid.showToast('testing!'); }");
}
class jsInterface{
@JavascriptInterface
public void showToast(String message){
Log.e("Testing", message);
Toast.makeText(context, message, Toast.LENGTH_LONG).show();
}
}
Since the WebView is not visible in the UI, it's hard to tell which part is breaking. All I know is that the first Log called is called, but the Log and Toast from the JavascriptInterface are never shown.
Is what I'm trying to do even possible? If so, what am I doing wrong? If not, why not?
EDIT
Stuck the view in the UI for testing, apparently the second call to loadUrl is not working. No matter what Javascript I try to inject, it doesn't work.
EDIT 2
I feel dumb for forgetting to enable Javascript, but it's still not working.. I've added the following lines..
WebSettings webSettings = webview.getSettings();
webSettings.setJavaScriptEnabled(true);
webview.loadUrl("javascript: alert('farts0');");
webview.loadUrl("https://example.com");
setContentView(webview);
String js = "document.body.innerHTML = '<p>test<p>';";
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
webview.evaluateJavascript(js, null);
}else{
webview.loadUrl("javascript: "+js);
}
EDIT 3
Thanks for everyone's suggestions, you've been helpful but so far it's still not working so unless someone provides working code in the next hour Nainal will get half the bounty. If so I'm not sure if I'll be allowed to place another bounty on it as the problem is still unresolved.
Here's my complete code so far after taking into account suggestions on this page and trying several settings from the manual that I don't really understand.
import android.graphics.Bitmap;
import android.os.Bundle;
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.webkit.JavascriptInterface;
import android.webkit.WebChromeClient;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
WebView webView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
webView = new WebView(getApplicationContext());
if(android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN)
webView.getSettings().setAllowFileAccessFromFileURLs(true);
if(android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN)
webView.getSettings().setAllowUniversalAccessFromFileURLs(true);
webView.getSettings().setDomStorageEnabled(true);
webView.getSettings().setJavaScriptEnabled(true);
try {
webView.setWebContentsDebuggingEnabled(true);
}catch(Exception e){}
webView.setWebChromeClient(new WebChromeClient());
webView.setWebViewClient(new WebViewClient() {
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
webView.setVisibility(View.GONE);
}
@Override
public void onPageFinished(final WebView view, String url) {
Log.e("checking", "MYmsg");
Log.e("content-url", webView.getSettings().getAllowContentAccess()?"y":"n");
webView.loadUrl("javascript: void window.CallToAnAndroidFunction.setVisible(document.getElementsByTagName('body')[0].innerHTML);");
}
});
webView.setVisibility(View.INVISIBLE);
webView.addJavascriptInterface(new myJavaScriptInterface(), "CallToAnAndroidFunction");
webView.loadUrl("http://example.com");
}
public class myJavaScriptInterface {
@JavascriptInterface
public void setVisible(final String aThing) {
Handler handler = new Handler();
Runnable runnable = new Runnable() {
@Override
public void run() {
MainActivity.this.runOnUiThread(new Runnable() {
@Override
public void run() {
webView.setVisibility(View.VISIBLE);
Toast.makeText(MainActivity.this, "Reached JS: "+aThing, Toast.LENGTH_LONG).show();
}
});
}
};handler.postDelayed(runnable,2000);
}}
}
Edit 4
Started a new bounty and increased the reward to 100pts. Nainal got the last bounty for being the most helpful, not for solving the problem.