Android集成腾讯X5WebView
生活随笔
收集整理的這篇文章主要介紹了
Android集成腾讯X5WebView
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
項目說明:最近在開發(fā)Android原生嵌套H5實現(xiàn)混合開發(fā),剛開始采用原生的WebView各種兼容性問題,之后決定采用騰訊的x5瀏覽器來開發(fā),遇到的一些問題列一下:
- x5Webview與H5的交互問題
- x5同步cookie問題
- WebView加載進度條問題處理
- H5調(diào)用Android攝像頭進行錄制視頻、H5調(diào)用Android相機進行拍照
- x5WebView-WebChromeClient的方法onShowFileChooser只執(zhí)行一次的問題
- X5WebView的Setting需要配置那些東西
先看效果圖
x5webview集成傳送門
x5webview同步cookie問題傳送門
1、Android集成X5內(nèi)核
public class MyApplication extends BaseApplication {@Overridepublic void onCreate() {super.onCreate();preInitX5Core();}private void preInitX5Core() {//預加載x5內(nèi)核Intent intent = new Intent(this, X5NetService.class);startService(intent);} } public class X5NetService extends IntentService {public static final String TAG = LogTAG.x5webview;public X5NetService(){super(TAG);}public X5NetService(String name) {super(TAG);}@Overridepublic void onHandleIntent(@Nullable Intent intent) {initX5Web();//初始化}public void initX5Web() {if (!QbSdk.isTbsCoreInited()) {// 設置X5初始化完成的回調(diào)接口QbSdk.preInit(getApplicationContext(), null);}QbSdk.initX5Environment(getApplicationContext(), cb);}QbSdk.PreInitCallback cb = new QbSdk.PreInitCallback() {@Overridepublic void onViewInitFinished(boolean arg0) {// TODO Auto-generated method stub}@Overridepublic void onCoreInitFinished() {// TODO Auto-generated method stub}}; } //自定義x5WebView public class X5WebView extends WebView {private static final String TAG = "x5webview";int progressColor = 0xFFFF4081;ProgressView mProgressview; //自定義WebView加載進度條TextView title;Context context;@SuppressLint("SetJavaScriptEnabled")public X5WebView(Context arg0, AttributeSet arg1) {super(arg0, arg1);this.context = arg0;initWebViewSettings();//初始化setting配置this.setWebViewClient(client) ;this.setWebChromeClient(chromeClient);this.setDownloadListener(downloadListener);initProgressBar();//初始化進度條this.getView().setClickable(true);}//setting配置private void initWebViewSettings() {WebSettings webSetting = this.getSettings();webSetting.setJavaScriptEnabled(true);//允許js調(diào)用webSetting.setJavaScriptCanOpenWindowsAutomatically(true);//支持通過JS打開新窗口 webSetting.setAllowFileAccess(true);//在File域下,能夠執(zhí)行任意的JavaScript代碼,同源策略跨域訪問能夠?qū)λ接心夸浳募M行訪問等webSetting.setLayoutAlgorithm(LayoutAlgorithm.NARROW_COLUMNS);//控制頁面的布局(使所有列的寬度不超過屏幕寬度)webSetting.setSupportZoom(true);//支持頁面縮放webSetting.setBuiltInZoomControls(true);//進行控制縮放webSetting.setAllowContentAccess(true);//是否允許在WebView中訪問內(nèi)容URL(Content Url),默認允許webSetting.setUseWideViewPort(true);//設置縮放密度webSetting.setSupportMultipleWindows(false);//設置WebView是否支持多窗口,如果為true需要實現(xiàn)onCreateWindow(WebView, boolean, boolean, Message)if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {//兩者都可以webSetting.setMixedContentMode(webSetting.getMixedContentMode());//設置安全的來源}webSetting.setAppCacheEnabled(true);//設置應用緩存webSetting.setDomStorageEnabled(true);//DOM存儲API是否可用webSetting.setGeolocationEnabled(true);//定位是否可用webSetting.setLoadWithOverviewMode(true);//是否允許WebView度超出以概覽的方式載入頁面,webSetting.setAppCacheMaxSize(Long.MAX_VALUE);//設置應用緩存內(nèi)容的最大值webSetting.setPluginState(WebSettings.PluginState.ON_DEMAND);//設置是否支持插件webSetting.setCacheMode(WebSettings.LOAD_NO_CACHE);//重寫使用緩存的方式webSetting.setAllowUniversalAccessFromFileURLs(true);//是否允許運行在一個file schema URL環(huán)境下的JavaScript訪問來自其他任何來源的內(nèi)容webSetting.setAllowFileAccessFromFileURLs(true);//是否允許運行在一個URL環(huán)境}//進度條private void initProgressBar() {mProgressview = new ProgressView(context);mProgressview.setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 6));mProgressview.setDefaultColor(progressColor);addView(mProgressview);}//客戶端配置private WebViewClient client = new WebViewClient() {@Overridepublic boolean shouldOverrideUrlLoading(com.tencent.smtt.sdk.WebView view, String url) {//這里直接加載urlview.loadUrl(url);return true;}@Overridepublic void onPageStarted(WebView webView, String s, Bitmap bitmap) {super.onPageStarted(webView, s, bitmap);}@Overridepublic void onPageFinished(com.tencent.smtt.sdk.WebView view, String url) {//處理客戶端與WebView同步,具體細節(jié)問題請看最上面?zhèn)魉烷TCookieManager cookieManager = CookieManager.getInstance();cookieManager.setAcceptCookie(true);String endCookie = cookieManager.getCookie(url);Log.i(TAG, "onPageFinished: endCookie : " + endCookie);if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {CookieSyncManager.getInstance().sync();//同步cookie } else {CookieManager.getInstance().flush();}super.onPageFinished(view, url);}@Overridepublic void onReceivedError(WebView webView, int i, String s, String s1) {super.onReceivedError(webView, i, s, s1);//網(wǎng)頁問題報錯的時候執(zhí)行webView.loadDataWithBaseURL(null, "", "text/html", "utf-8", null);webView.setVisibility(View.VISIBLE);}@Overridepublic void onReceivedSslError(WebView webView, SslErrorHandler sslErrorHandler, SslError sslError) {super.onReceivedSslError(webView, sslErrorHandler, sslError);if(sslError.getPrimaryError() == android.net.http.SslError.SSL_INVALID ){// 校驗過程遇到了bug//這里直接忽略ssl證書的檢測出錯問題,選擇繼續(xù)執(zhí)行頁面sslErrorHandler.proceed();}else{//不是證書問題時候則停止執(zhí)行加載頁面sslErrorHandler.cancel();}}};//x5瀏覽器配置可視頻播放、文件下載private WebChromeClient chromeClient = new WebChromeClient() {@Overridepublic boolean onJsConfirm(com.tencent.smtt.sdk.WebView arg0, String arg1, String arg2,com.tencent.smtt.export.external.interfaces.JsResult arg3) {return super.onJsConfirm(arg0, arg1, arg2, (com.tencent.smtt.export.external.interfaces.JsResult) arg3);}View myVideoView;View myNormalView;IX5WebChromeClient.CustomViewCallback callback;/*** 全屏播放配置*/@Overridepublic void onShowCustomView(View view,IX5WebChromeClient.CustomViewCallback customViewCallback) {FrameLayout normalView = null;ViewGroup viewGroup = (ViewGroup) normalView.getParent();viewGroup.removeView(normalView);viewGroup.addView(view);myVideoView = view;myNormalView = normalView;callback = customViewCallback;}@Overridepublic void onHideCustomView() {if (callback != null) {callback.onCustomViewHidden();callback = null;}if (myVideoView != null) {ViewGroup viewGroup = (ViewGroup) myVideoView.getParent();viewGroup.removeView(myVideoView);viewGroup.addView(myNormalView);}}@Overridepublic void onProgressChanged(com.tencent.smtt.sdk.WebView webView, int i) {super.onProgressChanged(webView, i);mProgressview.setProgress(i);}@Overridepublic boolean onJsAlert(com.tencent.smtt.sdk.WebView arg0, String arg1, String arg2,com.tencent.smtt.export.external.interfaces.JsResult arg3) {/*** 這里寫入你自定義的window alert*/return super.onJsAlert(null, arg1, arg2, arg3);}};//下載監(jiān)聽器DownloadListener downloadListener = new DownloadListener() {@Overridepublic void onDownloadStart(String arg0, String arg1, String arg2,String arg3, long arg4) {new AlertDialog.Builder(context).setTitle("allow to download?").setPositiveButton("yes",new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog,int which) {Toast.makeText(context,"fake message: i'll download...",Toast.LENGTH_LONG).show();}}).setNegativeButton("no",new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog,int which) {// TODO Auto-generated method stubToast.makeText(context,"fake message: refuse download...",Toast.LENGTH_SHORT).show();}}).setOnCancelListener(new DialogInterface.OnCancelListener() {@Overridepublic void onCancel(DialogInterface dialog) {// TODO Auto-generated method stubToast.makeText(context,"fake message: refuse download...",Toast.LENGTH_SHORT).show();}}).show();}};@Overrideprotected boolean drawChild(Canvas canvas, View child, long drawingTime) {boolean ret = super.drawChild(canvas, child, drawingTime);canvas.save();Paint paint = new Paint();paint.setColor(0x7fff0000);paint.setTextSize(24.f);paint.setAntiAlias(true);canvas.restore();return ret;}public X5WebView(Context arg0) {super(arg0);setBackgroundColor(85621);} } //進度條 public class ProgressView extends View {int defaultColor = 0xFFFF4081;Paint progressPaint = null;Paint progressCircle = null;int currentProgress = 0;int totalProgress = 0;boolean isHide = false;public ProgressView(Context context) {this(context, null);}public ProgressView(Context context, AttributeSet attrs) {this(context, attrs, -1);}public ProgressView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);init();}private void init() {setLayerType(LAYER_TYPE_SOFTWARE, null);progressPaint = new Paint();progressPaint.setColor(defaultColor);progressCircle = new Paint();progressCircle.setColor(defaultColor);progressCircle.setMaskFilter(new BlurMaskFilter(10, BlurMaskFilter.Blur.SOLID));}int viewWidth = 0;int viewHeight = 0;@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);viewWidth = getMeasuredWidth() - getPaddingLeft() - getPaddingRight();viewHeight = getMeasuredHeight();}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);if(currentProgress<=100&&isHide){isHide = false;this.setAlpha(1);}canvas.drawRect(0, 0, (float) (viewWidth * (currentProgress / 100.0)), viewHeight, progressPaint);canvas.drawCircle((float) (viewWidth * (currentProgress / 100.0)) - viewHeight / 2, viewHeight / 2, viewHeight, progressCircle);if (currentProgress >= 100) {hideSelf();}}private void hideSelf() {this.postDelayed(new Runnable() {@Overridepublic void run() {ViewCompat.animate(ProgressView.this).alpha(0);isHide=true;ProgressView.this.currentProgress = 0;}}, 100);}public int getDefaultColor() {return defaultColor;}public void setDefaultColor(int defaultColor) {this.defaultColor = defaultColor;}ValueAnimator animator;public void setProgress(int progress) {totalProgress = progress;if (animator != null) {if (animator.isRunning()) {animator.cancel();}}animator = ValueAnimator.ofInt(currentProgress, totalProgress);animator.setDuration(300);animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {@Overridepublic void onAnimationUpdate(ValueAnimator animation) {currentProgress = (int) animation.getAnimatedValue();invalidate();}});animator.start();}}2、Android同步cookie
//這里直接采用okhttp做同步cookie操作,具體可看上面cookie同步傳送門 public class OkHttpRequestUtil {private volatile static OkHttpRequestUtil netRequest;private static OkHttpClient okHttpClient; // OKHttp網(wǎng)絡請求private Handler mHandler;final String TAG = LogTAG.okhttp;private boolean checkNet;private final HashMap<String, List<Cookie>> cookieStore = new HashMap<>();private OkHttpRequestUtil() {okHttpClient = new OkHttpClient.Builder().connectTimeout(10, TimeUnit.SECONDS).readTimeout(10, TimeUnit.SECONDS).writeTimeout(10, TimeUnit.SECONDS).addNetworkInterceptor(new HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY)).addInterceptor(new AddCookiesInterceptor())//這里是關(guān)鍵!!!.addInterceptor(new SaveCookiesInterceptor())//這里是關(guān)鍵!!!.cookieJar(new SaCookieManger(MyApplication.context()))//這里是關(guān)鍵!!!.build();mHandler = new Handler(Looper.getMainLooper());}private static OkHttpRequestUtil getInstance() {if (netRequest == null) {netRequest = new OkHttpRequestUtil();}return netRequest;}/*** 異步get請求(Form),內(nèi)部實現(xiàn)方法* @param url url* @param params key value*/public void inner_GetFormAsync(String url, Map<String, String> params, final DataCallBack callBack) {if (params == null) {params = new HashMap<>();}final String doUrl = urlJoint(url, params);final Request request = new Request.Builder().url(doUrl).build();Call call = okHttpClient.newCall(request);call.enqueue(new Callback() {@Overridepublic void onFailure(Call call, IOException e) {deliverDataFailure(request, e, callBack);}@Overridepublic void onResponse(Call call, Response response) throws IOException {if (response != null && response.isSuccessful()) {String result = response.body().string();deliverDataSuccess(result, callBack);} else {throw new IOException(response + "");}}});}/*** get請求 沒有請求體** @param url* @param callBack*/private void getMethod(String url, final DataCallBack callBack) {final Request req = new Request.Builder().url(url).build();okHttpClient.newCall(req).enqueue(new Callback() {@Overridepublic void onFailure(Call call, IOException e) {deliverDataFailure(req, e, callBack);}@Overridepublic void onResponse(Call call, Response response) throws IOException {if (response != null && response.isSuccessful()) {String result = response.body().string();deliverDataSuccess(result, callBack);} else {deliverDataSuccess("請求異常", callBack);}}});}/*** 異步post請求(Form),內(nèi)部實現(xiàn)方法* @param url url* @param params params* @param callBack callBack*/private void inner_PostFormAsync(String url, Map<String, String> params, final DataCallBack callBack) {RequestBody requestBody;if (params == null) {params = new HashMap<>();}FormBody.Builder builder = new FormBody.Builder();/*** 在這對添加的參數(shù)進行遍歷*/for (Map.Entry<String, String> map : params.entrySet()) {String key = map.getKey();String value;/*** 判斷值是否是空的*/if (map.getValue() == null) {value = "";} else {value = map.getValue();}/*** 把key和value添加到formbody中*/builder.add(key, value);}requestBody = builder.build();final Request request = new Request.Builder().url(url).post(requestBody).build();okHttpClient.newCall(request).enqueue(new Callback() {@Overridepublic void onFailure(Call call, IOException e) {deliverDataFailure(request, e, callBack);}@Overridepublic void onResponse(Call call, Response response) throws IOException {if (response.isSuccessful()) { // 請求成功Headers newHead = response.networkResponse().request().headers();Log.i(TAG, "new headers :: " + newHead);//執(zhí)行請求成功的操作String result = response.body().string();deliverDataSuccess(result, callBack);} else {throw new IOException(response + "");}}});}private void inner_PostJsonAsync(String url, Map<String, String> params, final DataCallBack callBack) {// 將map轉(zhuǎn)換成json,需要引入Gson包String mapToJson = new Gson().toJson(params);final Request request = buildJsonPostRequest(url, mapToJson);okHttpClient.newCall(request).enqueue(new Callback() {@Overridepublic void onFailure(Call call, IOException e) {deliverDataFailure(request, e, callBack);}@Overridepublic void onResponse(Call call, Response response) throws IOException {if (response.isSuccessful()) { // 請求成功//執(zhí)行請求成功的操作String result = response.body().string();deliverDataSuccess(result, callBack);} else {throw new IOException(response + "");}}});}private Request buildJsonPostRequest(String url, String json) {RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), json);return new Request.Builder().url(url).post(requestBody).build();}/*** 分發(fā)失敗的時候調(diào)用* 客戶端沒有網(wǎng)絡 還是 服務器異常* @param request request* @param e e* @param callBack callBack*/private void deliverDataFailure(final Request request, final IOException e, final DataCallBack callBack) {/*** 在這里使用異步處理*/checkNet = CheckNetUtil.checkNet(NRApplication.context());mHandler.post(new Runnable() {@Overridepublic void run() {if (callBack != null) {try {if (checkNet) {callBack.requestFailure(request, e);} else {callBack.requestNoNet(ProjectDataDescribe.NET_NO_LINKING,ProjectDataDescribe.NET_NO_LINKING);}} catch (Exception e) {}}}});}/*** 分發(fā)成功的時候調(diào)用** @param result result* @param callBack callBack*/private void deliverDataSuccess(final String result, final DataCallBack callBack) {/*** 在這里使用異步線程處理*/mHandler.post(new Runnable() {@Overridepublic void run() {if (callBack != null) {try {callBack.requestSuccess(result);} catch (Exception e) {e.printStackTrace();}}}});}/*** 數(shù)據(jù)回調(diào)接口*/public interface DataCallBack {// 請求成功 響應成功void requestSuccess(String result) throws Exception; // 請求失敗 響應失敗void requestFailure(Request request, IOException e); // 客戶端沒有網(wǎng)絡連接void requestNoNet(String msg, String data);}/*** 拼接url和請求參數(shù)** @param url url* @param params key value* @return String url*/private static String urlJoint(String url, Map<String, String> params) {StringBuilder endUrl = new StringBuilder(url);boolean isFirst = true;Set<Map.Entry<String, String>> entrySet = params.entrySet();for (Map.Entry<String, String> entry : entrySet) {if (isFirst && !url.contains("?")) {isFirst = false;endUrl.append("?");} else {endUrl.append("&");}endUrl.append(entry.getKey());endUrl.append("=");endUrl.append(entry.getValue());}return endUrl.toString();}//-------------對外提供的方法Start--------------------------------/*** 建立網(wǎng)絡框架,獲取網(wǎng)絡數(shù)據(jù),異步get請求(Form)** @param url url* @param params key value* @param callBack data*/public static void okGetFormRequest(String url, Map<String, String> params, DataCallBack callBack) {getInstance().inner_GetFormAsync(url, params, callBack);}/*** 建立網(wǎng)絡框架,獲取網(wǎng)絡數(shù)據(jù),異步post請求(Form)* @param url url* @param params key value* @param callBack data*/public static void okPostFormRequest(String url, Map<String, String> params, DataCallBack callBack) {getInstance().inner_PostFormAsync(url, params, callBack);}/*** get 請求* 沒有請求體*/public static void okGetRequest(String url, DataCallBack callBack) {getInstance().getMethod(url, callBack);}} public class SaCookieManger implements CookieJar {private static final String TAG = LogTAG.cookie;private static Context mContext;public SaCookieManger(Context context) {mContext = context;}@Overridepublic void saveFromResponse(HttpUrl url, List<Cookie> cookies) {SaasCookieManager.loadCookie(cookies,url.host());}@Overridepublic List<Cookie> loadForRequest(HttpUrl url) {return new ArrayList<>();} } public class AddCookiesInterceptor implements Interceptor {private static final String COOKIE_PREF = "cookies_prefs";@Overridepublic Response intercept(Chain chain) throws IOException {Request request = chain.request();Request.Builder builder = request.newBuilder();String cookie = getCookie(request.url().toString(), request.url().host());if (!TextUtils.isEmpty(cookie)) {builder.addHeader("Cookie", cookie);Log.i(LogTAG.cookie, "interceptor addHeader Cookie: "+cookie);}return chain.proceed(builder.build());}private String getCookie(String url, String domain) {SharedPreferences sp = MyApplication.context().getSharedPreferences(COOKIE_PREF,Context.MODE_PRIVATE);String cookie = sp.getString(domain, "");Log.i(LogTAG.cookie, "interceptor getCookie: "+cookie);if (!TextUtils.isEmpty(domain) && sp.contains(domain) && !TextUtils.isEmpty(sp.getString(domain, ""))) {return sp.getString(domain, "");}return null;}} /*** 存儲cookie攔截器*/ public class SaveCookiesInterceptor implements Interceptor {private static final String COOKIE_PREF = "cookies_prefs";@Overridepublic Response intercept(Chain chain) throws IOException {Request request = chain.request();Response response = chain.proceed(request);if (!response.headers("set-cookie").isEmpty()) {List<String> cookies = response.headers("set-cookie");String cookie = encodeCookie(cookies);saveCookie(request.url().toString(), request.url().host(), cookie);}return response;}/*** 整合cookie為唯一字符串* @param cookies* @return*/private String encodeCookie(List<String> cookies) {StringBuilder sb = new StringBuilder();List<String> set = new ArrayList<>();for (String cookie : cookies) {String[] arr = cookie.split(";");for (String s : arr) {if (set.contains(s)) {continue;}set.add(s);}}Iterator<String> ite = set.iterator();while (ite.hasNext()) {String cookie = ite.next();sb.append(cookie).append(";");}int last = sb.lastIndexOf(";");if (sb.length() - 1 == last) {sb.deleteCharAt(last);}return sb.toString();}/*** 持久化cookie*/private void saveCookie(String url, String domain, String cookies) {SharedPreferences sp = MyApplication.context().getSharedPreferences(COOKIE_PREF,Context.MODE_PRIVATE);SharedPreferences.Editor editor = sp.edit();if (TextUtils.isEmpty(url)) {throw new NullPointerException("url is null.");}else{editor.putString(url, cookies);}if (!TextUtils.isEmpty(domain)) {editor.putString(domain, cookies);}editor.apply();}} //登陸請求 public class SimpleLogin {//TODO 賬號密碼String userName = bean.getUserName();String passWord = bean.getPassWord();HashMap<String,String> map = new HashMap<>();map.put("username",userName);map.put("password",passWord);//TODO 網(wǎng)絡請求OkHttpRequestUtil.okPostFormRequest(HttpUrlConstance.APP_LOGIN, map, new OkHttpRequestUtil.DataCallBack() {@Overridepublic void requestSuccess(String result) throws Exception {//TODO 成功JSONObject j = new JSONObject(result);//TODO 具體業(yè)務處理}@Overridepublic void requestFailure(Request request, IOException e) {//TODO 失敗}@Overridepublic void requestNoNet(String msg, String data) {//TODO 網(wǎng)絡問題}}); }3、X5WebView調(diào)用Android攝像頭、相機進行錄像、拍照
/*** WebView渲染Activity** @author wenhua.qin*/ public class BrowserActivity extends BaseActivity {private ValueCallback<Uri> uploadFile;private ValueCallback<Uri[]> uploadFiles;public String TAG = "AABBCC";private int mResultCode = Activity.RESULT_CANCELED;private X5WebView mWebView;private String mHomeUrl = "";@BindView(R.id.webView1)ViewGroup mViewParent;@Overrideprotected int getContentView() {return R.layout.activity_browser;}@Overrideprotected void initData() {super.initData();Intent intent = getIntent();if (intent != null) {mHomeUrl = (String) intent.getExtras().get("url"); //傳入的網(wǎng)頁}try {if (Integer.parseInt(android.os.Build.VERSION.SDK) >= 11) {getWindow().setFlags(android.view.WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,android.view.WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);}} catch (Exception e) {}init();}@Overrideprotected boolean getSwipeBack() {return true;}private void init() {mWebView = new X5WebView(this, null);WebSettings webSetting = mWebView.getSettings();webSetting.setAppCachePath(this.getDir("appcache", 0).getPath()); //設置應用緩存目錄webSetting.setDatabasePath(this.getDir("databases", 0).getPath()); //設置數(shù)據(jù)庫緩存路徑webSetting.setGeolocationDatabasePath(this.getDir("geolocation", 0).getPath());//設置定位的數(shù)據(jù)庫路徑mViewParent.addView(mWebView, new FrameLayout.LayoutParams(FrameLayout.LayoutParams.FILL_PARENT,FrameLayout.LayoutParams.FILL_PARENT));mWebView.addJavascriptInterface(new WebContrl(this, mWebView), "webCtrl");//與js進行交互mWebView.setWebChromeClient(chromeClient);mWebView.loadUrl(mHomeUrl);}@Overridepublic void onDestroy() { //銷毀時候需要處理Webview移除if (mWebView != null && mWebView.getParent() != null) {((ViewGroup) mWebView.getParent()).removeView(mWebView);mWebView.destroy();mWebView = null;ViewGroup view = (ViewGroup) getWindow().getDecorView();view.removeAllViews();}super.onDestroy();}//處于onPause、onStop狀態(tài)需要重寫onNewIntent方法@Overrideprotected void onNewIntent(Intent intent) {if (intent == null || mWebView == null || intent.getData() == null)return;mWebView.loadUrl(intent.getExtras().getString("url"));}@Overridepublic boolean onKeyDown(int keyCode, KeyEvent event) {if (keyCode == KeyEvent.KEYCODE_BACK) {//返回鍵監(jiān)聽 回滾H5頁面if (mWebView != null && mWebView.canGoBack()) {mWebView.goBack();if (Integer.parseInt(android.os.Build.VERSION.SDK) >= 16)changGoForwardButton(mWebView);return true;} elsereturn super.onKeyDown(keyCode, event);}return super.onKeyDown(keyCode, event);}private void changGoForwardButton(com.tencent.smtt.sdk.WebView view) {}//當前涉及調(diào)用拍照、攝像功能,需要重新設置WebChromeClientprivate WebChromeClient chromeClient = new WebChromeClient() {public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType) {}public void openFileChooser(ValueCallback<Uri> uploadMsgs) {}// For Android > 4.1.1public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) {}// For Android >= 5.0 該項目需求是在5.0之上開發(fā)、所以5.0以下不作處理public boolean onShowFileChooser(com.tencent.smtt.sdk.WebView webView,ValueCallback<Uri[]> filePathCallback,final WebChromeClient.FileChooserParams fileChooserParams) {uploadFiles = filePathCallback;new ActionSheetDialog(BrowserActivity.this).builder(uploadFile,uploadFiles)//這里是重點!!!,需要傳入uploadFile,uploadFiles進行判斷處理.setCancelable(true) //取消鍵.setCanceledOnTouchOutside(true)//空白地方取消dialog.addSheetItem("上傳照片",ActionSheetDialog.SheetItemColor.Blue,new ActionSheetDialog.OnSheetItemClickListener() {@Overridepublic void onClick(int which) {take();}}).addSheetItem("上傳視頻",ActionSheetDialog.SheetItemColor.Blue,new ActionSheetDialog.OnSheetItemClickListener() {@Overridepublic void onClick(int which) {Toast.makeText(BrowserActivity.this, "調(diào)用視頻", Toast.LENGTH_SHORT).show();Intent intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);intent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 1);//限制時長intent.putExtra(MediaStore.EXTRA_DURATION_LIMIT, 10);//開啟攝像機startActivityForResult(intent, 101);}})// .addSheetItem("調(diào)用相冊", // ActionSheetDialog.SheetItemColor.Blue, // new ActionSheetDialog.OnSheetItemClickListener() { // @Override // public void onClick(int which) { // Toast.makeText(BrowserActivity.this, "調(diào)用相冊", Toast.LENGTH_SHORT).show(); // Intent i = new Intent(Intent.ACTION_GET_CONTENT); // i.addCategory(Intent.CATEGORY_OPENABLE); // i.setType("image/*"); // startActivityForResult(Intent.createChooser(i, "選擇相冊"), 102); // } // }).show();return true;}};public boolean flag = true;@SuppressWarnings("null")@TargetApi(Build.VERSION_CODES.LOLLIPOP)private void onActivityResultAboveL(int requestCode, int resultCode, Intent data) {if (requestCode != 100|| uploadFiles == null) {return;}Uri[] results = null;if (resultCode == Activity.RESULT_OK) {if (data == null) {results = new Uri[]{imageUri};} else {String dataString = data.getDataString();ClipData clipData = data.getClipData();if (clipData != null) {results = new Uri[clipData.getItemCount()];for (int i = 0; i < clipData.getItemCount(); i++) {ClipData.Item item = clipData.getItemAt(i);results[i] = item.getUri();}}if (dataString != null)results = new Uri[]{Uri.parse(dataString)};}}if(results!=null){uploadFiles.onReceiveValue(results);uploadFiles = null;}else{results = new Uri[]{imageUri};uploadFiles.onReceiveValue(results);uploadFiles = null;}return;}private void take(){File imageStorageDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "MyApp");// Create the storage directory if it does not existif (! imageStorageDir.exists()){imageStorageDir.mkdirs();}File file = new File(imageStorageDir + File.separator + "IMG_" + String.valueOf(System.currentTimeMillis()) + ".jpg");imageUri = Uri.fromFile(file);final List<Intent> cameraIntents = new ArrayList<Intent>();final Intent captureIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);final PackageManager packageManager = getPackageManager();final List<ResolveInfo> listCam = packageManager.queryIntentActivities(captureIntent, 0);for(ResolveInfo res : listCam) {final String packageName = res.activityInfo.packageName;final Intent i = new Intent(captureIntent);i.setComponent(new ComponentName(res.activityInfo.packageName, res.activityInfo.name));i.setPackage(packageName);i.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);cameraIntents.add(i);}Intent i = new Intent(Intent.ACTION_GET_CONTENT);i.addCategory(Intent.CATEGORY_OPENABLE);i.setType("image/*");Intent chooserIntent = Intent.createChooser(i,"請選擇相冊或者拍照");chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, cameraIntents.toArray(new Parcelable[]{}));BrowserActivity.this.startActivityForResult(chooserIntent, 100);}Uri result;@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) {super.onActivityResult(requestCode, resultCode, data);if (resultCode == RESULT_OK) {switch (requestCode) {case 100://相片 拍照片if (null == uploadFile && null == uploadFiles) return;Uri result = data == null || resultCode != RESULT_OK ? null : data.getData();if (uploadFiles != null) {onActivityResultAboveL(requestCode, resultCode, data);}else if (uploadFile != null) {Log.e("result",result+"");if(result==null){uploadFile.onReceiveValue(imageUri);uploadFile = null;Log.e("imageUri",imageUri+"");}else {uploadFile.onReceiveValue(result);uploadFile = null;}}flag = true;break;case 101://相機 拍攝視頻if (null == uploadFile && null == uploadFiles) {Log.d(TAG, "onActivityResult null");return;}result = data == null || resultCode != RESULT_OK ? null : data.getData();Log.d(TAG, "onActivityResult path=" + result.getPath());if (uploadFiles != null) {if (resultCode == RESULT_OK) {Log.d(TAG, "onActivityResult 1");uploadFiles.onReceiveValue(new Uri[]{result});} else {Log.d(TAG, "onActivityResult 2");uploadFiles.onReceiveValue(new Uri[]{});uploadFiles = null;}} else if (uploadFile != null) {if (resultCode == RESULT_OK) {uploadFile.onReceiveValue(result);uploadFile = null;} else {Log.d(TAG, "onActivityResult 4");uploadFile.onReceiveValue(Uri.EMPTY);uploadFile = null;}}break;case 102:if (null != uploadFile) {result = data == null || resultCode != RESULT_OK ? null: data.getData();uploadFile.onReceiveValue(result);uploadFile = null;}if (null != uploadFiles) {result = data == null || resultCode != RESULT_OK ? null: data.getData();uploadFiles.onReceiveValue(new Uri[]{result});uploadFiles = null;}break;default:break;}} else if (resultCode == RESULT_CANCELED) {if (null != uploadFile) {uploadFile.onReceiveValue(null);uploadFile = null;}}}private Uri imageUri;@Overrideprotected void onResume() {super.onResume();// 取消選擇時需要回調(diào)onReceiveValue,否則網(wǎng)頁會掛住,不會再響應點擊事件if (mResultCode == Activity.RESULT_CANCELED) {try {if (uploadFiles != null) {uploadFiles.onReceiveValue(null);}if (uploadFile != null) {uploadFile.onReceiveValue(null);}} catch (Exception e) {e.printStackTrace();}}} } //采用ios風格彈出框,進行多項選擇(調(diào)用相機、調(diào)用攝像) public class ActionSheetDialog {private Context context;private Dialog dialog;private TextView txt_title;private TextView txt_cancel;private LinearLayout lLayout_content;private ScrollView sLayout_content;private boolean showTitle = false;private List<SheetItem> sheetItemList;private Display display;public ActionSheetDialog(Context context) {this.context = context;WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);display = windowManager.getDefaultDisplay();}public ActionSheetDialog builder(final ValueCallback<Uri> uploadFile,final ValueCallback<Uri[]> uploadFiles) {// 獲取Dialog布局View view = LayoutInflater.from(context).inflate(R.layout.view_actionsheet, null);// 設置Dialog最小寬度為屏幕寬度view.setMinimumWidth(display.getWidth());// 獲取自定義Dialog布局中的控件sLayout_content = (ScrollView) view.findViewById(R.id.sLayout_content);lLayout_content = (LinearLayout) view.findViewById(R.id.lLayout_content);txt_title = (TextView) view.findViewById(R.id.txt_title);txt_cancel = (TextView) view.findViewById(R.id.txt_cancel);txt_cancel.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) { //這里如果不做處理,onShowFileChooser只會執(zhí)行一次 // Toast.makeText(context,"按鈕取消",100).show();if (uploadFiles != null) {uploadFiles.onReceiveValue(null);}if (uploadFile != null) {uploadFile.onReceiveValue(null);}dialog.dismiss();}});// 定義Dialog布局和參數(shù)dialog = new Dialog(context, R.style.ActionSheetDialogStyle);dialog.setOnCancelListener(new DialogInterface.OnCancelListener() {@Overridepublic void onCancel(DialogInterface dialogInterface) {//這里如果不做處理,onShowFileChooser只會執(zhí)行一次 // Toast.makeText(context,"點擊屏幕取消",100).show();if (uploadFiles != null) {uploadFiles.onReceiveValue(null);}if (uploadFile != null) {uploadFile.onReceiveValue(null);}}});dialog.setContentView(view);Window dialogWindow = dialog.getWindow();dialogWindow.setGravity(Gravity.LEFT | Gravity.BOTTOM);WindowManager.LayoutParams lp = dialogWindow.getAttributes();lp.x = 0;lp.y = 0;dialogWindow.setAttributes(lp);return this;}public ActionSheetDialog setTitle(String title) {showTitle = true;txt_title.setVisibility(View.VISIBLE);txt_title.setText(title);return this;}public ActionSheetDialog setCancelable(boolean cancel) {dialog.setCancelable(cancel);return this;}public ActionSheetDialog setCanceledOnTouchOutside(boolean cancel) {dialog.setCanceledOnTouchOutside(cancel);return this;}/**** @param strItem* 條目名稱* @param color* 條目字體顏色,設置null則默認藍色* @param listener* @return*/public ActionSheetDialog addSheetItem(String strItem, SheetItemColor color,OnSheetItemClickListener listener) {if (sheetItemList == null) {sheetItemList = new ArrayList<SheetItem>();}sheetItemList.add(new SheetItem(strItem, color, listener));return this;}/** 設置條目布局 */private void setSheetItems() {if (sheetItemList == null || sheetItemList.size() <= 0) {return;}int size = sheetItemList.size();// TODO 高度控制,非最佳解決辦法// 添加條目過多的時候控制高度if (size >= 7) {LinearLayout.LayoutParams params = (LayoutParams) sLayout_content.getLayoutParams();params.height = display.getHeight() / 2;sLayout_content.setLayoutParams(params);}// 循環(huán)添加條目for (int i = 1; i <= size; i++) {final int index = i;SheetItem sheetItem = sheetItemList.get(i - 1);String strItem = sheetItem.name;SheetItemColor color = sheetItem.color;final OnSheetItemClickListener listener = (OnSheetItemClickListener) sheetItem.itemClickListener;TextView textView = new TextView(context);textView.setText(strItem);textView.setTextSize(18);textView.setGravity(Gravity.CENTER);// 背景圖片if (size == 1) {if (showTitle) {textView.setBackgroundResource(R.drawable.actionsheet_bottom_selector);} else {textView.setBackgroundResource(R.drawable.actionsheet_single_selector);}} else {if (showTitle) {if (i >= 1 && i < size) {textView.setBackgroundResource(R.drawable.actionsheet_middle_selector);} else {textView.setBackgroundResource(R.drawable.actionsheet_bottom_selector);}} else {if (i == 1) {textView.setBackgroundResource(R.drawable.actionsheet_top_selector);} else if (i < size) {textView.setBackgroundResource(R.drawable.actionsheet_middle_selector);} else {textView.setBackgroundResource(R.drawable.actionsheet_bottom_selector);}}}// 字體顏色if (color == null) {textView.setTextColor(Color.parseColor(SheetItemColor.Blue.getName()));} else {textView.setTextColor(Color.parseColor(color.getName()));}// 高度float scale = context.getResources().getDisplayMetrics().density;int height = (int) (45 * scale + 0.5f);textView.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, height));// 點擊事件textView.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {listener.onClick(index);dialog.dismiss();}});lLayout_content.addView(textView);}}public void show() {setSheetItems();dialog.show();}public interface OnSheetItemClickListener {void onClick(int which);}public class SheetItem {String name;OnSheetItemClickListener itemClickListener;SheetItemColor color;public SheetItem(String name, SheetItemColor color,OnSheetItemClickListener itemClickListener) {this.name = name;this.color = color;this.itemClickListener = itemClickListener;}}public enum SheetItemColor {Blue("#037BFF"), Red("#FD4A2E");private String name;private SheetItemColor(String name) {this.name = name;}public String getName() {return name;}public void setName(String name) {this.name = name;}} } //與js交互 public class WebContrl {private Context context;X5WebView mWebView;public WebContrl(Context context, X5WebView webView) {this.context=context;this.mWebView = webView;}@JavascriptInterfacepublic void finish(){((Activity)context).finish();}@JavascriptInterfacepublic void toastMessage(String message) {Log.i("toastMessage" , "傳遞過來的值是: "+message);}@JavascriptInterfacepublic String getMessage(String s){return s+"world !";} } //js部分代碼 <script>function showMsgInAndroid(){webCtrl.finish();} </script> <div class="header_left" onclick="showMsgInAndroid()"></> <input type="file" text="點擊拍照"> 需要引入的庫implementation 'com.zhy.base:fileprovider:1.0.0'implementation 'com.google.code.gson:gson:2.8.2'implementation 'com.squareup.okio:okio:1.13.0'implementation 'com.squareup.okhttp3:okhttp:3.9.0'implementation 'com.squareup.okhttp3:logging-interceptor:3.9.0'implementation 'pub.devrel:easypermissions:1.2.0' //權(quán)限部分代碼checkWritePermission();public static String[] PERMISSION = {Manifest.permission.READ_PHONE_STATE, Manifest.permission.CAMERA,Manifest.permission.WRITE_EXTERNAL_STORAGE};* 檢查讀寫權(quán)限權(quán)限*/private void checkWritePermission() {boolean result = PermissionManager.checkPermission(this,PERMISSION);if (!result) {PermissionManager.requestPermission(this, Permission.WRITE_PERMISSION_TIP, Permission.WRITE_PERMISSION_CODE, PERMISSION);}}@Overridepublic void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {super.onRequestPermissionsResult(requestCode, permissions, grantResults);//將請求結(jié)果傳遞EasyPermission庫處理EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this);}@Overridepublic void onPermissionsGranted(int requestCode, @NonNull List<String> perms) {Toast.makeText(this, "用戶授權(quán)成功", Toast.LENGTH_SHORT).show();}@Overridepublic void onPermissionsDenied(int requestCode, @NonNull List<String> perms) {Toast.makeText(this, "用戶授權(quán)失敗", Toast.LENGTH_SHORT).show();/*** 若是在權(quán)限彈窗中,用戶勾選了'NEVER ASK AGAIN.'或者'不在提示',且拒絕權(quán)限。* 這時候,需要跳轉(zhuǎn)到設置界面去,讓用戶手動開啟。*/if (EasyPermissions.somePermissionPermanentlyDenied(this, perms)) {new AppSettingsDialog.Builder(this).build().show();}}最后說明:項目剛結(jié)束、匆匆忙忙附上代碼、注釋很多未注明,最后附上源代碼https://download.csdn.net/download/jsniitqwh/10710585
總結(jié)
以上是生活随笔為你收集整理的Android集成腾讯X5WebView的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: MTK各个分区功能大全
- 下一篇: 如何划分机器学习的训练集和测试集