笔记
new View()
,它的layoutParam
默认是wrap_content
wrap_content看的是 子view 的大小,match_parent看的是 父view 的大小。
父view 是wrap_content,子view1 有个是具体值 则父view 大小就是子view1的大小(其他子view 是match_parent最大也是 子view1 的大小)(子view1的位置也可以不在第一个位置)【即具体值优先】
WebView
1 | // 获取当前页面的URL |
1 | webview.setScrollContainer(false); //内容是否可以滚动 |
WebSettings
1 | WebSettings settings = web.getSettings(); |
WebViewClient
1 | // 拦截页面加载,返回true表示宿主app拦截并处理了该url,否则返回false由当前WebView处理 |
WebChromeClient
1 | // 获得所有访问历史项目的列表,用于链接着色。 |
可以 将一些资源文件放在本地的 asset s目录, 然后重 写WebViewClient 的 shouldInterceptRequest
方法,对访问地址进行拦截,当 url 地址命中本地配置的url时,使用本地资源替代,否则就使用网络上的资源。
1 | mWebview.setWebViewClient(new WebViewClient() { |
WebView初始化慢,可以在初始化同时先请求数据,让后端和网络不要闲着。
后端处理慢,可以让服务器分trunk输出,在后端计算的同时前端也加载网络静态资源。
脚本执行慢,就让脚本在最后运行,不阻塞页面解析。
同时,合理的预加载、预缓存可以让加载速度的瓶颈更小。
WebView初始化慢,就随时初始化好一个WebView待用。
DNS和链接慢,想办法复用客户端使用的域名和链接。
脚本执行慢,可以把框架代码拆分出来,在请求页面之前就执行好。
setWebChromeClient中添加方法:
1 | @Override |
setWebViewClient中添加方法:
1 | @Override |
Android WebView自带的缓存机制有5种:
https://blog.csdn.net/Ever69/article/details/104479626
根据HTTP协议头里的Cache-Control(或Expires)和Last-Modified(或Etag)等字段来控制文件缓存的机制。
Cache-Control:用于控制文件在本地缓存有效时长
HTTP1.1中新加的字段。如服务器回包:Cache-Control:max-age=600,表示该文件在本地缓存的有效时长是600秒
Expires:与Cache-Control功能相同,即控制缓存的有效时间
HTTP1.0标准中的字段,若和Cache-Control同时出现,则后者优先级更高。
Last-Modified:标识文件在服务器上的最新更新时间
下次请求,如果文件缓存过期,浏览器会通过
if-Modified-Since
这个字段带上这个时间发给服务器,由服务器判断文件是否有修改。若没有修改,服务器返回304告诉浏览器继续使用缓存;若有修改,则返回200同时返回最新的文件
Etag:功能同 Last-Modified,即标识文件在服务器上的最新更新时间。
不同的是,Etag的取值是一个对文件进行标识的特征字串。
在向服务器查询文件是否有更新时,浏览器通过
If-None-Match
字段把特征字串发送给服务器,由服务器判断文件是否有更新。若没有更新回包304,若有更新回包200
注意:Etag和Last-Modified同时使用时,只要满足其中一个条件,就认为文件没有更新。
常见用法:
优点:支持Http协议层
不足:缓存文件需要首次加载后才产生;浏览器缓存的存储空间有限,缓存有被清除的可能;缓存的文件没有校验。对于上述问题可以参考手Q的离线包。
静态资源文件的存储,如JS
、CSS
、字体、图片等。
Android WebView会将缓存的文件记录及文件内容存在当前app的data目录中
Android WebView内置自动实现
已文件为单位进行缓存,且文件有一定更新机制(类似于浏览器缓存机制)
APPCache原理有两个关键点:manifest属性和manifest文件。
HTML在头中通过 manifest 属性 引用 manifest 文件。
manifest文件:就是以 appcache 结尾的一个普通文件
方便构建Web App的缓存,专门为Web App离线使用而开发的缓存机制,AppCache是对浏览器缓存机制的补充。
存储静态文件(如JS、CSS、字体文件等)
1 | // 通过设置WebView的settings来实现 |
注意:每个Application只调用一次
WebSettings.setAppCachePath()
和WebSettings.setAppCacheMaxSize()
通过存储字符串的 Key-Value 来提供
Dom Storage分为 sessionStorage 和 localStorage;二者使用方法基本相同,区别在于作用范围不同
1 | // 通过设置 `WebView`的`Settings`类实现 |
基于 SQL 的数据库存储机制
充分利用数据库的优势,可方便对数据进行增删查改
存储适合数据库的结构化数据
1 | // 通过设置WebView的settings实现 |
官方说明,Web SQL Database存储机制不再推荐使用(不再维护),取而代之的是 IndexedDB 缓存机制
数据 NoSQL 数据库,通过存储字符串 key-value 对来提供。
类似于 Dom Storage 存储机制的 key-value 存储方式
存储复杂、数据量大的结构化数据
通过设置WebView的settings实现,只需设置支持JS就自动打开IndexedDB存储机制,Android在4.4开始加入对 IndexedDB 的支持,只需打开允许 JS 执行的开关就好
1 | WebSettings settings = getSettings(); |
为H5页面的数据提供一个虚拟的文件系统
可存储数据体积较大的二进制数据,可预加载资源文件,可直接编辑文件
通过文件系统,管理数据
由于 File System 是H5 新加入的缓存机制,所以 Android We吧View 暂不支持
WebView | 腾讯X5内核 | JsBridge | AgentWeb | UC内核 | SuperWeb | DSBridge-Android | |
---|---|---|---|---|---|---|---|
地址 | https://github.com/lzyzsd/JsBridge | https://github.com/Justson/AgentWeb | https://github.com/Victory-Over/SuperWeb | https://github.com/wendux/DSBridge-Android | |||
说明 | 基于腾讯X5内核 | 侧重js与原生app交互,写法类似JSBridge | |||||
大小 | |||||||
占内存大小 | |||||||
加载速度 | |||||||
无网是否支持缓存 | |||||||
是否可定制窗口大小 | |||||||
进度条和自定义进度条 | 有进度条 | 支持进度条和自定义进度条 | 支持进度条 | ||||
进度条显隐是否页面抖动 | |||||||
支持原生交互 | true | true | |||||
Easy of use | 麻烦 | 简洁 | |||||
支持文件浏览 | false | true | |||||
支持文件下载 | false | true | true | ||||
支持文件下载断点续传 | true | ||||||
支持下载通知形式提示进度 | true | ||||||
支持文件上传 | false | true | true | ||||
加强web安全 | true | ||||||
全屏播放视频 | 不支持 | true | true | ||||
兼容低版本Js安全通信 | true | ||||||
支持调起微信支付 | true | ||||||
支持调起支付宝 | true | ||||||
支持传入WebLayout(下拉回弹效果) | true | true | |||||
支持定位 | true | ||||||
支持自定义WebView | true | ||||||
支持Js通信 | true | 更简洁 | |||||
支持JsBridge | true | ||||||
是否线程安全 | false | true | |||||
star数 | 8.4k | 8k | 835 | 3k | |||
本地html字体大小适配 | |||||||
大厂使用 |
如果更喜欢腾讯X5内核,可用AgentWebX5,该库3年前作者已通知已不再维护
AgentWeb、SuperWeb上一次在两三年前维护
配置
build.gradle
添加依赖。添加ndk
配置1 | android{ |
自行导入os文件(需要从官网下载sdk文件)
sdk接入示例,复制整个jniLibs到自己的项目中(放在与java、res同一级)
AndroidManifest.xml文件中加入
1 | <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> |
使用
初始化X5WebView
,下面方法复制可直接调用,记得在加载WebView之前调用,所以最好是放在打开项目的时候就调用该方法,提前加载X5替换webview配置
1 | /**************腾讯X5webview**************/ |
替换xml中webview
布局为com.tencent.smtt.sdk.WebView
1 | <com.tencent.smtt.sdk.WebView |
java中使用 X5 webview
1 | com.tencent.smtt.sdk.WebView TX_X5_webView;//全局变量 |
初始化腾讯内核在加载webview之后
AndroidManifest配置权限少了
缺少os文件
本地运行没问题,打包出来运行加载X5失败,查看日志发现NoClassDefFoundError:com.tencent.smtt.export.extern
错误,需要加混淆配置
1 | -dontwarn dalvik.** |
网络清单配置没有对tbs开放权限,所以网络请求初始化加载X5被阻止了,因为腾讯都是https请求。安卓7.0版本以上需要配置网络清单
1 | <domain includeSubdomains="true">android.bugly.qq.com</domain> |
将关于腾讯的域名添加到网络清单配置中即可
res
下新建xml
文件夹,文件夹下新建nextwork_security_config.xml
1 | <network-security-config> |
在项目的清单文件AndroidManifest.xml
的<application
中添加
1 | android:networkSecurityConfig="@xml/network_security_config" |
另,可以在测试的时候用省事的写法,把nextwork_security_config.xml
内容写为以下(正式的不要这么写,不安全)
1 | <?xml version="1.0" encoding="utf-8"?> |
其中还可以加其他参数
1 | <base-config cleartextTrafficPermitted="true"> |
system 设备中预装的系统证书
user 用户自装证书
resourceID /raw文件下的证书
使用了以下写法,需去除
1 | import android.*; |
回调是false,但是加载显示webview内容没问题,那可能是版本过低导致X5自动切回了原生webview
添加依赖
1 | repositories { |
或者下载源码拷贝到自己的工程内当类库
提供给JS调用
1 | webView.registerHandler("submitFromWeb", new BridgeHandler(){ |
Js调用Java提供的方法【值要写“submitFromWeb”,这个是Java定的】
1 | WebViewJavascriptBridge.callHandler( |
还有一种简单的没有回调的调用方式:
1 | //Java中提供的方法 |
1 | //Js中的调用方式 |
提供给Java调用
1 | //Js中定义方法 |
1 | //Java调用Handler,与Js的一样 |
同样的,在Js中也可注册默认的Handler,以方便Java调用,通过send方法发送数据
1 | bridge.init(function(message, responseCallback) { |
1 | //Java中调用send方法给js发送消息 |
添加依赖 build.gradle
1 | compile 'com.just.agentweb:agentweb:2.0.0' |
加载网页,以京东首页为例
1 | mAgentWeb = AgentWeb.with(this)//传入Activity |
不用配置 Setting , 不用添加 WebChromeClient 就有进度条 。
安卓调用JavaScript方法
1 | //Javascript 方法 |
JavaScript调用安卓方法
1 | //Android 端 , AndroidInterface 是一个注入类 ,里面有一个无参数方法:callAndroid |
跟随 Activity 或者 Fragment 生命周期 , 释放 CPU和资源, 更省电
1 | @Override |
两者之间的不同之一就是,作用域不同,在manifest.xml
文件中,<uses-permission>
是和<application>
同级的节点,一般<uses-permission >
是在</application>
后面的。但<permission>
就不同了,是定义在<application>
和</application>
之间,和Activity
、Service
同级别的,同时使用group
的权限组可以大幅减少你同类型相似权限的声明。(这段表述有误,应该是同级别)
其二可能就是<uses-permission>
是官方定义的权限,是调用别人的东西的时候自己需要声明的权限,<permission>
是自己定义的权限,就是别人调用这个程序时需要用<uses-permission>
来声明。
1 | public class CustomManager { |