I am working on an android project using HTML and webview to display.
I have
display.loadUrl("file:///android_asset/index.html");
display.setWebViewClient(new WebViewClient() {
public void onPageFinished(WebView view, String url)
{
display.loadUrl("javascript:openDialog()");
}
});
and this works perfectly. But the javascript function i want to call is in another page (chat.html). How do i call the javascript functions on this pages from java?
If you are the owner of the webpage (chat.html), you can integrate a JS-function which invokes a native method. And in this native method you can call your target-JS:
chat.html:
function callItNow() {
if (typeof Android != "undefined"){
if (Android.caller!= "undefined") {
Android.caller();
}
}
}
in native Code, define a class:
class MyJavascriptBridge {
public void caller() {
//now you know you are on the right place (chat.html)
webView.loadUrl("javascript:openDialog()");
}
}
and of course you have to declare the bridge to your webview:
webView.addJavascriptInterface(new MyJavascriptBridge(), "Android");
suppose you'r function in javascript is hello.
webview.loadUrl("javascript:hello();");
I think that'll do it.
I'm trying to simply set and retrieve a cookie inside a webview in android. I have tried numerous cookie manager scripts to try and get this to work. I have JavaScript enabled.
When running the application on a Samsung S3 and a Samsung Galaxy Tab 10.1 cookies don't appear to set at all (android 4.1). However, when running the software on a Samsung Galaxy ace, HTC Desire Z and in the android emulators, the cookies are set and read perfectly fine.
When working, the webview returns the string as expected, when not working, the output is simply "null"; the cookie has not value/is not set.
My specific case also uses sliding Navigation class, which is an extension of Actionbar Sherlock.
I'd really appreciate any help, I've been struggling with this for several weeks now.
Thank you.
HTML:
<html>
<head>
<title>
</title>
<script>
function createCookie(name, value)
{
var day = (1 * 24 * 60 * 60 * 1000);
var date = new Date();
date.setTime(date.getTime() + (20 * 365 * day));
var expires = "; expires=" + date.toGMTString();
document.cookie = name + '=; expires=Thu, 01 Jan 1970 00:00:01 GMT;';
document.cookie = name + "=" + value + expires + "; path=/";
}
function readCookie(name)
{
var nameEQ = name + "=";
var ca = document.cookie.split(';');
for(var i=0;i < ca.length;i++) {
var c = ca[i];
while (c.charAt(0)==' ') c = c.substring(1,c.length);
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
}
return null;
}
</script>
</head>
<body>
<h1 class="">
<script type="text/javascript">
createCookie("test", "If this is working, it returns this string. If this is not working, it returns null.");
document.write("test: " + readCookie("test"));
</script>
</body>
</html>
Java Code:
public class MainActivity extends SherlockActivity implements ISideNavigationCallback {
public static final String EXTRA_TITLE = "com.devspark.sidenavigation.sample.extra.MTGOBJECT";
public static final String EXTRA_RESOURCE_ID = "com.devspark.sidenavigation.sample.extra.RESOURCE_ID";
public static final String EXTRA_MODE = "com.devspark.sidenavigation.sample.extra.MODE";
public static String WebLoaded = "0";
public static String page = "signup.php";
private ImageView icon;
private SideNavigationView sideNavigationView;
private WebView engine;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
icon = (ImageView) findViewById(android.R.id.icon);
sideNavigationView = (SideNavigationView) findViewById(R.id.side_navigation_view);
sideNavigationView.setMenuItems(R.menu.side_navigation_menu);
sideNavigationView.setMenuClickCallback(this);
if (getIntent().hasExtra(EXTRA_TITLE)) {
String title = getIntent().getStringExtra(EXTRA_TITLE);
int resId = getIntent().getIntExtra(EXTRA_RESOURCE_ID, 0);
setTitle(title);
icon.setImageResource(resId);
sideNavigationView.setMode(getIntent().getIntExtra(EXTRA_MODE, 0) == 0 ? Mode.LEFT : Mode.RIGHT);
}
//test
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
String domain = "localhost";
CookieManager cookieManager = CookieManager.getInstance();
cookieManager.setAcceptCookie(true);
cookieManager.setCookie(domain, "name=value");
cookieManager.setCookie(domain, "path=/");
cookieManager.setCookie(domain, "HttpOnly");
//enable cookies
CookieManager.getInstance().setAcceptCookie(true);
//navigates web engine, including on nav click
engine = (WebView) findViewById(R.id.web_engine);
engine.loadUrl("file:///android_asset/" + page);
//enable JavaScript support - disabled by default for some weird reason
engine.getSettings().setJavaScriptEnabled(true);
engine.setWebViewClient(new WebViewClient());
//disables text selection
engine.setOnLongClickListener(new View.OnLongClickListener() {
public boolean onLongClick(View v) {
return true;
}
});
}
#Override
public void onPause()
{
super.onPause();
engine.getSettings().setJavaScriptEnabled(false);
}
#Override
public void onResume()
{
super.onResume();
engine.getSettings().setJavaScriptEnabled(true);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
sideNavigationView.toggleMenu();
break;
case R.id.mode_left:
item.setChecked(true);
sideNavigationView.setMode(Mode.LEFT);
break;
case R.id.mode_right:
item.setChecked(true);
sideNavigationView.setMode(Mode.RIGHT);
break;
default:
return super.onOptionsItemSelected(item);
}
return true;
}
#Override
public void onSideNavigationItemClick(int itemId) {
switch (itemId) {
case R.id.side_navigation_menu_item1:
invokeActivity(getString(R.string.title1), R.drawable.ic_android1);
page = "index.html";
break;
case R.id.side_navigation_menu_item2:
invokeActivity(getString(R.string.title2), R.drawable.ic_android2);
page = "test.html";
break;
case R.id.side_navigation_menu_item3:
invokeActivity(getString(R.string.title3), R.drawable.ic_android3);
break;
case R.id.side_navigation_menu_item4:
invokeActivity(getString(R.string.title4), R.drawable.ic_android4);
break;
case R.id.side_navigation_menu_item5:
invokeActivity(getString(R.string.title5), R.drawable.ic_android5);
break;
default:
return;
}
finish();
}
After over a month of research I've concluded that setting a cookie in android versions greater than 2.3 is not possible in a webview where the file is on the localhost (read directly from the assets folder).
I went through many alternatives to to using cookie storage, including using HTML's localstorage. The whole issue here, I am led to believe, is security. If I were to create a cookie or localstorage on the localhost, then other apps could access that storage, thus is a major security threat.
My ultimate problem was trying to bridge the webview with two-way communication with java and also having a place to store data during the process. My solution was to take advantage of the JavascriptInterface
The idea is as follows:
Parse data to function in javascript
Javascript calls a special javascript function e.g. "setData(myDataName, myData)"
Java has a function which listens to this, and will take arguments set by javscript, and can also return values to javascript.
Once data is parsed to Java, java stores this in a series of files in assets.
When javascript function "getData(myDataName)" is called, the data is returned by the same kind of method by Java.
I found this very useful: Android JavascriptInterface Documentation, Handling JavascriptInterface in Android 2.3
The only major 'hang-ups' come with a what I found was a fairly serious bug in Android 2.3 (fixed in 3.0) which effectively broke the JavascriptInterface. The second link above describes the best workaround I have found.
Here is an example of how to get the two-way communication working (it's very messy, but it works):
Custom webinterface class:
public class webViewInterface {
//#JavascriptInterface //for SDK 12+
public String showToast(String myText) {
Toast.makeText(context, myText, Toast.LENGTH_LONG).show();
return myText;
}
}
Main class:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
engine = (WebView) findViewById(R.id.web_engine);
context = this;
WebSettings webSettings = engine.getSettings();
webSettings.setJavaScriptEnabled(true);
engine.setWebViewClient(new WebViewClient());
engine.loadUrl("file:///android_asset/" + page);
boolean javascriptInterfaceBroken = false;
try {
if (Build.VERSION.RELEASE.startsWith("2.3")) {
javascriptInterfaceBroken = true;
}
} catch (Exception e) {
// Ignore, and assume user javascript interface is working correctly.
}
// Add javascript interface only if it's not broken
// #TODO: write the workaround for < 2.3 devices
if (!javascriptInterfaceBroken) {
engine.addJavascriptInterface(new webViewInterface(), "MainActivityInterface");
}
//disables text selection
engine.setOnLongClickListener(new View.OnLongClickListener() {
public boolean onLongClick(View v) {
return true;
}
});
}
HTML:
<html>
<head>
</head>
<body>
<input type="button" value="Say hello" onClick="showAndroidToast();" />
<script type="text/javascript">
function showAndroidToast() {
document.write(MainActivityInterface.showToast("eureka!"));
}
</script>
</body>
</html>
I encountered the same limitations. I am loading local html files from the assets fodler. On a 2.2 emulator, cookies are stored and can be retrieved via JavaScript. However, testing on my 4.1 device, cookies set by a local page won't persist.
Based on #kirgy's and #user3220983's suggestions, I made it using the Javascript interface.
webview.addJavascriptInterface(new JavaScriptInterface(this), "Android");
public class JavaScriptInterface {
...
#JavascriptInterface
public void setCookie(String name, String value) {
Editor editor = activity.settings.edit();
editor.putString(name, value);
editor.commit();
}
#JavascriptInterface
public String getCookie(String name) {
return activity.settings.getString(name, "");
}
#JavascriptInterface
public void deleteCookie(String name) {
Editor editor = activity.settings.edit();
editor.remove(name);
editor.commit();
}
Note: these functions does not provide full cookie functionality (expiration, path), I am posting this as an idea of a good starting point.
You need to set the cookie's expiration date or else the cookie won't be be accepted.
Something like this:
document.setCookie = function(sName,sValue)
{
var oDate = new Date();
oDate.setYear(oDate.getFullYear()+1);
var sCookie = sName.escape() + '=' + escape(sValue) + ';expires=' + oDate.toGMTString() + ';path=/';
document.cookie= sCookie;
}
Good luck, hope it works!
I encountered the same issue as kirgy. I was trying to use cookies (with javascript) in a Droid webview that displayed local content. It would not store the data. The same code worked perfectly if run from a remote url in the same webview though. Enabling cookies in java (with the Android CookieManger) had no effect.
Fortunately, I used custom javascript functions to encapsulate all my cookie needs in the local web app. Using the webview javascript interface, when running on the droid I just managed my cookies in a virtual manner by handling it up in the java.
For my needs, I only required session storage, so just put the cookies data in a java HashMap. I didn't worry about expiration dates or long term storage. If you need your "virtual cookies" to implement those details, it shouldn't be too difficult to figure out once the data is going to and from java via the js interface.
I have developing phonegap android application. I'm trying to establish the communication between javascript and android java classes.
For Communication i have used addJavaScriptInterfaceMethod in android main activity.So that i can use java object and method in javascript.
following is the Java Code :
public class Activity extends DroidGap
{
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setIntegerProperty("loadUrlTimeoutValue", 60000);
super.loadUrl("file:///android_asset/www/jq3.html");
MapTablesWrapper table = new MapTablesWrapper();
super.appView.addJavascriptInterface(new MapTablesWrapper(), "tables");
}
}
And in javascript :the following code does not printing the table value.It's alerting undefined
var tableName = tables.getTableName();
function(){
alert(tableName);
}
And if i declare var table inside the function.Its printing the tableName and following code is
function(){
var table = tables.getTableName();
alert(tableName);
}
But i would like to declare variable outside of the function and want to use that varaible in inside the function.
You can do like
var global = {
table : null
};
function()
{
global.table = tables.getTableName();
alert(global.table);
}
you can rename global as your JS file name, so that this variable can be accessed all the functions in the current file and also in any other JS File by using your fileName.table here it is global.table
I'm trying very simply to test the 3.0 Facebook get started guide. https://developers.facebook.com/docs/getting-started/facebook-sdk-for-android/3.0/
I have had some problems with imports and references but I don't know it that's relevant. The issue I'm having is when I try to run the test Activity ant get this error:
Could not find class 'com.test1.test2.FacebookLogin$1', referenced from method com.test1.test2.FacebookLogin.onCreate
Code:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_facebook_login);
//Error occurs here when I use 'this'
Session.openActiveSession(this, true, new Session.StatusCallback() {
// callback when session changes state
#Override
public void call(Session session, SessionState state, Exception exception) {
if (session.isOpened()) {
// make request to the /me API
Request.executeMeRequestAsync(session, new Request.GraphUserCallback() {
// callback after Graph API response with user object
#Override
public void onCompleted(GraphUser user, Response response) {
if (user != null) {
TextView welcome = (TextView) findViewById(R.id.welcome);
welcome.setText("Hello " + user.getName() + "!");
}
}
});
}
}
});
}
How can I get a NoClassDefFoundError when I use this?
UPDATE:
After testing with the Scrumtious tutorial https://developers.facebook.com/docs/tutorials/androidsdk/3.0/scrumptious/authenticate/ as well I'm getting the same error when I call the Session.StatusCallback() method. I still don't know what my problem is though.
Thanks for the help
Maybe you updated to Android sdk tools revision 22. There is an issue there. You have to add the libraries you use in the export path. Check:
Android Sdk tools Revision 22 issue?
Im trying to figure out the easiest way to check my Main Activity's URL inside my (WebView). This is going to be in a Unit Test using the Robotium 4.1 framework. All i am trying to figure out how i can interact with the webview, such as send the activity a URL to load, so i can test against that and make sure the correct URL is loaded and also check my actionbar items as well.
Any Codes, suggestions or recommendations would be highly appreciated.
public class ErrorHandling extends
ActivityInstrumentationTestCase2<Webview_Main> {
private Solo solo;
private WebView web;
..
protected void setUp() throws Exception {
super.setUp();
solo = new Solo(getInstrumentation(),getActivity());
}
Updated per recommendations (Currently - NullPointerException Erorrs)
public void testUrl() {
String URL = solo.getString(com.example.webview.R.string.url);
web = (WebView) getActivity().findViewById(R.id.webview_main); //Added
try {
solo.assertCurrentActivity("Launching Main Activity", Webview_Main.class);
assertTrue(solo.getWebUrl().equals("URL")); }
catch (Error error) {
}
}
public void testWeb() {
try {
web = (WebView) getActivity().findViewById(R.id.webview_main); //Added
solo.getCurrentActivity().runOnUiThread(new Runnable() {
public void run() {
web.loadUrl("http://www.google.com");
}
});
solo.sleep(1000);
} catch (Error error) {
}
}
first, calling
web.getSettings();
gives you nothing. It provides you WebSettings, but you don't do anything with that object.
To assert current url in your webview you can use:
assertTrue(solo.getWebUrl().equals("your url"));
To load specified url in your webview you have to run it in another thread (here I'm not sure, if it should be runOnMainSync or runOnUiThread, however I tried runOnUiThread and it worked fine), for instance:
solo.getCurrentActivity().runOnUiThread(new Runnable() {
public void run() {
web.loadUrl("http://www.OTHER_url_TO_test_AGAINST");
}
});
The steps to check the URL are as follows:
1) Create the webview object for the specific application
obj = (WebView)getActivity().findViewById((package name of source or apk).R.id.(Id of the source webview))
Note: If you dont have the source code of the source application of whome you are writing the test case then use the hierarchy viewer to find the id of the webview.
2) Add some sleep so that it will wait the time taken to load the url
solo.sleep(time)
3) Use this to get the current value or status of the application.
obj.getSettings()
4) Take a Boolean variable and store the value of
Boolean variable = solo.getWebUrl().equals("URL to be tested");
5) assertTrue(Boolean variable)
To verify the value true or false.