Masalah Cookie Tampilan Web Android

89

Saya memiliki server yang mengirim aplikasi android saya cookie sesi untuk digunakan untuk komunikasi yang diautentikasi. Saya mencoba memuat WebView dengan URL yang menunjuk ke server yang sama dan saya mencoba untuk meneruskan cookie sesi untuk otentikasi. Saya mengamati bahwa itu bekerja sesekali tetapi saya tidak tahu mengapa. Saya menggunakan cookie sesi yang sama untuk melakukan panggilan lain di server saya dan otentikasi ini tidak pernah gagal. Saya hanya mengamati masalah ini saat mencoba memuat URL di WebView, dan itu tidak terjadi setiap saat. Sangat membuat frustasi.

Di bawah ini adalah kode yang saya gunakan untuk melakukan ini. Bantuan apa pun akan sangat dihargai.

String myUrl = ""http://mydomain.com/"; 
CookieSyncManager.createInstance(this); 
CookieManager cookieManager = CookieManager.getInstance(); 
Cookie sessionCookie =  getCookie(); 
if(sessionCookie != null){ 
    String cookieString = sessionCookie.getName() +"="+sessionCookie.getValue()+"; domain="+sessionCookie.getDomain(); 
    cookieManager.setCookie(myUrl, cookieString); 
    CookieSyncManager.getInstance().sync(); 
} 

WebView webView = (WebView) findViewById(R.id.webview); 
webView.getSettings().setBuiltInZoomControls(true); 
webView.getSettings().setJavaScriptEnabled(true); 
webView.setWebViewClient(new MyWebViewClient()); 
webView.loadUrl(myUrl);
nannerpus.dll
sumber
lihat pertanyaan ini stackoverflow.com/questions/2566485/…
neeraj t

Jawaban:

55

Terima kasih justingrammens ! Itu berhasil untuk saya, saya berhasil membagikan cookie dalam permintaan DefaultHttpClient dan aktivitas WebView saya:

//------- Native request activity
private DefaultHttpClient httpClient;
public static Cookie cookie = null;

//After Login
List<Cookie> cookies = httpClient.getCookieStore().getCookies();
for (int i = 0; i < cookies.size(); i++) {
    cookie = cookies.get(i);
}

//------- Web Browser activity
Cookie sessionCookie = myapp.cookie;
CookieSyncManager.createInstance(this);
CookieManager cookieManager = CookieManager.getInstance();
if (sessionCookie != null) {
    cookieManager.removeSessionCookie();
    String cookieString = sessionCookie.getName() + "=" + sessionCookie.getValue() + "; domain=" + sessionCookie.getDomain();
    cookieManager.setCookie(myapp.domain, cookieString);
    CookieSyncManager.getInstance().sync();
}   
k7k0
sumber
Ini bekerja dengan baik untuk saya. Saya membuat url cookie saya sebagai berikut: String url = (cookie.isSecure ()? "Https": "http") + ": //" + cookie.getDomain () + cookie.getPath ();
Heath Borders
terima kasih untuk posnya ... itu membantu saya dalam menerapkan logout twitter untuk aplikasi saya ...;)
rahul
dapatkah kamu tahu apa yang harus ditulis di tempat myapp.cookie
suraj jain
kata kuncinya adalah: String cookieString = sessionCookie.getName () + "=" + sessionCookie.getValue () + "; domain =" + sessionCookie.getDomain (); cookieManager.setCookie (myapp.domain, cookieString);
Zennichimaro
1
CookieSyncManager tidak digunakan lagi sekarang :(
Misha Akopov
18

Terima kasih Android karena telah merusak hari Minggu saya. . . Inilah yang memperbaiki Aplikasi saya (setelah Anda masuk ke tampilan web Anda)

if ( Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP ) {

  CookieManager cookieManager = CookieManager.getInstance();

  cookieManager.setAcceptThirdPartyCookies( webView, true );

}

Saya harus mengatakan jawaban di atas mungkin akan berfungsi tetapi dalam situasi saya saat Android pergi v5 + 'apps' javascript webview android saya mati.

Jody Jacobus Geers
sumber
1
Oh! Anda baru saja menyelamatkan hari saya!
Le Minh
14

Solusi: Webview CookieSyncManager

CookieSyncManager cookieSyncManager = CookieSyncManager.createInstance(mWebView.getContext());
CookieManager cookieManager = CookieManager.getInstance();
cookieManager.setAcceptCookie(true);
cookieManager.removeSessionCookie();
cookieManager.setCookie("http://xx.example.com","mid="+MySession.GetSession().sessionId+" ; Domain=.example.com");
cookieSyncManager.sync();

String cookie = cookieManager.getCookie("http://xx.example.com");

Log.d(LOGTAG, "cookie ------>"+cookie);
mWebView.getSettings().setJavaScriptEnabled(true);
mWebView.setWebViewClient(new TuWebViewClient());
mWebView.loadUrl("http://xx.example.com");
Sanket
sumber
apa yang kamu dapat cookie?, saya hanya mendapatkan seperti: PHPSESSID=ljfakdjfklasdfaj!, apakah itu cukup?
Francisco Corrales Morales
6
Apa MySession di sini?
Pengguna3
3

Saya akan menyimpan cookie sesi itu sebagai preferensi dan secara paksa mengisi kembali pengelola cookie dengannya. Kedengarannya bahwa cookie sesi tidak bertahan dari Aktivitas restart

Bostone
sumber
Saya harus menambahkan bahwa aplikasi saya membuat banyak panggilan non-WebView lainnya di server saya yang tidak pernah gagal dalam otentikasi. Hanya ketika saya mencoba memuat URL di WebView, saya melihat masalah ini. "Cookie sessionCookie = getCookie ();" mengambil cookie sesi dari DB aplikasi yang saya gunakan untuk semua pesan dengan server saya.
nannerpus
Nah jika Anda menggunakan HttpClient untuk itu ia memiliki penyimpanan Cookie sendiri, jadi jika Anda memegang satu contoh klien, cookie Anda akan bertahan, tetapi mungkin tidak ada hubungannya dengan yang digunakan oleh tampilan web Anda
Bostone
Jika saya memahami Anda dengan benar, Anda mengatakan bahwa CookieManager dikembalikan oleh CookieManager.getInstance (); akan memengaruhi cookie yang digunakan oleh instance HttpClient, yang tidak digunakan WebView. Jika ini benar, apakah Anda tahu bagaimana saya bisa secara eksplisit mengirimkan cookie ke WebView? Selain itu, melihat dokumen CookieManager, mungkin tidak memanggil "cookieManager.setAcceptCookie (true)" menyebabkan saya bermasalah? Terima kasih atas bantuannya, sangat menghargainya.
nannerpus
3

Saya telah menghabiskan separuh lebih dari 3 jam mengerjakan masalah yang sangat mirip. Dalam kasus saya, saya memiliki sejumlah panggilan, yang saya lakukan ke layanan web menggunakan a DefaulHttpClientdan kemudian saya ingin mengatur sesi dan semua cookie terkait lainnya di saya WebView.

Saya tidak tahu apakah ini akan menyelesaikan masalah Anda, karena saya tidak tahu apa fungsi getCookie()metode Anda, tetapi dalam kasus saya, saya benar-benar harus menelepon.

cookieManager.removeSessionCookie();

Pertama, hapus cookie sesi, lalu tambahkan kembali. Saya menemukan bahwa ketika saya mencoba menyetel JSESSIONIDcookie tanpa menghapusnya terlebih dahulu, nilai yang ingin saya setel tidak disimpan. Tidak yakin apakah ini akan membantu Anda dalam masalah tertentu, tetapi saya pikir saya akan membagikan apa yang saya temukan.

Justin
sumber
mengapa tidak CookieManager.getInstance().removeAllCookie ();?
Francisco Corrales Morales
2

Setelah beberapa waktu meneliti, saya telah mengumpulkan beberapa bagian yang membuat saya mendapatkan solusi ini. Setelah CookieSyncManager tidak digunakan lagi, ini mungkin cara terbaik untuk menyetel cookie tertentu untuk tampilan web di Kotlin saat ini, Anda tidak memerlukan yang lain.

private fun setCookie(){
    val webView = WebView(this) // this = context
    val cookieManager = CookieManager.getInstance()
    cookieManager.acceptCookie()

    val domain = "https://www.yourdomain.com/"

    webView.webViewClient = WebViewClient()
    webView.settings.javaScriptEnabled = true

    cookieManager.setCookie(domain,"$cookieKey=$cookieValue")
    cookieManager.setAcceptThirdPartyCookies(webView, true)

    webView.loadUrl(domain)
}
Samuel Luís
sumber
1

Saya memiliki pendekatan yang berbeda dari orang lain di sini, dan ini merupakan pendekatan yang dijamin bekerja tanpa berurusan dengan CookieSyncManager (di mana Anda berada di bawah kekuasaan semantik seperti "Perhatikan bahwa bahkan sinkronisasi () terjadi secara tidak sinkron").

Pada dasarnya, kami menjelajah ke domain yang benar, lalu kami menjalankan javascript dari konteks halaman untuk menyetel cookie untuk domain itu (dengan cara yang sama seperti halaman itu sendiri). Dua kelemahan dari metode ini adalah yang mungkin memperkenalkan waktu perjalanan pulang pergi ekstra karena permintaan http tambahan yang harus Anda buat; dan jika situs Anda tidak memiliki padanan halaman kosong, itu mungkin flash URL apa pun yang Anda muat terlebih dahulu sebelum membawa Anda ke tempat yang tepat.

import org.apache.commons.lang.StringEscapeUtils;
import org.apache.http.cookie.Cookie;
import android.annotation.SuppressLint;
import android.webkit.CookieManager;
import android.webkit.CookieSyncManager;
import android.webkit.WebView;
import android.webkit.WebViewClient;

public class WebViewFragment {
    private static final String BLANK_PAGE = "/blank.html"

    private CookieSyncManager mSyncManager;
    private CookieManager mCookieManager;

    private String mTargetUrl;
    private boolean mInitializedCookies;
    private List<Cookie> mAllCookies;

    public WebViewFragment(Context ctx) {
        // We are still required to create an instance of Cookie/SyncManager.
        mSyncManager = CookieSyncManager.createInstance(ctx);
        mCookieManager = CookieManager.getInstance();
    }

    @SuppressLint("SetJavaScriptEnabled") public void loadWebView(
                String url, List<Cookie> cookies, String domain) {
        final WebView webView = ...

        webView.setWebViewClient(new CookeWebViewClient());
        webView.getSettings().setJavaScriptEnabled(true);

        mInitializedCookies = false;
        mTargetUrl = url;
        mAllCookies = cookies;
        // This is where the hack starts.
        // Instead of loading the url, we load a blank page.
        webView.loadUrl("http://" + domain + BLANK_PAGE);
    }

    public static String buildCookieString(final Cookie cookie) {
        // You may want to add the secure flag for https:
        // + "; secure"
        // In case you wish to convert session cookies to have an expiration:
        // + "; expires=Thu, 01-Jan-2037 00:00:10 GMT"
        // Note that you cannot set the HttpOnly flag as we are using
        // javascript to set the cookies.
        return cookie.getName() + "=" + cookie.getValue()
                    + "; path=" + cookie.getPath()
                    + "; domain=" + cookie.getDomain()
    };

    public synchronized String generateCookieJavascript() {
        StringBuilder javascriptCode = new StringBuilder();
        javascriptCode.append("javascript:(function(){");
        for (final Cookie cookie : mAllCookies) {
            String cookieString = buildCookieString(cookie);
            javascriptCode.append("document.cookie=\"");
            javascriptCode.append(
                     StringEscapeUtils.escapeJavascriptString(cookieString));
            javascriptCode.append("\";");
        }
        // We use javascript to load the next url because we do not
        // receive an onPageFinished event when this code finishes.
        javascriptCode.append("document.location=\"");
        javascriptCode.append(
                StringEscapeUtils.escapeJavascriptString(mTargetUrl));
        javascriptCode.append("\";})();");
        return javascriptCode.toString();
    }

    private class CookieWebViewClient extends WebViewClient {
        @Override public void onPageFinished(WebView view, String url) {
            super.onPageFinished(view, url);
            if (!mInitializedCookies) {
                mInitializedCookies = true;
                // Run our javascript code now that the temp page is loaded.
                view.loadUrl(generateCookieJavascript());
                return;
            }
        }
    }
}

Jika Anda mempercayai domain asal cookie, Anda mungkin dapat keluar tanpa apache commons, tetapi Anda harus memahami bahwa ini dapat menimbulkan risiko XSS jika Anda tidak berhati-hati.

Patrick Horn
sumber
1

Ini adalah sedikit kode yang berfungsi.

    private void setCookie(DefaultHttpClient httpClient, String url) {
    List<Cookie> cookies = httpClient.getCookieStore().getCookies();
    if (cookies != null) {
        CookieSyncManager.createInstance(context);
        CookieManager cookieManager = CookieManager.getInstance();
        cookieManager.setAcceptCookie(true);

        for (int i = 0; i < cookies.size(); i++) {
            Cookie cookie = cookies.get(i);
            String cookieString = cookie.getName() + "=" + cookie.getValue();
            cookieManager.setCookie(url, cookieString);
        }
        CookieSyncManager.getInstance().sync();
    }
}

Di sini httpclient adalah objek DefaultHttpClient yang Anda gunakan dalam permintaan HttpGet / HttpPost. Juga satu hal untuk memastikan adalah nama dan nilai cookie, itu harus diberikan

String cookieString = cookie.getName() + "=" + cookie.getValue();

setCookie akan mengatur cookie untuk URL yang diberikan.

anak droid
sumber
Sekadar catatan: Anda tidak dapat menyimpan cookie sesi menggunakan CookieManager.setCookie
John Doe
saya tidak mengerti ... bisakah kamu menjelaskan?
anak droid
1

Saya secara ajaib menyelesaikan semua masalah cookie saya dengan satu baris ini di onCreate:

CookieHandler.setDefault(new CookieManager());

edit: berhenti bekerja hari ini. :( apa-apaan ini, android.

Chani
sumber
jadi, ada pembaruan? mengapa itu berhenti bekerja?, apakah kamu menyelesaikannya?
Francisco Corrales Morales
1

Menemukan ini juga. Inilah yang saya lakukan.

Di LoginActivity saya, di dalam AsyncTask, saya memiliki yang berikut:

CookieStoreHelper.cookieStore = new BasicCookieStore();
BasicHttpContext localContext = new BasicHttpContext();
localContext.setAttribute(ClientContext.COOKIE_STORE, CookieStoreHelper.cookieStore);

HttpResponse postResponse = client.execute(httpPost,localContext);
CookieStoreHelper.sessionCookie = CookieStoreHelper.cookieStore.getCookies();

// DI MANA CookieStoreHelper.sessionCookie adalah kelas lain yang berisi variabel sessionCookie yang didefinisikan sebagai cookie Daftar; dan cookieStore didefinisikan sebagai BasicCookieStore cookieStore;

Kemudian di Fragmen saya, di mana WebView saya berada, saya memiliki yang berikut:

//DECLARE LIST OF COOKIE
List<Cookie> sessionCookie;

di dalam metode saya atau tepat sebelum Anda menyetel WebViewClient ()

WebSettings settings = webView.getSettings();
settings.setJavaScriptEnabled(true);
webView.setScrollBarStyle(WebView.SCROLLBARS_OUTSIDE_OVERLAY);

sessionCookie = CookieStoreHelper.cookieStore.getCookies();
CookieSyncManager.createInstance(webView.getContext());
CookieSyncManager.getInstance().startSync();
CookieManager cookieManager = CookieManager.getInstance();
CookieManager.getInstance().setAcceptCookie(true);
if (sessionCookie != null) {
   for(Cookie c:  sessionCookie){
      cookieManager.setCookie(CookieStoreHelper.DOMAIN, c.getName() + "=" + c.getValue());
   }
   CookieSyncManager.getInstance().sync();

 }

 webView.setWebViewClient(new WebViewClient() {
    //AND SO ON, YOUR CODE
 }

Tip Cepat: Instal firebug di firefox atau gunakan konsol pengembang di chrome dan uji halaman web Anda terlebih dahulu, tangkap Cookie dan periksa domainnya sehingga Anda dapat menyimpannya di suatu tempat dan pastikan Anda menyetel domain yang benar dengan benar.

Edit: CookieStoreHelper.cookies telah diedit menjadi CookieStoreHelper.sessionCookie

Burnok
sumber
1

Kode kerja saya

public View onCreateView(...){
    mWebView = (WebView) view.findViewById(R.id.webview);

    WebSettings webSettings = mWebView.getSettings();
    webSettings.setJavaScriptEnabled(true);

        ...
        ...
        ...

    CookieSyncManager.createInstance(mWebView.getContext());
    CookieManager cookieManager = CookieManager.getInstance();
    cookieManager.setAcceptCookie(true);
    //cookieManager.removeSessionCookie(); // remove
    cookieManager.removeAllCookie(); //remove
    // Recommended "hack" with a delay between the removal and the installation of "Cookies"
    SystemClock.sleep(1000);

    cookieManager.setCookie("https://my.app.site.com/", "cookiename=" + value + "; path=/registration" + "; secure"); // ;
    CookieSyncManager.getInstance().sync();

    mWebView.loadUrl(sp.getString("url", "") + end_url);

    return view;
}

Untuk men-debug kueri, "cookieManager.setCookie (....);" Saya sarankan Anda untuk melihat-lihat isi database webviewCookiesChromium.db (disimpan di "/data/data/my.app.webview/database") Di sana Anda dapat melihat pengaturan yang benar.

Menonaktifkan "cookieManager.removeSessionCookie ();" dan / atau "cookieManager.removeAllCookie ();"

//cookieManager.removeSessionCookie();
// and/or
//cookieManager.removeAllCookie();"

Bandingkan nilai yang ditetapkan dengan yang ditetapkan oleh browser. Sesuaikan permintaan untuk instalasi cookie sebelumnya sampai browser "flags" tidak diinstal akan sesuai dengan apa yang Anda putuskan. Saya menemukan bahwa kueri dapat berupa "flags":

// You may want to add the secure flag for https:
+ "; secure"
// In case you wish to convert session cookies to have an expiration:
+ "; expires=Thu, 01-Jan-2037 00:00:10 GMT"
// These flags I found in the database:
+ "; path=/registration"
+ "; domain=my.app.site.com"
Vadim.Ivanov
sumber
Saya telah menggunakan kode di atas untuk menyimpan cookie di tampilan web tetapi tolong beri tahu saya tentang jalur. apa jalan disini?
Mehul Tank
@MehulTank Parameter jalur menentukan lokasi dokumen. Cookie hanya dikirim ke server jika jalur cocok dengan lokasi dokumen induk atau saat ini.
Roland van der Linden
1

Beberapa komentar (setidaknya untuk API> = 21) yang saya temukan dari pengalaman saya dan membuat saya pusing:

  1. httpdan httpsurl berbeda. Menyetel cookie http://www.example.comberbeda dengan menyetel cookiehttps://www.example.com
  2. Garis miring di akhir url juga dapat membuat perbedaan. Dalam kasus saya https://www.example.com/berhasil tetapi https://www.example.comtidak berhasil.
  3. CookieManager.getInstance().setCookiesedang melakukan operasi asinkron. Jadi, jika Anda memuat url segera setelah Anda menyetelnya, tidak ada jaminan bahwa cookie sudah ditulis. Untuk mencegah perilaku tak terduga dan tidak stabil, gunakan CookieManager # setCookie (String url, String value, ValueCallback callback) ( link ) dan mulai muat url setelah callback dipanggil.

Saya berharap dua sen saya menghemat waktu beberapa orang sehingga Anda tidak harus menghadapi masalah yang sama seperti yang saya alami.

giorgos.nl
sumber
Seberapa berbeda Menetapkan cookie untuk example.com berbeda dengan menyetel cookie untuk example.com ?
softmarshmallow
0

Saya menghadapi masalah yang sama dan Ini akan menyelesaikan masalah ini di semua versi android

private void setCookie() {
    try {
        CookieSyncManager.createInstance(context);
        CookieManager cookieManager = CookieManager.getInstance();
        cookieManager.setAcceptCookie(true);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            cookieManager.setCookie(Constant.BASE_URL, getCookie(), value -> {
                String cookie = cookieManager.getCookie(Constant.BASE_URL);
                CookieManager.getInstance().flush();
                CustomLog.d("cookie", "cookie ------>" + cookie);
                setupWebView();
            });
        } else {
            cookieManager.setCookie(webUrl, getCookie());
            new Handler().postDelayed(this::setupWebView, 700);
            CookieSyncManager.getInstance().sync();
        }

    } catch (Exception e) {
        CustomLog.e(e);
    }
}
Prinkal Kumar
sumber
0

Perhatikan bahwa mungkin lebih baik menggunakan subdomain daripada URL biasa. Jadi, atur .example.comsaja https://example.com/.

Terima kasih kepada Jody Jacobus Geers dan lainnya, saya menulis demikian:

if (savedInstanceState == null) {
    val cookieManager = CookieManager.getInstance()
    cookieManager.acceptCookie()
    val domain = ".example.com"
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        cookieManager.setCookie(domain, "token=$token") {
            view.webView.loadUrl(url)
        }
        cookieManager.setAcceptThirdPartyCookies(view.webView, true)
    } else {
        cookieManager.setCookie(domain, "token=$token")
        view.webView.loadUrl(url)
    }
} else {
    // Check whether we're recreating a previously destroyed instance.
    view.webView.restoreState(savedInstanceState)
}
CoolMind
sumber
-4

Jangan gunakan url mentah Anda

Dari pada:

cookieManager.setCookie(myUrl, cookieString); 

gunakan seperti ini:

cookieManager.setCookie("your url host", cookieString); 
Jason
sumber