SYMMETRIC Web開発ブログ
レスポンシブWebデザイン、CSSフレームワークなど、Webフロントエンド開発に関するBLOGです。
※SYMMETRIC公式BLOGと統合し、ブログ名称を変更しました

window.openerがiOS版Chromeで使えない問題に対処するには?

こんにちは!エンジニアの宇都宮です。

普段はジーンコードを利用したスマートフォンサイトの構築を担当しています。今回はiPhoneのGoogle Chrome(以下、iOS版Chrome)でポップアップウィンドウがあるサイトを変換する際のTipsをご紹介したいと思います!

「ポップアップの住所検索画面で入力した内容が、親画面に反映されない!iOSのChromeだけ!といった問題に遭遇したことはないでしょうか?

これは子ウィンドウで入力したデータをwindow.opener経由で親ウィンドウに渡しているjavacsript処理が正常に動作していないことが原因と考えられます。PCで確認した場合やAndroidでは動作するのに、iOS版Chromeでだけ動作しない場合はwindow.openerが原因の可能性が高いです。

iOS版Chromeではwindow.openの戻り値がnull!?

iOS版Chromeはウィンドウ関連のjavascriptAPIの挙動がPC版とは異なります。window.openの戻り値がwindowオブジェクトではなくnullになったり、ポップアップで表示したウィンドウでwindow.openerオブジェクトがnullになったりします。

実はこのバグはバージョン48のiOS版Chromeで修正されています。バージョン48からはレンダリングを担う機能が「UIWebView」から「WKWebView」に変更された際に、一緒に修正されたようです。ただし、古いバージョンのiOS版Chromeではwindow.openerはnullのままです。

以下のURLにアクセスすると、以下のキャプチャの様にどちらのWebViewを使用しているか確認できます。
https://jsfiddle.net/j4vkwjj2/1/

blog1

iOS版Chromeではwindow.openerの代わりにwindow.localStorageを使う!

window.openerで親子間のウィンドウでデータの受け渡しができない場合、代替手段としてwindow.localStorageが使えます。window.localStorageはブラウザにデータを保存する仕組みです。Javascriptでデータの保存、取得、削除が可能です。

実際にサンプルコードを見てみましょう。

親ウィンドウのソースコード

<!DOCTYPE html>
<html>
<head>
    <meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
    <a id="link" href="#">window.open!</a>
    <script>
    
        var link = document.getElementById('link');
        link.onclick = function() {
            var win = window.open('child2.html');
        }
    
        // 1秒毎にlocalStorageを監視するポーリングスクリプト
        var pollingStart = function() {
            // ポーリングスクリプトの初回起動時にlocalStorageのデータを削除します
            localStorage.removeItem('gcInfo')
            var checkStorage = function() {
                // localStorageにデータが存在する場合の処理
                if (localStorage.gcInfo) {
                    var gcInfo = JSON.parse(localStorage.gcInfo);
                    if (gcInfo.submit){
                        alert('ポップアップウィンドウでデータがセットされました');  
                        localStorage.removeItem('gcInfo')
                    }
                // localStorageにデータが存在しない場合の処理
                }else{
                    setTimeout(checkStorage, 1000);
                }
            }
            checkStorage();
        }
        pollingStart();
        
    </script>
</body>
</html>

親ウィンドウは1秒毎にlocalStorageに子ウィンドウが設定したデータが存在するか監視しています。子ウィンドウが設定したデータが存在する場合はアラートメッセージを表示しています。データが存在しない場合はsetTimeout関数で1秒後にまたlocalStorageを参照するようセットしています。

子ウィンドウのソースコード

<!DOCTYPE html>
<html>
<head>
    <meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
    <a id="link" href="#">localStorageにデータをセット!</a>
    <script>
    
        // localStorageにデータをセットしてウィンドウを閉じます
        var link = document.getElementById('link');
        link.onclick = function() {
            var obj = {};
            obj.submit = true;
            localStorage.gcInfo = JSON.stringify(obj);
            window.close();
        }
    
    </script>
</body>
</html>

子ウィンドウではリンクのonclickイベントでlocalStorageにデータをセットし、ウィンドウを閉じています。
localStorageのデータは、ブラウザを閉じた後も残り続けるため、画面初期表示時やデータを取り出した後に削除しています。

まとめ

localStorageを経由することで、window.openerが使えないブラウザでも親子間のウィンドウで連携する処理を書くことができました。ジーンコードでPCサイトを変換してスマートフォンサイトを構築する場合は、PCサイト側のwindow.openerを使用した処理を、localStorageを利用した処理に差し替えます。iOS版Chromeでポップアップウィンドウが正常に動かない場合は、localStorageを利用した方法を検討されてはいかがでしょうか。

シンメトリックでは、スマホサイトを制作するだけでマルチデバイス対応を実現する「スマホのサイト制作。PCは自動変換 | alter.js」を提供しています。
スマホ中心のサイト制作、リニューアルをお考えでしたら、ぜひ使ってみてください。

【参考情報】

Page Top