Android 的 Webview 在低版本和高版本采用了不同的webkit版本内核,4.4后直接使用了Chrome。
简单的加载 WebView 界面:
· 带有Http请求头的
loadUrl(String url,Mapadditional HttpHeaders)
· 不带Http请求头的
loadUrl(String url)
· 常用属性:
· clearHistory():清除当前webview访问的历史记录。
· reload():重新reload当前的URL,即刷新。常见用法:Back键控制网页后退问题:在不做任何处理前提下 ,浏览网页时点击系统的“Back”键,整个 Browser 会调用 finish()而结束自身 目标:点击返回后,是网页回退而不是推出浏览器
· getScrollY():该方法返回的当前可见区域的顶端距整个页面顶端的距离,也就是当前内容滚动的距离。
· getHeight():方法都返回当前WebView这个容器的高度。其实以上两个方法都属于View。
· getContentHeight():该方法返回整个HTML页面的高度,但该高度值并不等同于当前整个页面的高度,因为WebView有缩放功能, 所以当前整个页面的高度实际上应该是原始HTML的高度再乘上缩放比例。因此,准确的判断方法应该是
if (webView.getContentHeight() * webView.getScale() == (webView.getHeight() + webView.getScrollY())) {
//已经处于底端
}
if(webView.getScrollY() == 0){
//处于顶端
}
pageUp(boolean top):将WebView展示的页面滑动至顶部。
pageDown(boolean bottom):将WebView展示的页面滑动至底部。
解决方案:在当前Activity中处理并消费掉该 Back 事件
public boolean onKeyDown(int keyCode, KeyEvent event) {
if ((keyCode == KEYCODE_BACK) && mWebView.canGoBack()) {
mWebView.goBack();
return true;
}
return super.onKeyDown(keyCode, event);
}
· 清除网页缓存和 Cookie
CookieSyncManager cookieSyncManager = CookieSyncManager.createInstance(getApplicationContext());
CookieManager cookieManager = CookieManager.getInstance();
cookieManager.setAcceptCookie(true);
cookieManager.removeSessionCookie();
cookieManager.removeAllCookie();
cookieSyncManager.sync();
WebSettings
作用:对 WebView 进行的管理
WebSettings webSettings = webView.getSettings();
· 属性
WebSettings webSettings = webView.getSettings();
//如果访问的页面中要与Javascript交互,则webview必须设置支持Javascript
webSettings.setJavaScriptEnabled(true);
// 若加载的 html 里有JS 在执行动画等操作,会造成资源浪费(CPU、电量)
// 在 onStop 和 onResume 里分别把 setJavaScriptEnabled() 给设置成 false 和 true 即可
webSettings.setPluginsEnabled(true);//设置自适应屏幕,两者合用
webSettings.setUseWideViewPort(true); //将图片调整到适合webview的大小
webSettings.setLoadWithOverviewMode(true); // 缩放至屏幕的大小
//缩放操作
webSettings.setSupportZoom(true); //支持缩放,默认为true。是下面那个的前提。
webSettings.setBuiltInZoomControls(true); //设置内置的缩放控件。若为false,则该WebView不可缩放
webSettings.setDisplayZoomControls(false); //隐藏原生的缩放控件
//其他细节操作
webSettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK); //关闭webview中缓存
webSettings.setAllowFileAccess(true); //设置可以访问文件
webSettings.setJavaScriptCanOpenWindowsAutomatically(true); //支持通过JS打开新窗口
webSettings.setLoadsImagesAutomatically(true); //支持自动加载图片
webSettings.setDefaultTextEncodingName("utf-8");//设置编码格式
· 获取WebView的标题
WebChromeClient wvcc = new WebChromeClient() {
@Override
public void onReceivedTitle(WebView view, String title) {
super.onReceivedTitle(view, title);
setTitle(title);
}
};
webView.setWebChromeClient(wvcc);
· 防止 webview 跳转到系统浏览器
webView.setWebViewClient(new WebViewClient() {
@Override
public boolean shouldOverrideUrlLoading(WebView view,
String url) {
//返回值是true的时候控制去WebView打开,为false调用系统浏览器或第三方浏览器
view.loadUrl(url);
return true;
}
});
· 当 webview 加载完成之后
webview.setWebViewClient(new WebViewClient() {
@Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
//自定义操作
}
});
· 开启Js
webview.addJavascriptInterface(newgetPayJson()); //方法名 (和后台沟通写一致的)
· 如果对 js 的返回的东西进行修改那么:
onJsAlert: 修改js弹框 (由网页的弹窗修改为原生和自定义的dialog)
onJsConfirm:处理confirm弹出框
onJsPrompt:处理prompt弹出框
详细代码:
@Override
public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
final AlertDialog.Builder builder = new AlertDialog.Builder(view.getContext());
builder.setTitle("提示").setMessage(message).setPositiveButton("确定", null);
// 不需要绑定按键事件
// 屏蔽keycode等于84之类的按键
builder.setOnKeyListener(new OnKeyListener() {
public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
Log.v("onJsAlert", "keyCode==" + keyCode + "event=" + event);
return true;
}
});
// 禁止响应按back键的事件
builder.setCancelable(false);
AlertDialog dialog = builder.create();
dialog.show();
result.confirm();// 因为没有绑定事件,需要强行confirm,否则页面会变黑显示不了内容。
return true;
}
@Override
public boolean onJsConfirm(WebView view, String url, String message, final JsResult result) {
final AlertDialog.Builder builder = new AlertDialog.Builder(view.getContext());
builder.setTitle("提示").setMessage(message).setPositiveButton("确定", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
result.confirm();
}
}).setNeutralButton("取消", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
result.cancel();
}
});
builder.setOnCancelListener(new DialogInterface.OnCancelListener() {
@Override
public void onCancel(DialogInterface dialog) {
result.cancel();
}
});
// 屏蔽keycode等于84之类的按键,避免按键后导致提示消息而页面无法再弹出提示的问题
builder.setOnKeyListener(new OnKeyListener() {
@Override
public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
Log.v("onJsConfirm", "keyCode==" + keyCode + "event=" + event);
return true;
}
});
// 禁止响应按back键的事件
// builder.setCancelable(false);
AlertDialog dialog = builder.create();
dialog.show();
return true;
}
@Override
public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, final JsPromptResult result) {
final AlertDialog.Builder builder = new AlertDialog.Builder(view.getContext());
builder.setTitle("提示").setMessage(message);
final EditText et = new EditText(view.getContext());
et.setSingleLine();
et.setText(defaultValue);
builder.setView(et).setPositiveButton("确定", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
result.confirm(et.getText().toString());
}
})
.setNeutralButton("取消", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
result.cancel();
}
});
// 屏蔽keycode等于84之类的按键,避免按键后导致提示消息而页面无法再弹出提示的问题
builder.setOnKeyListener(new OnKeyListener() {
public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
Log.v("onJsPrompt", "keyCode==" + keyCode + "event=" + event);
return true;
}
});
AlertDialog dialog = builder.create();
dialog.show();
return true;
}
};
最后贴上这个类的全部代码:带有微信支付宝银联支付
import android.annotation.SuppressLint;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.text.TextUtils;
import android.util.Log;
import android.view.KeyEvent;
import android.webkit.JavascriptInterface;
import android.webkit.JsPromptResult;
import android.webkit.JsResult;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.app.AlertDialog;
import com.alipay.sdk.app.PayTask;
import com.orhanobut.logger.Logger;
import com.tencent.mm.sdk.modelpay.PayReq;
import com.unionpay.UPPayAssistEx;
import com.unionpay.uppay.PayActivity;
import android.content.DialogInterface.OnKeyListener;
import android.widget.EditText;
import org.json.JSONException;
import org.json.JSONObject;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;
import sdy.com.longjiangtravel.R;
import sdy.com.longjiangtravel.app.MyApplication;
import sdy.com.longjiangtravel.http.api.UrlApi;
import sdy.com.longjiangtravel.http.json.JSONObjectEx;
import sdy.com.longjiangtravel.pay.PayResult;
import sdy.com.longjiangtravel.utils.AlertView.AlertView;
import sdy.com.longjiangtravel.utils.AlertView.OnItemClickListener;
import sdy.com.longjiangtravel.utils.AndroidDes3Util;
import sdy.com.longjiangtravel.utils.GetToast;
import static android.view.KeyEvent.KEYCODE_BACK;
/**
* Created by admin on 2017/5/2.
*/
public class WebYunkanDetialActivity extends AppCompatActivity {
private WebView seckill_webview;
private Map<String, String> extraHeaders;
private static final int SDK_PAY_FLAG = 1;
private static final int SDK_AUTH_FLAG = 2;
private String head_title = "";
private String backurl;
public static OnR onR;
private static final String R_SUCCESS = "success";
private static final String R_FAIL = "fail";
private static final String R_CANCEL = "cancel";
@SuppressLint("HandlerLeak")
private Handler mHandler = new Handler() {
@SuppressWarnings("unused")
public void handleMessage(Message msg) {
switch (msg.what) {
case SDK_PAY_FLAG: {
@SuppressWarnings("unchecked")
PayResult payResult = new PayResult((Map<String, String>) msg.obj);
String resultInfo = payResult.getResult();
String resultStatus = payResult.getResultStatus();
if (TextUtils.equals(resultStatus, "9000")) {
new AlertView("提示", "支付成功", "确定", null, null, WebYunkanDetialActivity.this, AlertView.Style.Alert, new OnItemClickListener() {
@Override
public void onItemClick(Object o, int position) {
if (position == -1) finish();
}
}).show();
Intent intent = new Intent(getApplicationContext(), MyOrderActivity.class);
Bundle bundle = new Bundle();
bundle.putString("tab", "0");
intent.putExtra("data", bundle);
startActivity(intent);
} else {
new AlertView("提示", "取消支付", "确定", null, null, WebYunkanDetialActivity.this, AlertView.Style.Alert, null).show();
Intent intent = new Intent(getApplicationContext(), MyOrderActivity.class);
Bundle bundle = new Bundle();
bundle.putString("tab", "0");
intent.putExtra("data", bundle);
startActivity(intent);
}
break;
}
case SDK_AUTH_FLAG: {
}
default:
break;
}
}
};
public static final String LOG_TAG = "PayDemo";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_news);
seckill_webview = (WebView) findViewById(R.id.webview);
load();
onR = new OnR() {
@Override
public void onR() {
load();
}
};
}
private void initView() throws Exception {
seckill_webview.loadUrl(backurl, extraHeaders);
seckill_webview.addJavascriptInterface(new getPayJson(), "honorsoft");
seckill_webview.setWebViewClient(new WebViewClient() {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
// TODO Auto-generated method stub
//返回值是true的时候控制去WebView打开,为false调用系统浏览器或第三方浏览器
view.loadUrl(url);
return true;
}
});
}
public boolean onKeyDown(int keyCode, KeyEvent event) {
if ((keyCode == KEYCODE_BACK)) {
if (head_title.equals("龙江游详情")) {
WebYunkanDetialActivity.this.finish();
} else if (head_title.equals("龙美收银台")) {
Intent intent = new Intent(WebYunkanDetialActivity.this, MyOrderActivity.class);
Bundle bundle = new Bundle();
bundle.putString("tab", "1");
intent.putExtra("data", bundle);
startActivity(intent);
WebYunkanDetialActivity.this.finish();
} else {
//重新刷机界面(如果没有加载出来数据)
load();
}
return true;
}
return super.onKeyDown(keyCode, event);
}
public class getPayJson {
@JavascriptInterface
public void getPayJson(String type, String json) throws JSONException {
Log.d("xzw", "++++++++++++++" + json);
Log.d("xzw", "+---------++++" + type);
if (type.equals("alipay")) {
payV2(json);
} else if (type.equals("wxpay")) {
JSONObject jsonObject = new JSONObject(json);
PayReq request = new PayReq();
request.appId = jsonObject.getString("appid");
request.partnerId = jsonObject.getString("partnerid");
request.prepayId = jsonObject.getString("prepayid");
request.packageValue = jsonObject.getString("package");
request.nonceStr = jsonObject.getString("noncestr");
request.timeStamp = jsonObject.getString("timestamp");
request.sign = jsonObject.getString("sign");
MyApplication.api.sendReq(request);
Intent intent = new Intent(getApplicationContext(), MyOrderActivity.class);
Bundle bundle = new Bundle();
bundle.putString("tab", "0");
intent.putExtra("data", bundle);
startActivity(intent);
} else if (type.equals("unionpay")) {
if (type.equals(null)) {
} else {
JSONObjectEx jsonObject = new JSONObjectEx(json);
String tn = jsonObject.getString("tn");
String serverMode = "00";
UPPayAssistEx.startPayByJAR(WebYunkanDetialActivity.this, PayActivity.class, null, null, tn, serverMode);
}
}
}
@JavascriptInterface
//添加购物车成功:
public void ljyCartSuccess() {
if (!MyApplication.P2PPreferences.getUid().equals("")) {
Log.d("添加购物车成功", "++++++++++=+++==++++");
Intent intent = new Intent(WebYunkanDetialActivity.this, ShoppingCarActivity.class);
startActivity(intent);
} else {
GetToast.useString(WebYunkanDetialActivity.this, "请先登录");
Intent intent = new Intent(WebYunkanDetialActivity.this, LoginActivity.class);
startActivity(intent);
}
}
@JavascriptInterface
public void ljyCartFail(String message) {
// GetToast.useString(WebYunkanDetialActivity.this, message);
if (!MyApplication.P2PPreferences.getUid().equals("")) {
Log.d("加入购物车失败", "-----------------------");
GetToast.useString(WebYunkanDetialActivity.this, message);
} else {
GetToast.useString(WebYunkanDetialActivity.this, "请先登录");
Intent intent = new Intent(WebYunkanDetialActivity.this, LoginActivity.class);
startActivity(intent);
}
}
@JavascriptInterface
public void dotel(String tel) {
// GetToast.useString(WebYunkanDetialActivity.this, tel);
Intent intent = new Intent();
intent.setAction(Intent.ACTION_DIAL);
Uri uri = Uri.parse("tel:" + tel);
intent.setData(uri);
startActivity(intent);
}
@JavascriptInterface
public void login() {
GetToast.useString(WebYunkanDetialActivity.this, "请先登录");
Intent intent = new Intent(WebYunkanDetialActivity.this, LoginActivity.class);
startActivity(intent);
}
//返回
@JavascriptInterface
public void ljyDetailBack() {
WebYunkanDetialActivity.this.finish();
}
//订单相关页面回退地址:
@JavascriptInterface
public void backUrl(String url) {
backurl = url;
Log.d("WebYunkanDetialActivity", "url======" + backurl);
}
//支付回退:
@JavascriptInterface
public void payGoBack() {
Log.d("WebYunkanDetialActivity", "======");
Intent intent = new Intent(WebYunkanDetialActivity.this, MyOrderActivity.class);
Bundle bundle = new Bundle();
bundle.putString("tab", "1");
intent.putExtra("data", bundle);
startActivity(intent);
WebYunkanDetialActivity.this.finish();
}
}
public void payV2(final String orderInfoJson) {
Runnable payRunnable = new Runnable() {
@Override
public void run() {
PayTask alipay = new PayTask(WebYunkanDetialActivity.this);
String orderInfo = orderInfoJson;
Map<String, String> result = alipay.payV2(orderInfo, true);
Log.i("msp", result.toString());
Message msg = new Message();
msg.what = SDK_PAY_FLAG;
msg.obj = result;
mHandler.sendMessage(msg);
}
};
Thread payThread = new Thread(payRunnable);
payThread.start();
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (data == null) {
return;
}
String str = data.getExtras().getString("pay_result");
if (str.equalsIgnoreCase(R_SUCCESS)) {
GetToast.useid(WebYunkanDetialActivity.this, R.string.pay_success);
Intent intent = new Intent(getApplicationContext(), MyOrderActivity.class);
Bundle bundle = new Bundle();
bundle.putString("tab", "0");
intent.putExtra("data", bundle);
startActivity(intent);
} else if (str.equalsIgnoreCase(R_FAIL)) {
GetToast.useid(WebYunkanDetialActivity.this, R.string.pay_fail);
Intent intent = new Intent(getApplicationContext(), MyOrderActivity.class);
Bundle bundle = new Bundle();
bundle.putString("tab", "0");
intent.putExtra("data", bundle);
startActivity(intent);
} else if (str.equalsIgnoreCase(R_CANCEL)) {
GetToast.useid(WebYunkanDetialActivity.this, R.string.pay_cancel);
}
}
public interface OnR {
public void onR();
}
private void load() {
try {
final String str = URLEncoder.encode(AndroidDes3Util.encode(MyApplication.P2PPreferences.getUid()), "UTF-8");
backurl = UrlApi.ip_js + "Order/ljyDetail?" + "row_id=" + getIntent().getStringExtra("scenicid") + "&user_id_crypt=" + str + "&mode=AES";
WebSettings setting = seckill_webview.getSettings();
setting.setJavaScriptEnabled(true);
WebChromeClient wvcc = new WebChromeClient() {
@Override
public void onReceivedTitle(WebView view, String title) {
super.onReceivedTitle(view, title);
head_title = title;
}
@Override
public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
final AlertDialog.Builder builder = new AlertDialog.Builder(view.getContext());
builder.setTitle("提示").setMessage(message).setPositiveButton("确定", null);
// 不需要绑定按键事件
// 屏蔽keycode等于84之类的按键
builder.setOnKeyListener(new OnKeyListener() {
public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
Log.v("onJsAlert", "keyCode==" + keyCode + "event=" + event);
return true;
}
});
// 禁止响应按back键的事件
builder.setCancelable(false);
AlertDialog dialog = builder.create();
dialog.show();
result.confirm();// 因为没有绑定事件,需要强行confirm,否则页面会变黑显示不了内容。
return true;
}
@Override
public boolean onJsConfirm(WebView view, String url, String message, final JsResult result) {
final AlertDialog.Builder builder = new AlertDialog.Builder(view.getContext());
builder.setTitle("提示").setMessage(message).setPositiveButton("确定", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
result.confirm();
}
}).setNeutralButton("取消", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
result.cancel();
}
});
builder.setOnCancelListener(new DialogInterface.OnCancelListener() {
@Override
public void onCancel(DialogInterface dialog) {
result.cancel();
}
});
// 屏蔽keycode等于84之类的按键,避免按键后导致提示消息而页面无法再弹出提示的问题
builder.setOnKeyListener(new OnKeyListener() {
@Override
public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
Log.v("onJsConfirm", "keyCode==" + keyCode + "event=" + event);
return true;
}
});
// 禁止响应按back键的事件
// builder.setCancelable(false);
AlertDialog dialog = builder.create();
dialog.show();
return true;
}
@Override
public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, final JsPromptResult result) {
final AlertDialog.Builder builder = new AlertDialog.Builder(view.getContext());
builder.setTitle("提示").setMessage(message);
final EditText et = new EditText(view.getContext());
et.setSingleLine();
et.setText(defaultValue);
builder.setView(et).setPositiveButton("确定", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
result.confirm(et.getText().toString());
}
})
.setNeutralButton("取消", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
result.cancel();
}
});
// 屏蔽keycode等于84之类的按键,避免按键后导致提示消息而页面无法再弹出提示的问题
builder.setOnKeyListener(new OnKeyListener() {
public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
Log.v("onJsPrompt", "keyCode==" + keyCode + "event=" + event);
return true;
}
});
AlertDialog dialog = builder.create();
dialog.show();
return true;
}
};
seckill_webview.setWebChromeClient(wvcc);
extraHeaders = new HashMap<String, String>();
extraHeaders.put("Honorsoft-App", "true");
} catch (Exception e) {
e.printStackTrace();
}
try {
initView();
} catch (Exception e) {
e.printStackTrace();
}
}
}