一菩掏、android WebView 替換方案
1.騰訊X5(推薦)X5內(nèi)核下載地址
2.Crosswalk(包會打10--20mb
可能導(dǎo)致第三方APP無法開啟X5內(nèi)核的情況)
二璃岳、TBS(騰訊瀏覽服務(wù))的優(yōu)勢
速度快:相比系統(tǒng)webview的網(wǎng)頁打開速度有30+%的提升挚赊;
省流量:使用云端優(yōu)化技術(shù)使流量節(jié)省20+%;
更安全:安全問題可以在24小時(shí)內(nèi)修復(fù)逃沿;
更穩(wěn)定:經(jīng)過億級用戶的使用考驗(yàn),CRASH率低于0.15%;
兼容好:無系統(tǒng)內(nèi)核的碎片化問題疲迂,更少的兼容性問題才顿;
體驗(yàn)優(yōu):支持夜間模式、適屏排版尤蒿、字體設(shè)置等瀏覽增強(qiáng)功能郑气;
功能全:在Html5、ES6上有更完整支持腰池;
更強(qiáng)大:集成強(qiáng)大的視頻播放器竣贪,支持視頻格式遠(yuǎn)多于系統(tǒng)webview;
視頻和文件格式的支持x5內(nèi)核多于系統(tǒng)內(nèi)核
防劫持是x5內(nèi)核的一大亮點(diǎn)
三巩螃、騰訊X5內(nèi)核的使用
1 首先我們按照官方文檔集成 SDK演怎,下載jar包,以及配置權(quán)限避乏! 在application里面進(jìn)行初始化爷耀。
具體例子看官方demo,已經(jīng)很詳細(xì)了
騰訊 X5官網(wǎng) http://x5.tencent.com/tbs/
2 MainActivity
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Set layout
getWindow().setFormat(PixelFormat.TRANSLUCENT);
setContentView(R.layout.activity_main);
mWebView = (com.tencent.smtt.sdk.WebView) findViewById(R.id.forum_context);
mWebView.getSettings().setJavaScriptEnabled(true);// 支持js
mWebView.getSettings().setUseWideViewPort(true); //自適應(yīng)屏幕
mWebView.loadUrl("http://res.ky-express.com/h5/video/72.html");
}
3 activity_main
<com.tencent.smtt.sdk.WebView
android:id="@+id/forum_context"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:paddingLeft="5dp"
android:paddingRight="5dp"/>
四拍皮、一些注意的問題
1 多個(gè).So庫的問題
要把對應(yīng)的so包導(dǎo)入歹叮。如果你的項(xiàng)目當(dāng)中也用到了其他的.so庫,這時(shí)你不僅要分包導(dǎo)入铆帽。so庫咆耿,同時(shí)還要在gradle里面進(jìn)行配置!
ndk {
abiFilters"armeabi","armeabi-v7a","x86","mips"
}
2 關(guān)于首期啟動加載X5內(nèi)核會出現(xiàn)過慢的問題
可以考慮用線程加載或者服務(wù)加載
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
initX5();
preinitX5WebCore();
}
private void initX5() {
QbSdk.initX5Environment(getApplicationContext(), QbSdk.WebviewInitType.FIRSTUSE_AND_PRELOAD, cb);
Log.d("gggbbb","預(yù)加載中...");
}
QbSdk.PreInitCallback cb = new QbSdk.PreInitCallback() {
@Override
public void onViewInitFinished(boolean arg0) {
// TODO Auto-generated method stub
Log.e("0912", " onViewInitFinished is " + arg0);
}
@Override
public void onCoreInitFinished() {
// TODO Auto-generated method stub
}
};
private void preinitX5WebCore() {
if(!QbSdk.isTbsCoreInited()) {
// preinit只需要調(diào)用一次爹橱,如果已經(jīng)完成了初始化萨螺,那么就直接構(gòu)造view
QbSdk.preInit(MainActivity.this, null);// 設(shè)置X5初始化完成的回調(diào)接口
}
}
Application代碼
@Override
public void onCreate() {
super.onCreate();
initX5();
}
private void initX5() {
Intent intent = new Intent(this, PreLoadX5Service.class);
startService(intent);
}
3 我們會發(fā)現(xiàn)集成X5后,項(xiàng)目編譯變慢了,可以在build.config里面加上下面這段代碼試試
dexOptions {
javaMaxHeapSize "4g"
preDexLibraries = false
}
4 視頻全屏的時(shí)候有個(gè)qq瀏覽器的推廣的去掉
設(shè)置布局改變的監(jiān)聽:
getWindow().getDecorView().addOnLayoutChangeListener()
監(jiān)聽里面通過 getWindow().getDecorView() 的 findViewsWithText() 方法可以拿到顯示推廣文案的 TextView愧驱,把拿到的 view 設(shè)置為 GONE 狀態(tài)就可以去掉了慰技。
五、webview與x5的測試對比
1组砚、一個(gè)鏈接的第一次的加載webview會比x5速度快一點(diǎn)吻商。
2、如果重復(fù)點(diǎn)擊一個(gè)鏈接糟红,來回切換艾帐,只要次數(shù)足夠多,X5速度會比webview快盆偿。
3柒爸、如果點(diǎn)擊不同鏈接,并且次數(shù)不是很多陈肛,webview會比x5速度快揍鸟。
另外補(bǔ)充一下webview的基本常識
關(guān)于webview的加載
//打開本包內(nèi)asset目錄下的index.html文件
wView.loadUrl(" file:///android_asset/index.html ");
//打開本地sd卡內(nèi)的index.html文件
wView.loadUrl("content://com.android.htmlfileprovider/sdcard/index.html");
//打開指定URL的html文件
wView.loadUrl(" http://m.oschina.net");
關(guān)于js 調(diào)用 native
有三種方式
- 第一種方式:通過 addJavascriptInterface 方法進(jìn)行添加對象映射
mWebView.getSettings().setJavaScriptEnabled(true);
這個(gè)函數(shù)會有一個(gè)警告,因?yàn)樵谔囟ǖ陌姹局聲蟹浅NkU(xiǎn)的漏洞,設(shè)置完這個(gè)屬性之后阳藻,Native 需要定義一個(gè)類:
public class JSObject {
private Context mContext;
public JSObject(Context context) {
mContext = context;
}
@JavascriptInterface
public String showToast(String text) {
Toast.show(mContext, text, Toast.LENGTH_SHORT).show();
return "success";
}
}
...
需要注意的是在 API17 版本之后晰奖,需要在被調(diào)用的地方加上 @addJavascriptInterface 約束注解,因?yàn)椴患由献⒔獾姆椒ㄊ菦]有辦法被調(diào)用的腥泥,JS 代碼也很簡單:
function showToast(){
var result = myObj.showToast("我是來自web的Toast");
}
- 第二種方式:利用 WebViewClient 接口回調(diào)方法攔截 url
需要使用WebViewClient 中 shouldOverrideUrlLoading (WebView view, WebResourceRequest request) 利用這個(gè)攔截 url匾南,然后解析這個(gè) url 的協(xié)議,如果發(fā)現(xiàn)是我們預(yù)先約定好的協(xié)議就開始解析參數(shù)蛔外,執(zhí)行相應(yīng)的邏輯蛆楞。
public boolean shouldOverrideUrlLoading(WebView view, String url) {
//假定傳入進(jìn)來的 url = "js://openActivity?arg1=111&arg2=222",代表需要打開本地頁面夹厌,并且?guī)胂鄳?yīng)的參數(shù)
Uri uri = Uri.parse(url);
String scheme = uri.getScheme();
//如果 scheme 為 js豹爹,代表為預(yù)先約定的 js 協(xié)議
if (scheme.equals("js")) {
//如果 authority 為 openActivity,代表 web 需要打開一個(gè)本地的頁面
if (uri.getAuthority().equals("openActivity")) {
//解析 web 頁面帶過來的相關(guān)參數(shù)
HashMap<String, String> params = new HashMap<>();
Set<String> collection = uri.getQueryParameterNames();
for (String name : collection) {
params.put(name, uri.getQueryParameter(name));
}
Intent intent = new Intent(getContext(), MainActivity.class);
intent.putExtra("params", params);
getContext().startActivity(intent);
}
//代表應(yīng)用內(nèi)部處理完成
return true;
}
return super.shouldOverrideUrlLoading(view, url);
}
我們看一下 JS 的代碼
function openActivity(){
document.location = "js://openActivity?arg1=111&arg2=222";
}
這個(gè)代碼執(zhí)行之后矛纹,就會觸發(fā)本地的 shouldOverrideUrlLoading 方法臂聋,然后進(jìn)行參數(shù)解析,調(diào)用指定方法或南。這個(gè)方式不會存在第一種提到的漏洞問題孩等,但是它也有一個(gè)很繁瑣的地方是,如果 web 端想要得到方法的返回值采够,只能通過 WebView 的 loadUrl 方法去執(zhí)行 JS 方法把返回值傳遞回去肄方,相關(guān)的代碼如下:
//java
mWebView.loadUrl("javascript:returnResult(" + result + ")");
//javascript
function returnResult(result){
alert("result is" + result);
}
所以說第二種方式在返回值方面還是很繁瑣的,但是在不需要返回值的情況下蹬癌,比如打開 Native 頁面权她,還是很合適的,制定好相應(yīng)的協(xié)議冀瓦,就能夠讓 web 端具有打開所有本地頁面的能力了伴奥。
- 第三種方式:利用 WebChromeClient 回調(diào)接口的三個(gè)方法攔截消息
這個(gè)方法的原理和第二種方式原理一樣写烤,都是攔截相關(guān)接口翼闽,只是攔截的接口不一樣:
@Override
public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
return super.onJsAlert(view, url, message, result);
}
@Override
public boolean onJsConfirm(WebView view, String url, String message, JsResult result) {
return super.onJsConfirm(view, url, message, result);
}
@Override
public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {
//假定傳入進(jìn)來的 message = "js://openActivity?arg1=111&arg2=222",代表需要打開本地頁面洲炊,并且?guī)胂鄳?yīng)的參數(shù)
Uri uri = Uri.parse(message);
String scheme = uri.getScheme();
if (scheme.equals("js")) {
if (uri.getAuthority().equals("openActivity")) {
HashMap<String, String> params = new HashMap<>();
Set<String> collection = uri.getQueryParameterNames();
for (String name : collection) {
params.put(name, uri.getQueryParameter(name));
}
Intent intent = new Intent(getContext(), MainActivity.class);
intent.putExtra("params", params);
getContext().startActivity(intent);
//代表應(yīng)用內(nèi)部處理完成
result.confirm("success");
}
return true;
}
return super.onJsPrompt(view, url, message, defaultValue, result);
}
onJsAlert 方法是彈出警告框感局,一般情況下在 Android 中為 Toast,在文本里面加入\n就可以換行暂衡。onJsConfirm 彈出確認(rèn)框询微,會返回布爾值,通過這個(gè)值可以判斷點(diǎn)擊時(shí)確認(rèn)還是取消狂巢,true表示點(diǎn)擊了確認(rèn)撑毛,false表示點(diǎn)擊了取消。onJsPrompt 彈出輸入框唧领,點(diǎn)擊確認(rèn)返回輸入框中的值藻雌,點(diǎn)擊取消返回 null雌续。
關(guān)于native 調(diào)用 js
//java
mWebView.loadUrl("javascript:show(" + result + ")");
//javascript
<script type="text/javascript">
function show(result){
alert("result"=result);
return "success";
}
</script>
已知的 WebView 任意代碼執(zhí)行漏洞有 4 個(gè):
- 針對某些特定機(jī)型會存在 addJavascriptInterface API 引起的遠(yuǎn)程代碼執(zhí)行漏洞
- WebView 中內(nèi)置導(dǎo)出的 “searchBoxJavaBridge_” Java Object 可能被利用,實(shí)現(xiàn)遠(yuǎn)程任意代碼胯杭。
- WebView 內(nèi)置導(dǎo)出 “accessibility” 和 “accessibilityTraversal” 兩個(gè) Java Object 接口驯杜,可被利用實(shí)現(xiàn)遠(yuǎn)程任意代碼執(zhí)行鸽心。
判斷WebView是否已經(jīng)滾動到頁面底端 或者 頂端:
getScrollY() //方法返回的是當(dāng)前可見區(qū)域的頂端距整個(gè)頁面頂端的距離,也就是當(dāng)前內(nèi)容滾動的距離.
getHeight()或者getBottom() //方法都返回當(dāng)前WebView這個(gè)容器的高度
getContentHeight()返回的是整個(gè)html的高度,但并不等同于當(dāng)前整個(gè)頁面的高度,因?yàn)閃ebView有縮放功能,所以當(dāng)前整個(gè)頁面的高度實(shí)際上應(yīng)該是原始html的高度再乘上縮放比例.因此,更正后的結(jié)果,準(zhǔn)確的判斷方法應(yīng)該是:
if (webView.getContentHeight() * webView.getScale() == (webView.getHeight() + webView.getScrollY())) {
//已經(jīng)處于底端
}
if(webView.getScrollY() == 0){
//處于頂端
}
前進(jìn)、后退
goBack()//后退
goForward()//前進(jìn)
goBackOrForward(intsteps) //以當(dāng)前的index為起始點(diǎn)前進(jìn)或者后退到歷史記錄中指定的steps居暖,
如果steps為負(fù)數(shù)則為后退,正數(shù)則為前進(jìn)
canGoForward()//是否可以前進(jìn)
canGoBack() //是否可以后退
返回鍵:返回上一次瀏覽的頁面
public boolean onKeyDown(int keyCode, KeyEvent event) {
if ((keyCode == KeyEvent.KEYCODE_BACK) && mWebView.canGoBack()) {
mWebView.goBack();
return true;
}
return super.onKeyDown(keyCode, event);
}
在 WebView 中長按保存圖片
//1. 給 WebView添加監(jiān)聽
mWebview.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
}
});
//2太闺、獲取點(diǎn)擊的圖片地址:先獲取類型,根據(jù)相應(yīng)的類型來處理對應(yīng)的數(shù)據(jù)。
WebView.HitTestResult result = ((WebView) v).getHitTestResult();
int type = result.getType();
//3冀宴、獲取具體信息灭贷,圖片這里就是圖片地址
String imgurl = result.getExtra();
//4、操作圖片(完整代碼)
mWebView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
WebView.HitTestResult result = ((WebView)v).getHitTestResult();
if (null == result)
return false;
int type = result.getType();
if (type == WebView.HitTestResult.UNKNOWN_TYPE)
return false;
// 這里可以攔截很多類型略贮,我們只處理圖片類型就可以了
switch (type) {
case WebView.HitTestResult.PHONE_TYPE: // 處理撥號
break;
case WebView.HitTestResult.EMAIL_TYPE: // 處理Email
break;
case WebView.HitTestResult.GEO_TYPE: // 地圖類型
break;
case WebView.HitTestResult.SRC_ANCHOR_TYPE: // 超鏈接
break;
case WebView.HitTestResult.SRC_IMAGE_ANCHOR_TYPE:
break;
case WebView.HitTestResult.IMAGE_TYPE: // 處理長按圖片的菜單項(xiàng)
// 獲取圖片的路徑
String saveImgUrl = result.getExtra();
// 跳轉(zhuǎn)到圖片詳情頁甚疟,顯示圖片
Intent i = new Intent(MainActivity.this, ImageActivity.class);
i.putExtra("imgUrl", saveImgUrl);
startActivity(i);
break;
default:
break;
}
}
});
type有這幾種類型:
- WebView.HitTestResult.UNKNOWN_TYPE 未知類型
- WebView.HitTestResult.PHONE_TYPE 電話類型
- WebView.HitTestResult.EMAIL_TYPE 電子郵件類型
- WebView.HitTestResult.GEO_TYPE 地圖類型
- WebView.HitTestResult.SRC_ANCHOR_TYPE 超鏈接類型
- WebView.HitTestResult.SRC_IMAGE_ANCHOR_TYPE 帶有鏈接的圖片類型
- WebView.HitTestResult.IMAGE_TYPE 單純的圖片類型
- WebView.HitTestResult.EDIT_TEXT_TYPE 選中的文字類型
webview的封裝
public class WebViewActivity extends AppCompatActivity {
private FrameLayout mFrameLayout;
private WebView mWebView;
private MyWebChromeClient mMyWebChromeClient;
private String URL = "http://m.tv.sohu.com/20130704/n380744170.shtml";
@Override
protected void onCreate(Bundle savedInstanceState) {
requestWindowFeature(Window.FEATURE_NO_TITLE);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_webview);
mFrameLayout = (FrameLayout) findViewById(R.id.mFrameLayout);
mWebView = (WebView) findViewById(R.id.mWebView);
initWebView();
mWebView.loadUrl(URL);
}
private void initWebView() {
WebSettings settings = mWebView.getSettings();
//設(shè)置了這個(gè)屬性后我們才能在 WebView 里與我們的 Js 代碼進(jìn)行交互
settings.setJavaScriptEnabled(true);
//WebView 是否支持多窗口,如果設(shè)置為 true逃延,需要重寫
//WebChromeClient#onCreateWindow(WebView, boolean, boolean, Message) 函數(shù)览妖,默認(rèn)為 false
//settings.setSupportMultipleWindows(true);
//顯示W(wǎng)ebView提供的縮放控件
settings.setDisplayZoomControls(false);
settings.setBuiltInZoomControls(true);
//設(shè)置頁面是否支持縮放
webSettings.setSupportZoom(true);
//設(shè)置文本的縮放倍數(shù),默認(rèn)為 100
//webSettings.setTextZoom(2);
//打開 WebView 的 storage 功能揽祥,這樣 JS 的 localStorage,sessionStorage 對象才可以使用
//settings .setDomStorageEnabled(true);
//打開 WebView 的 LBS 功能讽膏,這樣 JS 的 geolocation 對象才可以使用
//settings.setGeolocationEnabled(true);
// settings.setGeolocationDatabasePath("");
//設(shè)置是否打開 WebView 表單數(shù)據(jù)的保存功能
//settings.setSaveFormData(true);
//設(shè)置 WebView 的默認(rèn) userAgent 字符串
//settings.setUserAgentString("");
//設(shè)置 WebView 的字體,可以通過這個(gè)函數(shù)拄丰,改變 WebView 的字體府树,默認(rèn)字體為 "sans-serif"
//settings.setStandardFontFamily("");
//設(shè)置 WebView 字體的大小,默認(rèn)大小為 16
//settings.setDefaultFontSize(20);
//設(shè)置 WebView 支持的最小字體大小料按,默認(rèn)為 8
//settings.setMinimumFontSize(12);
//設(shè)置 JS 是否可以打開 WebView 新窗口
settings.setJavaScriptCanOpenWindowsAutomatically(true);
//被這個(gè) tag 聲明的寬度將會被使用奄侠,如果頁面沒有這個(gè) tag 或者沒有提供一個(gè)寬度,那么一個(gè)寬型 viewport 將會被使用垄潮。
settings.setUseWideViewPort(true);
settings.setPluginState(WebSettings.PluginState.ON);
settings.setAllowFileAccess(true);
settings.setLoadWithOverviewMode(true);
settings.setCacheMode(WebSettings.LOAD_NO_CACHE);
settings.setCacheMode(WebSettings.LOAD_DEFAULT);
mMyWebChromeClient = new MyWebChromeClient();
mWebView.setWebChromeClient(mMyWebChromeClient);
//WebViewClient主要輔助WebView執(zhí)行處理各種響應(yīng)請求事件的
mWebView.setWebViewClient(new WebViewClient() {
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
return true;
}
@Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
}
});
}
//WebChromeClient 主要輔助 WebView 處理J avaScript 的對話框弯洗、網(wǎng)站 Logo、網(wǎng)站 title涂召、load 進(jìn)度等處理
private class MyWebChromeClient extends WebChromeClient {
private View mCustomView;
private CustomViewCallback mCustomViewCallback;
@Override
public void onShowCustomView(View view, CustomViewCallback callback) {
super.onShowCustomView(view, callback);
if (mCustomView != null) {
callback.onCustomViewHidden();
return;
}
mCustomView = view;
mFrameLayout.addView(mCustomView);
mCustomViewCallback = callback;
mWebView.setVisibility(View.GONE);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
}
public void onHideCustomView() {
mWebView.setVisibility(View.VISIBLE);
if (mCustomView == null) {
return;
}
mCustomView.setVisibility(View.GONE);
mFrameLayout.removeView(mCustomView);
mCustomViewCallback.onCustomViewHidden();
mCustomView = null;
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
super.onHideCustomView();
}
}
@Override
public void onConfigurationChanged(Configuration config) {
super.onConfigurationChanged(config);
switch (config.orientation) {
case Configuration.ORIENTATION_LANDSCAPE:
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
break;
case Configuration.ORIENTATION_PORTRAIT:
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
break;
}
}
@Override
public void onPause() {
super.onPause();
mWebView.onPause();
}
@Override
public void onResume() {
super.onResume();
mWebView.onResume();
}
@Override
public void onBackPressed() {
if (mWebView.canGoBack()) {
mWebView.goBack();
return;
}
super.onBackPressed();
}
@Override
public void onDestroy() {
super.onDestroy();
mWebView.destroy();
}
}
一個(gè)完整的Html5Activity
https://github.com/Wing-Li/Html5WebView/tree/master
import android.graphics.Bitmap;
import android.os.Bundle;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.KeyEvent;
import android.webkit.GeolocationPermissions;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import com.lyl.test.R;
public class Html5Activity extends AppCompatActivity {
private String mUrl;
private LinearLayout mLayout;
private WebView mWebView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_web);
Bundle bundle = getIntent().getBundleExtra("bundle");
mUrl = bundle.getString("url");
Log.d("Url:", mUrl);
mLayout = (LinearLayout) findViewById(R.id.web_layout);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
mWebView = new WebView(getApplicationContext());
mWebView.setLayoutParams(params);
mLayout.addView(mWebView);
WebSettings mWebSettings = mWebView.getSettings();
mWebSettings.setSupportZoom(true);
mWebSettings.setLoadWithOverviewMode(true);
mWebSettings.setUseWideViewPort(true);
mWebSettings.setDefaultTextEncodingName("utf-8");
mWebSettings.setLoadsImagesAutomatically(true);
//調(diào)用JS方法.安卓版本大于17,加上注解 @JavascriptInterface
mWebSettings.setJavaScriptEnabled(true);
saveData(mWebSettings);
newWin(mWebSettings);
mWebView.setWebChromeClient(webChromeClient);
mWebView.setWebViewClient(webViewClient);
mWebView.loadUrl(mUrl);
}
@Override
public void onPause() {
super.onPause();
webView.onPause();
webView.pauseTimers(); //小心這個(gè)!G镉尽迫皱!暫停整個(gè) WebView 所有布局、解析卓起、JS戏阅。
}
@Override
public void onResume() {
super.onResume();
webView.onResume();
webView.resumeTimers();
}
/**
* 多窗口的問題
*/
private void newWin(WebSettings mWebSettings) {
//html中的_bank標(biāo)簽就是新建窗口打開,有時(shí)會打不開奕筐,需要加以下
//然后 復(fù)寫 WebChromeClient的onCreateWindow方法
mWebSettings.setSupportMultipleWindows(false);
mWebSettings.setJavaScriptCanOpenWindowsAutomatically(true);
}
/**
* HTML5數(shù)據(jù)存儲
*/
private void saveData(WebSettings mWebSettings) {
//有時(shí)候網(wǎng)頁需要自己保存一些關(guān)鍵數(shù)據(jù),Android WebView 需要自己設(shè)置
mWebSettings.setDomStorageEnabled(true);
mWebSettings.setDatabaseEnabled(true);
mWebSettings.setAppCacheEnabled(true);
String appCachePath = getApplicationContext().getCacheDir().getAbsolutePath();
mWebSettings.setAppCachePath(appCachePath);
}
WebViewClient webViewClient = new WebViewClient(){
/**
* 多頁面在同一個(gè)WebView中打開离赫,就是不新建activity或者調(diào)用系統(tǒng)瀏覽器打開
*/
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
return true;
}
};
WebChromeClient webChromeClient = new WebChromeClient() {
//=========HTML5定位==========================================================
//需要先加入權(quán)限
//<uses-permission android:name="android.permission.INTERNET"/>
//<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
//<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
@Override
public void onReceivedIcon(WebView view, Bitmap icon) {
super.onReceivedIcon(view, icon);
}
@Override
public void onGeolocationPermissionsHidePrompt() {
super.onGeolocationPermissionsHidePrompt();
}
@Override
public void onGeolocationPermissionsShowPrompt(final String origin, final GeolocationPermissions.Callback callback) {
callback.invoke(origin, true, false);//注意個(gè)函數(shù),第二個(gè)參數(shù)就是是否同意定位權(quán)限旬盯,第三個(gè)是是否希望內(nèi)核記住
super.onGeolocationPermissionsShowPrompt(origin, callback);
}
//=========HTML5定位==========================================================
//=========多窗口的問題==========================================================
@Override
public boolean onCreateWindow(WebView view, boolean isDialog, boolean isUserGesture, Message resultMsg) {
WebView.WebViewTransport transport = (WebView.WebViewTransport) resultMsg.obj;
transport.setWebView(view);
resultMsg.sendToTarget();
return true;
}
//=========多窗口的問題==========================================================
};
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK && mWebView.canGoBack()) {
mWebView.goBack();
return true;
}
return super.onKeyDown(keyCode, event);
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mWebView != null) {
mWebView.clearHistory();
((ViewGroup) mWebView.getParent()).removeView(mWebView);
mWebView.loadUrl("about:blank");
mWebView.stopLoading();
mWebView.setWebChromeClient(null);
mWebView.setWebViewClient(null);
mWebView.destroy();
mWebView = null;
}
}
}
App通過調(diào)用外部瀏覽器打開網(wǎng)頁
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);//"android.intent.action.VIEW"
Uri content_url = Uri.parse("www.ycxc.com");
intent.setData(content_url);
//方案一
//startActivity(Intent.createChooser(intent, "請選擇瀏覽器"));
//方案二
/*if (intent.resolveActivity(getPackageManager()) != null) {
startActivity(intent);
}*/
//方案三
intent.setClassName("com.android.browser","com.android.browser.BrowserActivity");
startActivity(intent);