6

AndroidのWebビュー内でCookieを設定して取得しようとしています。これを機能させるために、多数のCookieマネージャースクリプトを試しました。JavaScript を有効にしました。

アプリケーションを Samsung S3 および Samsung Galaxy Tab 10.1 で実行すると、Cookie がまったく設定されていないように見えます (android 4.1)。ただし、Samsung 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 コード:

public class MainActivity extends SherlockActivity implement 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();
}
4

4 に答える 4

4

1 か月以上の調査の結果、ファイルがローカルホスト上にある (assets フォルダーから直接読み取る) Web ビューでは、Android バージョン 2.3 以降で Cookie を設定することはできないと結論付けました。

HTML の localstorage を使用するなど、Cookie ストレージの使用に代わる多くの方法を試しました。ここでの全体的な問題は、私が信じているように、セキュリティです。localhost で Cookie または localstorage を作成すると、他のアプリがそのストレージにアクセスできるため、重大なセキュリティ上の脅威になります。

私の最終的な問題は、Java との双方向通信で webview を橋渡ししようとすることと、プロセス中にデータを保存する場所を確保することでした。私の解決策は、JavascriptInterfaceを利用することでした

考え方は次のとおりです。

  • データを解析して JavaScript で機能させる
  • Javascript は、「setData(myDataName, myData)」などの特別な JavaScript 関数を呼び出します。
  • Java には、これをリッスンする関数があり、javascript によって設定された引数を取り、javascript に値を返すこともできます。
  • データが Java に解析されると、Java はこれをアセット内の一連のファイルに格納します。
  • JavaScript関数「getData(myDataName)」を呼び出すと、Javaでも同様のメソッドでデータが返されます。

これは非常に便利だと思いました: Android JavascriptInterface DocumentationAndroid 2.3 での JavascriptInterface の処理

唯一の主要な「ハングアップ」は、Android 2.3 のかなり深刻なバグ(3.0 で修正済み) であり、JavascriptInterface を効果的に壊していました。上記の 2 番目のリンクは、私が見つけた最善の回避策を説明しています。

双方向通信を機能させる方法の例を次に示します (非常に面倒ですが、機能します)。

カスタム 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>
于 2013-10-19T22:29:12.483 に答える
3

私は同じ制限に遭遇しました。アセット フォドラーからローカルの html ファイルを読み込んでいます。2.2 エミュレーターでは、Cookie が保存され、JavaScript を介して取得できます。ただし、私の 4.1 デバイスでテストしたところ、ローカル ページによって設定された Cookie は保持されません。

@kirgy と @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 の完全な機能 (有効期限、パス) を提供するものではありません。良い出発点のアイデアとしてこれを投稿しています。

于 2014-07-22T20:59:11.643 に答える
1

kirgy と同じ問題が発生しました。ローカル コンテンツを表示する Droid Webview で (JavaScript を使用して) Cookie を使用しようとしていました。データは保存されません。ただし、同じ Web ビューでリモート URL から実行すると、同じコードが完全に機能しました。(Android CookieMangerを使用して)JavaでCookieを有効にしても効果はありませんでした。

幸いなことに、カスタム JavaScript 関数を使用して、ローカル Web アプリで必要なすべての Cookie をカプセル化しました。ドロイド上で実行しているときに、webview javascript インターフェイスを使用して、Java で処理することにより、Cookie を仮想的に管理しました。

私のニーズでは、セッション ストレージのみが必要だったので、Cookie データを Java HashMap に入れるだけです。賞味期限や長期保存の心配もありませんでした。これらの詳細を実装するために「仮想 Cookie」が必要な場合、データが js インターフェースを介して Java との間でやり取りされると、それを理解するのは難しくありません。

于 2014-07-01T17:49:11.720 に答える
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;
}

うまくいきますように!

于 2013-10-17T12:02:55.603 に答える