WebView-Android与H5交互、设置cookie、po
2017-12-28 本文已影响11人
喂_balabala
mWbRealize.loadUrl("http://652857502.scene.eqxiu.com/s/vknb0n8W?eqrcode=1&from=singlemessage&isappinstalled=0");
//支持javascript
web.getSettings().setJavaScriptEnabled(true);
// 设置可以支持缩放
web.getSettings().setSupportZoom(true);
// 设置出现缩放工具
web.getSettings().setBuiltInZoomControls(true);
//扩大比例的缩放
web.getSettings().setUseWideViewPort(true);//让webview读取网页设置的viewport,pc版网页
//自适应屏幕
web.getSettings().setLayoutAlgorithm(LayoutAlgorithm.SINGLE_COLUMN);//适应屏幕,内容将自动缩放
webView.getSettings().setLayoutAlgorithm(LayoutAlgorithm.NARROW_COLUMNS);//适应内容大小
web.getSettings().setLoadWithOverviewMode(true);
settings.setDomStorageEnabled(true);//打开DOM储存API
settings.setBlockNetworkImage(true);//拦截图片的加载
web.setInitialScale(25);//为25%,最小缩放等级
// 设置缓存模式:不使用缓存
mWebView.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE);
// 设置启动缓存
webView.getSettings().setDefaultTextEncodingName("utf-8");
webView.getSettings().setAppCacheEnabled(true);
webView.getSettings().setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);
postUrl
//需要访问的网址
String url = "http://www.cqjg.gov.cn/netcar/FindThree.aspx";
//post访问需要提交的参数
String postDate = "txtName=zzz&QueryTypeLst=1&CertificateTxt=dsds";
//由于webView.postUrl(url, postData)中 postData类型为byte[] ,
//通过EncodingUtils.getBytes(data, charset)方法进行转换
webView.postUrl(url, EncodingUtils.getBytes(postDate, "UTF-8"));
EncodingUtils是 HttpCore里面的,要加依赖
compile 'org.apache.httpcomponents:httpcore:4.4.4'
网页只加载出一部分,下面就不加载了?
● I/chromium(27693): [INFO:CONSOLE(8)] “Uncaught TypeError: Cannot call method ‘getItem’ of null”, source: url
网页加载不完成并报出如上错误时,有可能是你的DOM储存API没有打开,在代码中加上一行:
mWebView.getSettings().setDomStorageEnabled(true);
如果希望点击链接由自己处理,而不是新开Android的系统browser中响应该链接。给WebView加一个事件监听对象(WebViewClient)并重写其中的一些方法:shouldOverrideUrlLoading:对网页中超链接按钮的响应。当按下某个连接时WebViewClient会调用这个方法,并传递参数:按下的url。
webView.setWebViewClient(new WebViewClient(){
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url); //在当前的webview中跳转到新的url
//如果不需要其他对点击链接事件的处理返回true,否则返回false
return true;
}
@Override
public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
if (url.startsWith("http") || url.startsWith("https")) { //http和https协议开头的执行正常的流程
return super.shouldInterceptRequest(view, url);
} else { //其他的URL则会开启一个Acitity然后去调用原生APP
if (url.contains("mqqwpa")){
if (OthersUtil.isQQClientAvailable(mContext)){
Intent in = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
startActivity(in);
return null;
}else {
// Toast.makeText(mContext, "您的手机未安装手机QQ", Toast.LENGTH_SHORT).show();
// return super.shouldInterceptRequest(view, url);
return null;
}
}
Intent in = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
startActivity(in);
return null;
}
}
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
// showErrorPage();//显示错误页面
hideErrorPage();
};
public void onPageFinished(WebView view, String url) {//处理网页加载成功时
// loading_over.setVisibility(View.GONE);
// hideErrorPage();
}
//监听webview界面切换
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
super.onPageStarted(view, url, favicon);
if (url.contains("https://www.hzjr.com/Mobile/Index/customer?token=")){
mCloseService.setVisibility(View.GONE);
}
}
});
onReceivedError 不能捕捉失败的回调???
onReceivedError 有两个重载的方法,要重写第二个
1、public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
2、 public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
点击超链接启动QQ
mWebView = (ProgressWebView) findViewById(R.id.baseweb_webview); mWebView.getSettings().setJavaScriptEnabled(true); String url ="http://wpa.qq.com/msgrd?v=3&uin=748895431&site=qq&menu=yes"; mWebView.loadUrl(url); mWebView.setWebViewClient(new WebViewClient() {
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url); return true;
}
@Override public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
if (url.startsWith("http") || url.startsWith("https")) {
//http和https协议开头的执行正常的流程 return super.shouldInterceptRequest(view, url);
} else {
//其他的URL则会开启一个Acitity然后去调用原生APP Intent in = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); startActivity(in); return null;
}
}
});
滑动监听
自定义webview重写onScrollChanged方法,利用接口回调
public class HzjrWebView extends WebView {
private OnScrollChangedCallback mOnScrollChangedCallback;
public HzjrWebView(Context context) {
super(context);
}
public HzjrWebView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public HzjrWebView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onScrollChanged(final int l, final int t, final int oldl,
final int oldt) {
super.onScrollChanged(l, t, oldl, oldt);
if (mOnScrollChangedCallback != null) {
mOnScrollChangedCallback.onScroll(l , oldl, t , oldt);
}
}
// public OnScrollChangedCallback getOnScrollChangedCallback() {
// return mOnScrollChangedCallback;
// }
public void setOnScrollChangedCallback(
final OnScrollChangedCallback onScrollChangedCallback) {
mOnScrollChangedCallback = onScrollChangedCallback;
}
/**
* Impliment in the activity/fragment/view that you want to listen to the webview
*/
public interface OnScrollChangedCallback {
void onScroll(int l,int oldl,int t, int oldt);
}
}
页面关闭之后,视频或者音频还在播放的问题
方法1:
调用
webView.loadUrl("about:blank");
这个方法会 销毁所有的video和audio 包括js的所有正在运行的function
方法2:
@Override
public void onPause() {
super.onPause();
myWebView.onPause();
myWebView.pauseTimers();
}
@Override
public void onResume() {
super.onResume();
myWebView.resumeTimers();
myWebView.onResume();
}
@Override
protected void onDestroy() {
myWebView.destroy();
myWebView = null;
super.onDestroy();
}
复写生命周期的方法;最好的方法;(有时会挂 java.lang.IllegalArgumentException: Receiver not registered: android.widget.ZoomButtonsController$1@3ed4bcc7)
要在销毁之前把根布局的所有子布局remove
mLlH5.removeAllViews();
回退时回到上一个页面,而不是退出WebView
mWebView.goBack(); //后退
mWebView.goForward();//前进
mWebView.reload(); //刷新
public class MainActivity extends Activity {
private WebView webview;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//2、在Activity中实例化WebView
setContentView(R.layout.activity_main);
webview = (WebView) findViewById(R.id.webview);
//第2步也可以替换为下面这两句,就不要R.layout.activity_main布局文件了
//mwebview = new WebView(this); //实例化WebView对象
//setContentView(mwebview);
// 设置WebView属性,能够执行Javascript脚本
webview.getSettings().setJavaScriptEnabled(true);
//3、 加载需要显示的网页
webview.loadUrl("http://www.baidu.com/");
///4、设置响应超链接,在安卓5.0系统,不使用下面语句超链接也是正常的,但在MIUI中安卓4.4.4中需要使用下面这条语句,才能响应超链接
webview.setWebViewClient(new HelloWebViewClient());
}
@Override
// 设置回退
// 5、覆盖Activity类的onKeyDown(int keyCoder,KeyEvent event)方法
public boolean onKeyDown(int keyCode, KeyEvent event) {
//按下返回键并且webview界面可以返回
if ((keyCode == KeyEvent.KEYCODE_BACK) && webview.canGoBack()) {
webview.goBack(); // goBack()表示返回WebView的上一页面
return true;
}
return super.onKeyDown(keyCode,event);
}
// Web视图
private class HelloWebViewClient extends WebViewClient {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
return true;
}
}
}
设置cookie
ATTENTION:
要在webView设置setting之后,loadUrl之前调用此方法,否则无效
关于设置cookie失效的问题,在5.0以下可能会有失效的情况,sync是异步操作。
失效的原因是在removeSessionCookie之后立马setCookie可能会是设置之后又被清除了,可以加个延迟。
在5.0以上官方回调了同步方法。
具体介绍参考博客:https://blog.csdn.net/b275518834/article/details/51004237
/**
* 给WebView同步Cookie
*
* @param context 上下文
* @param url 可以使用[domain][host]
*/
private void syncCookie(Context context, String url) {
CookieSyncManager.createInstance(context);
CookieManager cookieManager = CookieManager.getInstance();
cookieManager.setAcceptCookie(true);
// cookieManager.removeSessionCookie();// 移除旧的[可以省略]
cookieManager.setCookie(url,cookie);
CookieSyncManager.getInstance().sync();// To get instant sync instead of waiting for the timer to trigger, the host can call this.
}
还有权限:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
H5与Android交互
首先最重要最容易忽略的网络权限
public class MainActivity extends AppCompatActivity {
/***************************************************************
* H5和Android通信三种方式
* 1.android主动调用js:javascript:方法名(参数)
* 2.js主动调用Android
* 3.js callback式调用Android,来源(解耦H5只关心H5,客户端只关心android)
* ***************************************************************
*/
private WebView mWebview;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
//设置webview
WebSettings settings = mWebview.getSettings();
settings.setJavaScriptEnabled(true);
//页面加载完成调用js方法
//重新浏览器内核对象
initWebClient();
//js和Android两种不同开发语言,不认识
//核心方法:设置js和Android通信桥梁接口(简而言之,就是设置通信桥梁类)
JavascriptMethos jsMethos = new JavascriptMethos(this, mWebview);
//参数1:提供给js调用的方法的对象, 参数2:参数1的映射字符串(第一个参数的别名),因为字符串再所有开发一样通用
mWebview.addJavascriptInterface(jsMethos, JavascriptMethos.JSINTERFACE);
//显示
mWebview.loadUrl("http:/10.0.3.2:8080/html35/index.html");
}
private void initWebClient() {
mWebview.setWebChromeClient(new WebChromeClient());
mWebview.setWebViewClient(new WebViewClient() {
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
super.onPageStarted(view, url, favicon);
}
//页面加载完成调用该方法
@Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
//调用js 方法
//WebView.loadUrl("javascript:方法名(参数)")
JSONObject json = new JSONObject();
try {
json.put("name", "android");
json.put("msg", "你好,我是Android,加个蚝友");
mWebview.loadUrl("javascript:receiveMessage("+json.toString()+")");
} catch (JSONException e) {
e.printStackTrace();
}
}
});
}
private void initView() {
mWebview = (WebView) findViewById(R.id.webview);
}
}
/**
* 统一管理所有js和Android通信
*
*/
public class JavascriptMethos {
public static String JSINTERFACE = "jsInterface";
private Context mContext;
private WebView mWebView;
public JavascriptMethos(Context mContext, WebView mWebView) {
this.mContext = mContext;
this.mWebView = mWebView;
}
/**
* 给js调用的弹出toast方法
* 为什么要添加注解:android4.2以上(包含),如果不加注解,
* js无法调用Android方法,因为4.2之前js和android通信有安全问题,如果不加上该注解,4.2以上js无法调用Android方法
*
* @param json
*/
@JavascriptInterface
public void showToast(String json) {
Toast.makeText(mContext, json, Toast.LENGTH_SHORT).show();
}
@JavascriptInterface
public void getHotelData(String json) throws JSONException {
//解析callbak方法名
JSONObject jsJson = new JSONObject(json);
final String callback = jsJson.optString("callback");
System.out.println("接收到js传递callback参数=" + json);
//模拟访问网络
//返回json
final JSONObject callbackJson = new JSONObject();
try {
callbackJson.put("name", "8天连锁酒店");
callbackJson.put("hotel", "99");
callbackJson.put("phone", "075588888888");
//调用js方法
//mWebView.loadUrl("javascript:方法名(参数)");默认Android调用js独立运行在一个进程WebViewCoreThread
mHandler.post(new Runnable() {
@Override
public void run() {
//mWebView.loadUrl("javascript:receiveHotelData(" + callbackJson.toString() + ")");
mWebView.loadUrl("javascript:"+callback+"(" + callbackJson.toString() + ")");
}
});
} catch (JSONException e) {
e.printStackTrace();
}
}
private Handler mHandler = new Handler();
}
demo
https://github.com/jiaweizeng/H5AndAndroid
control是java对象名称,toastMessage是方法名称,双方约定俗成,写死。
<body>
<button type="button" id="button" onclick="toastMessage('js调用了android方法')">js访问android中方法</button>
<script>
function toastMessage(message) {
window.control.toastMessage(message)
}
</script>
</body>
public class MainActivity extends AppCompatActivity {
@SuppressLint({"JavascriptInterface", "AddJavascriptInterface", "SetJavaScriptEnabled"})
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
WebView webView = findViewById(R.id.wv);
WebSettings webSettings = webView.getSettings();
webSettings.setJavaScriptEnabled(true);
webSettings.setJavaScriptCanOpenWindowsAutomatically(true);
webView.loadUrl("http://192.168.1.38/hzjrH5/jiaohu.html");
//js访问android,定义接口
webView.addJavascriptInterface(this, "control");
}
@JavascriptInterface
public void toastMessage(String s){
Toast.makeText(MainActivity.this, s, Toast.LENGTH_LONG).show();
finish();
}
}