Here's my code for injecting CSS into a Webview:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getSupportActionBar().setTitle("Ubqari");
ww = (WebView) findViewById(R.id.ww);
ww.getSettings().setJavaScriptEnabled(true);
ww.getSettings().setDomStorageEnabled(true);
ww.setWebViewClient(new WebViewClient(){
public void onPageFinished(WebView view, String url) {
injectCSS();
}
});
ww.loadUrl("http://ubqari.org");``
}
And here's injectCSS function:
private void injectCSS() {
try {
InputStream inputStream = getAssets().open("style.css");
byte[] buffer = new byte[inputStream.available()];
inputStream.read(buffer);
inputStream.close();
String encoded = Base64.encodeToString(buffer, Base64.NO_WRAP);
ww.loadUrl("javascript:(function() {" +
"alert('Hello! I am an alert box!');"+
"var parent = document.getElementsByTagName('head').item(0);" +
"var style = document.createElement('style');" +
"style.type = 'text/css';" +
// Tell the browser to BASE64-decode the string into your script !!!
"style.innerHTML = window.atob('" + encoded + "');" +
"parent.appendChild(style)" +
"})()");
} catch (Exception e) {
e.printStackTrace();
}
}
I don't know what's going wrong in this code. My style.css code is correct but the problem is in the onPageFinished section. It's not injecting the CSS when the page has finished loading. Any expert can answer me?
Related
I hava webView application in Android. I have defined the javascript interface myapp and I can successfully call it from webpage. I am testing the interface in an ajax function but when I call the functions in ajax success callback, nothing happens:
My Javascript codes in webpage:
function notif(t,v){
try {
myapp.Logit("start"); // I can see this message in Logcat
}catch(err){}
$.ajax({
method:"post",
url:"test.asp",
data:{t:t,v:v},
success:function(data){
alert("done"); // Alert works in webpage
try {
myapp.Logit("finish"); // Nothing happens in Logcat
}catch(err){}
}
})
}
And this is the simple function in Android app to log events in logcat:
#JavascriptInterface
public void Logit(String message){
Log.i("message:",message);
}
How are you injecting the Java object into this WebView?
Please make sure that the you are injecting the Java object into the WebView as below. Without that you won't be able to access the Java objects's method in WebView
webView.addJavascriptInterface(new MyApp(), "MyApp");
It will also help to see if you are getting any error in the debug console. Article on how to setup the remote debugging
below is the sample working code. Hope this helps.
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final WebView myWebView = (WebView) findViewById(R.id.webview);
WebSettings webSettings = myWebView.getSettings();
webSettings.setJavaScriptEnabled(true);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
if (0 != (getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE))
{ WebView.setWebContentsDebuggingEnabled(true); }
}
myWebView.setWebViewClient(new WebViewClient() {
public void onPageFinished(WebView view, String url) {
System.out.println("Web View loaded");
}
});
Button loadBtn = (Button) findViewById(R.id.load_button);
loadBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String unencodedHtml =
"<!DOCTYPE html>\n" +
"<html>\n" +
" <head>\n" +
" <script src=\"https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js\"></script>\n" +
" <script>\n" +
" $(document).ready(function(){\n" +
" $(\"button\").click(function(){\n" +
" $.ajax({\n" +
" method:\"get\",\n" +
" url: \"https://my-json-server.typicode.com/typicode/demo/posts\", \n" +
" success: function(result){\n" +
" alert(\"done\"); \n" +
" try {\n" +
" MyApp.Logit(\"finish\"); // Nothing happens in Logcat\n" +
" }catch(err){}\n" +
" }});\n" +
" });\n" +
" });\n" +
" </script>\n" +
" </head>\n" +
" <body>\n" +
" <button>Get External Content</button>\n" +
" </body>\n" +
"</html>";
String encodedHtml = Base64.encodeToString(unencodedHtml.getBytes(),
Base64.NO_PADDING);
myWebView.loadData(encodedHtml, "text/html", "base64");
}
});
myWebView.addJavascriptInterface(new MyApp(), "MyApp");
}
}
class MyApp
{
#JavascriptInterface
public void Logit(String message){
Log.i("message:",message);
}
}
I am trying to get the src of a captcha image found in a webview but when i type the below code the output says:
Uncaught TypeError: Cannot read property 'src' of null
and another question if i get the image src how can i put the image in an image view?
any help will be really appreciated
here is my code so far:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
wv = (WebView) findViewById(R.id.wv) ;
mImgCaptcha = (ImageView) findViewById(R.id.imgCaptcha);
done = (Button) findViewById(R.id.done);
contentView = (TextView) findViewById(R.id.textView);
username = (EditText) findViewById(R.id.editText);
password = (EditText) findViewById(R.id.password);
code = (EditText) findViewById(R.id.code);
WebSettings webSettings = wv.getSettings();
webSettings.setJavaScriptEnabled(true);
wv.getSettings().setDomStorageEnabled(true);
wv.loadUrl("https://noor.moe.gov.sa/NOOR/Login.aspx");
wv.loadUrl("javascript:var a = document.getElementById('imgCaptcha').src;");
System.out.println(wv.getUrl());
done.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
wv.loadUrl("javascript:var x = document.getElementById('tbPublic').value = '" + username.getText().toString() + "';");
wv.loadUrl("javascript:var x = document.getElementById('tbPrivate').value = '" + password.getText().toString() + "';");
wv.loadUrl("javascript:var x = document.getElementById('tbCaptcha').value = '" + code.getText().toString() + "';");
try {
Thread.sleep(2000);
wv.loadUrl("javascript:(function(){" +
"l=document.getElementById('btnLogin');" +
"e=document.createEvent('HTMLEvents');" +
"e.initEvent('click',true,true);" +
" l.dispatchEvent(e);" +
"})()");
} catch (InterruptedException e) {
e.printStackTrace();
}
It's because the page is not loaded yet when you are trying to query the DOM. You need to query the DOM when you can be sure that the page has loaded.
We need to set the WebViewClient for the webview and then listen to onPageFinished event. The code might look something like this:
webView.setWebViewClient(new WebViewClient(){
#Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
// you can now query the DOM.
webView.loadUrl("javascript:var a = document.getElementById('imgCaptcha').src;");
}
});
Further reading: https://developer.android.com/reference/android/webkit/WebViewClient#onPageFinished(android.webkit.WebView,%2520java.lang.String)
Background:-
I am trying to call a #JavascriptInterface annotated method processVideo() form the loadUrl() of webview to get callback when someone click on any video on the webpage.
The following is my approach and it's working perfectly
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_download);
webView = findViewById(R.id.web_view_facebook);
webView.getSettings().setJavaScriptEnabled(true);
webView.getSettings().setPluginState(WebSettings.PluginState.ON);
webView.getSettings().setBuiltInZoomControls(true);
webView.getSettings().setDisplayZoomControls(true);
webView.getSettings().setUseWideViewPort(true);
webView.getSettings().setLoadWithOverviewMode(true);
webView.addJavascriptInterface(this, "Downloader");
webView.setWebViewClient(new WebViewClient() {
#Override
public void onLoadResource(WebView view, String url) {
webView.loadUrl("javascript:(function prepareVideo() { "
+ "var el = document.querySelectorAll('div[data-sigil]');"
+ "for(var i=0;i<el.length; i++)"
+ "{"
+ "var sigil = el[i].dataset.sigil;"
+ "if(sigil.indexOf('inlineVideo') > -1){"
+ "delete el[i].dataset.sigil;"
+ "console.log(i);"
+ "var jsonData = JSON.parse(el[i].dataset.store);"
+ "el[i].addEventListener('click',function(){Downloader.processVideo(jsonData['src'],jsonData['videoID']);});"
+ "}" + "}" + "})()");
}
});
webView.loadUrl("https://m.facebook.com");
}
#JavascriptInterface
public void processVideo(final String vidData, final String vidID) {
try {
Toast.makeText(this, "Download Started", Toast.LENGTH_LONG).show();
} catch (Exception e) {
Toast.makeText(this, "Download Failed: " + e.toString(), Toast.LENGTH_LONG).show();
}
}}
Now The Problem:-
But as i load custom javascript function in loadUrl(), i lost the ability to play video on click.
i think it will happen as i intercepted and load my custom code
So what i want to achieve is when any user click on video, then the video should play and also i get the callback that i wanted at first place
What i have tried so far:-
to play the video on click, i used
addEventListener('click',function(){
var video = document.getElementById(jsonData['videoID']);
video.play(); }
This one is working perfectly to play the video.
but when i use this solution with my callback like following
addEventListener('click',function(){
Downloader.processVideo(jsonData['src'],jsonData['videoID']);
var video = document.getElementById(jsonData['videoID']);
video.play(); }
then I am not able to get callback in my processVideo().
If i use them individually, both functionality (callback and play video) working perfectly inside addEventListener(), but not working together.
This code line: var video = document.getElementById('jsonData['videoID']') throws an error because you used more than two 's in one argument.
Try replacing by var video = document.getElementById(jsonData['videoID']).
Hope this helps.
I have solved this issue and i am pasting complete code here:
webView.setWebViewClient(new WebViewClient()
{
#Override
public void onPageFinished(WebView view, String url)
{
//query_string = "" + url;
// view.loadUrl("javascript:(function() { document.getElementsByTagName('video')[0].play(); })()");
}
#Override
public void onLoadResource(WebView view, String url)
{
// query_string=""+url;
webView.loadUrl("javascript:(function prepareVideo() " +
"{ "
+ "var el = document.querySelectorAll('div[data-sigil]');"
+"var ID;"
+"var SRC;"
+ "for(var i=0;i<el.length; i++)"
+ "{"
+ "var sigil = el[i].dataset.sigil;"
+ "if(sigil.indexOf('inlineVideo') > -1)" +
"{"
+ "delete el[i].dataset.sigil;"
+ "console.log(i);"
+ "var jsonData = JSON.parse(el[i].dataset.store);"
+"ID=jsonData['videoID'];"
+"SRC=jsonData['src'];"
// +"document.getElementsByTagName(\"'+jsonData['videoID']+'\")[0].play();"
+ "el[i].setAttribute('onClick','FBDownloader.processVideo(\"'+jsonData['src']+'\",\"'+jsonData['videoID']+'\");');"
+ "}"
+ "}"
+ "})()");
}
});
JAVA ACTIVITY FUNCTION WHICH IS CALL FROM JAVASCRIPT WEBVIEW
public void processVideo(final String vidData, final String vidID)
{
this.vidData=vidData;
this.vidID=vidID;
Get_Download_Permission();
showtoast("video ID ="+this.vidID);
webView.loadUrl("https://www.facebook.com/video/embed?video_id="+this.vidID);//193766537709747/");
}
Say, I set my WebView into example.com then I clicked on the page and load the example.com/about.
In the WebView I've injected Javascript to modify the HTML on the example.com, and it worked, and the problem is, how to inject another JavaScript to modify example.com/about. I mean how to inject multiple JavaScript to a multiple page of WebView?
public class MainActivity extends AppCompatActivity {
WebView mWebView;
private int getScale() {
Display display = ((WindowManager) getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
int width = display.getWidth();
Double val = new Double(width) / new Double(100);
val = val * 100d;
return val.intValue();
}
#Override
protected void onCreate(Bundle savedInstanceState) {
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mWebView = (WebView) findViewById(R.id.activity_main_webview);
// Enable Javascript
WebSettings webSettings = mWebView.getSettings();
mWebView.setWebViewClient(new WebViewClient());
webSettings.setJavaScriptEnabled(true);
webSettings.setAllowUniversalAccessFromFileURLs(true);
mWebView.setWebViewClient(new WebViewClient());
mWebView.setWebViewClient(new WebViewClient() {
#Override
public void onPageFinished(WebView view, String url) {
// Inject CSS when page is done loading
injectCSS();
mWebView.loadUrl("javascript:var greeting = function (name) {\n" +
" console.log(\"Great to see you,\" + \" \" + name);\n" +
"};");
super.onPageFinished(view, url);
//Inject JS to edit html
injectScriptFile(view, "script.js"); // see below ...
// test if the script was loaded
view.loadUrl("javascript:setTimeout(test(), 500)");
}
private void injectScriptFile(WebView view, String scriptFile) {
InputStream input;
try {
input = getAssets().open(scriptFile);
byte[] buffer = new byte[input.available()];
input.read(buffer);
input.close();
// String-ify the script byte-array using BASE64 encoding !!!
String encoded = Base64.encodeToString(buffer, Base64.NO_WRAP);
view.loadUrl("javascript:(function() {" +
"var parent = document.getElementsByTagName('head').item(0);" +
"var script = document.createElement('script');" +
"script.type = 'text/javascript';" +
// Tell the browser to BASE64-decode the string into your script !!!
"script.innerHTML = window.atob('" + encoded + "');" +
"parent.appendChild(script)" +
"})()");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
return false;
}
});
mWebView.loadUrl("example.com");
mWebView.getSettings().setBuiltInZoomControls(true);
mWebView.getSettings().setDisplayZoomControls(false);
}
private void injectCSS() {
try {
InputStream inputStream = getAssets().open("style.css");
byte[] buffer = new byte[inputStream.available()];
inputStream.read(buffer);
inputStream.close();
String encoded = Base64.encodeToString(buffer, Base64.NO_WRAP);
mWebView.loadUrl("javascript:(function() {" +
"var parent = document.getElementsByTagName('head').item(0);" +
"var style = document.createElement('style');" +
"style.type = 'text/css';" +
// Tell the browser to BASE64-decode the string into your script !!!
"style.innerHTML = window.atob('" + encoded + "');" +
"parent.appendChild(style)" +
"})()");
} catch (Exception e) {
e.printStackTrace();
}
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mWebView.saveState(outState);
}
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
mWebView.restoreState(savedInstanceState);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu); // Add menu items, second value is the id, use this in the onCreateOptionsMenu
menu.add(0, 1, 0, "Back");
menu.add(0, 2, 0, "Refresh");
menu.add(0, 3, 0, "Forward");
getMenuInflater().inflate(R.menu.menu_main, menu);
return true; // End of menu configuration
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case 3: //If the ID equals 3 , go forward
mWebView.canGoForward();
item.setIcon(R.drawable.forward);
return true;
}
return super.onOptionsItemSelected(item);
}
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) { // Enables browsing to previous pages with the hardware back button
if ((keyCode == KeyEvent.KEYCODE_BACK) && mWebView.canGoBack()) { // Check if the key event was the BACK key and if there's history
mWebView.goBack();
return true;
} // If it wasn't the BACK key or there's no web page history, bubble up to the default
// system behavior (probably exit the activity)
return super.onKeyDown(keyCode, event);
}
}
I am trying to use JavaScript in an Android webview. I used following code. I did not get color changed or offset height of body.
webview.getSettings().setJavaScriptEnabled(true);
webview.addJavascriptInterface(new myJavaScriptInterface(webview), "jsInterface");
webview.loadUrl("file:///android_asset/sample/contents.html");
//webview.loadData("file:///android_asset/sample",convertStreamToString(inputStream), "text/html", "UTF-8");
webview.loadUrl("javascript:" +
"document.getElementsByTagName('p')[0].style.color='red';" +
"");
wbview.loadUrl("javascript:window.jsInterface.EchoText(document.body.offsetHeight);");
//webview.
}
class myJavaScriptInterface
{
WebView mywebview;
public myJavaScriptInterface(WebView webview)
{
this.mywebview=webview;
}
public void EchoText(String message)
{
Toast.makeText(mywebview.getContext(), message, Toast.LENGTH_SHORT).show();
}
}
What am I missing?
I think this is because your page is not loaded (still loading) when you are using webview.loadUrl("javascript:" + ...) statements.
Try the following...
webview.loadUrl("file:///android_asset/sample/contents.html");
webview.setWebViewClient(new WebViewClient() {
public void onPageFinished(WebView webview, String url) {
webview.loadUrl("javascript:" +
"document.getElementsByTagName('p')[0].style.color='red';");
wbview.loadUrl("javascript:" +
"window.jsInterface.EchoText(document.body.offsetHeight);");
}
});