2014年6月18日 星期三

如何取得 WebView 內 Javascript function 的 return 值

最近公司的案子有一個需求,某些由編輯撰寫的文章要在 App 內以 WebView 的方式呈現,而分享文章使用 App 內的 Native Button 來操作,因為分享的連結和 App 內 WebView 中顯示的不一定相同,所以不能直接拿文章的 URL 來做分享,相關情境和撰寫 Web 的部門開過會後,決定在 Web 內加一個 Javascript 的 function 回傳文章的分享連結。

之前就知道在 Windows Phone 中的 WebView 可以使用 WebBrowser.InvokeScript 這個 Method 呼叫網頁中的 Javascript function 取得回傳值,所以當下直接和處理 Web 端的同事說 Android 也可以比照辦理,實際在開發時才發現事情並沒有想像中的順利,Android 的 WebView 並沒有提供類似的 Method,只能透過 External Object 的方式來間接達到效果。

假設我的網頁內容長這樣,裡面有個叫作 getFacebookShareURL 的 Javascript function 供 Client 查詢分享連結

<html>
    <head>
        <script type="text/javascript">
         function getFacebookShareURL()
         {
          return "http://www.facebook.com/xxx/yyy/zzz";
         }
        </script>
    </head>
    <body>
        <font size="5">Hello</font>
    </body>
</html>

在 Windows 上直接很方便的使用 WebBrowser.InvokeScript("getFacebookShareURL") 就可以拿到 return 的值,看過同事 iOS 專案的程式碼,也是類似的 Method 一行搞定,但在 Android 上 call 網頁上的 Javascript function 的方式是使用 WebView.loadUrl("Javascript:function()") 這樣的方式,這個 Method 並沒有回傳值,所以我們拿不到這個 function 的 return 值,因為這個原因,我們必須製作一個 External Object 讓網頁執行將資料送給 Client 的動作,而這個 External Object 所要回傳的值,我們利用參數的方式帶進去,也就是 gerFacebookShareURL 這個 function 的 return 值,如此我們還是可以使用同樣的網頁來取得 Javascript function 想告訴 App 的資訊,同樣以 getFacebookShareURL 為範例,我在網頁載入完成的事件加入如下指令

public class MyActivity extends Activity {

    private String shareURL;
    private WebView webView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_my);

        webView = (WebView) findViewById(R.id.webview);
        WebSettings webSettings = webView.getSettings();
        webSettings.setSupportZoom(true);
        webSettings.setBuiltInZoomControls(true);
        webSettings.setJavaScriptEnabled(true);

        webView.addJavascriptInterface(new JsCallBack(), "ExtObj");
        webView.setWebViewClient(new WebViewClientImpl());

        webView.loadUrl("http://192.168.10.183/~ascii/news.html");
    }

    private final class WebViewClientImpl extends WebViewClient
    {
        @Override
        public void onPageFinished(WebView view, String url)
        {
            view.loadUrl("javascript:window.ExtObj.responseResult(getFacebookShareURL())");
        }
    }

    private class JsCallBack
    {
        @JavascriptInterface
        public void responseResult(final String result)
        {
            shareURL = result;
        }
    }
}

如果撰寫 External Object 時,在網頁上直接顯示找不到 responseResult 的錯誤訊息,特別注意一下是不是忘了在 Method 加上 @JavascriptInterface 這個 annotation,這在 Android Level 17 以上是必須的。



沒有留言:

張貼留言