近年来,混合开发也越来越用的更多,而原生webview的各种坑,比如说 上传图片、文件问题、视频全屏问题(什么在微信上打开都是好的,你这怎么全屏不了)、版本差异问题,所以还是建议使用腾讯x5浏览器。
废话不多说,我们开始集成吧
1.去官网上下载最新的jar、so文件等 链接点这里
2.添加jar包、so文件,配置gradle
在build.gradle 中添加libs、配置ndk
sourceSets { main { jniLibs.srcDirs = ['libs'] } }
ndk { abiFilters "armeabi" }
3.在Application中添加初始化x5代码,记得在AndroidManifest.xml中注册你自定的Application
QbSdk.PreInitCallback cb = new QbSdk.PreInitCallback() { @Override public void onViewInitFinished(boolean arg0) { //x5內核初始化完成的回调,为true表示x5内核加载成功,否则表示x5内核加载失败,会自动切换到系统内核。 Log.d("app", " onViewInitFinished is " + arg0); } @Override public void onCoreInitFinished() { } }; //x5内核初始化接口 QbSdk.initX5Environment(getApplicationContext(), cb);
4.添加权限
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.READ_PHONE_STATE" /> <uses-permission android:name="android.permission.READ_SETTINGS" /> <uses-permission android:name="android.permission.WRITE_SETTINGS" /> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <!-- 硬件加速对X5视频播放非常重要,建议开启 --> <uses-permission android:name="android.permission.GET_TASKS" />
5.添加WebActivity,初始化x5配置 记得在AndroidManifest.xml中注册
webView = (WebView) findViewById(R.id.webView); WebSettings webSetting = webView.getSettings(); webSetting.setJavaScriptEnabled(true); webSetting.setJavaScriptCanOpenWindowsAutomatically(true); webSetting.setAllowFileAccess(true); webSetting.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NARROW_COLUMNS); webSetting.setSupportZoom(true); webSetting.setBuiltInZoomControls(false); webSetting.setUseWideViewPort(true); webSetting.setSupportMultipleWindows(true); // webSetting.setLoadWithOverviewMode(true); webSetting.setAppCacheEnabled(true); // webSetting.setDatabaseEnabled(true); webSetting.setDomStorageEnabled(true); webSetting.setGeolocationEnabled(true); webSetting.setAppCacheMaxSize(Long.MAX_VALUE); // webSetting.setPageCacheCapacity(IX5WebSettings.DEFAULT_CACHE_CAPACITY); webSetting.setPluginState(WebSettings.PluginState.ON_DEMAND); // webSetting.setRenderPriority(WebSettings.RenderPriority.HIGH); webSetting.setCacheMode(WebSettings.LOAD_NO_CACHE); getWindow().setFormat(PixelFormat.TRANSLUCENT); webView.getView().setOverScrollMode(View.OVER_SCROLL_ALWAYS); // this.getSettingsExtension().setPageCacheCapacity(IX5WebSettings.DEFAULT_CACHE_CAPACITY);//extension // settings 的设计 webView.setWebViewClient(new WebViewClient() { @Override public boolean shouldOverrideUrlLoading(WebView webView, String url) { webView.loadUrl(url); return true; } });
添加上传文件、图片适配代码
webView.setWebChromeClient(new WebChromeClient() { // For Android 3.0+ public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType) { uploadFile = uploadFile; openFileChooseProcess(); } // For Android < 3.0 public void openFileChooser(ValueCallback<Uri> uploadMsgs) { uploadFile = uploadFile; openFileChooseProcess(); } // For Android > 4.1.1 public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) { uploadFile = uploadFile; openFileChooseProcess(); } // For Android >= 5.0 public boolean onShowFileChooser(com.tencent.smtt.sdk.WebView webView, ValueCallback<Uri[]> filePathCallback, WebChromeClient.FileChooserParams fileChooserParams) { uploadFiles = filePathCallback; openFileChooseProcess(); return true; } });
private void openFileChooseProcess() { Intent i = new Intent(Intent.ACTION_GET_CONTENT); i.addCategory(Intent.CATEGORY_OPENABLE); i.setType("*/*"); startActivityForResult(Intent.createChooser(i, "test"), 0); }
处理选择文件、图片后回调
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (resultCode == RESULT_OK) { switch (requestCode) { case 0: if (null != uploadFile) { Uri result = data == null || resultCode != RESULT_OK ? null : data.getData(); uploadFile.onReceiveValue(result); uploadFile = null; } if (null != uploadFiles) { Uri 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; } } }
添加视频全屏相关代码
webView.setWebChromeClient(new WebChromeClient() { // For Android 3.0+ public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType) { uploadFile = uploadFile; openFileChooseProcess(); } // For Android < 3.0 public void openFileChooser(ValueCallback<Uri> uploadMsgs) { uploadFile = uploadFile; openFileChooseProcess(); } // For Android > 4.1.1 public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) { uploadFile = uploadFile; openFileChooseProcess(); } // For Android >= 5.0 public boolean onShowFileChooser(com.tencent.smtt.sdk.WebView webView, ValueCallback<Uri[]> filePathCallback, WebChromeClient.FileChooserParams fileChooserParams) { uploadFiles = filePathCallback; openFileChooseProcess(); return true; } View myVideoView; View myNormalView; IX5WebChromeClient.CustomViewCallback callback; /** * 全屏播放配置 */ @Override public void onShowCustomView(View view, IX5WebChromeClient.CustomViewCallback customViewCallback) { FrameLayout normalView = (FrameLayout) findViewById(R.id.web_filechooser); ViewGroup viewGroup = (ViewGroup) normalView.getParent(); viewGroup.removeView(normalView); viewGroup.addView(view); myVideoView = view; myNormalView = normalView; callback = customViewCallback; } @Override public void onHideCustomView() { if (callback != null) { callback.onCustomViewHidden(); callback = null; } if (myVideoView != null) { ViewGroup viewGroup = (ViewGroup) myVideoView.getParent(); viewGroup.removeView(myVideoView); viewGroup.addView(myNormalView); } } });
webView.addJavascriptInterface(new WebViewJavaScriptFunction() { @Override public void onJsFunctionCalled(String tag) { } @JavascriptInterface public void onX5ButtonClicked() { enableX5FullscreenFunc(); } @JavascriptInterface public void onCustomButtonClicked() { disableX5FullscreenFunc(); } @JavascriptInterface public void onLiteWndButtonClicked() { enableLiteWndFunc(); } @JavascriptInterface public void onPageVideoClicked() { enablePageVideoFunc(); } }, "Android");
// 向webview发出信息 private void enableX5FullscreenFunc() { if (webView.getX5WebViewExtension() != null) { Bundle data = new Bundle(); data.putBoolean("standardFullScreen", false);// true表示标准全屏,false表示X5全屏;不设置默认false, data.putBoolean("supportLiteWnd", false);// false:关闭小窗;true:开启小窗;不设置默认true, data.putInt("DefaultVideoScreen", 2);// 1:以页面内开始播放,2:以全屏开始播放;不设置默认:1 webView.getX5WebViewExtension().invokeMiscMethod("setVideoParams", data); } } private void disableX5FullscreenFunc() { if (webView.getX5WebViewExtension() != null) { Bundle data = new Bundle(); data.putBoolean("standardFullScreen", true);// true表示标准全屏,会调起onShowCustomView(),false表示X5全屏;不设置默认false, data.putBoolean("supportLiteWnd", false);// false:关闭小窗;true:开启小窗;不设置默认true, data.putInt("DefaultVideoScreen", 2);// 1:以页面内开始播放,2:以全屏开始播放;不设置默认:1 webView.getX5WebViewExtension().invokeMiscMethod("setVideoParams", data); } } private void enableLiteWndFunc() { if (webView.getX5WebViewExtension() != null) { Bundle data = new Bundle(); data.putBoolean("standardFullScreen", false);// true表示标准全屏,会调起onShowCustomView(),false表示X5全屏;不设置默认false, data.putBoolean("supportLiteWnd", true);// false:关闭小窗;true:开启小窗;不设置默认true, data.putInt("DefaultVideoScreen", 2);// 1:以页面内开始播放,2:以全屏开始播放;不设置默认:1 webView.getX5WebViewExtension().invokeMiscMethod("setVideoParams", data); } } private void enablePageVideoFunc() { if (webView.getX5WebViewExtension() != null) { Bundle data = new Bundle(); data.putBoolean("standardFullScreen", false);// true表示标准全屏,会调起onShowCustomView(),false表示X5全屏;不设置默认false, data.putBoolean("supportLiteWnd", false);// false:关闭小窗;true:开启小窗;不设置默认true, data.putInt("DefaultVideoScreen", 1);// 1:以页面内开始播放,2:以全屏开始播放;不设置默认:1 webView.getX5WebViewExtension().invokeMiscMethod("setVideoParams", data); } }
添加下载相关代码
webView.setDownloadListener(new DownloadListener() { @Override public void onDownloadStart(String s, String s1, String s2, String s3, long l) { } });
最后,当Activity销毁时,释放webview
/** * 确保注销配置能够被释放 */ @Override protected void onDestroy() { if (this.webView != null) { webView.destroy(); } super.onDestroy(); }
到这里,x5浏览器的集成已经完成了,快去试试吧
常见问题
1.视频无法全屏
请注意AndroidManifest.xml 中配置
<activity android:name=".WebActivity" android:configChanges="orientation|screenSize|keyboardHidden"></activity>
2.原生与webview 共享cookie
首先,原生需要将cookie 持久化的保存起来,具体可以参考 【Android架构】基于MVP模式的Retrofit2+RXjava封装之常见问题(四),至于非okhttp网络的,可以自行百度
然后传递给webview
//创建CookieSyncManager CookieSyncManager.createInstance(context); //得到CookieManager CookieManager cookieManager = CookieManager.getInstance(); cookieManager.setAcceptCookie(true); cookieManager.removeSessionCookie();// 移除 cookieManager.removeAllCookie(); //得到向URL中添加的Cookie的值 store = new PersistentCookieStore(context); List<Cookie> cookieList = store.getCookies(); if (cookieList != null && cookieList.size() > 0) { Cookie cookie = null; for (Cookie c : cookieList) { if (c.domain() != null) { if (c.domain().contains("38")) { cookie = c; } } } if (cookie == null) { cookie = cookieList.get(0); } cookieManager.setCookie(url, cookie.name() + "=" + cookie.value()); if (Build.VERSION.SDK_INT < 21) { CookieSyncManager.getInstance().sync(); } else { CookieManager.getInstance().flush(); } }