参考博客
Android版本要求及H5 api支持情况
在Android版本4.4之前,由于维护和开发Android版本时使用的是AppleWebkit开源内核,虽然也非常不错,但不支持许多html5 api,在Android4.4使用了Chromium才得以发展,
目前支持的html 5如下:
Web Workers | 支持 | javaScript多线程 |
WebSocket | 支持 | javascript套接字,TCP长链接 |
IDBFactory/indexDB | 支持 | 索引数据库 |
ApplicationCache | 支持 | web离线缓存 |
postMessage/onMessage | 支持 | 收发消息 |
ondeviceorientation,ondevicemotion,onorientationchange | 支持 | 屏幕旋转,移动 |
onvolumechange | 支持 | 声音改变 |
RequestAnimationFrame | 支持 | 页面UI动画更新引擎 |
LocalStorage/sessionStorage | 支持 | 本地缓存 |
FileReader | 支持 | 本地文件读取 |
FormData | 支持 | 模拟表单,表单模型 |
EventSource | 支持 | Server-Sent Events(SSE)功能,允许服务端推送数据到客户端。(通常叫数据推送) |
CacheStorage | 不支持 | 异步缓存 |
Promise | 不支持 | 异步范式 |
Crypto | 不支持 | javascript加密API |
WebAudio | 不支持 | 流媒体播放 |
WebRTC | 不支持 | 流媒体通讯 |
WebGL | 不支持 | Web GL图像框架 |
GeoLocation | 支持 | 地理定位 |
Notification | 不支持 | web通知 |
Blob | 支持 | 二进制数据对象 |
在这里我们主要了解WebSocket在Android WebView上的支持,这里给出一个基于php WebSocketServer的例子:
【以下例子来自开源中国博客】
体验位置:
(请使用你的PC浏览器和你的Android4.4的设备上的浏览器)
WebSocket Server端实现
php端
master=$this->createSocketServer($address, $port,$maxLink); $this->sockets=array($this->master); } function run() { while(true){ $changes=$this->sockets; $write=NULL; $except=NULL; socket_select($changes,$write,$except,NULL); /** * 监听读写操作,socket_select (array &$read, array &$write, array &$except, $tv_sec, $tv_usec = null) * $read 注意,这里使用了引用,$read表示要监听读操作的socket,socket_select可以调用多次,之前监听的socket不会被取消(注意,socket连接也是read) * $write 注意,这里使用了引用,$read表示要监听写操作的socket,socket_select可以调用多次,之前监听的socket不会被取消 * $$except 监听异常的socket * 以上&read,&write,&except是被引用的,也就意味着变量的值可以输入输出,把监听到的socket输出,把想被监听的socket输入 * 最后一个参数是超时时间,默认是0 * * 该函数会阻塞 */ foreach($changes as $sock){ if($sock==$this->master){ /** * 接受客户端socket * @var unknown */ $client=socket_accept($this->master); $key=uniqid(); $this->sockets[]=$client; $this->users[$key]=array( 'socket'=>$client, 'handshake'=>false ); }else{ $len=0; $buffer=''; do{ $l=socket_recv($sock,$buf,1000,0); $len+=$l; $buffer.=$buf; }while($l==1000); $k=$this->search($sock); if($len<7){ $this->send2($k); continue; } if(!$this->users[$k]['handshake']){ $this->handshake($k,$buffer); }else{ $buffer = $this->uncode($buffer,$k); if($buffer==false){ continue; } $this->send($k,$buffer); } } } } } function close($k){ socket_close($this->users[$k]['socket']); unset($this->users[$k]); $this->sockets=array($this->master); foreach($this->users as $v){ $this->sockets[]=$v['socket']; } $this->e("key:$k close"); } function search($sock){ foreach ($this->users as $k=>$v){ if($sock==$v['socket']) return $k; } return false; } /** * * @param string $address 地址 * @param int $port 端口 * @param number $maxLink 最大连接数 */ function createSocketServer($address,$port,$maxLink=16){ $server = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); socket_set_option($server, SOL_SOCKET, SO_REUSEADDR, 1); socket_bind($server, $address, $port); socket_listen($server,$maxLink); $this->e('Server Started : '.date('Y-m-d H:i:s')); $this->e('Listening on : '.$address.' port '.$port); return $server; } /** * 握手 * @param string $k 要握手的socket * @param byte $buffer 缓冲数据 * @return boolean */ function handshake($k,$buffer){ $buf = substr($buffer,strpos($buffer,'Sec-WebSocket-Key:')+18); $key = trim(substr($buf,0,strpos($buf,"\r\n"))); $new_key = base64_encode(sha1($key."258EAFA5-E914-47DA-95CA-C5AB0DC85B11",true)); $new_message = "HTTP/1.1 101 Switching Protocols\r\n"; $new_message .= "Upgrade: websocket\r\n"; $new_message .= "Sec-WebSocket-Version: 13\r\n"; $new_message .= "Connection: Upgrade\r\n"; $new_message .= "Sec-WebSocket-Accept: " . $new_key . "\r\n\r\n"; socket_write($this->users[$k]['socket'],$new_message,strlen($new_message)); $this->users[$k]['handshake']=true; return true; } function uncode($str,$key){ $mask = array(); $data = ''; $msg = unpack('H*',$str); $head = substr($msg[1],0,2); if ($head == '81' && !isset($this->sum_length[$key])) { $len=substr($msg[1],2,2); $len=hexdec($len); if(substr($msg[1],2,2)=='fe'){ $len=substr($msg[1],4,4); $len=hexdec($len); $msg[1]=substr($msg[1],4); }else if(substr($msg[1],2,2)=='ff'){ $len=substr($msg[1],4,16); $len=hexdec($len); $msg[1]=substr($msg[1],16); } $mask[] = hexdec(substr($msg[1],4,2)); $mask[] = hexdec(substr($msg[1],6,2)); $mask[] = hexdec(substr($msg[1],8,2)); $mask[] = hexdec(substr($msg[1],10,2)); $s = 12; $n=0; }else if($this->sum_length[$key] > 0){ $len=$this->sum_length[$key]; $mask=$this->salt_key[$key]; $n=$this->per_data_len[$key]; $s = 0; } $e = strlen($msg[1])-2; for ($i=$s; $i<= $e; $i+= 2) { $data .= chr($mask[$n%4]^hexdec(substr($msg[1],$i,2))); $n++; } $dlen=strlen($data); if($len > 255 && $len > $dlen+intval($this->rec_data_length[$key])){ $this->salt_key[$key]=$mask; $this->sum_length[$key]=$len; $this->rec_data_length[$key]=$dlen+intval($this->rec_data_length[$key]); $this->rec_data_packets[$key]=$this->rec_data_packets[$key].$data; $this->per_data_len[$key]=$n; return false; }else{ unset($this->salt_key[$key],$this->sum_length[$key],$this->rec_data_length[$key],$this->per_data_len[$key]); $data=$this->rec_data_packets[$key].$data; unset($this->rec_data_packets[$key]); return $data; } } function code($msg){ $frame = array(); $frame[0] = '81'; $len = strlen($msg); if($len < 126){ $frame[1] = $len<16?'0'.dechex($len):dechex($len); }else if($len < 65025){ $s=dechex($len); $frame[1]='7e'.str_repeat('0',4-strlen($s)).$s; }else{ $s=dechex($len); $frame[1]='7f'.str_repeat('0',16-strlen($s)).$s; } $frame[2] = $this->ord_hex($msg); $data = implode('',$frame); return pack("H*", $data); } function ord_hex($data) { $msg = ''; $l = strlen($data); for ($i= 0; $i<$l; $i++) { $msg .= dechex(ord($data{$i})); } return $msg; } //用户加入 function send($k,$msg){ parse_str($msg,$g); $ar=array(); if($g['type']=='add'){ $this->users[$k]['name']=$g['ming']; $ar['type']='add'; $ar['name']=$g['ming']; $key='all'; }else{ $ar['nrong']=$g['nr']; $key=$g['key']; } $this->send1($k,$ar,$key); } function getusers(){ $ar=array(); foreach($this->users as $k=>$v){ $ar[]=array('code'=>$k,'name'=>$v['name']); } return $ar; } /** * @param string $k 发信息人的code * @param string $ar 数据 * @param string $key 接受人的 code */ function send1($k,$ar,$key='all'){ $ar['code1']=$key; $ar['code']=$k; $ar['time']=date('m-d H:i:s'); $str = $this->code(json_encode($ar)); if($key=='all'){ $users=$this->users; if($ar['type']=='add'){ $ar['type']='madd'; $ar['users']=$this->getusers(); $str1 = $this->code(json_encode($ar)); socket_write($users[$k]['socket'],$str1,strlen($str1)); unset($users[$k]); } foreach($users as $v){ socket_write($v['socket'],$str,strlen($str)); } }else{ socket_write($this->users[$k]['socket'],$str,strlen($str)); socket_write($this->users[$key]['socket'],$str,strlen($str)); } } //用户退出 function send2($k){ $this->close($k); $ar['type']='rmove'; $ar['nrong']=$k; $this->send1(false,$ar,'all'); } function e($str){ //$path=dirname(__FILE__).'/log.txt'; $str=$str."\n"; //error_log($str,3,$path); echo iconv('utf-8','gbk//IGNORE',$str); }}$sk=new Sock('127.0.0.1',8000);$sk->run();?>
WebSocket Client端实现
client端
HTML5 websocket 网页聊天室 javascript php