I'm using crosswalk now. I need to call a Java method when a user clicks a button in the HTML, which may look like:
Start
I'm not sure if Crosswalk extension is what I wanted, which seems to be so heavy-weighted just for calling a Java function.
Is there a simpler way to do this? Or should I use Cordova with Crosswalk in this case?
Here is about how to call java function with js in the crosswalk XWalkView. How to use XWalkView refer this answer.
References:
crosswalk-calling-java-methods-with-javascript
XWalkView manual
Below is the process to call java from js, and notices.
add this to activity you XWalkView in
webSettings.setJavaScriptEnabled(true);
mXWalkView.addJavascriptInterface(new JsInterface(), "NativeInterface");
and this, you also make it a class
public class JsInterface {
public JsInterface() {
}
#JavascriptInterface
public void act() {
//do something
}
}
and in the html page
<button onclick="NativeInterface.act()">Call Java Here</button>
when you import JavascriptInterface, take care, make sure you imported the exact one.
import org.xwalk.core.JavascriptInterface;
Not this one, this is for webview
import android.webkit.JavascriptInterface;
If you import this one, this will cause no action when you operation on the page and below error in your android studio.
12-02 13:24:49.921 12376-12376/com.xxxxxx.app E/chromium:
[ERROR:xwalk_autofill_client.cc(121)] Not implemented reached in
virtual void xwalk::XWalkAutofillClient::OnFirstUserGestureObserved()
Usually when you import the JavascriptInterface, the first one is what we want just like below pic shows.
But sometime when you change from webview to XWalkView, you may forget to change the JavascriptInterface.
If you are only using XWalkView as an embedded view, the addJavascriptInterface is sufficient to inject Java object into XWalkView(JavaScript), which is just like the addJavascriptInterface in android.webkit.WebView:
https://crosswalk-project.org/apis/embeddingapidocs_v2/reference/org/xwalk/core/XWalkView.html
http://developer.android.com/guide/webapps/webview.html#BindingJavaScript
Related
I am currently making a Cordova plugin that will have call a method which starts a tween animation on the main activity.
cordova.getActivity().customMethod();
Does not work because the plugin does not know whether the method is implemented or not. How do I do this?
Thanks!
Edit: To clarify my question a little bit better: How do I make a Cordova Plugin start an Android view-animation in the current activity?
Did you add your plugin name to plugins.xml or config.xml(as from version 2.0.0)?
like -->
<plugin name="Your_plugin_name" value="packagename.Your_plugin_name"/>
Edit:
As you are simply calling a method in your activity,I wouldn't want to write a plugin for that...but you can do that just by getting a reference from that activity in the plugin and calling the method.After all the Plugin is implemented in native Java code.But if you have implemented CordovaWebView,then instead I would rather call it directly from the javascript.
In onCreate:
cordovaWebView.getSettings().setJavaScriptEnabled(true);
cordovaWebView.addJavascriptInterface(this, "reference");
In you activity:
public void animate()
{
//do animation
}
In JS :
reference.animate();
Do as you may like.
I setup ActionBarSherlock with my app, and I'm trying to use the Intermediate Progress, I'm using this:
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
setSupportProgressBarIndeterminateVisibility(false);
In my onCreate, and then using:
setSupportProgressBarIndeterminateVisibility(true);
To enable it.
It works fine in ICS but it doesn't work at all in Gingerbread or Froyo, does anyone know how to get it to work? Thanks
I just had the same problem. Jake's solution above did not fix it for me - the method is undefined.
I found a working solution posted by Jake on the bug list for ActionBarSherlock here:
Action Bar Indeterminate Progress Bar Not Disappearing
See Jake's response to the poster - the trick is to call getSupportActionBar() first, to "trigger creation of the views".
So my onCreate() method is:
protected void onCreate(Bundle arg0)
{
super.onCreate(arg0);
// allow window to show progress spinner in the action bar
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
getSupportActionBar();
setSupportProgressBarIndeterminateVisibility(false);
}
Update based on comment from Laux:
Make sure your imports reflect com.actionbarsherlock.view.Window.FEATURE_INDETERMINATE_PROGRESS for this to work.
Here is part of my import block from an app that uses this pattern:
import com.actionbarsherlock.app.ActionBar;
import com.actionbarsherlock.app.SherlockActivity;
import com.actionbarsherlock.view.ActionProvider;
import com.actionbarsherlock.view.Menu;
import com.actionbarsherlock.view.MenuItem;
import com.actionbarsherlock.view.Window;
import com.actionbarsherlock.widget.ShareActionProvider;
This is a very good thing to remember when working with ABS - many of your normal Android imports should be updated to refer to ABS instead.
It may be a good idea to revisit your import block, or possibly remove it entirely and let Eclipse rebuild it for you (CTRL-SHIFT-O) to which point Eclipse will prompt you for each import that ABS redeclares.
This was also explained by Glebbb in his answer.
I'm sure you've probably figured it out by now, but the most likely culprit is you including the wrong file because it's so easy to do automatically.
Replace any import of android.view.Window with com.actionbarsherlock.view.Window and the needed features will work.
You need to call supportRequestWindowFeature.
requestWindowFeature is a final method on Activity and couldn't be overriden.
Check, if you are using Theme.Sherlock.NoActionBar or similar no action bar theme for this activity.
In this case setSupportProgressBarIndeterminateVisibility method fails for me with
Caused by: java.lang.NullPointerException
at com.actionbarsherlock.internal.ActionBarSherlockCompat.updateProgressBars(ActionBarSherlockCompat.java:710)
at com.actionbarsherlock.internal.ActionBarSherlockCompat.onIntChanged(ActionBarSherlockCompat.java:686)
at com.actionbarsherlock.internal.ActionBarSherlockCompat.updateInt(ActionBarSherlockCompat.java:681)
at com.actionbarsherlock.internal.ActionBarSherlockCompat.setFeatureInt(ActionBarSherlockCompat.java:665)
at com.actionbarsherlock.internal.ActionBarSherlockCompat.setProgressBarIndeterminateVisibility(ActionBarSherlockCompat.java:637)
at com.actionbarsherlock.app.SherlockFragmentActivity.setSupportProgressBarIndeterminateVisibility(SherlockFragmentActivity.java:282)
I guess you should use a progress dialog instead to indicate loading process or regular Theme with activity title bar and then use setProgressBarIndeterminateVisibility method for older platforms.
I want to know if there is way to call javascript from java on android?
In my program, I interact java and javascript together. I am using java to receive response(json data) from TCP server and save them into a file. In webview I am using javascript jQuery getJSON() function to retrieve that file and using jQuery plot chart library to draw chart. Now, there is no relationship between java and javascript. Every time when I update data and file, I still need to click a button in webview to trigger the draw function. I want the programmes to be smart and handy. Is that a way to call or execute javascript from java. I know one way:
Button update = (Button)findViewById(R.id.update);
update.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
wv.loadUrl("javascript:document.write('hello')");
}
});
But the problem is I already do a index page by loadurl().
final WebView wv = (WebView) findViewById(R.id.webkankan);
wv.getSettings().setJavaScriptEnabled(true);
wv.loadUrl("file:///android_asset/index.html");
When I trigger this click event, all contents were gone only a string "hello" there. Another thing is why I need to change webview's type to final to avoid eclipse error. Does this is the problem to trigger my main problem? If so, how can I fix it?
Thanks for you patience.
Cheers!
For instance you have a javascript method in the index.html called loadData() which reads the file you saved in the java, then what you can do is wv.loadUrl("javascript:loadData()");. This actually call the javascript method and you can then read the file in that method. Hope this solves your problem.
or in simple terms. jus do this webView.loadUrl("javascript:jsmethodname()"); to execute javascript from java.
You can try to communicate java with javascript registering a java object to the webview that is executing the javascript.
The method addJavascriptInterface from Webview will allow you to make available a Java object to the Javascript scope, something like this:
WebView mWebView = new WebView(mContext);
//... webview initialization, js enabling etc.
MyProxyObject obj = new MyProxyObject(); //This object can interchange just basic types, but Strings are basic types
mWebView.addJavascriptInterface(obj,"myproxyobj");
With that code what you will have in the Javascript context you will have an object 'myproxyobj' that is actually a Java object.
Remember, you can interchange just basic types.
For more info check the following url:
http://developer.android.com/guide/webapps/webview.html
Specially check the section: Binding JavaScript code to Android code
Cheers,
Francisco
I try to reuse an existing WebView by clearing any private data the previous user left behind:
CookieManager.getInstance().removeAllCookie();
webview.clearHistory();
webview.clearFormData();
webview.clearCache(true);
clearHistory seems only to clear the back/forward list, accessible via API, but not the internal list used for coloring links inside the web content.
I even tried the following, suggested by another stackoverflow answer:
deleteDatabase("webview.db");
deleteDatabase("webviewCache.db");
I still have no luck: CSS :visited selectors still work after reloading the page.
An alternative would be to use the API level 11 private browsing feature (new constructor argument), but then I cannot benefit from visited links at all; and can no longer target older versions.
Maybe someone has a solution for this issue? Thanks for your help.
Summary of the answers I got so far:
I tried these two answers, but the first seems to clear HTML5 data storage and the latter seems to be specific to the built-in browser:
WebStorage.getInstance().deleteAllData();
Browser.clearHistory(getContentResolver());
WebChromeClient.getVisitedHistory(ValueCallback<String[]> callback) is only called after the first time I create a new WebView in a recently installed application.
I tried to remove the WebView from view hierachy and create a new one, but unfortunately the visited history seems to be stored for the whole application.
Override WebChromeClient and WebViewClient... Damn that was hidden.
I actually had to dig up a bit to find this out.
WebView webView = (WebView)findViewById(R.id.myWebView);
WebChromeClient myWebChromeClient = new WebChromeClient(){
#Override
public void getVisitedHistory(ValueCallback<String[]> callback) {
// called during webview initialization, original implementation does strictly nothing
// and defaults to the native method WebViewCore.nativeProvideVisitedHistory()
String[] myUserHistory = getVisitedUrlsFromMyOwnDatabase(userId);
callback.onReceiveValue(myUserHistory);
}
};
WebViewClient myWebViewClient = new WebViewClient(){
#Override
public void doUpdateVisitedHistory(WebView view, String url,
boolean isReload) {
// called whenever there is a new link being visited
insertIfNotExistVisitedUrlIntoMyOwnDatabaseForUser(userId);
super(view, url, isReload);
}
}
webView.setWebViewClient(myWebViewClient);
webView.setChromeClient(myWebChromeClient);
webView.getSettings().etc(whatever)...
I think I'm "almost there". Here's the part I managed: what it does so far is remove css history altogether, so we're halfway there. I can't get the browser to recognize the url format I'm providing in "myUserHistory", so in effect the only feature this code does is reset css history altogether, but it's only called once when the WebView is instanciated (or created, didn't check), so for a true multiuser experience you'd need to recreate the webview at each login.
My problem now is that I can't manage to load the urlHistory properly. My Honeycomb Xoom webview seems to ignore my data.
Ah well, I hope it works for you. For me just calling callback.onReceiveValue(new String[]{}); in getVisitedHistory() will be good enough.
EDIT:
I just put twenty more minutes into it because I'm curious. This method is what delegates to the WebChromeClient (mCallbackProxy = WebChromeClient).
protected void populateVisitedLinks() {
ValueCallback callback = new ValueCallback<String[]>() {
public void onReceiveValue(String[] value) {
sendMessage(EventHub.POPULATE_VISITED_LINKS, (Object)value);
}
};
mCallbackProxy.getVisitedHistory(callback);
}
It's protected in WebViewCore, which is a private attribute of WebView with no accessor. The sendMessage delegates to EventHub which is private, and WebViewCore is filled with private native methods, and one of these seems to be the one actually calling the populateVisitedLinks() method during the initialization.
Unless someone at Google adds a public method to WebView to trigger the repopulation, I'm afraid it's practically impossible to achieve your goal. Sorry :(
As a side note, all these native visited history handling really makes me wonder: why do hardware manufacturers care so much about which urls we visited? ;) <<< sarcasm
As an alternate solution, you could try adding your own CSS with the same base colors the default CSS has and switch the CSS by another one (with same color for both "types" of links) when you want to reset the visited links.
A:link{color: "#990000"; text-decoration: none;}
A:visited{color: "#990000"; text-decoration: none;}
A:hover{color: "#ff0000"; text-decoration: none;}
If you can obtain a Browser instance (maybe you can set a WebChromeClient to WebView) you can use its clearHistory() method.
Does WebStorage.clearAllData() have the desired effect? Unfortunately, the documentation on this class is very sparse compared to WebView and doesn't say whether it applies to WebViews.
The exact time you're calling clearHistory() may also have an effect. Clearing it and then navigating to a new page may still keep the first page in history, and you have to call the method after the new page has loaded.
Personally, if privacy is a real issue, I would create a new set of objects from scratch for this new session if possible.
I'm working on a project where we're using a Java applet for part of the UI (a map, specifically), but building the rest of the UI around the applet in HTML/JavaScript, communicating with the applet through LiveConnect/NPAPI. A little bizarre, I know, but let's presume that setup is not under discussion. I started out planning on using jQuery as my JavaScript framework, but I've run into two issues.
Issue the first:
Selecting the applet doesn't provide access to the applet's methods.
Java:
public class MyApplet extends JApplet {
// ...
public String foo() { return "foo!"; }
}
JavaScript:
var applet = $("#applet-id");
alert(applet.foo());
Running the above JavaScript results in
$("#applet-id").foo is not a function
This is in contrast to Prototype, where the analogous code does work:
var applet = $("applet-id");
alert(applet.foo());
So...where'd the applet methods go?
Issue the second:
There's a known problem with jQuery and applets in Firefox 2: http://www.pengoworks.com/workshop/jquery/bug_applet/jquery_applet_bug.htm
It's a long shot, but does anybody know of a workaround? I suspect this problem isn't fixable, which will mean switching to Prototype.
Thanks for the help!
For the first issue, how about trying
alert( $("#applet-id")[0].foo() );
For the second issue here is a thread with a possible workaround.
Quoting the workaround
// Prevent memory leaks in IE
// And prevent errors on refresh with events like mouseover in other browsers
// Window isn't included so as not to unbind existing unload events
jQuery(window).bind("unload",
function() {
jQuery("*").add(document).unbind();
});
change that code to:
// Window isn't included so as not to unbind existing unload events
jQuery(window).bind("unload",
function() {
jQuery("*:not('applet, object')").add(document).unbind();
});