2013-10-07 18 views
6

Sto cercando di impostare e recuperare semplicemente un cookie all'interno di una visualizzazione Web in Android. Ho provato numerosi script di cookie manager per cercare di farlo funzionare. Ho abilitato JavaScript.Il cookie di webview Android restituisce null

Quando si esegue l'applicazione su un Samsung S3 e un Samsung Galaxy Tab 10.1, i cookie non sembrano impostati (Android 4.1). Tuttavia, quando si esegue il software su un Samsung Galaxy asso, HTC Desire Z e sugli emulatori Android, i cookie vengono impostati e letti perfettamente.

Quando funziona, la vista Web restituisce la stringa come previsto, quando non funziona, l'output è semplicemente "null"; il cookie non ha valore/non è impostato.

Il mio caso specifico utilizza anche la classe di navigazione scorrevole, che è un'estensione di Actionbar Sherlock.

Apprezzerei davvero qualsiasi aiuto, ho lottato con questo per diverse settimane. Grazie.

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> 

del codice Java:

public class MainActivity estende SherlockActivity implementa 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

Sono stati rilevati errori/avvisi correlati in logcat per il processo in esecuzione? Non hai specificato il dominio in JS, quindi verrà risolto nell'host corrente che potrebbe essere 'localhost', o un indirizzo IP specifico, e non sono sicuro che sia sempre trattato in modo sicuro (stessa origine). Inoltre non ho capito le tue manipolazioni con i cookie in Java - dovrebbero avere qualche effetto sulla parte JavaScript? – Stan

+0

Suppongo che abbiate già controllato questo articolo: http://blog.winfieldpeterson.com/2013/01/17/cookies-in-hybrid-android-apps/ e questa domanda: http://stackoverflow.com/ domande/1652850/android-webview-cookie-problem. Hai provato a risolverli? quali sono i risultati? –

+0

Le versioni Android recenti richiedono la data di scadenza impostata nel valore del cookie! Altrimenti non sarà accettato da CookieManager. – sk2212

risposta

3

Dopo oltre un mese di ricerche, ho concluso che l'impostazione di un cookie nelle versioni Android superiori a 2,3 non è possibile in una visualizzazione Web in cui il file si trova sull'host locale (letto direttamente dalla cartella delle risorse).

Sono passato attraverso molte alternative a utilizzare la memorizzazione dei cookie, compreso l'utilizzo di localstorage di HTML. L'intera questione qui, sono portato a credere, è la sicurezza. Se dovessi creare un cookie o una localstorage sull'host locale, allora altre app potrebbero accedere a quella memoria, quindi è una delle principali minacce alla sicurezza.

Il mio ultimo problema è stato il tentativo di collegare la webview con la comunicazione bidirezionale con java e avere anche un posto dove archiviare i dati durante il processo. La mia soluzione era quella di sfruttare la JavascriptInterface

L'idea è la seguente:

  • dati Analizza per funzionare in javascript
  • JavaScript chiama una speciale funzione javascript per esempio "setData (myDataName, myData)"
  • Java ha una funzione che lo ascolta e accetta gli argomenti impostati da javscript e può anche restituire valori a javascript.
  • Una volta analizzati i dati su Java, java lo memorizza in una serie di file nelle risorse.
  • Quando viene chiamata la funzione javascript "getData (myDataName)", i dati vengono restituiti dallo stesso tipo di metodo di Java.

Ho trovato questo molto utile: Android JavascriptInterface Documentation, Handling JavascriptInterface in Android 2.3

l'unico grande 'hang-up' sono dotati di un quello che ho trovato è stato un fairly serious bug in Android 2.3 (fissato in 3.0) che di fatto ha rotto il JavascriptInterface. Il secondo link sopra descrive la soluzione migliore che ho trovato.

Ecco un esempio di come ottenere la comunicazione bidirezionale di lavoro (è molto disordinato, ma funziona):

classe interfaccia web personalizzata:

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

Classe principale: 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> 
1

È necessario impostare la data di scadenza del cookie, altrimenti il ​​cookie non sarà essere accettato

Qualcosa di simile a questo:

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

Buona fortuna, spero che funziona!

+0

Ciao, apprezzo molto i tuoi commenti. Ho provato a implementarlo e non ha funzionato per me.Ma durante le mie ricerche da quando ho postato questo ho scoperto che il problema è che non posso impostare il cookie quando carico il file HTML dalla directory/assets - quando carico lo stesso file dal web, il cookie imposta bene. Sai perché è questo? Apprezzerei molto il tuo aiuto! – kirgy

+0

Non sono sicuro del perché, magari provare a ricaricare e vedere se funziona. –

+1

La ragione per cui credo sia dovuta ai motivi di sicurezza nella webview che il cookie sia impostato rispetto a localhost. La soluzione consiste nell'impostare il cookie su un host remoto, perdendo così i file ospitati localmente o scartando tutti i cookie. L'ho fatto più tardi e ho usato un'interfaccia javascript per risolvere il problema della memorizzazione dei dati. – kirgy

1

ho incontrato lo stesso problema come kirgy. Stavo cercando di utilizzare i cookie (con javascript) in una web view di Droid che mostrava contenuti locali. Non memorizzerebbe i dati. Lo stesso codice funzionava perfettamente se eseguito da un URL remoto nella stessa webview. L'abilitazione dei cookie in java (con Android CookieManger) non ha avuto alcun effetto.

Fortunatamente, ho usato funzioni javascript personalizzate per incapsulare tutte le mie esigenze di cookie nell'app Web locale. Usando l'interfaccia javascript webview, quando si esegue sul droide ho appena gestito i miei cookie in modo virtuale gestendolo in java.

Per le mie esigenze, ho solo richiesto la memorizzazione della sessione, quindi basta inserire i dati dei cookie in una HashMap java. Non mi sono preoccupato delle date di scadenza o dell'archiviazione a lungo termine. Se hai bisogno dei tuoi "cookie virtuali" per implementare quei dettagli, non dovrebbe essere troppo difficile capire una volta che i dati andranno ae da java tramite l'interfaccia js.

+0

Sono precedentemente "user3220983" – BuvinJ

3

Ho riscontrato le stesse limitazioni. Sto caricando i file html locali dal fodler delle risorse. Su un emulatore 2.2, i cookie sono memorizzati e possono essere recuperati tramite JavaScript. Tuttavia, test sul mio dispositivo 4.1, i cookie impostati da una pagina locale non persistono.

Sulla base dei suggerimenti di @ kirgy's e @ user3220983, l'ho realizzato utilizzando l'interfaccia 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(); 
    } 

Nota: queste funzioni non fornisce funzionalità cookie completo (scadenza, percorso), sto postando questo come idea di un buon punto di partenza.

Problemi correlati