首页 文章 精选 留言 我的

精选列表

搜索[兼容性],共7460篇文章
优秀的个人博客,低调大师

关于Android程序真机不兼容性问题总结及手机ROOT方法

1.Android 编程下短信监听在小米手机中失效的解决办法 http://www.cnblogs.com/sunzn/p/3766158.html 2.将小米手机版本刷低,以便于测试. http://bbs.xiaomi.cn/thread/index/tid/8712185 http://刷机如此简单 小米手机四种刷机方法(2) http://www.muzisoft.com/soft/81482.html 木子软件 3.小米手机刷Android 原生 4.0rom教程及root方法 http://bbs.zol.com.cn/sjbbs/d34002_1302.html http://bbs.xiaomi.cn/thread/index/tid/2422505 4.安卓小米手机如何安装双操作系统切换教程 http://samsung.tgbus.com/201204/422941_2.shtml 5.小米刷机包下载地址 小米2/2S官方原生版安卓Android 4.4发布(非MIUI) http://www.romzhijia.net/shuaji/3208 6.小米手机刷机工具MIflash下载及教程 小米手机刷机教程 http://www.wishdown.com/article/5277.html 7.刷机包下载网址 ROM下载之家 http://www.romzhijia.net/romlist/69_0_5_1_10_2 -------------------------------------------------------------------------------------- 其实,没有必要这么麻烦,直接用刷机大师即可方便完成刷机!其实很简单,学Android的,不会ROOT就OUT了! http://www.romzhijia.net/romtutorials/1 Android双机(网络和USB)调试及其完美ROOT http://www.cnblogs.com/nokiaguy/archive/2013/05/05/3061431.html ----------------------------------------------------------------------------------------- Root虽然爽,但是需要注意以下几个地方: 1.root之前要备份你手机重要的东西 ■联系人:手机自带的备份连接人常见有2种方式,导出到SIM卡和导出到存储设备;对应的导入 就是从SIM卡导入和从存储设备导入。root只是root手机内存的位置,对这两个地方 不会有影响。也可以用其它的备份软件来备份。 联系人备份之后会生成一个.vcf文件,旧的版本会生成多个,一个联系人一个。 ■其它文件:放到硬盘里,这个就没有必要说了吧。 2.root之后恢复备份的文件 3.如果Eclipse在手机root之后,调试都打开了,还是连接不了手机,请重启Eclipse。 本文转自屠夫章哥 51CTO博客,原文链接:http://blog.51cto.com/4259297/1683489,如需转载请自行联系原作者

优秀的个人博客,低调大师

IvorySQL 核心技术解读:双 Parser 架构如何定义数据库兼容性

引言 PostgreSQL 与 Oracle 的语法差异较大,为兼容 Oracle 语法并保持原生 PostgreSQL 语法,IvorySQL 采用了双 Parser 框架,动态切换不同 Parser,实现 Oracle 兼容语法与 PostgreSQL 原生语法的共存。 双 Parser 架构设计总览 双 Parser 的实现目标是在 SQL 和服务器编程语言两个层面兼容 Oracle。通过端口选择或兼容模式设定,实现 Oracle/PG 语法解析的"热切换"。 涉及到的核心模块包括: SQL 解析层,即 Oracle 风格语法树生成; 服务器端编程语言层(通过全新的 PL/iSQL 过程语言实现兼容 Oracle 的 PLSQL) SQL 端词法语法分离 概述 基本做法是新增一套兼容 Oracle 风格的语法和词法,在开启 Oracle 兼容模式时,采用 Oracle 风格的语法分析,生成对应的语法树。 具体实现步骤 在 src/backend/ 目录下新建一个 oracle_Parser 目录,将 src/backend/Parser/ 中的 scan.l 和 gram.y 复制到新目录,并分别重命名为 ora_gram.y 和 ora_scan.l,添加 Oracle 风格的语法和词法分析代码。同时,将 keywords.c 文件复制到该目录,用于存放自定义的关键字。该 oracle_Parser 目录会编译成一个动态库 libParser_oracle.so。当开启 Oracle 兼容模式时,配置文件 ivorysql.conf 将被嵌入到 postgresql.conf 的末尾,并在 ivorysql.conf 中的 shared_preload_libraries 参数中添加 liboracle_Parser,确保数据库启动时自动加载 liboracle_Parser 动态库。 新增 ora_raw_Parser 函数指针,当 libParser_oracle.so 动态库加载时,动态库中的 _PG_init() 函数会将 oracle_raw_Parser() 函数的地址赋值给 ora_raw_Parser,而 _PG_fini() 函数则在兼容模式切换时负责将 ora_raw_Parser 重置为空。 每个后端进程会调用 BackendInitialize() 函数,根据后端进程所连接的端口号设置 port->connmode。如果端口是 Oracle 兼容端口,则将 connmode 设置为 'o',否则设置为 'p'。 在 PostgresMain() 调用 InitIvorysql() 后,如果 port->connmode 为 'o',则调用 SetConfigOption("ivorysql.compatible_mode", "oracle", PGC_USERSET, PGC_S_OVERRIDE)。由于该参数设置了 assign_hook,在 SetConfigOption() 中执行 assign_hook() 时,实际上会调用 assign_compatible_mode(),从而将 sql_raw_Parser 设置为 ora_raw_Parser。 在对 SQL 语句进行分析时,函数 pg_parse_query()->raw_Parser() 通过函数指针 sql_raw_Parser 调用 standard Parser() 或者 ora_raw_Parser()。 下面的图演示了 SQL 语句分析时发生的事情。 服务器端编程语言词法语法分离 概述 与 SQL 端类似,基本做法是新增一套兼容 Oracle 风格的编程语言 PL/iSQL,在开启 Oracle 兼容的情况下,使用 PL/iSQL 语言进行编译。 具体实现步骤 将 PostgreSQL 源码中的 plpgsql 目录复制一份并改名为 plisql,同时将目录内的文件名修改为以 plisql 开头。由于 plpgsql 是一种语言,改造后的 plisql 也将成为一种语言,因此,plpgsql 语言的注册函数如 plpgsql_validator、plpgsql_call_handler、plpgsql_inline_handler 等也需要修改为以 plisql 开头,其他函数名同样按此规则改为以 plisql 开头。 plisql 目录构建为一个插件,initdb 时如果数据库模式是 Oracle,则创建这个插件。这个插件会将 pliSQL 语言注册到数据库的系统表中。 PL/iSQL 本身没有独立的词法解析体系,而是依赖于 SQL 端的词法分析器。因此,为了确保 PL/iSQL 兼容 Oracle 的词法规则,主要的改造是在 plisql_scanner_init 函数中,需调用 ora_scanner_init() 函数,同时,plisql 目录中的 internal_yylex() 函数也应调用 ora_core_yylex()。 PL/iSQL 语法规则在 plisql/src/pl_gram.y 中,兼容 Oracle PLSQL 块的语法规则都在这个模块中实现。 SQL 端创建函数,没有指定 language 的时候,如果当前是兼容 Oracle 模式,则默认 language 是 PL/iSQL,如果是兼容 pg 模式,则默认 language 是 PL/pgSQL。oracle_Parser 中的 ora_gram.y 默认是 PL/iSQL,pg Parser 中的 gram.y 默认是 PL/pgSQL。 匿名块没有指定 language 的时候,如果是兼容 Oracle 模式,默认 PL/iSQL;如果是兼容 pg 模式,则默认 PL/pgSQL。 处理过程的 ExecuteDoStmt 函数同样根据兼容模式来决定默认 language。 下面的图演示了块语句编译分析时发生的事情。 总结 双 Parser 框架作为 IvorySQL 的重要基础,确保同时支持原生 PG 与 Oracle 语法风格,避免两者相互干扰,为 IvorySQL 的兼容特性提供了坚实保障。 IvorySQL 生态大会预告 2025 年 6 月 27 日,IvorySQL 生态大会将在济南盛大开幕,已确认多位全球 PostgreSQL 大咖参与,包括: Bruce Momjian:PG 全球开发小组联合创始人和核心团队成员 Cédric Villemain:法国,Data Bene 创始人&CEO Chris Travers:印度尼西亚,PG 和基础设施专家 Ivan Blinkov:俄罗斯,YDB 副总裁 Michael Meskes:德国,Meskes 董事长(原 Credativ 创始人) Yurii Rashkovskii:加拿大,Omnigres 公司创始人 Álvaro Hernández:西班牙,OnGres 创始人 更多重量级嘉宾正在确认中!目前议题仍在火热征集中,欢迎提交您的议题! 无论你是数据库开发者、架构师还是技术爱好者,这都是与全球顶尖专家面对面交流的绝佳机会。6 月 27 日,相约济南,共同探索 PostgreSQL 的无限可能! 本文由博客一文多发平台 OpenWrite 发布!

优秀的个人博客,低调大师

WebSocket 学习笔记--IE,IOS,Android等设备的兼容性问题与代码实现

一、背景 公司最近准备将一套产品放到Andriod和IOS上面去,为了统一应用的开发方式,决定用各平台APP嵌套一个HTML5浏览器来实现,其中数据通信,准备使用WebSocket的方式。于是,我开始在各大浏览器上测试。 二、协议分析 2.1 WebSocket的请求包 首先把原来做Socket通信的程序拿出来,跟踪下浏览器在WebSocket应用请求服务端的时候发的数据包的内容: IE11: GET /chat HTTP/1.1 Origin: http://localhost Sec-WebSocket-Key: 98JFoEb6pMLFYhAQATn6hw== Connection: Upgrade Upgrade: Websocket Sec-WebSocket-Version: 13 User-Agent: Mozilla/5.0 (Windows NT 6.3; Trident/7.0; rv:11.0) like Gecko Host: 127.0.0.1:1333 Cache-Control: no-cache Cookie: s_pers=%20s_20s_nr%3D1390552565333-Repeat%7C1422088565333%3B FireFox 26.0: GET /chat HTTP/1.1 Host: 127.0.0.1:1333 User-Agent: Mozilla/5.0 (Windows NT 6.3; rv:26.0) Gecko/20100101 Firefox/26.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3 Accept-Encoding: gzip, deflate Sec-WebSocket-Version: 13 Origin: http://localhost Sec-WebSocket-Key: kO4aF1Gpm1mBwOr6j30h0Q== Connection: keep-alive, Upgrade Pragma: no-cache Cache-Control: no-cache Upgrade: websocket Google Chrome 33.0.1707.0 : GET /chat HTTP/1.1 Upgrade: websocket Connection: Upgrade Host: 127.0.0.1:1333 Origin: http://192.168.137.1 Pragma: no-cache Cache-Control: no-cache Sec-WebSocket-Key: NvxdeWLLsLXkt5DirLJ1yA== Sec-WebSocket-Version: 13 Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits, x-webkit-deflate-frame User-Agent: Mozilla/5.0 (Windows NT 6.3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1707.0 Safari/537.36 Apple Safari 5.1.7(7534.57.2)Windows 版本 GET /chat HTTP/1.1 Upgrade: WebSocket Connection: Upgrade Host: 127.0.0.1:1333 Origin: http://localhost Sec-WebSocket-Key1: 25 58 510 64 > = 7 Sec-WebSocket-Key2: 13q9% 974M${fdj6 2`Qn32 �����R�q 分析了下这几种不同的浏览器,除了 Safari,其它均使用了最新的 WebSocket版本 即 Sec-WebSocket-Version:13 但是 Safrai 使用的还是老式的 WebSocket 7.5-7.6版本。 有下面一些文章,对于WebSocket的版本进行了说明: WebSocket握手总结http://www.hoverlees.com/blog/?p=1413 基于Websocket草案10协议的升级及基于Netty的握手实现 http://blog.csdn.net/fenglibing/article/details/6852497 WebSocket握手协议http://blog.163.com/liwei1987821@126/blog/static/17266492820133190211333/ 2.2,IE 对WebSocket的支持问题 这里有必要单独拿出来说,IE10以后才支持HTML5,因此也要这个版本后的浏览器才支持WebSocket,所以默认的Win7下面的浏览器都没法支持。我测试用的是Win8.1的IE11,可以支持WebSocket,效果跟FireFox、Chrome一样,但有一个恼火的问题,IE的WebSocket它会自动向服务器端发起“心跳包”,而此时服务端使用SockeAsyncEventArgs 组件,会出问题,需要客户端多次发数据之后,才会取到正确的客户端请求的数据。 另外,.NET 4.5内置支持了WebSocket,但要求操作系统是Win8或者 Server2012以上的版本。所以如果生产环境的服务器没有这么新,那么WebSocketServer只有自己写了。 2.3,IOS系统上WebSoket问题 Apple 内置的浏览器就是 Safrai,那么IOS上面的浏览器 支持的 WebSocket 版本怎么样呢 ? 找了下同事的 iPhone 4s,IOS 7.0.1 的版本 ,经过测试 ,正常,跟其它浏览器一样,但不知道其它版本的IOS下面的浏览器支持得 怎么样。这就奇怪了,为何Windows 桌面版本的Safrai 不行呢 ? 2.4,安卓上的WebSocket问题 很不幸,目前安卓最新的版本 ,内置的浏览器插件仍然不支持WebSocket,而下载的QQ浏览器等是可以支持的。但是安卓上面的 App默认使用的都是 Andriod内核的浏览器插件,因此它们没法支持WebSocket。但是,既然是系统上面运行的 APP了,为何不直接走Socket 通信方式呢?同事说是为了2个平台能够使用同一套Web应用,毕竟应用嵌套在一个浏览器里面对于开发维护还是最方便的。 所以,解决的路径还是想办法让安卓的默认浏览器插件能够支持WebSocket,查找了下资料,大概有这些资料: android怎么集成支持websocket的浏览器内核http://www.oschina.net/question/1049351_116337 在android的webview中实现websockethttp://xuepiaoqiyue.blog.51cto.com/4391594/1285791 但同事说,这些方法用过了,就是现在测试的效果,跟真正的WebSocket 兼容得不好,使用我的程序测试可以握手连接,但是解析内容上不成功。后来分析,是同事的程序对数据有特殊格式的要求,只要按照他的要求去分析,那么是可以解析得到正确的结果的。 三、WebSocket 服务端和客户端实现 最新的WebSocket 13 版本支持的服务端代码: SocketServer 对于WebSocket信息的处理: private void ProcessReceive(SocketAsyncEventArgs e) { // check if the remote host closed the connection AsyncUserToken token = (AsyncUserToken)e.UserToken; if (e.BytesTransferred > 0 && e.SocketError == SocketError.Success) { //increment the count of the total bytes receive by the server Interlocked.Add(ref m_totalBytesRead, e.BytesTransferred); Console.WriteLine("The server has read a total of {0} bytes", m_totalBytesRead); //echo the data received back to the client //增加自定义处理 string received = System.Text.Encoding.UTF8.GetString(e.Buffer, e.Offset, e.BytesTransferred); Byte[] sendBuffer = null; //IE:Upgrade: Websocket //FireFox: Upgrade: websocket //Chrome: Upgrade: websocket if (received.IndexOf("Upgrade: websocket", StringComparison.OrdinalIgnoreCase) > 0) { //Web Socket 初次连接 token.Name = "WebSocket"; Console.WriteLine("Accept WebSocket."); sendBuffer=PackHandShakeData(GetSecKeyAccetp(received)); } else { if (token.Name == "WebSocket") { string clientMsg; if (e.Offset > 0) { byte[] buffer = new byte[e.BytesTransferred]; Array.Copy(e.Buffer, e.Offset, buffer, 0, buffer.Length); clientMsg = AnalyticData(buffer, buffer.Length); Console.WriteLine("--DEBUG:Web Socket Recive data offset:{0}--",e.Offset); } else { clientMsg = AnalyticData(e.Buffer, e.BytesTransferred); } Console.WriteLine("接受到客户端数据:" + clientMsg); if (!string.IsNullOrEmpty(clientMsg)) { //解析来的真正消息,执行服务器处理 //To Do // //发送数据 string sendMsg = "Hello," + clientMsg; Console.WriteLine("发送数据:“" + sendMsg + "” 至客户端...."); sendBuffer = PackData(sendMsg); } else { sendBuffer = PackData("心跳包"); } } else { Console.WriteLine("服务器接收到的数据:[{0}],将进行1000ms的处理。CurrentThread.ID:{1}", received, System.Threading.Thread.CurrentThread.ManagedThreadId); System.Threading.Thread.Sleep(1000); Console.WriteLine("线程{0} 任务处理结束,发送数据", System.Threading.Thread.CurrentThread.ManagedThreadId); // 格式化数据后发回客户端。 sendBuffer = Encoding.UTF8.GetBytes("Returning " + received); } } //设置传回客户端的缓冲区。 e.SetBuffer(sendBuffer, 0, sendBuffer.Length); //结束 bool willRaiseEvent = token.Socket.SendAsync(e); if (!willRaiseEvent) { ProcessSend(e); } } else { CloseClientSocket(e); } } 下面是一些相关的WebSocket 处理代码,包括握手、打包数据等: // <summary> /// 打包握手信息 /// <remarks> http://www.hoverlees.com/blog/?p=1413 Safari 早期版本不支持标准的version 13,握手不成功。 /// 据测试,最新的IOS 7.0 支持 /// </remarks> /// </summary> /// <param name="secKeyAccept">Sec-WebSocket-Accept</param> /// <returns>数据包</returns> private static byte[] PackHandShakeData(string secKeyAccept) { var responseBuilder = new StringBuilder(); responseBuilder.Append("HTTP/1.1 101 Switching Protocols" + Environment.NewLine); responseBuilder.Append("Upgrade: websocket" + Environment.NewLine); responseBuilder.Append("Connection: Upgrade" + Environment.NewLine); responseBuilder.Append("Sec-WebSocket-Accept: " + secKeyAccept + Environment.NewLine + Environment.NewLine); //如果把上一行换成下面两行,才是thewebsocketprotocol-17协议,但居然握手不成功,目前仍没弄明白! //responseBuilder.Append("Sec-WebSocket-Accept: " + secKeyAccept + Environment.NewLine); //responseBuilder.Append("Sec-WebSocket-Protocol: chat" + Environment.NewLine); return Encoding.UTF8.GetBytes(responseBuilder.ToString()); } /// <summary> /// 生成Sec-WebSocket-Accept /// </summary> /// <param name="handShakeText">客户端握手信息</param> /// <returns>Sec-WebSocket-Accept</returns> private static string GetSecKeyAccetp(string handShakeText) //byte[] handShakeBytes, int bytesLength { //string handShakeText = Encoding.UTF8.GetString(handShakeBytes, 0, bytesLength); string key = string.Empty; Regex r = new Regex(@"Sec\-WebSocket\-Key:(.*?)\r\n"); Match m = r.Match(handShakeText); if (m.Groups.Count != 0) { key = Regex.Replace(m.Value, @"Sec\-WebSocket\-Key:(.*?)\r\n", "$1").Trim(); } byte[] encryptionString = SHA1.Create().ComputeHash(Encoding.ASCII.GetBytes(key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11")); return Convert.ToBase64String(encryptionString); } /// <summary> /// 解析客户端数据包 /// </summary> /// <param name="recBytes">服务器接收的数据包</param> /// <param name="recByteLength">有效数据长度</param> /// <returns></returns> private static string AnalyticData(byte[] recBytes, int recByteLength) { if (recByteLength < 2) { return string.Empty; } bool fin = (recBytes[0] & 0x80) == 0x80; // 1bit,1表示最后一帧 if (!fin) { return string.Empty;// 超过一帧暂不处理 } bool mask_flag = (recBytes[1] & 0x80) == 0x80; // 是否包含掩码 if (!mask_flag) { return string.Empty;// 不包含掩码的暂不处理 } int payload_len = recBytes[1] & 0x7F; // 数据长度 byte[] masks = new byte[4]; byte[] payload_data; if (payload_len == 126) { Array.Copy(recBytes, 4, masks, 0, 4); payload_len = (UInt16)(recBytes[2] << 8 | recBytes[3]); payload_data = new byte[payload_len]; Array.Copy(recBytes, 8, payload_data, 0, payload_len); } else if (payload_len == 127) { Array.Copy(recBytes, 10, masks, 0, 4); byte[] uInt64Bytes = new byte[8]; for (int i = 0; i < 8; i++) { uInt64Bytes[i] = recBytes[9 - i]; } UInt64 len = BitConverter.ToUInt64(uInt64Bytes, 0); payload_data = new byte[len]; for (UInt64 i = 0; i < len; i++) { payload_data[i] = recBytes[i + 14]; } } else { Array.Copy(recBytes, 2, masks, 0, 4); payload_data = new byte[payload_len]; //修改,WebSocket如果自动触发了心跳,之后再发送数据,可能出错,增加下面的判断 if (recBytes.Length < 6 + payload_len) Array.Copy(recBytes, 6, payload_data, 0, recBytes.Length - 6); else Array.Copy(recBytes, 6, payload_data, 0, payload_len); } for (var i = 0; i < payload_len; i++) { payload_data[i] = (byte)(payload_data[i] ^ masks[i % 4]); } return Encoding.UTF8.GetString(payload_data); } /// <summary> /// 打包服务器数据 /// </summary> /// <param name="message">数据</param> /// <returns>数据包</returns> private static byte[] PackData(string message) { byte[] contentBytes = null; byte[] temp = Encoding.UTF8.GetBytes(message); if (temp.Length < 126) { contentBytes = new byte[temp.Length + 2]; contentBytes[0] = 0x81; contentBytes[1] = (byte)temp.Length; Array.Copy(temp, 0, contentBytes, 2, temp.Length); } else if (temp.Length < 0xFFFF) { contentBytes = new byte[temp.Length + 4]; contentBytes[0] = 0x81; contentBytes[1] = 126; contentBytes[2] = (byte)(temp.Length & 0xFF); contentBytes[3] = (byte)(temp.Length >> 8 & 0xFF); Array.Copy(temp, 0, contentBytes, 4, temp.Length); } else { // 暂不处理超长内容 } return contentBytes; } 测试配套的客户端 HTML代码: <html> <head> <meta charset="UTF-8"> <title>Web sockets test</title> <script type="text/javascript"> var ws; function ToggleConnectionClicked() { try { var ip = document.getElementById("txtIP").value; ws = new WebSocket("ws://" + ip + ":1333/chat"); //连接服务器 ws://localhost:1818/chat ws.onopen = function(event){alert("已经与服务器建立了连接\r\n当前连接状态:"+this.readyState);}; ws.onmessage = function(event){alert("接收到服务器发送的数据:\r\n"+event.data);}; ws.onclose = function(event){alert("已经与服务器断开连接\r\n当前连接状态:"+this.readyState);}; ws.onerror = function(event){alert("WebSocket异常!");}; } catch (ex) { alert(ex.message); } }; function SendData() { try{ ws.send("张三."); }catch(ex){ alert(ex.message); } }; function seestate(){ alert(ws.readyState); } </script> </head> <body> Server IP:<input type="text" id="txtIP" value="127.0.0.1"/> <button id='ToggleConnection' type="button" onclick='ToggleConnectionClicked();'>连接服务器</button><br /><br /> <button id='ToggleConnection' type="button" onclick='SendData();'>发送我的名字:beston</button><br /><br /> <button id='ToggleConnection' type="button" onclick='seestate();'>查看状态</button><br /><br /> </body> </html> 但是上面的代码依然无法处理IE的“心跳”数据引起的问题。此时需要修改一下WebSocket对接受到数据的处理方式,如果客户端发送的是无效的数据,比如IE的心跳数据 ,那么直接过滤,不写入任何数据,将服务端的代码做下面的修改即可: if (sendBuffer != null) { //设置传回客户端的缓冲区。 e.SetBuffer(sendBuffer, 0, sendBuffer.Length); //结束 bool willRaiseEvent = token.Socket.SendAsync(e); if (!willRaiseEvent) { ProcessSend(e); } } else { ProcessSend(e); } 这样,就得到了最终正确的结果了。此问题困扰了我好几天。下面是运行结果图: 本文转自深蓝医生博客园博客,原文链接:http://www.cnblogs.com/bluedoctor/p/3534087.html,如需转载请自行联系原作者

优秀的个人博客,低调大师

Chrome 开始测试三位数用户代理,以检查网站兼容性

在上个月,我们曾报道了 Mozilla 开始在 Firefox 上测试 "Firefox/100.0" 用户代理,以避免 Firefox 浏览器在明年 3 月从现有的两位数版本号升级至三位数时,可能出现的网站加载异常情况的发生(点击查看此前报道)。 Chrome 目前最新的稳定版版本号已更新至 94,比 Firefox 目前的版本号(92)更加高。Chrome 作为目前用户最多、市场占有率最高的浏览器,如果没有经过严谨的测试,在 Chrome 升级至 100 版本后,对用户的影响范围也会更加大。 近日,Google 正式开始测试将 Chrome 浏览器的用户代理改为三位数的 "Chrome/100" 后,是否会导致那些只能将用户代理解析为两位数的网站出现网站功能异常。 用户代理是网络浏览器使用的一个字符串,其中包括关于该软件的信息,例如名称、版本和使用的技术概要。当一个浏览器发布新版本的时候,开发者也会增加用户代理字符串中的版本号。 以之前报道的 Mozilla Firefox 为例,它的用户代理将会如下显示: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:92.0) Gecko/20100101 Firefox/92.0 Firefox 的用户代理可以被拆分为以下几个部分: Mozilla/5.0 (platform; rv:geckoversion) Gecko/geckotrailFirefox/firefoxversion Mozilla/5.0表明该浏览器与 Mozilla 相兼容的通用字符串。此字段几乎存在于现今所有浏览器的用户代理之中; platform描述了浏览器所运行的本地操作系统平台(例如:Windows、Mac、Linux 或 Android),以及其是否为移动设备; rv:geckoversion显示了 Gecko 的版本号。在最近几个版本的浏览器中, geckoversion与firefoxversion一致; Gecko/geckotrail标明浏览器基于 Gecko,在桌面端 geckotrail的值恒为"20100101"; Firefox/firefoxversion标明浏览器是 Firefox,并提供了版本号; Chrome 的用户代理结构与 Firefox 十分相似,对于 Chrome 94 而言,它的用户代理是: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.54 Safari/537.36 通过向网站发送浏览器用户代理,网站的开发人员可以通过用户代理来改变网站或应用程序的功能,以适应各种浏览器的标准、特性和能力。如今 Google 还将 Chrome 的更新周期从此前的六周更改为四周,进一步加速了 Chrome 版本更替周期,针对三位数的用户代理测试已刻不容缓。 开发者也可手动修改 Chrome 的用户代理,以提前测试自己的网站是否会出现问题,及时做出调整。

优秀的个人博客,低调大师

那日了狗的上半年的兼容性问题,下半年来解决。

android机型繁多,在一款机型下适配成功。另一款机型却崩溃退出。而丢给你的却是这样一堆莫名其妙的异常。上头的臭骂,机型没有,如何是好?可是开发狗是狗,不是神。那怎么办呢?记录下这狗血的异常和解决办法。 07-01 09:33:08.663 3067-3067/com.test.tao E/AndroidRuntime: FATAL EXCEPTION: main android.view.InflateException: Binary XML file line #13: Error inflating class <unknown> at android.view.LayoutInflater.createView(LayoutInflater.java:613) at com.android.internal.policy.impl.PhoneLayoutInflater.onCreateView(PhoneLayoutInflater.java:56) at android.view.LayoutInflater.onCreateView(LayoutInflater.java:660) at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:685) at android.view.LayoutInflater.rInflate(LayoutInflater.java:746) at android.view.LayoutInflater.parseInclude(LayoutInflater.java:830) at de.robv.android.xposed.XposedBridge.invokeOriginalMethodNative(Native Method) at de.robv.android.xposed.XposedBridge.handleHookedMethod(XposedBridge.java:631) at android.view.LayoutInflater.parseInclude(Native Method) at android.view.LayoutInflater.rInflate(LayoutInflater.java:736) at android.view.LayoutInflater.rInflate(LayoutInflater.java:749) at android.view.LayoutInflater.inflate(LayoutInflater.java:489) at de.robv.android.xposed.XposedBridge.invokeOriginalMethodNative(Native Method) at de.robv.android.xposed.XposedBridge.handleHookedMethod(XposedBridge.java:631) at android.view.LayoutInflater.inflate(Native Method) at android.view.LayoutInflater.inflate(LayoutInflater.java:396) at com.test.tao.utils.GlobalUtils.inflate(GlobalUtils.java:91) at com.test.tao.base.BaseFragment.onCreateView(BaseFragment.java:59) at android.support.v4.app.Fragment.performCreateView(Fragment.java:1974) at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1067) at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1252) at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:742) at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1617) at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:517) at android.os.Handler.handleCallback(Handler.java:725) at android.os.Handler.dispatchMessage(Handler.java:92) at android.os.Looper.loop(Looper.java:137) at android.app.ActivityThread.main(ActivityThread.java:5069) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:511) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560) at de.robv.android.xposed.XposedBridge.main(XposedBridge.java:132) at dalvik.system.NativeStart.main(Native Method) Caused by: java.lang.reflect.InvocationTargetException at java.lang.reflect.Constructor.constructNative(Native Method) at java.lang.reflect.Constructor.newInstance(Constructor.java:417) at android.view.LayoutInflater.createView(LayoutInflater.java:587) at com.android.internal.policy.impl.PhoneLayoutInflater.onCreateView(PhoneLayoutInflater.java:56) at android.view.LayoutInflater.onCreateView(LayoutInflater.java:660) at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:685) at android.view.LayoutInflater.rInflate(LayoutInflater.java:746) at android.view.LayoutInflater.parseInclude(LayoutInflater.java:830) at de.robv.android.xposed.XposedBridge.invokeOriginalMethodNative(Native Method) at de.robv.android.xposed.XposedBridge.handleHookedMethod(XposedBridge.java:631) at android.view.LayoutInflater.parseInclude(Native Method) at android.view.LayoutInflater.rInflate(LayoutInflater.java:736) at android.view.LayoutInflater.rInflate(LayoutInflater.java:749) at android.view.LayoutInflater.inflate(LayoutInflater.java:489) at de.robv.android.xposed.XposedBridge.invokeOriginalMethodNative(Native Method) at de.robv.android.xposed.XposedBridge.handleHookedMethod(XposedBridge.java:631) at android.view.LayoutInflater.inflate(Native Method) at android.view.LayoutInflater.inflate(LayoutInflater.java:396) at com.test.tao.utils.GlobalUtils.inflate(GlobalUtils.java:91) at com.test.tao.base.BaseFragment.onCreateView(BaseFragment.java:59) at android.support.v4.app.Fragment.performCreateView(Fragment.java:1974) at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1067) at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1252) at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:742) at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1617) at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:517) at android.os.Handler.handleCallback(Handler.java:725) at android.os.Handler.dispatchMessage(Handler.java:92) at android.os.Looper.loop(Looper.java:137) at android.app.ActivityThread.main(ActivityThread.java:5069) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:511) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560) at de.robv.android.xposed.XposedBridge.main(XposedBridge.java:132) at dalvik.system.NativeStart.main(Native Method) Caused by: java.lang.UnsupportedOperationException: Can't convert to dimension: type=0x1 at android.content.res.TypedArray.getDimensionPixelSize(TypedArray.java:463) at android.content.res.XResources$XTypedArray.getDimensionPixelSize(XResources.java:945) at android.widget.TextView.<init>(TextView.java:916) at android.widget.TextView.<init>(TextView.java:578) at java.lang.reflect.Constructor.constructNative(Native Method) at java.lang.reflect.Constructor.newInstance(Constructor.java:417) at android.view.LayoutInflater.createView(LayoutInflater.java:587) at com.android.internal.policy.impl.PhoneLayoutInflater.onCreateView(PhoneLayoutInflater.java:56) at android.view.LayoutInflater.onCreateView(LayoutInflater.java:660) at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:685) at android.view.LayoutInflater.rInflate(LayoutInflater.java:746) at android.view.LayoutInflater.parseInclude(LayoutInflater.java:830) at de.robv.android.xposed.XposedBridge.invokeOriginalMethodNative(Native Method) at de.robv.android.xposed.XposedBridge.handleHookedMethod(XposedBridge.java:631) at android.view.LayoutInflater.parseInclude(Native Method) at android.view.LayoutInflater.rInflate(LayoutInflater.java:736) at android.view.LayoutInflater.rInflate(LayoutInflater.java:749) at android.view.LayoutInflater.inflate(LayoutInflater.java:489) at de.robv.android.xposed.XposedBridge.invokeOriginalMethodNative(Native Method) at de.robv.android.xposed.XposedBridge.handleHookedMethod(XposedBridge.java:631) at android.view.LayoutInflater.inflate(Native Method) at android.view.LayoutInflater.inflate(LayoutInflater.java:396) at com.test.tao.utils.GlobalUtils.inflate(GlobalUtils.java:91) at com.test.tao.base.BaseFragment.onCreateView(BaseFragment.java:59) at android.support.v4.app.Fragment.performCreateView(Fragment.java:1974) at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1067) at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1252) at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:742) at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1617) at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:517) at android.os.Handler.handleCallback(Handler.java:725) at android.os.Handler.dispatchMessage(Handler.java:92) at android.os.Looper.loop(Looper.java:137) at android.app.ActivityThread.main(ActivityThread.java:5069) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:511) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560) at de.robv.android.xposed.XposedBridge.main(XposedBridge.java:132) at dalvik.system.NativeStart.main(Native Method) 网上查了N多资料说的是values里面少了默认值。可是在一堆配置文件里面怎么把它找出来呢?一开始我是拒绝的,无从下手。相信不少做android开发的都会碰到这样的问题。这里说说开发狗是怎么解决这个问题的吧。 碰到这样的现象主要体现在如下方面: 1、别人的讥讽笑料,见惯不怪了。 2、心绪低落,不开心;拉到会议室,被上头狗血淋头地骂一顿;内心只有呵呵...,该下班下班。 3、来一杯红酒,该吃吃该喝喝。哦,对了,那都是上半年的事情了。 当你碰到一个问题的时候,很多时候无论走路吃饭都会想着。无从下手,内心着实是有种无力感。然而想起当初学程序时的那个最简单的调试方法,错了找不着问题,删掉一部分一部分加进来测试不就OK了吗? 上半年的bug,下半年解决。于是开启模拟器,将所有相关代码注释掉,把相关配置文件删掉。反复几次后,问题给定位出来了。网上说的问题没错,确实是由于value-xxx下定义了某个属性值,而values下没有默认值,导致不同机型下找不到默认值而导致app崩溃。好吧,问题定位到了,下面是具体解决办法。 1、将values-XXX全部备份后删掉。 2、将报错的信息一个个添加回values。 3、好的解决办法都是简单的。 造成这种情况的原因: 1、开发狗是狗,不是神。 2、在做第三方集成的时候由于一些资源文件冲突,没有整合到values文件夹下,被丢弃了。 本文转自秋楓博客园博客,原文链接:http://www.cnblogs.com/rwxwsblog/p/5632598.html,如需转载请自行联系原作者

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册