在Samsung S3和Samsung Galaxy Tab 10.1上运行应用程序时,似乎根本没有设置cookie(android 4.1).但是,当在三星Galaxy ace,HTC Desire Z和Android模拟器上运行软件时,cookie被设置并读取完全正常.
工作时,webview按预期返回字符串,当不工作时,输出只是“null”; cookie没有值/没有设置.
我的具体情况也使用了滑动导航类,它是Actionbar Sherlock的扩展.
我真的很感激任何帮助,我几周来一直在努力解决这个问题.
谢谢.
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代码:
公共类MainActivity扩展SherlockActivity实现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(); }
解决方法
我经历了许多使用cookie存储的替代方案,包括使用HTML的本地存储.我被引导相信,这里的整个问题是安全问题.如果我要在localhost上创建cookie或localstorage,那么其他应用程序可以访问该存储,因此是一个主要的安全威胁.
我的最终问题是尝试通过与Java的双向通信来桥接webview,并且还有一个在此过程中存储数据的地方.我的解决方案是利用JavascriptInterface
这个想法如下:
>解析数据以在javascript中运行
> Javascript调用特殊的javascript函数,例如“setData(myDataname,myData)”
> Java有一个侦听它的函数,它将接受javscript设置的参数,并且还可以将值返回给javascript.
>将数据解析为Java后,java会将其存储在资产中的一系列文件中.
>当调用javascript函数“getData(myDataname)”时,Java会使用相同类型的方法返回数据.
我发现这非常有用:Android JavascriptInterface Documentation,Handling JavascriptInterface in Android 2.3
我发现的唯一主要“挂机”是Android 2.3中的fairly serious bug(固定在3.0),它有效地打破了JavascriptInterface.上面的第二个链接描述了我找到的最佳解决方法.
这是一个如何使双向通信工作的例子(它非常混乱,但它有效):
自定义Web接口类:
public class webViewInterface { //@JavascriptInterface //for SDK 12+ public String showToast(String myText) { Toast.makeText(context,myText,Toast.LENGTH_LONG).show(); return myText; } }
主要课程:
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>