Android Javascript interface function not works in ajax callback - javascript

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);
}
}

Related

Get an image src from a webview in android

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)

Using Javascript in android WebView to call a function

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/");
}

Android Studio: Trying to remove HTML element in webview: blank page

I am trying to remove an HTML element in webview. Here is my code. Everything compiles fine.
I have looked at other questions and none of the answers work for me.
// load web url
final WebView webView = (WebView) mRootView.findViewById(R.id.fragment_main_webview);
webView.getSettings().setJavaScriptEnabled(true);
webView.setWebViewClient(new WebViewClient() {
#Override
public void onPageFinished(WebView view, String url) {
webView.loadUrl("javascript:(function() { " + "document.getElementsByTagName('publicTabs')[0].style.display=\"none\"; " + "})()");
}
});
webView.loadUrl(mUrl);
When I open the app on my phone, no webpage loads. Just blank. If I remove:
webView.getSettings().setJavaScriptEnabled(true);
webView.setWebViewClient(new WebViewClient() {
#Override
public void onPageFinished(WebView view, String url) {
webView.loadUrl("javascript:(function() { " + "document.getElementsByTagName('publicTabs')[0].style.display=\"none\"; " + "})()");
}
});
the webpage loads.
Also, can someone tell me how to remove multiple HTML elements at the same time?
Any help would be appreciated.
Heres the answers: Also check if the element is a class or Id in the website. Like the one below in my code.
String url = "https://www.example.com";
final WebView webView = (WebView) findViewById(R.id.fragment_main_webview);
webView.getSettings().setJavaScriptEnabled(true);
webView.setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY);
webView.getSettings().setSavePassword(true);
webView.getSettings().setSupportZoom(true);
webView.getSettings().setSaveFormData(true);
webView.getSettings().setSupportZoom(false);
webView.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE);
webView.getSettings().setDomStorageEnabled(true);
webView.getSettings().setSupportMultipleWindows(false);
webView.getSettings().setLightTouchEnabled(true);
webView.getSettings().setBuiltInZoomControls(true);
webView.getSettings().setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NORMAL);
webView.setWebViewClient(new WebViewClient() {
#Override
public void onPageFinished(WebView view, String url) {
webView.loadUrl("javascript:(function() { " +
"document.getElementsByClassName('header home_header')[0].style.display='none'; " +
"document.getElementsByClassName('glyphicon glyphicon-menu-hamburger')[0].style.display='none'; " +
"document.getElementsByClassName('searchBottomLinks_index searchBottomLinks_internal')[0].style.display='none'; " +
"document.getElementsByClassName('list-unstyled list-inline')[0].style.display='none'; " +
"document.getElementsByClassName('row')[0].style.display='none'; "+
"document.getElementsByClassName('header home_header')[0].style.display='none'; " +
"document.getElementsById('header-inner')[0].style.display='none'; " +
"document.getElementsById('fixed-header')[0].style.display='none'; " +
"document.getElementsByClassName('collapse navbar-collapse')[0].style.display='none'; " +
"document.getElementsByClassName('navbar navbar-inverse sidebars')[0].style.display='none'; " +
"document.getElementsByClassName('footer')[0].style.display='none'; " +
"document.getElementsByClassName('footer2')[0].style.display='none'; " +
"document.getElementsByClassName('container')[0].style.display='none'; " +
"document.getElementsByClassName('acad-slider')[0].style.display='none'; " +
"})()");
}
});
webView.loadUrl("https://www.example.com");
}
}
I had the same problem, and fixed it with adding "var x=" before the javascript line :
webView.loadUrl("javascript:var x = document.getElementsByClassName('header')[0].style.display='none';");

Webview is not loading two page

In my app one of my Activity is based on a webpage..I want to load a webpage that will display the ExamSeatingPlan from my Student Portal.I am logging into the website using JavaScript and then I want to load the page which will display my ExamSeatingPlan on the same webview. The problem I am facing is when I logged in using javascript the login is successful, but then it's not loading the web page that display my ExamSeatingPlan. It loads the required page if I minimize the app and then after a few second maximize it. I think I didn't implement the onPageFinished correct.It will be very helpful if someone help me solve the problem.
Thanks
MainActivity.java
package com.example.ebad.badwae;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
public class MainActivity extends AppCompatActivity {
final String url = "http://111.68.99.8/StudentProfile/";
final String urltesting = "http://111.68.99.8/StudentProfile/ExamSeatingPlan.aspx";
WebView view;
boolean loaded;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
view = (WebView) findViewById(R.id.webview);
WebSettings webSettings = view.getSettings();
webSettings.setJavaScriptEnabled(true);
view.loadUrl(url);
view.setWebViewClient(new WebViewClient() {
#Override
public void onPageFinished(WebView views, String urls) {
view.loadUrl("javascript: {" + "document.getElementById('ctl00_Body_ENROLLMENTTextBox_tb').value = '" + "01-134121-061" + "';" +
"document.getElementById('ctl00_Body_PasswordTextBox_tb').value = '" + "123456789" + "';" +
"document.getElementsByName('ctl00$Body$LoginButton')[0].click();" + "};");
onPageFinishede(views, urls);
}
public void onPageFinishede(WebView views, String urls) {
if (!loaded) {
views.loadUrl(urltesting);
loaded = true;
}
}
});
}
}
Now It is loading the new page but it is using almost 80% of CPU. Is there any way to reduce the CPU usage?
Try calling the loadotherpage() after your first page finished.
So you need to change the following lines
view.setWebViewClient(new WebViewClient() {
public void onPageFinished(WebView views, String urls) {
view.loadUrl("javascript: {" + "document.getElementById('ctl00_Body_ENROLLMENTTextBox_tb').value = '" + "01-134121-061" + "';" +
"document.getElementById('ctl00_Body_PasswordTextBox_tb').value = '" + "123456789" + "';" +
"document.getElementsByName('ctl00$Body$LoginButton')[0].click();" + "};");
}
});
loadotherpage();
to
view.setWebViewClient(new WebViewClient() {
public void onPageFinished(WebView views, String urls) {
view.loadUrl("javascript: {" + "document.getElementById('ctl00_Body_ENROLLMENTTextBox_tb').value = '" + "01-134121-061" + "';" +
"document.getElementById('ctl00_Body_PasswordTextBox_tb').value = '" + "123456789" + "';" +
"document.getElementsByName('ctl00$Body$LoginButton')[0].click();" + "};");
if(!loaded){
loadotherpage();
loaded = true;
}
}
});

WebView code generating Uncaught TypeError and Uncaught ReferenceError errors on Android 4.4.2 (API 19) emulator

I'm having a problem with my code when running on a Android 4.4.2 KitKat (API 19) emulator...
When I emulate my project on a Android 4.3 (API 18) emulator, it works normally and creates the mathematical expressions with MathJax:
Image of emulator
But when I use a Android 4.4.2 emulator, the app don't work correctly:
Image of emulator
Here is the code of my project:
package com.testes.testesapp;
import android.app.Activity;
import android.graphics.Color;
import android.os.Bundle;
import android.view.View;
import android.webkit.WebView;
import android.widget.Button;
import android.widget.EditText;
public class MainActivity extends Activity implements View.OnClickListener {
private int exampleIndex = 0;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
WebView webView = (WebView) findViewById(R.id.webview);
webView.getSettings().setJavaScriptEnabled(true);
//webView.getSettings().setBuiltInZoomControls(true);
webView.loadDataWithBaseURL("http://test", "<script type='text/x-mathjax-config'>"
+ "MathJax.Hub.Config({ "
+ "showMathMenu: false, "
+ "jax: ['input/TeX','output/HTML-CSS'], " // output/SVG
+ "extensions: ['tex2jax.js','toMathML.js'], "
+ "TeX: { extensions: ['AMSmath.js','AMSsymbols.js',"
+ "'noErrors.js','noUndefined.js'] }, "
// + "'SVG' : { blacker: 30, "
// + "styles: { path: { 'shape-rendering': 'crispEdges' } } } "
+ "});</script>"
+ "<script type='text/javascript' "
+ "src='file:///android_asset/MathJax/MathJax.js'"
+ "></script>"
+ "<span id='math'></span>","text/html","utf-8","");
EditText edit = (EditText) findViewById(R.id.edit);
edit.setBackgroundColor(Color.LTGRAY);
edit.setTextColor(Color.BLACK);
edit.setText("");
Button btnShow = (Button) findViewById(R.id.btnShow);
btnShow.setOnClickListener(this);
Button btnClear = (Button) findViewById(R.id.btnClear);
btnClear.setOnClickListener(this);
Button btnExample = (Button) findViewById(R.id.btnExample);
btnExample.setOnClickListener(this);
}
private String doubleEscapeTeX(String s) {
String t="";
for (int i=0; i < s.length(); i++) {
if (s.charAt(i) == '\'') t += '\\';
if (s.charAt(i) != '\n') t += s.charAt(i);
if (s.charAt(i) == '\\') t += "\\";
}
return t;
}
private String getExample(int index) {
return getResources().getStringArray(R.array.tex_examples)[index];
}
public void onClick(View v) {
if (v == findViewById(R.id.btnShow)) {
WebView webView = (WebView) findViewById(R.id.webview);
EditText edit = (EditText) findViewById(R.id.edit);
webView.loadUrl("javascript:document.getElementById('math').innerHTML='\\\\["
+ doubleEscapeTeX(edit.getText().toString()) + "\\\\]';");
webView.loadUrl("javascript:MathJax.Hub.Queue(['Typeset',MathJax.Hub]);");
}
else if (v == findViewById(R.id.btnClear)) {
WebView webView = (WebView) findViewById(R.id.webview);
EditText edit = (EditText) findViewById(R.id.edit);
edit.setText("");
webView.loadUrl("javascript:document.getElementById('math').innerHTML='';");
}
else if (v == findViewById(R.id.btnExample)) {
WebView webView = (WebView) findViewById(R.id.webview);
EditText edit = (EditText) findViewById(R.id.edit);
edit.setText(getExample(exampleIndex++));
if (exampleIndex > getResources().getStringArray(R.array.tex_examples).length - 1)
exampleIndex=0;
webView.loadUrl("javascript:document.getElementById('math').innerHTML='\\\\["
+ doubleEscapeTeX(edit.getText().toString()) + "\\\\]';");
webView.loadUrl("javascript:MathJax.Hub.Queue(['Typeset',MathJax.Hub]);");
}
}
}
When I press the "Example" or the "Show" button, LogCat emits the errors:
I/chromium(1254): [INFO:CONSOLE(1)] "Uncaught TypeError: Cannot set property 'innerHTML' of null", source: http://test/ (1)
I/chromium(1254): [INFO:CONSOLE(1)] "Uncaught ReferenceError: MathJax is not defined", source: http://test/ (1)
I have no idea how to fix this problem, and would like somebody's help to solve this. Thanks.
I got this problem too.
Here is my solution:
change your base URL from "http://test" to "http://test/"
change this code webView.loadUrl(..) to webView.evaluateJavascript(..);. Especially for code where we want to load innerHTML. Don't forget to add anotation #TargetApi(Build.VERSION_CODES.KITKAT) because it's only for Android 4.4 and above
never put webView.loadWithBaseUrl(..) in the same process with webView.loadUrl(..). Because If webView.loadUrl(..) was loaded before webView.loadWithBaseUrl(..) finished, it will raise error as OP stated above.
For number 3, your codes is already conform with this (because in your codes, webView.loadUrl(..) execution was already separated with webView.loadWithBaseUrl(..) by using OnClick event. So, don't pay attention to it.
But if your apps need to load them at one event, consider to separate them by using this code:
`
private void initiateWebView(){
webViewEquationDisplay.setWebViewClient(new WebViewClient() {
#Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT){
loadUrlKitKat(equationSymbolFinal+equationToBeDisplayedFinal);
}
else{
webViewEquationDisplay.loadUrl("javascript:document.getElementById('math').innerHTML='<font color=\"yellow\">`"+equationToBeDisplayedFinal+"`</font>';");
}
webViewEquationDisplay.loadUrl("javascript:MathJax.Hub.Queue(['Typeset',MathJax.Hub]);");
}
});
final String mathJaxOfflineUrl = "file:///android_asset/MathJax/MathJax.js";
webViewEquationDisplay.loadDataWithBaseURL("http://bar/", "<script type='text/x-mathjax-config'>"
+"MathJax.Hub.Config({ "
+"showMathMenu: false, "
+"jax: ['input/AsciiMath','output/HTML-CSS'], "
+"extensions: ['asciimath2jax.js'], "
+"AsciiMath: { fixphi: true, useMathMLspacing: true, displaystyle: false, decimalsign: \".\" }, "
+"});</script>"
+"<script type='text/javascript' "
+"src='"+mathJaxOfflineUrl+"'"
+"></script><span id='math'></span>","text/html","utf-8","");
}
#TargetApi(Build.VERSION_CODES.KITKAT)
private void loadUrlKitKat(String param){
webViewEquationDisplay.evaluateJavascript("javascript:document.getElementById('math').innerHTML='<font color=\"#97FD97\">`"+param+"`</font>';",null);
}
`
good luck
I had the same problem when I moved different javascript functions out of the main page to an separate .js file. For some reason, Android can't find externally-loaded JavaScript webview functions from Java - only the ones in the main page. Once I moved the function back from the JS file, it immediately started working.
Try making a "proxy" function like this directly inside the main HTML:
function proxy() {
call_some_other_function_from_JS_file();
}
This worked for me. I'm sure there must be a way to get find these functions, because I didn't have this problem on iOS. Someone please comment if you know a better way.
webview.evaluateJavascript("javascript:document.getElementById('math').innerHTML='"+doubleEscapeTeX(questn)+"';",null);
webview.loadUrl("javascript:MathJax.Hub.Queue(['Typeset',MathJax.Hub]);");
This is the sollution for api 19 or above

Categories

Resources