2013-10-07 123 views
6

我想簡單地設置和檢索android中的webview內的cookie。我已經嘗試了許多Cookie管理器腳本來嘗試使這個工作。我啓用了JavaScript。Android的webview cookie返回null

在三星S3和三星Galaxy Tab 10.1上運行應用程序時,根本沒有設置cookie(android 4.1)。但是,在三星Galaxy ace,HTC Desire Z以及android模擬器上運行軟件時,cookies會被設置並讀取得非常好。

工作時,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(); 
} 
+0

您是否在運行過程中獲得了logcat中的相關錯誤/警告?你沒有在JS中指定域名,所以它會被解析成當前的主機,它可能是'localhost',或者一個特定的IP地址,我不確定它總是被安全處理(相同的原點)。另外我不明白你在Java中使用cookie的操作 - 它們是否應該對JavaScript部分有一些影響? – Stan

+0

我假設你已經檢查了這篇文章:http://blog.winfieldpeterson.com/2013/01/17/cookies-in-hybrid-android-apps/和這個問題:http://stackoverflow.com/問題/ 1652850/android-webview-cookie-problem。你是否試圖解決它?結果是什麼? –

+0

最近的Android版本需要cookie值中設置的過期日期!否則它不會被CookieManager接受。 – sk2212

回答

3

超過一個月的研究後,我已經得出結論,在設定的Android版本大於2.3的一個cookie無法在網頁視圖文件所在的本地主機(從資產文件夾中直接讀取)。

我經歷了許多替代使用cookie存儲,包括使用HTML的本地存儲。我認爲,這裏的所有問題都是安全問題。如果我要在本地主機上創建cookie或本地存儲,則其他應用程序可以訪問該存儲,這是一個主要的安全威脅。

我最終的問題是試圖彌合與Java的雙向通信的網頁流量,並且還具有過程中存儲數據的地方。我的解決辦法就是把JavascriptInterface的優勢

的想法如下:

  • 解析數據的功能在javascript
  • 的Javascript例如調用一個特殊的JavaScript函數「使用setData(myDataName,MYDATA的)」
  • Java有監聽到這一點,並會採取通過javscript設置參數,也可以返回值的JavaScript函數。
  • 將數據解析爲Java後,java將其存儲在資產中的一系列文件中。
  • 當javascript函數「的getData(myDataName)」之稱,該數據是由Java中的同一種方法的返回。

我發現這非常有用:Android JavascriptInterface DocumentationHandling JavascriptInterface in Android 2.3

唯一的主要「掛起等」都配備了什麼,我發現在的Android 2.3(固定在3.0),從而有效地打破了JavascriptInterface一個fairly serious bug。上面的第二個鏈接描述了我找到的最佳解決方法。

下面是如何獲得雙向通信工作的例子(這是非常混亂的,但它的工作原理):

定製webinterface類:

public class webViewInterface { 
    //@JavascriptInterface //for SDK 12+ 
    public String showToast(String myText) { 
     Toast.makeText(context, myText, Toast.LENGTH_LONG).show(); 
     return myText; 
    } 
    } 

主要類: 保護無效的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> 
1

您需要設置cookie的有效期,否則該cookie不會被接受。

事情是這樣的:

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; 
} 

祝你好運,希望工程!

+0

嗨,我真的很感謝你的意見。我試圖實現,並沒有爲我工作。但在我發佈這篇文章後的調查中,我發現問題是我無法在從/ assets目錄加載HTML文件時設置cookie - 當從Web上加載相同的文件時,Cookie設置正常。你知道這是爲什麼嗎?我真的很感謝你的幫助! – kirgy

+0

我不知道這是爲什麼,也許嘗試重新加載,看看是否可行。 – 2013-10-18 01:57:56

+1

我認爲這是因爲webview中的安全原因,cookie設置爲針對本地主機。解決方法是將cookie設置爲遠程主機,從而丟失本地託管文件,或將cookie全部取消。我做了以後,並使用JavaScript接口來解決存儲數據的問題。 – kirgy

1

我遇到了同樣的問題,因爲kirgy。我試圖在顯示本地內容的Droid webview中使用cookie(使用JavaScript)。它不會存儲數據。儘管如果從同一webview中的遠程URL運行相同的代碼工作完美。在Java中啓用cookie(使用Android CookieManger)不起作用。

幸運的是,我使用自定義JavaScript函數來封裝我所有的cookie需求在本地web應用程序中。使用webview JavaScript界面​​,在Droid上運行時,我只是通過在Java中處理它來以虛擬方式管理我的Cookie。

爲了我的需要,我只需要會話存儲,因此只需將cookie數據放入java HashMap。我不擔心到期日期或長期存儲。如果你需要你的「虛擬餅乾」來實現這些細節,一旦數據通過js接口進入和從java進入並不難。

+0

我以前是「user3220983」 – BuvinJ

3

我遇到了同樣的限制。我從資產fodler加載本地html文件。在2.2模擬器上,Cookie被存儲並可以通過JavaScript獲取。但是,在我的4.1設備上測試時,本地頁面設置的Cookie不會持續。

根據@ kirgy's和@ user3220983的建議,我使用了Javascript界面​​。

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(); 
    } 

注:這些功能不提供完整的cookie功能(過期,路徑),我張貼這是一個很好的起點的想法。