Android webview cookie returns null

I am trying to just set and load a cookie inside webview in android. I tried many cookie admin scripts to try and get this to work. I have JavaScript enabled.

When launching the application on Samsung S3 and Samsung Galaxy Tab 10.1, cookies are not displayed at all (android 4.1). However, when you run the software on the Samsung Galaxy, HTC Desire Z and Android emulators, cookies are set and read perfectly.

When working, webview returns a string as expected, when it does not work, the result is simply "null"; cookie does not matter / not set.

In my particular case, a sliding navigation class is also used, which is an extension of the Actionbar Sherlock.

I would really appreciate any help; I have been struggling with this for several weeks now. Thanks.

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 ISIDNavigationCallback {

 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(); } 
+6
source share
4 answers

After more than a month of research, I came to the conclusion that setting a cookie in Android versions greater than 2.3 is not possible in a web view, where the file is located on a local host (read directly from the resources folder).

I took advantage of many alternatives to using cookie storage, including using HTML localstorage. The whole question here, I am convinced, is security. If I were to create a cookie or localstorage on a local host, then other applications could gain access to this store, which is a serious security risk.

My last problem was trying to flatten a webview with two-way communication with java, as well as having a place to store data during the process. My solution was to use JavascriptInterface

The idea is this:

  • Data analysis for working in javascript
  • Javascript calls a special javascript function, for example. "setData (myDataName, myData)"
  • Java has a function that listens for this and takes the arguments given by javscript, and can also return values ​​in javascript.
  • After parsing Java data, Java saves this as multiple files in assets.
  • When the javascript function getData (myDataName) is called, the data is returned by the same Java method.

I found this very useful: Android JavascriptInterface Documentation , Handling JavascriptInterface in Android 2.3

The only major β€œhang” is what I found is a pretty serious bug in Android 2.3 (fixed in version 3.0) that effectively broke JavascriptInterface. The second link above describes the best workaround I have found.

Here is an example of how to work with two-way communication (it is very dirty, 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 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> 
+3
source

I faced the same limitations. I am loading local html files from fodler. On emulator 2.2, cookies are stored and can be obtained using JavaScript. However, testing on my device 4.1, cookies set by the local page will not be saved.

Based on the suggestions of @kirgy and @ user3220983, I did this 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 do not provide the full functionality of cookies (expiration, path), I publish this as an idea of ​​a good starting point.

+3
source

You need to set the cookie expiration date, otherwise the cookie will not be accepted.

Something like that:

 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!

+1
source

I ran into the same problem as kirgy. I tried to use cookies (with javascript) in a Droid webview that displayed local content. It will not save data. The same code worked fine if it was run from a remote URL in the same web browser. The inclusion of cookies in java (with Android CookieManger) did not affect.

Fortunately, I used javascript custom functions to encapsulate all my cookie needs into a local web application. Using the javascript webview interface, when working on a droid, I simply managed my files in virtual mode, processing it in java.

For my needs, I only need to store the session, so just put the cookie data in the java HashMap file. I was not worried about expiration dates or long-term storage. If you need your "virtual cookies" to implement these details, it should not be too difficult to figure out once the data is sent, and from java through the js interface.

+1
source

Source: https://habr.com/ru/post/955449/


All Articles