webviewへデータを渡すには
String url = "javascript:setImg(data)";
wv.loadUrl(url);
のような形がお約束。
ではこれでどのくらいのデータが渡せるか。
渡し方から想像できるようにURLとしての長さの制限(256)を受けます。
つまり関数名やあたまのjavascript:を考えると200ちょっと。
普通はこれで足りるんですが、画像データをbase64形式で渡したかったんです。
で、考えたのはjavascriptの関数を読んで、またnativeを呼び返して、と繰り返していけば40kのデータでも200回繰り返せば渡せるな、と。
そんなにnative-webviewの連続呼び出しがスムーズに行くのかって疑問があるので検証。
まずはbase64のデータを配列にしてコマ切れに。base64にするときにNO_WRAP指定すると改行が無くせます。
URLに改行入ってくると面倒なので先に。
Base64.encodeToString(bytearray, Base64.NO_WRAP);
private String[] imagedata;
private int maxDataLength=100;
private void callbackPhoto(String image64) {
int datalength = image64.length();
imagedata=new String[(int) Math.ceil((double)datalength/(double)maxDataLength)];
for(int i=0;i<imagedata.length;i++){
int start =maxDataLength*i;
int limit =Math.min(start+maxDataLength,datalength);
imagedata[i] = image64.substring(start,limit);
}
wv.loadUrl("javascript:setImg(1,\""+imagedata[0]+"\")");
}
javascriptにはいくつめのデータかと、細切れにしたデータを渡してます。
次にjavascript。今回はcount=0のデータがくると最後のデータと判別してます。
base64data="";
function setImg (count,data) {
base64data+=data;
if(count==0){
setImage(base64data);
}else{
AndroidApp.getNextImgData(count+1);
}
}
受け取ったらnativeのgetNextImgDataを呼んで次のデータを待つ。
setImage は後で呼びます。
handler用意して、
Handler mHandler = new Handler();
interfaceでうけとる。スレッドのアレがあるのでhandlerで呼んで
@JavascriptInterface
public void getNextImgData(final int count){
mHandler.post(new Runnable() {
public void run() {
callbackPhoto2Next(count);
}
});
}
次のデータを渡す。最後だったら0を一つ目のパラメータに。
private void callbackPhoto2Next(int count) {
int id=count;
if(imagedata.length==count){
id=0;
}
String url = "javascript:setImg("+id+",\""+imagedata[count-1]+"\")";
wv.loadUrl(url);
}
全部渡しきったらあとはJSでcanvasに表示。
function setImage (result) {
c = document.getElementById("canvas");
ctx = c.getContext("2d");
img = new Image();
img.onload = function(){
ctx.drawImage(img, 0,0,img.width, img.height, 0,0,img.width, img.height);
};
img.src = "data:image/jpeg;base64,"+result;
}
こんなに何度もやり取りしたら遅いだろうと思ったら、30kのデータで0.15s。十分実用範囲。