[Android] WebView內的本地網頁,使用XMLHttpRequest讀取本地檔案

摘要:[Android] WebView內的本地網頁,使用XMLHttpRequest讀取本地檔案

[Android] WebView內的本地網頁,使用XMLHttpRequest讀取本地檔案

問題情景

在Android裡,可以使用WebView來呈現本地或是遠端的網頁內容。但是在顯示本地網頁時,如果開發人員在網頁裡使用了XMLHttpRequest來額外載入本地檔案(ex:AngularJS裡Route功能的TemplateURL),在部分手機上會呈現下列的錯誤訊息:

Failed to execute 'send' on 'XMLHttpRequest': Failed to load 'file:///android_asset/content.txt'.

發生這個錯誤的原因,是因為Android基於安全性的考量,從Android 4.1版開始禁止了WebView內的本地網頁使用XMLHttpRequest來讀取本地檔案(4.1版之前無限制)。這也就造成了「Android 4.1之前的手機」可以正常使用XMLHttpRequest,而「Android 4.1之後的手機」無法正常使用XMLHttpRequest。

解決方案

為了讓Android 4.1之後的本地網頁,也能正常使用XMLHttpRequest來讀取本地檔案內容。開發人員可以依照下列程式碼的方式,使用WebView原生提供的「AllowFileAccessFromFileURLs」函式,來重新開啟XMLHttpRequest讀取檔案功能,後續在WebView中執行的本地網頁就可以正常使用XMLHttpRequest來讀取本地檔案內容。

  • MainActivity.java

    public class MainActivity extends Activity {
    
        @SuppressLint({ "SetJavaScriptEnabled", "NewApi" }) 
        @Override
        protected void onCreate(Bundle savedInstanceState) {
    
            // base
            super.onCreate(savedInstanceState);
    
            // content
            setContentView(R.layout.activity_main);
    
            // Browser
            android.webkit.WebView webView = (WebView)this.findViewById(R.id.webView1);   
    
            // WebSettings
            WebSettings settings = webView.getSettings();
            settings.setJavaScriptEnabled(true);
            if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN) {
                settings.setAllowFileAccessFromFileURLs(true);
            }
    
            // LoadUrl
            webView.loadUrl("file:///android_asset/index.html");      
        }
    }
    
  • index.html

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8" />
        <title></title>
    </head>
    <body>
    
        <h1 id="contentBox"></h1>
    
        <script>
    
            // ContentBox
            function display(message) {
                var contentBox = document.getElementById("contentBox");
                contentBox.innerHTML = message;
            }        
    
            // XMLHttpRequest
            var xhr = new XMLHttpRequest();
    
            xhr.onload = function () {            
                display(xhr.responseText);
            };
    
            try {
                xhr.open("get", "content.txt", true);
                xhr.send();
            }
            catch (ex) {
                display(ex.message);
            }        
    
        </script>
    </body>
    </html>
    

範例下載

範例下載:點此下載

參考資料

期許自己
能以更簡潔的文字與程式碼,傳達出程式設計背後的精神。
真正做到「以形寫神」的境界。