Activity と WebView の中の js との i/f

ええと、AndroidとJavaScriptを連携させる方法というエントリを参考に

  • Android から WebView で読み込む javascript な function を呼び出す方法
  • WebView で読み込む javascript から Android なメソドを呼び出す方法

というのは理解できておりました。
上記エントリを参考に以下なサンプルをでっち上げてました。Activity の一部が以下ッス。

public class GMapSample extends Activity implements LocationListener {
	
	private Location loc;

	class JsObj {
		public double getLat() {
			return loc.getLatitude();
			//return 26.19;
		}

		public double getLng() {
			return loc.getLongitude();
			//return 127.67;
		}
	}

	private WebView webView;
	private JsObj jo;
	private LocationManager locationManager;

上記な形で javascript との i/f な内部クラスを定義しておきます。で、onCreate メソドの定義が以下のようなカンジ。

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        webView = new WebView(this);
        webView.getSettings().setJavaScriptEnabled(true);
        
        jo = new JsObj();
        
        locationManager = (LocationManager)getSystemService(LOCATION_SERVICE);
        locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 10000, 0, this);
        loc = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
        
        webView.addJavascriptInterface(jo, "roid");
        webView.loadUrl("file:///android_asset/index.html");
        setContentView(webView);
    }

上記最後らへんの WebView#addJavascriptInterface というメソドで javascript 側から jo なオブジェクトを roid という識別子で参照できるようにしている。
onLocationChange メソドとかで測位情報を属性に設定してたり onPause やら onResume の作法的な実装を書いておりますが略。
読み込むコンテンツ (assets/index.html) の記述が以下ッス。

<html>
<head>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false"></script>
<script type="text/javascript">

  var map;
  var marker;
  
  function setMarker(location) {
    marker = new google.maps.Marker({
      position: location,
      map: map
    });
    marker.setMap(map);
  }
  
  function initialize() {
    var latlng = new google.maps.LatLng(roid.getLat(), roid.getLng());
    var myOptions = {
      zoom: 16,
      center: latlng,
      mapTypeId: google.maps.MapTypeId.ROADMAP
    };
    map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
    setMarker(latlng);
  }
  
  function reloadFunction() {
    marker.setMap(null);
    var latlng = new google.maps.LatLng(roid.getLat(), roid.getLng());
//    map.setCenter(latlng);
    setMarker(latlng);    
  }

</script>
</head>
<body onload="initialize()">
  <div id="map_canvas" style="width:100%; height:100%"></div>
</body>
</html>

上記の例だととにかく状態に変化があったら reloadFunction を呼んでるのでパフォーマンス的に微妙です。marker も度ごとに生成しとりますな。

一応、Android 側から javascript 側にオブジェクトではない形で値を渡せる事は分かっていたんですが、逆って可能なの? という疑問に今更至ってしまった訳です。
javascript な function の戻りはおそらく受け取れないんだけどなぁ、と言いつつ随分前に同じ検討してて javascript 側から Android オブジェクトな属性が欲しい場合は getter 呼べば良くって、逆に値を戻したいのであれば setter 作って呼べばいいじゃん、って事に気がついた。というか思い出した次第で。
いちいち手続きを呼び出さないと駄目なんか的微妙さはありますが、双方で生データの値のやりとりは可能である、という事が分かって一安心だった訳です。