I am using Android WebView to load a simple HTML page. The HTML depends on a tiny piece of Javascript code.
I need to inject the Javascript before html loaded. So I do it like this:
public class MainActivity extends Activity {
WebView mWebView;
Button mButton;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mWebView = (WebView)findViewById(R.id.webview);
mWebView.getSettings().setJavaScriptEnabled(true);
mWebView.setWebChromeClient(new WebChromeClient(){
#Override
public boolean onJsAlert(WebView view, String url, String message,JsResult result) {
return super.onJsAlert(view, url, message, result);
}
});
mButton = (Button)findViewById(R.id.button);
mButton.setOnClickListener(new myListener());
}
class myListener implements OnClickListener{
int mCount = 1;
#Override
public void onClick(View arg0) {
System.out.println("Load test page=>"+mCount+" times");
mWebView.loadUrl("javascript:var output='This string is defined before html loaded.'");
mWebView.loadUrl("file:///android_asset/test.html");
mCount++;
}
}
}
HTML code:
<html>
<head>
<script>
alert(output);
</script>
<head>
<body>
</body>
</html>
The JS and HTML works fine when I click the button first time. But when I click the button to execute the load again, it failed.
Logs:
Load test page=>1 times
Load test page=>2 times
Uncaught ReferenceError: output is not defined at file:///android_asset/test.html:5
Load test page=>3 times
Uncaught ReferenceError: output is not defined at file:///android_asset/test.html:5
Any suggestion?
This may seem like a long-winded approach, but could you have your android code write the js code to a file, then reference that file in your html file?
Related
I have a webView, and I am scraping the HTML:
webView.addJavascriptInterface(new WebScraper(), "HtmlViewer");
view.loadUrl("javascript:HtmlViewer.showHTML" +
"('<html>'+document.getElementsByTagName('html')[0].innerHTML+'</html>');");
And the parameter html contains the whole HTML page:
#JavascriptInterface
public void showHTML(String html) {
scrapePage(html);
}
Now the problem is, sometimes my HTML page shows an error message if the data hasnt fully loaded, or AJAX calls failed. When that happens I want to refresh the page. So i did:
if (matcher.find()) {
id = matcher.group(1);
getLecture(dom);
} else {
Log.d("errors", "looks like player didnt load try again by refreshing page");
webView.post(new Runnable() {
#Override
public void run() {
webView.reload();
}
});
}
But it doesnt look like my showHTML(String html) method is called again after refreshing. I was hoping someone could help me.
thnkas
Wait until the page has finished loading through the interface method onPageFinished (in the WebViewClient class) and then get the content of the page using the evaluateJavascript method. This way you can get the content of the site without using the JavaScriptInterface annotation
The code will look like this
webView.evaluateJavascript("<GET HTML>", new ValueCallback<String>() {
#Override
public void onReceiveValue(String value) {
Log.i(TAG, "Found HTML content: " + value);
}
}
I'm a beginner at android.
I used javascript method in android. And I want to call it when the app is loaded for first time.
For example,
testMethod = function(str) {
alert("hi" + str);
}//javascript
and
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mWebView.getSettings().setJavaScriptEnabled(true);
mWebView.getSettings().setDefaultTextEncodingName("utf-8");
mWebView.loadUrl("file:///index.html");
mWebView.addJavascriptInterface(androidBridge, "jsinterface");
mWebView.loadUrl("javascript:testMethod('javascript')");
}
What I was thinking here is the alert will pop up immediately when I start the app.
But nothing happens.
About this, I have two questions.
1.Can I call and use the javascript method in Android's onCreate method?
2.If it is possible, How can I do?
if you want to show a popup on start just use the default AlertDialog. see the code below.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
showMessage("My Message Here", "Title here");
}
private void showMessage(String data, String title){
new AlertDialog.Builder(this)
.setTitle(title)
.setMessage(data)
.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
// continue
}
})
.show();
}
check out whether index.html is REALLY loaded. I guess that webview didn't load your html properly, bcz it's not an invalid file path. try file:///mnt/sdcard/index.html. (or something likely)
try to put mWebView.loadUrl("javascript:testMethod('javascript')") in view.post or view.postDelayed.
Enabled Javascript on WebView. Because without JavaScipt web page image scaling is not working properly. This is my code how I am loading url in WebView:
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final String url = "http://nuz.uz/ekonomika-i-finansy/18651-v-2017-godu-v-uzbekistane-prekratitsya-realizaciya-lampochek-ilicha.html";
final WebView webview = (WebView) findViewById(R.id.webview);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
WebView.setWebContentsDebuggingEnabled(true);
}
webview.getSettings().setJavaScriptEnabled(true);
webview.setWebChromeClient(new WebChromeClient() {
public void onConsoleMessage(String message, int lineNumber, String sourceID) {
Log.d("Tag", message + " -- From line "
+ lineNumber + " of "
+ sourceID);
}
});
webview.setWebViewClient(new WebViewClient() {
#Override
public boolean shouldOverrideUrlLoading(WebView view, String loadingUrl) {
if (loadingUrl.equals(url)) return false;//open news link in webview
else {
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(loadingUrl));
startActivity(browserIntent);
return true;
}
}
#Override
public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error){
Log.d("Tag", "Error occured: "+error.toString());
}
});
webview.loadUrl(url);
}
}
When I am running app, it is opening web page. After loading all content of page, app is crashing. I tried to show error on console it is showing following error:
12-14 02:42:06.936 25760-25760/? D/Tag: Uncaught TypeError: Cannot
call method 'init' of undefined -- From line 951 of
http://nuz.uz/ekonomika-i-finansy/18651-v-2017-godu-v-uzbekistane-prekratitsya-realizaciya-lampochek-ilicha.html
I have checked url's content and found following which is causing app crash :
<script type="text/javascript">
jQuery(document).ready(function () {
App.init();
});
</script>
line 951: App.init();
How I can solve this problem without turning off JavaScript? How to prevent WebView from crashing app?
If you look at the source code of the page, right above line 951, you'll find
<script type="text/javascript" src="/templates/nuz_uz/assets/js/app.js"></script>
This script declares the App variable to be the result of the anonymous function, but the function doesn't return anything. Therefore App is still undefined at the time jQuery fires the ready event. You basically need to fix the error on the website, your Android app is fine.
I'm trying to access my Java method helloWorld(); using JavaScriptInterface in Android, from the page I'm viewing using WebView
I'm a little new to this, and I don't know why I'm not getting the value to my html page
This is the Android code I'm using:
WebView web;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
web = (WebView) findViewById(R.id.webview01);
JavaScriptInterface jsInterface = new JavaScriptInterface(this);
web.getSettings().setJavaScriptEnabled(true);
web.addJavascriptInterface(jsInterface, "JSInterface");
web.getSettings().setUseWideViewPort(true);
web.getSettings().setLoadWithOverviewMode(true);
web.setWebViewClient(new myWebClient());
web.getSettings().setJavaScriptEnabled(true);
web.loadUrl("http://exampleweb:10110/exWeb/deposits.jsp");
}
public class myWebClient extends WebViewClient
{
#Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
// TODO Auto-generated method stub
super.onPageStarted(view, url, favicon);
}
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
// TODO Auto-generated method stub
view.loadUrl(url);
return true;
}
}
public class JavaScriptInterface {
private Activity activity;
public JavaScriptInterface(Activity activity) {
this.activity = activity;
}
#JavascriptInterface
public String helloWorld(){
return("hello world");
}
}
}
This is the JavaScript code I've been using (on the page I'm viewing with WebView)
HTML button
<td> <button type="button" class="btn btn-xs btn-primary connectToAndroid">Test android</button></td>
JavaScript
$(".connectToAndroid").on('click', function () {
var val = window.JSInterface.helloWorld();
alert(val);
});
Does anyone know what I'm doing wrong here? I just want to alert an "Hello World" from android in my HTML page.
Any pointers are greatly appreciated!
Try by adding this line of code before loading the url and make sure you reference your jQuery library in the html.
web.setWebChromeClient(new WebChromeClient(this));
This is very weird, I tried using this a couple of hours ago:
$(".connectToAndroid").on('click', function () {
var val = Android.helloWorld();
alert(val);
});
Then I changed it, it didn't say Android anymore,
yet I kept getting an error saying:
Uncaught ReferenceError: Android is not defined
And after a while I figured, Android.helloWorld(); must be cached somehow in my webview app or something.
So, I changed back to this:
$(".connectToAndroid").on('click', function () {
var val = Android.helloWorld();
alert(val);
});
And added this:
web.addJavascriptInterface(jsInterface, "Android");
And now it works like a charm, as it should have from the beginning if it wasn't for some cache somewhere,
Can anyone explain why this happens? Does android webview actually cache javascript code? And can I prevent this behaviour in the future somehow? Cache bothers a lot when coding/testing new stuff.
I have some problem with calling a JavaScript function in a WebView and getting response in the app (on my Galaxy Tab 2 '10). I call the js-function directly after content loading. According this one solution i use a PictureListener
webView.setPictureListener(new PictureListener() {
#Override
public void onNewPicture(WebView view, Picture picture) {
webView.loadUrl("javascript: JsImpl.init('{response}');");
}
});
it works fine: when content is loaded, onNewPicture always is started.
"javascript: JsImpl.init('{response}') loads js that calls:
class JsImpl {
private final static String LOG_TAG = "JsImpl";
#JavascriptInterface
public void init(String json) {
Log.d(LOG_TAG, json);
}
}
In the log i see D/JsImpl(18400): {response}. It seems to be everything okay but...
When I switch my tab on a landscape or portrait mode the WebView is recreated, onNewPicture are started but the method public void init(String json) in the JsImpl is often not called at all!
So if i change orientation, sometimes js works, sometimes doesn't work. No exception, no errors...
Who faced with the same problem?
Below is full code
public class NextActivity extends Activity {
#SuppressLint("SetJavaScriptEnabled")
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_next);
final WebView wv = (WebView) findViewById(R.id.WebView);
wv.getSettings().setJavaScriptEnabled(true);
wv.loadUrl("file:///android_asset/index.html");
wv.addJavascriptInterface(new JsImpl(), "JsImpl");
wv.setPictureListener(new PictureListener() {
#Override
public void onNewPicture(WebView view, Picture picture) {
wv.loadUrl("javascript: JsImpl.init('{responce}');");
}
});
}
class JsImpl {
private final static String LOG_TAG = "JsImpl";
#JavascriptInterface
public void init(String json) {
Log.d(LOG_TAG, json);
}
}
}
html code is not needed here, just put on the assets dir an empty html file index.html.
EDIT:
I've found one soution but i dont know exactly is it correct varion. But it works.
I added handler loop
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
if (isJSSetup) return;
Log.i("handler-loop", "JS didn't handle. Reload page");
wv.loadUrl(CONTENT_PAGE);
handler.postDelayed(this, 1000);
}
}, 1000);
when #JavascriptInterface init(String json) is called, isJSSetup became true. In handler loop i check if JS is setup or no if (isJSSetup) return;. If no - i reload URL again wv.loadUrl(CONTENT_PAGE) and try to call init(String json). So long as it is not going to work. It's hardcode, so i'm still looking for a good solution.
I hope this will help, but I can't say for sure because you are not showing how your WebView is restored after orientation changes.
I was having very hard time making my nested fragments to work properly after orientation changes. I wanted to retain the form values and all functionality during screen rotations. It all worked fine except the JavascriptInterface was NEVER working after orientation changes.
My WebView is restored in the onCreateView. I had to remove the restoreState call for my WebView and it all works now.
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
rootView = inflater.inflate(R.layout.layoutT4, container, false);
webView = (WebView) rootView.findViewById(R.id.webViewT4);
prepareBrowser(); // the browser is initiated here including the JavascriptInterface
if (webView != null) {
String URL = (savedInstanceState == null) ? "" : savedInstanceState.getString("URL");
if (URL.equals("")) {
webView.loadUrl("yourhome.html");
} else {
//webView.restoreState(savedInstanceState.getBundle("webViewBundle")); // this line was preventing the JavascriptInterface to work properly
webView.loadUrl(URL); // this is saved in onSaveInstanceState - I just reopen the URL here, the PHP page will take care of reloading the data
}
}
return rootView;
}