2011年7月16日 星期六

startActivityForResult and callback in WebView

想半天標題不知道怎下, 有點不是很貼切, 內容也寫的有點懶 :P 有可能會看不懂吧

最近開始想要一個禮拜想一個東西來實踐一下(不知道可以持續多久:P), 這禮拜想到的是這個: 從WebView內的javascript去叫起一個Activity, 然後把這Activity回傳的結果回傳給WebView內的javascript

具體的假想應用範例: import contact information, 從Javascript內叫contact picker, 並把所選的contact資訊匯入WebView內的form中

首先, 呼叫contact picker的範例如下:

public void launch()

{
    Intent intent = new Intent(Intent.ACTION_PICK);
    intent.setType(ContactsContract.Contacts.CONTENT_TYPE);
    startActivityForResult(intent, PICK_CONTACT);
}

基本上, 是要使用startActivityForResult, 這樣才能把所選定的contact給回傳給我們的Activity

但如何讓這lauch被javascript call到呢? 我們必須把這個method封裝到一個class內, 我用一個名叫ContactLauncher的class來做封裝, 並且將這個interface指定給WebView:

webView.addJavascriptInterface(new ContactLauncher(), "contactPicker");

這樣一來, 我們在javascript內就有一個contactPicker可以供呼叫了, javascript的範例如下:

function launchPicker()
{
    if(contactPicker) {
         //register callback
          window.activitycallback = function(response) {
                  $('#name').val(response.name);
          };

          //call picker
         contactPicker.launch();
    } else { //no picker }
}

我們可以在javascript內透過"contactPicker.launch()"來叫起Contact picker, 這個就會直接呼叫ContactLauncher裡的lauch()

那在這之前的程式碼是幹啥用的呢? 由於launch()並不是一個blocking call, 並不會等到結果回傳後才結束, 而我們又要startActivityForResult回傳回來的資料, 因此我們需要一個callback來接收回傳的資料

那怎讓javascript可以接收回傳回來後的資料呢, 這邊我利用一個類似javascript injection的方式來做(原理是利用WebView可以接收"javascript:"這種形態的url)

以下是onActivityResult的實作 (這邊偷懶只取一個Display name):

 

protected void onActivityResult(int requestCode, int resultCode, Intent data) { if(requestCode == PICK_CONTACT) { Cursor c = managedQuery(data.getData(), null, null, null, null); c.moveToNext(); String name = c.getString(c.getColumnIndexOrThrow(ContactsContract.Contacts.DISPLAY_NAME));  String json = "{name:'"+name+"'}"; webView.loadUrl("javascript:window.activitycallback("+json+");"); } }

 

因為在WebView內的那個javascript page我已經先安插了一個activitycallback, 所以就利用loadUrl來呼叫它, 這樣就大功告成了!

這只是一個簡單的範例, 還可以做的更generic一點, 比如說把傳入的資料轉化成json這段, 這招應該還可以做一些應用才對