onBackPressed event is not working properly in webview - javascript

I am developing an android app using webview. after a button is clicked it navigates to other page. i used javascript function onClick() to navigate.when back button is pressed it used to close that application but i want it to navigate to previous page. after using following code it states "unfortunately, myapp stopped working". I tried all possible ways. please help me
package com.example.anush.teamcetrankevaluator;
import android.app.Activity;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.webkit.WebView;
public class MainActivity extends Activity {
WebView web;
#Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
WebView web=(WebView)this.findViewById(R.id.webview);
web.loadUrl("file:///android_asset/webview.html");
web.getSettings().setJavaScriptEnabled(true);
//web.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
#Override
public void onBackPressed() {
super.onBackPressed();
if (web.canGoBack()) {
web.goBack();
}
else
{
super.onBackPressed();
finish();
}
}
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
// TODO Auto-generated method stub
// finish the activity
if (keyCode == KeyEvent.KEYCODE_BACK && web.canGoBack()) {
web.goBack();
return true;
}
return super.onKeyDown(keyCode, event);
}
}
Logcat Error :
09-10 20:44:52.688 10542-10542/? D/AndroidRuntime﹕ Shutting down VM
09-10 20:44:52.690 10542-10542/? E/AndroidRuntime﹕ FATAL EXCEPTION: main
Process: com.example.anush.teamcetrankevaluator, PID: 10542
java.lang.NullPointerException: Attempt to invoke virtual method 'boolean android.webkit.WebView.canGoBack()' on a null object reference
at com.example.anush.teamcetrankevaluator.MainActivity.onKeyDown(MainActivity.java:65)
at android.view.KeyEvent.dispatch(KeyEvent.java:2622)
at android.app.Activity.dispatchKeyEvent(Activity.java:2714)
at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchKeyEvent(PhoneWindow.java:2221)
at android.view.ViewRootImpl$ViewPostImeInputStage.processKeyEvent(ViewRootImpl.java:3988)
at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:3950)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3509)
at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3562)
at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3528)
at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:3638)
at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3536)
at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:3695)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3509)
at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3562)
at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3528)
at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3536)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3509)
at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3562)
at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3528)
at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:3671)
at android.view.ViewRootImpl$ImeInputStage.onFinishedInputEvent(ViewRootImpl.java:3832)
at android.view.inputmethod.InputMethodManager$PendingEvent.run(InputMethodManager.java:2210)
at android.view.inputmethod.InputMethodManager.invokeFinishedInputEventCallback(InputMethodManager.java:1851)
at android.view.inputmethod.InputMethodManager.finishedInputEvent(InputMethodManager.java:1842)
at android.view.inputmethod.InputMethodManager$ImeInputEventSender.onInputEventFinished(InputMethodManager.java:2187)
at android.view.InputEventSender.dispatchInputEventFinished(InputEventSender.java:141)
at android.os.MessageQueue.nativePollOnce(Native Method)
at android.os.MessageQueue.next(MessageQueue.java:143)
at android.os.Looper.loop(Looper.java:122)
at android.app.ActivityThread.main(ActivityThread.java:5312)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:901)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:696)
09-10 20:44:54.495 10542-10542/? I/Process﹕ Sending signal. PID: 10542 SIG: 9

Edit your onBackPressed to look like this:
#Override
public void onBackPressed() {
// get rid of this --> super.onBackPressed();
if (web.canGoBack()) {
web.goBack();
}
else
{
super.onBackPressed();
// get rid of this --> finish();
}
}
You've also got an error in onCreate:
WebView web;
#Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// this line is wrong: WebView web=(WebView)this.findViewById(R.id.webview);
//should be:
web=(WebView)this.findViewById(R.id.webview);
web.loadUrl("file:///android_asset/webview.html");
web.getSettings().setJavaScriptEnabled(true);
//web.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);
}
This line is the useful part of your logcat error:
java.lang.NullPointerException: Attempt to invoke virtual method 'boolean android.webkit.WebView.canGoBack()' on a null object reference
It means that web was null, but you were trying to do web.canGoBack();

You create your variable WebView web in the main activity and then declare the same variable in the oncreate method. By doing this, you cannot access this initialised variable web outside of the scope of the oncreate bundle.
So the variable that you are attempting to access, the class variable WebView web that you declared first is not initialised, this is what is causing your app to stop.
So as the other answer Joe says, just
web=(WebView)this.findViewById(R.id.webview);
within your oncreate bundle.
This is a link which discusses variable scope in java.
http://www.java-made-easy.com/variable-scope.html
edit just saw your logcat:
java.lang.NullPointerException: Attempt to invoke virtual method 'boolean android.webkit.WebView.canGoBack()' on a null object reference
at com.example.anush.teamcetrankevaluator.MainActivity.onKeyDown(MainActivity.java:65)
at android.view.KeyEvent.dispatch(KeyEvent.java:2622)
The null object reference is referring to the uninitialised Webview web, when there is an attempt to access it in your onKeyDown method.

Related

kotlin.UninitializedPropertyAccessException: lateinit property WebView has not been initialized

I created an android app and loading an html file on android webView. Which is loaded successfully and working fine.
class MainActivity : AppCompatActivity() {
private lateinit var myAndroidWebView: WebView;
#SuppressLint("SetJavaScriptEnabled")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setWebviewDetails();
}
private fun setWebviewDetails(){
//if(!::myAndroidWebView.isInitialized){
myAndroidWebView = findViewById(R.id.webView);
//}
myAndroidWebView.settings.javaScriptEnabled = true;
myAndroidWebView.loadUrl("file:///android_asset/App/index.html");
myAndroidWebView.addJavascriptInterface(WebAppInterface(this), "AndroidApp");
}
public fun testMessage(param: String){
println("Interface call-2")
myAndroidWebView.post(Runnable {
val str = "xxxXXXXXXXXXXXXXx $param"
myAndroidWebView.loadUrl("javascript:Application.UserInterface.sample('$str')")
})
println("Interface call-3")
}
}
Now I want to send message to Android app to JS and vice versa.
I have a button in HTML and triggeting the function
public fun showToast(toast: String) {}
From HTML view by using, AndroidApp.showToast("hello");
Which is working fine and I am getting call from JS to Android interface function showToast()
Now on request from the JS I want to get some values from Android and send back to JS as well.
I have an interface, on trigger button from HTML I am getting call on the below interface function.
And trying to call a method in the MainActivity, public fun testMessage(param: String){} is triggered succssfully.
Issue:
I am trying to send data to JS by using,
myAndroidWebView.loadUrl("javascript:Application.UserInterface.sample('$str')")
Here I am getting error.
W/System.err: kotlin.UninitializedPropertyAccessException: lateinit property myAndroidWebView has not been initialized
How do I resolve it.
Thanks.
/** Instantiate the interface and set the context */
class WebAppInterface(private val mContext: Context) {
var mainActivity:MainActivity = MainActivity();
/** Show a toast from the web page */
#JavascriptInterface
public fun showToast(toast: String) {
println("Interface call-1")
mainActivity.testMessage(mContext,toast);
}
}
lateinit property not initialized exception is thrown because you are trying to create an instance of MainActivity in WebInterface. var mainActivity:MainActivity = MainActivity();
It is Android system's job to create and load your activities. You should never try to initiate an activity.
Here, a rough improvement of your code. Try to adapt it to your needs.
interface JsCommunicator {
fun testMessage(param: String)
}
class WebAppInterface(private val communicator: JsCommunicator) {
#JavascriptInterface
fun showToast(toast: String) {
communicator.testMessage(toast)
}
}
class YourMainActivity : JsCommunicator {
// ...
private lateinit var myAndroidWebView: WebView
override fun testMessage(param: String) {
println("Interface call-2")
myAndroidWebView.post(Runnable {
val str = "xxxXXXXXXXXXXXXXx $param"
myAndroidWebView.loadUrl("javascript:Application.UserInterface.sample('$str')")
})
println("Interface call-3")
}
}
You are accessing web-view without initialising it.
call setWebviewDetails() first then testMessage()
or you can make webview nullable like this
private var myAndroidWebView: WebView? = null;
also you need to call startActivity() to create Activity not by
creating objects as this is framework class managed by Android
System.

Javascript calling Android methods in WebView

I have some javascript running in WebView. In this Javascript code there a function which returns a boolean. I want to check the return value from this function and depends on it hide or not a view in my android code. I tried for one day and it does not work. Do someone knows where is my error? This is my code:
public class MyActivity extends Activity {
private static final String JS_INTERFACE = "Android";
....
webView.getSettings().setJavaScriptEnabled(true);
webView.setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY);
webView.loadUrl(getUrl(this.getResources().getString(R.string.host)));
webView.addJavascriptInterface(new WebViewJavaScriptInterface(this), JS_INTERFACE);
webView.setWebViewClient(new WebViewClient(progressBar, this, tvError));
webView.setWebChromeClient(new WebChromeClient(progressBar));
webView.loadUrl("javascript:window.Android.showAdBanner(showSdkAd())");
}
public class WebViewJavaScriptInterface
{
....
#JavascriptInterface
public void showAdBanner(String jsResult) {
if (jsResult == "true") {
((Activity) context).findViewById(R.id.adView).setVisibility(View.GONE);
} else {
((Activity) context).findViewById(R.id.adView).setVisibility(View.GONE);
}
}
}
You're setting the visibility to View.GONE in both cases of the if (jsResult == "true") if statement.
I think the window in the js is unneeded, so
webView.loadUrl("javascript:window.Android.showAdBanner(showSdkAd())");
Should be
webView.loadUrl("javascript:Android.showAdBanner(showSdkAd())");
Also, the javascript callback will be executed in a background thread, so you need to move to the main thread (posting a runnable to a view, runOnUiThread, using a handler etc), before performing Ui operations.
If you have a reference to a View, you can do:
#JavascriptInterface
public void showAdBanner(String jsResult) {
viewReference.post(new Runnable() {
public void run() {
if (jsResult == "true") {
((Activity) context).findViewById(R.id.adView).setVisibility(View.GONE);
} else {
((Activity) context).findViewById(R.id.adView).setVisibility(View.GONE);
}
}
}
Since, you have a reference to the activity, you can replace viewReference.post with ((Activity) context).runOnUiThread
If you initialise a Handler on the main thread, it will be bound to the main thread. As a field of the Activity, you could have:
private Handler mHandler = new Handler();
And then replace viewReference.post with mHandler.post
You could also make a custom Handler that implements handleMessage(Message msg) and then you can just send it an empty message. However, you should read https://techblog.badoo.com/blog/2014/08/28/android-handler-memory-leaks/ to avoid memory issues.

Android to javascript response

I'm developing an hybrid app in Android. I want to show an alertDialog(instead of an alert/confirm JavaScript function) and when the user touch YES, return a true response to JavaScript, otherwise return false. Then if it's true I want to redirect to another URL.
Here's the 'binding JavaScript code to Android code':
public class WebAppInterface {
Context mContext;
boolean result;
/** Instantiate the interface and set the context */
WebAppInterface(Context c) {
mContext = c;
}
/** Show a toast from the web page */
#JavascriptInterface
public boolean showAlert(String title, String message) {
new AlertDialog.Builder(mContext)
.setTitle(title)
.setMessage(message)
.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
result = true;
}
})
.setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
result = false;
}
})
.show();
return result;
}
}
And the JavaScript part:
if (Android.showAlert('Title example', 'Are you sure you wanna exit?') == true) {
window.location = "http://newurl.com/example.html";
}
It actually works but not as it supposed to do. JavaScript receives the result when I open again the alertDialog and then redirect to the new URL, It needs to redirect at the moment the user touch the YES button.
I've done lot of research on this particular case and sadly found nothing.
Thank you.
Here is the Javascript Code. Add a function to navigate to a page. Like doNavigate:
<script type="text/javascript">
function showAlert(toast) {
navigate = Android.showAlert('Title example', 'Are you sure you wanna exit?');
}
function doNavigate(){
window.location = "http://www.google.com"
}
</script>
And here is the Android code for show alert. Call the javascript method from onClick positive button:
#JavascriptInterface
public boolean showAlert(String title, String message) {
new AlertDialog.Builder(mContext)
.setTitle(title)
.setMessage(message)
.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
((Activity)mContext).runOnUiThread(new Runnable() {
#Override
public void run() {
myWeb.loadUrl("javascript:doNavigate()");
}
});
result = true;
}
})
.setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
result = false;
}
})
.show();
return result;
}
Keep a reference of the WebView in your WebAppInterface:
public static class WebAppInterface{
Context mContext;
boolean result;
WebView myWeb;
/** Instantiate the interface and set the context */
WebAppInterface(Context c, WebView webView) {
mContext = c;
myWeb = webView;
}
Probably when on click gets executed it doesnt immediately return the desired boolean value.
I'm thinking the next time you open the dialog then the if statment gets executed.
Maybe you can try injecting the logic through the constructor using an interface or class. And when the positive button is clicked it will call a method of that interface setting window.location
Hope it helps . Good luck

vaadin. Do smth when client refresh page

I start use vaadin.
I need to run my javascript after reloading page.
How can i do something when client refresh page?
Or how to catch "refresh page" event in vaadin?
Sorry for my English.
Probably overriding paint method can help:
public class HelloWorldApplication extends Application {
#Override
public void init() {
final Window mainWindow = new Window("Hello world app");
SomeComponent hl = new SomeComponent();
hl.addComponent(new Label("Hello world"));
mainWindow.addComponent(hl);
setMainWindow(mainWindow);
}
public class SomeComponent extends HorizontalLayout {
#Override
public void paint(PaintTarget target) throws PaintException {
// TODO Auto-generated method stub
super.paint(target);
getWindow().executeJavaScript("alert('paint invoked')");
}
}

Android Window already focussed warning javascript Interface

I am trying to interact with the JavaScript through Android. i followed the tutorial found [here][1].
But I am getting the following warning.system.out.println is also not working
WARN/KeyCharacterMap(310): No keyboard for id 0
WARN/KeyCharacterMap(310): Using default keymap: /system/usr/keychars/qwerty.kcm.bin
WARN/InputManagerService(66): Window already focused, ignoring focus gain of: com.android.internal.view.IInputMethodClient$Stub$Proxy#44faba68
cause of which I am not able to pass values or get the values back
webEngine=(WebView) findViewById(R.id.webengine);
webEngine.getSettings().setJavaScriptEnabled(true);
webEngine.addJavascriptInterface(this, "android");
webEngine.setWebViewClient(new WebViewClient()
{
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url)
{
return false;
}
});
webEngine.loadUrl("http://www.a11y.in/a11y_fs/");
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.menu, menu);
// TODO Auto-generated method stub
return super.onCreateOptionsMenu(menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// TODO Auto-generated method stub
// Handle item selection
switch (item.getItemId())
{
case R.id.edit:
webEngine.loadUrl("javascript:var path =android.path();var newContent=android.newContent();var name = 'myname'; android.toast(name););
return true;
case R.id.renarration:
return true;
default:
return super.onOptionsItemSelected(item);
}
}
public String path()
{
return xPath = "//H3[#id='header']";
}
public String newContent()
{
return newContent ="my New Home";
}
public void toast(String x)
{
Toast.makeText(this, "hello from js"+x, Toast.LENGTH_LONG).show();
}
plz help
First, those error messages are not related to your code, so you can just ignore them.
Then there seems to be some error with the quotes, there do not match (which also breaks the syntax highlighting in your question)... or it might be only this site which parses it incorrectly...
I also don't see the "path" method in your class, although you are accessing it from javascript. Similarly the "newContent" method.

Categories