目录
一,简介
二,WebView,WebSettings、WebViewClient、WebChromeClient方法
三,Native与Js交互
四,腾讯浏览服务X5内核
五,X5内核WebView +全屏视频 + JsBridge框架javascript
这部分主要介绍下 WebView,WebView 是一个用来显示 Web 网页的控件,继承自 AbsoluteLayout,和使用系统其余控件没什么区别,只是 WeView 控件方法比较多比较丰富。由于它就是一个微型浏览器,包含一个浏览器该有的基本功能,例如:滚动、缩放、前进、后退下一页、搜索、执行 Js等功能。html
在 Android 4.4 以前使用 WebKit 做为渲染内核,4.4 以后采用 chrome 内核。Api 使用兼容低版本。前端
主要包含 WebView 的使用方法。 咱们基于这些方法能扩展不少其余功能,例如:JsBridge、缓存等。
WebView方法:html5
方法 | 说明 |
---|---|
void loadUrl(String url) | 加载网络连接 url |
boolean canGoBack() | 判断 WebView 当前是否能够返回上一页 |
goBack() | 回退到上一页 |
boolean canGoForward() | 判断 WebView 当前是否能够向前一页 |
goForward() | 回退到前一页 |
onPause() | 相似 Activity 生命周期,页面进入后台不可见状态 |
pauseTimers() | 方法面向全局整个应用程序的webview,它会暂停全部webview的layout,parsing,JavaScript Timer。当程序进入后台时,该方法的调用能够下降CPU功耗。 |
onResume() | 在调用 onPause()后,能够调用该方法来恢复 WebView 的运行 |
resumeTimers() | 恢复pauseTimers时的全部操做。(注:pauseTimers和resumeTimers 方法必须一块儿使用,不然再使用其它场景下的 WebView 会有问题) |
destroy() | 销毁 WebView |
clearHistory() | 清除当前 WebView 访问的历史记录。 |
clearCache(boolean includeDiskFiles): | 清空网页访问留下的缓存数据。须要注意的时,因为缓存是全局的,因此只要是WebView用到的缓存都会被清空,即使其余地方也会使用到。该方法接受一个参数,从命名便可看出做用。若设为false,则只清空内存里的资源缓存,而不清空磁盘里的。 |
reload() | 从新加载当前请求 |
setLayerType(int layerType, Paint paint) | 设置硬件加速、软件加速 |
removeAllViews() | 清除子view。 |
clearSslPreferences(): | 清除ssl信息 |
clearMatches() | 清除网页查找的高亮匹配字符 |
removeJavascriptInterface(String interfaceName) | 删除interfaceName 对应的注入对象 |
addJavascriptInterface(Object object,String interfaceName) | 注入 java 对象 |
setVerticalScrollBarEnabled(boolean verticalScrollBarEnabled) | 设置垂直方向滚动条。 |
setHorizontalScrollBarEnabled(boolean horizontalScrollBarEnabled) | 设置横向滚动条 |
loadUrl(String url, Map additionalHttpHeaders) | 加载制定url并携带http header数据 |
stopLoading() | 中止 WebView 当前加载 |
freeMemory() | 释放内存,不过貌似很差用。 |
clearFormData() | 清除自动完成填充的表单数据。须要注意的是,该方法仅仅清除当前表单域自动完成填充的表单数据,并不会清除WebView存储到本地的数据。 |
WebSettings方法java
方法 | 说明 |
---|---|
setJavaScriptEnabled(boolean flag) | 是否支持 Js 使用 |
setCacheMode(int mode) | 设置 WebView 的缓存模式 |
setAppCacheEnabled(boolean flag) | 是否启用缓存模式 |
setAppCachePath(String appCachePath) | Android 私有缓存存储,若是你不调用setAppCachePath方法,WebView将不会产生这个目录 |
setGeolocationEnabled | 是否支持定位 |
setGeolocationDatabasePath | 设置定位数据库路径 |
setSupportZoom(boolean support) | 是否支持缩放。 |
setTextZoom(int textZoom) | 设置页面中文本缩放百分比,默认100% |
setAllowFileAccess(boolean allow) | 是否容许加载本地 html 文件/false |
setDatabaseEnabled(boolean flag) | 是否开启数据库缓存 |
setDomStorageEnabled(boolean flag) | 是否开启DOM缓存 |
setUserAgentString(String ua) | 设置 UserAgent 属性 |
setLoadsImagesAutomatically(boolean flag) | 支持自动加载图片 |
boolean getLoadsImagesAutomatically() | 是否支持自动加载图片 |
setMixedContentMode | 设置混合模式,当一个安全的https请求加载不安全的http时 |
setLoadWithOverviewMode | 设置webview加载在override模式,就是缩小内容以适应屏幕宽,当加载的内容宽大于Webview控制的宽时 |
setDisplayZoomControls | 设置webview是否显示缩放控制按钮 |
项目中使用设置:android
WebSettings settings = mWebView.getSettings();
settings.setJavaScriptEnabled(true);
settings.setDatabaseEnabled(false);
settings.setSaveFormData(false);
settings.setBuiltInZoomControls(true);
if (Build.VERSION.SDK_INT >= 11)
settings.setDisplayZoomControls(false);
settings.setAllowFileAccess(true);
settings.setUseWideViewPort(true);
settings.setLoadWithOverviewMode(true);
settings.setDomStorageEnabled(true);
settings.setAppCacheEnabled(true);
settings.setGeolocationEnabled(true);
settings.setGeolocationDatabasePath(getActivity().getCacheDir().toString());
settings.setUserAgentString(settings.getUserAgentString() + " " + DeviceUtil.getUserAgent(getActivity()));
// android 5.0以上默认不支持Mixed Content
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
settings.setMixedContentMode(
WebSettings.MIXED_CONTENT_COMPATIBILITY_MODE);
}
复制代码
WebViewClient方法:
主要做用:主要帮助WebView处理各类通知、请求事件的web
方法 | 说明 |
---|---|
onPageStarted(WebView view, String url, Bitmap favicon) | WebView 开始加载页面时回调,一次Frame加载对应一次回调 |
onLoadResource(WebView view, String url) | WebView 加载页面资源时会回调,每个资源产生的一次网络加载,除非本地有当前 url 对应有缓存,不然就会加载 |
shouldInterceptRequest(WebView view, String url) | WebView 能够拦截某一次的 request 来返回咱们本身加载的数据,这个方法在后面缓存会有很大做用 |
shouldOverrideUrlLoading(WebView view, String url) | 是否在 WebView 内加载页面,返回true表明当前Webview完成这次加载,false表明交给系统浏览器加载 |
onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) | WebView ssl 访问证书出错,handler.cancel()取消加载,handler.proceed()对然错误也继续加载 |
onPageFinished(WebView view, String url) | WebView 完成加载页面时回调,一次Frame加载对应一次回调 |
onReceivedError(WebView view, int errorCode, String description, String failingUrl) | WebView 访问 url 出错 |
WebChromeClient方法
要辅助WebView处理Javascript的对话框、网站图标、网站title、加载进度等chrome
方法 | 说明 |
---|---|
onConsoleMessage(String message, int lineNumber,String sourceID) | 输出 Web 端日志 |
onProgressChanged(WebView view, int newProgress) | 当前 WebView 加载网页进度 |
onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) | 处理 JS 中的 Prompt对话框 |
onJsAlert(WebView view, String url, String message, JsResult result) | Js 中调用 alert() 函数,产生的对话框 |
onReceivedTitle(WebView view, String title): | 接收web页面的 Title |
onReceivedIcon(WebView view, Bitmap icon) | 接收web页面的icon |
View getVideoLoadingProgressView() | 获取在全屏视频正在缓冲的同时显示的视图。宿主应用程序能够重写此方法,以提供包含旋转器或相似物的视图。 |
onShowCustomView(View view, CustomViewCallback callback) | 网页中有H5播放flash video的时候按下全屏按钮将会调用到这个方法,通常用做设置网页播放全屏操做 |
onHideCustomView() | 取消全屏方法 |
首先说Native调用js代码,或者说执行js代码很简单:数据库
Native 调用 Js:mWebView.loadUrl(js);
复制代码
Js代码调用Native的代码,一共有三种方式:json
标准方式使用清单:
//开启Js可用
mWebView.getSettings().setJavaScriptEnabled(true);
// 建立要注入的 Java 类
public class NativeInterface {
private Context mContext;
public NativeInterface(Context context) {
mContext = context;
}
// 使用JavascriptInterface注解标注的方法能够被JS代码调用
@JavascriptInterface
public void hello() {
Toast.makeText(mContext, "hello", Toast.LENGTH_SHORT).show();
}
@JavascriptInterface
public void hello(String params) {
Toast.makeText(mContext, params, Toast.LENGTH_SHORT).show();
}
@JavascriptInterface
public String getAndroid() {
Toast.makeText(mContext, "getAndroid", Toast.LENGTH_SHORT).show();
return "Android data";
}
}
// WebView 注入便可,第二个参数是注入的java对象的别名
mWebView.addJavascriptInterface(new NativeInterface(this), "AndroidNative");
//Js编写
<script>
function callHello(){
AndroidNative.hello();
}
function callHello1(){
// 在js代码中别名AndroidNative就至关于java中实例对象new NativeInterface(this),可调用方法
AndroidNative.hello('hello Android');
}
function callAndroid(){
var temp = AndroidNative.getAndroid();
console.log(temp);
alert(temp);
}
</script>
复制代码
最经常使用的方式使用清单:
在shouldOverrideUrlLoading
接口下,拦截js回调操做,使用scheme协议,即scheme://host[:post]/path/jsonparams
,双方定义格式解析
假如 :协定的格式为 appname://jsbridge/call/func/jsonparams
jsonparams 的是格式为:
{ "callback" : "js用于区分此操做的标识", // 这一项是必须的
"key1": value1,
"key2": value2,
"key3": value3
……
}
// js获取userinfo为例:
// func = userinfo
// jsonparams 的是格式为:
// { "callback" : "cbUserInfo_1"
// }
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
if (!TextUtils.isEmpty(url) && url.startsWith("appname://jsbridge/call/")) {
String[] values = url.replace("appname://jsbridge/call/", "").split("/", 2);
String func = values[0];
String params = values[1];
// 1,js调用native代码,处理Native端的逻辑
switch(func) {
case "userinfo":
JSONObject job = new JSONObject(params);
String callback = job.optString("callback"); // 此处是“cbUserInfo_1”
// 客户端获取一些信息等等
JSONObject result = new JSONObject();
result.put("isLogin",Config.isLogin());
result.put("nickName", Config.getUserName());
result.put("userId", Config.getUserId());
result.put("headimgUrl", Config.getPicUrl());
/// 等等
// 2, Native调用js代码将处理的结果返回给js,Js须要用callback区分这次请求
String js = "callback 和 params组成js";
// 这里须要把callback和params组成js,须要和前端商定,而后使用loadUrl("javascript:" + js) 就能够将结果传给js
if (mWebView != null) {
mWebView.loadUrl("javascript:" + js);
}
break;
}
return true;
}
}
复制代码
以上就是JsBridge的原理,固然,在业务复杂时能够进行封装
腾讯浏览服务网址:https://x5.tencent.com/
接入指南:https://x5.tencent.com/tbs/guide/sdkInit.html
使用很简单和系统的WebView同样。
为何要更换X5内核
Android 4.4如下web内核是WebKit,4.4 以后采用 chrome 内核,当前端在开发时,会出现前端使用的新特性在低版本安卓手机上不能表现出来,因此须要统一内核
X5内核的技术特性
腾讯浏览服务是致力于优化移动端webview体验的整套解决方案。该方案由SDK、手机QQ浏览器X5内核和X5云端服务组成,解决移动端webview使用过程当中出现的一切问题,优化用户的浏览体验。同时,腾讯还将持续提供后续的更新和优化,为开发者提供最新最优秀的功能和服务。
其中,SDK是经过共享使用用户手机上微信、手机QQ、空间等软件已经下载好的X5内核,低成本实现对系统webview的替代。该SDK大小只有200+K,接入时仅需修改几行代码。
其中,X5内核相对于系统webview,具备下述明显优点:
1) 速度快:相比系统webview的网页打开速度有30+%的提高;
2) 省流量:使用云端优化技术使流量节省20+%;
3) 更安全:安全问题能够在24小时内修复;
4) 更稳定:通过亿级用户的使用考验,CRASH率低于0.15%;
5) 兼容好:无系统内核的碎片化问题,更少的兼容性问题;
6) 体验优:支持夜间模式、适屏排版、字体设置等浏览加强功能;
7) 功能全:在Html五、ES6上有更完整支持;
8) 更强大:集成强大的视频播放器,支持视频格式远多于系统webview;
9) 视频和文件格式的支持x5内核多于系统内核
10) 防劫持是x5内核的一大亮点
下载TbsSDK,会有不少文档:
// 注意:代码中的WebView,均为腾讯的WebView
import com.tencent.smtt.sdk.WebChromeClient;
import com.tencent.smtt.sdk.WebView;
import com.tencent.smtt.sdk.WebChromeClient;
// X5WebView.java:继承自腾讯的x5内核的WebView
public class X5WebView extends WebView {
public static final String TAG = X5WebView.class.getSimpleName();
private boolean addedJavascriptInterface;
public X5WebView(Context context) {
super(context);
addedJavascriptInterface = false;
}
public X5WebView(Context context, AttributeSet attributeSet) {
super(context, attributeSet);
addedJavascriptInterface = false;
}
public X5WebView(Context context, AttributeSet attributeSet, int i) {
super(context, attributeSet, i);
addedJavascriptInterface = false;
}
public X5WebView(Context context, AttributeSet attributeSet, int i, boolean b) {
super(context, attributeSet, i, b);
addedJavascriptInterface = false;
}
public X5WebView(Context context, AttributeSet attributeSet, int i, Map<String, Object> map, boolean b) {
super(context, attributeSet, i, map, b);
addedJavascriptInterface = false;
}
@Override
@SuppressLint("SetJavaScriptEnabled")
public void setWebChromeClient(WebChromeClient client) {
getSettings().setJavaScriptEnabled(true);
super.setWebChromeClient(client);
}
@Override
public void loadData(String data, String mimeType, String encoding) {
addJavascriptInterface();
super.loadData(data, mimeType, encoding);
}
@Override
public void loadDataWithBaseURL(String baseUrl, String data,
String mimeType, String encoding,
String historyUrl) {
addJavascriptInterface();
super.loadDataWithBaseURL(baseUrl, data, mimeType, encoding, historyUrl);
}
@Override
public void loadUrl(String url) {
addJavascriptInterface();
super.loadUrl(url);
}
@Override
public void loadUrl(String url, Map<String, String> additionalHttpHeaders) {
addJavascriptInterface();
super.loadUrl(url, additionalHttpHeaders);
}
private void addJavascriptInterface() {
if (!addedJavascriptInterface) {
// Add javascript interface to be called when the video ends (must be done before page load)
addJavascriptInterface(new Object() {
}, "_VideoEnabledWebView"); // Must match Javascript interface name of VideoEnabledWebChromeClient
addedJavascriptInterface = true;
}
}
// X5WebViewClient.java: 继承自腾讯的x5内核的WebViewClient
public class X5WebViewClient extends WebViewClient {
}
// X5WebChromeClient.java :构建一个全屏显示Video的WebChromeClient, 网上能够找到实现,只是作了继承X5的WebChromeClient
public class X5WebChromeClient extends WebChromeClient implements MediaPlayer.OnPreparedListener, MediaPlayer.OnCompletionListener, MediaPlayer.OnErrorListener {
// 将被隐藏的View
private View willHiddenView;
// 将全屏显示的ViewGroup
private ViewGroup willDisplayedViewGroup;
// 加载View
private View loadingView;
// 核心的WebView
private X5WebView webView;
// 进度条
private ProgressBar mProgressBar;
// 代表是否在使用自定义View 显示全屏Video
private boolean isVideoFullscreen;
// 保存全屏Video容器
private FrameLayout videoViewContainer;
// 保存自定义View回调
private IX5WebChromeClient.CustomViewCallback videoViewCallback;
// 全屏Video回调
private ToggledFullscreenCallback toggledFullscreenCallback;
// 接收标题回调
private onReceivedTitleCallback receivedTitleCallback;
/**
* Never use this constructor alone.
* This constructor allows this class to be defined as an inline inner class in which the user can override methods
*/
public X5WebChromeClient() {
}
/**
* 构建一个全屏显示Video的WebChromeClient
*
* @param willHiddenView 当video全屏时,activity布局中的应该被隐藏的View
* @param willDisplayedViewGroup activity布局中,将要显示的 ViewGroup,特别是你想使此ViewGroup全屏显示。
*/
public X5WebChromeClient(View willHiddenView, ViewGroup willDisplayedViewGroup) {
this.willHiddenView = willHiddenView;
this.willDisplayedViewGroup = willDisplayedViewGroup;
this.loadingView = null;
this.webView = null;
this.isVideoFullscreen = false;
}
/**
* 构建一个全屏显示Video的WebChromeClient
*
* @param willHiddenView 当video全屏时,activity布局中的应该被隐藏的View
* @param willDisplayedViewGroup activity布局中,将要显示的 ViewGroup,特别是你想使此ViewGroup全屏显示
* @param loadingView 加载视频时显示的视图(一般仅在API级别<11时使用)。必须被预先inflate,且无父布局
*/
public X5WebChromeClient(View willHiddenView, ViewGroup willDisplayedViewGroup, View loadingView) {
this.willHiddenView = willHiddenView;
this.willDisplayedViewGroup = willDisplayedViewGroup;
this.loadingView = loadingView;
this.webView = null;
this.isVideoFullscreen = false;
}
/**
* 构建一个全屏显示Video的WebChromeClient
*
* @param willHiddenView 当video全屏时,activity布局中的应该被隐藏的View
* @param willDisplayedViewGroup activity布局中,将要显示的 ViewGroup,特别是你想使此ViewGroup全屏显示
* @param loadingView 加载视频时显示的视图(一般仅在API级别<11时使用)。必须被预先inflate,且无父布局
* @param webView X5WebView
*
* 经过它将使X5WebChromeClient检测HTML5视频结束事件并退出全屏。
* 注意:为了使HTML5视频结束事件正常工做,网页只能包含一个视频标记。若是须要的话,能够改进这一点(参见javascript代码)。
*/
public X5WebChromeClient(View willHiddenView, ViewGroup willDisplayedViewGroup, View loadingView, X5WebView webView) {
this.willHiddenView = willHiddenView;
this.willDisplayedViewGroup = willDisplayedViewGroup;
this.loadingView = loadingView;
this.webView = webView;
this.isVideoFullscreen = false;
}
/**
* 手动 进去全屏时 调用
* @param view
* @param callback
*/
@Override
public void onShowCustomView(View view, IX5WebChromeClient.CustomViewCallback callback) {
if (view instanceof FrameLayout) {
PalLog.d(X5WebView.TAG, "onShowCustomView");
// A video wants to be shown
FrameLayout frameLayout = (FrameLayout) view;
// 焦点View
View focusedChild = frameLayout.getFocusedChild();
// 保存Video相关变量
this.isVideoFullscreen = true;
this.videoViewContainer = frameLayout;
this.videoViewCallback = callback;
// 隐藏non-video的View
willHiddenView.setVisibility(View.GONE);
// 添加video的View并显示
willDisplayedViewGroup.addView(videoViewContainer, new RelativeLayout.LayoutParams(ActionBar.LayoutParams.MATCH_PARENT, ActionBar.LayoutParams.MATCH_PARENT));
willDisplayedViewGroup.setVisibility(View.VISIBLE);
// 焦点View是VideoView
if (focusedChild instanceof VideoView) {
// VideoView (typically API level <11)
VideoView videoView = (VideoView) focusedChild;
// VideoView设置准备监听器,完成监听器,错误监听器
videoView.setOnPreparedListener(this);
videoView.setOnCompletionListener(this);
videoView.setOnErrorListener(this);
} else {
// Usually android.webkit.HTML5VideoFullScreen$VideoSurfaceView, sometimes android.webkit.HTML5VideoFullScreen$VideoTextureView
// HTML5VideoFullScreen (typically API level 11+)
// Handle HTML5 video ended event
if (webView != null && webView.getSettings().getJavaScriptEnabled()) {
// Run javascript code that detects the video end and notifies the interface
String js = "javascript:";
js += "_ytrp_html5_video = document.getElementsByTagName('video')[0];";
js += "if (_ytrp_html5_video !== undefined) {";
{
js += "function _ytrp_html5_video_ended() {";
{
js += "_ytrp_html5_video.removeEventListener('ended', _ytrp_html5_video_ended);";
js += "_VideoEnabledWebView.notifyVideoEnd();"; // Must match Javascript interface name and method of VideoEnableWebView
}
js += "}";
js += "_ytrp_html5_video.addEventListener('ended', _ytrp_html5_video_ended);";
}
js += "}";
webView.loadUrl(js);
}
}
// 最后通知全屏改变
if (toggledFullscreenCallback != null) {
toggledFullscreenCallback.toggledFullscreen(true);
}
}
}
@Override
public void onShowCustomView(View view, int requestedOrientation, IX5WebChromeClient.CustomViewCallback callback) // Only available in API level 14+
{
onShowCustomView(view, callback);
}
/**
* 手动取消全屏时调用
*/
@Override
public void onHideCustomView() {
PalLog.d(X5WebView.TAG, "onHideCustomView");
// This method must be manually (internally) called on video end in the case of VideoView (typically API level <11)
// This method must be manually (internally) called on video end in the case of HTML5VideoFullScreen (typically API level 11+) because it's not always called automatically
// This method must be manually (internally) called on back key press (from this class' onBackPressed() method)
if (isVideoFullscreen) {
// Hide the video view, remove it, and show the non-video view
willDisplayedViewGroup.setVisibility(View.GONE);//播放视频的
willDisplayedViewGroup.removeView(videoViewContainer);
willHiddenView.setVisibility(View.VISIBLE);
// Call back
if (videoViewCallback != null) {
videoViewCallback.onCustomViewHidden();
}
// Reset video related variables
isVideoFullscreen = false;
videoViewContainer = null;
videoViewCallback = null;
// Notify full-screen change
if (toggledFullscreenCallback != null) {
toggledFullscreenCallback.toggledFullscreen(false);
}
}
}
/**
* Video will start loading, only called in the case of VideoView (typically API level <11)
* @return
*/
@Override
public View getVideoLoadingProgressView() {
if (loadingView != null) {
loadingView.setVisibility(View.VISIBLE);
return loadingView;
} else {
return super.getVideoLoadingProgressView();
}
}
/**
* Video will start playing, only called in the case of VideoView (typically API level <11)
* @param mp
*/
@Override
public void onPrepared(MediaPlayer mp) {
PalLog.d(X5WebView.TAG, "onPrepared");
if (loadingView != null) {
loadingView.setVisibility(View.GONE);
}
}
/**
* Video finished playing, only called in the case of VideoView (typically API level <11)
* @param mp
*/
@Override
public void onCompletion(MediaPlayer mp) {
PalLog.d(X5WebView.TAG, "onCompletion");
onHideCustomView();
}
/**
* Error while playing video, only called in the case of VideoView (typically API level <11)
* @param mp
* @param what
* @param extra
* @return
*/
@Override
public boolean onError(MediaPlayer mp, int what, int extra) {
// By returning false, onCompletion() will be called
return false;
}
/**
* 设置标题回调
* @param callback
*/
public void setOnReceivedTitleCallback(onReceivedTitleCallback callback) {
receivedTitleCallback = callback;
}
/**
* 设置进度条
* @param progressBar
*/
public void setProgressBar(ProgressBar progressBar) {
this.mProgressBar = progressBar;
}
/**
* 指示是否使用自定义视图(一般为全屏)显示视频
*
* @return true 使用自定义视图(一般为全屏)显示视频
*/
public boolean isVideoFullscreen() {
return isVideoFullscreen;
}
/**
* 设置全屏切换回调
*
* @param callback 全屏切换回调
*/
public void setOnToggledFullscreen(ToggledFullscreenCallback callback) {
this.toggledFullscreenCallback = callback;
}
@Override
public void onProgressChanged(WebView view, int newProgress) {
super.onProgressChanged(view, newProgress);
if (mProgressBar != null) {
mProgressBar.setProgress(newProgress);
if (newProgress == 100) {
// onPageFinished
mProgressBar.setVisibility(View.GONE);
}
}
}
@Override
public void onReceivedTitle(WebView view, String title) {
super.onReceivedTitle(view, title);
if (receivedTitleCallback != null) {
receivedTitleCallback.onReceivedTitle(title);
}
}
/**
* Notifies the class that the back key has been pressed by the user.
* This must be called from the Activity's onBackPressed(), and if it returns false, the activity itself should handle it. Otherwise don't do anything.
*
* @return Returns true if the event was handled, and false if it is not (video view is not visible)
*/
public boolean onBackPressed() {
if (isVideoFullscreen) {
onHideCustomView();
return true;
} else {
return false;
}
}
@Override
public boolean onJsAlert(WebView view, String url, String message, final JsResult result) {
return true;
}
/**
* 切换全屏,取消全屏时回调
*/
public interface ToggledFullscreenCallback {
public void toggledFullscreen(boolean fullscreen);
}
/**
* 接收标题回调
*/
public interface onReceivedTitleCallback {
public void onReceivedTitle(String title);
}
}
复制代码
// Native调Js代码的接口
public interface JSCallBack {
// callback 和 params 是 上面“三,Native与Js交互# 最多见方式的使用清单”
void jsCallback(String callback, String params);
void jsCallback(String callback, Object object);
}
复制代码
下面重点介绍是Js调用Native代码的封装AppJsBridge.java
// IJSBridge是Js调用Native代码的接口
public interface IJSBridge {
// 见“三,Js与Native交互”
void processJsBridge(String func, String params);
void setJSCallBack(JSCallBack jsCallBack);
}
// AppJsBridge.java 是Js调用Native代码的封装
public class AppJSBridge implements IJSBridge {
private static final String TAG = "AppJSBridge";
public static final String KEY_CALLBACK = "callback";
// Activity
private BaseActivity mActivity;
// 实际执行Native代码的接口
private OnInvokeCallback mOnInvokeCallback;
// 客户端执行js代码,把结果传给js
private JSCallBack mJSCallBack;
//当前页面的host,用于判断白名单
private String mCurHost;
//白名单
private List<JSBridgeSpecialBean> jsList;
@Override
public void setJSCallBack(JSCallBack jsCallBack) {
mJSCallBack = jsCallBack;
}
/**
* 是不是白名单
*/
private boolean isJsBridgeSpecial(String func) {
if (jsList == null || mCurHost == null)
return false;
for (JSBridgeSpecialBean jsSpecial : jsList) {
if (jsSpecial.allow == null || jsSpecial.allow.isEmpty()) continue;
if (jsSpecial.domain.equals(JSBridgeSpecialBean.TAG_ALL) ||
mCurHost.endsWith(jsSpecial.domain.toLowerCase())) {
if (jsSpecial.allow.get(0).equals(JSBridgeSpecialBean.TAG_ALL))
return true;
else if (jsSpecial.allow.contains(func))
return true;
}
}
return false;
}
@Override
public void processJsBridge(String func, String params, String callbackId) {
PalLog.d(TAG, "func=" + func);
PalLog.d(TAG, "params=" + params);
if (!isJsBridgeSpecial(func)) {
PalLog.e(TAG, func + " 不属于白名单,禁止使用该JS接口");
return;
}
switch (func) {
case "deviceInfo": //获取设备信息
getDeviceInfo(params);
break;
case "userInfo": //获取用户信息
getUserInfo(params);
break;
/// 等等其余case
default:
PalLog.e(TAG, "没法处理的事件: " + func);
break;
}
}
/**
* 获取用户信息
*/
private void getUserInfo(String params) {
if (mJSCallBack == null) return;
try {
// 1,执行Native代码
JSONObject job = new JSONObject(params);
String callback = job.optString(KEY_CALLBACK);
// 从客户端获取一些信息等等
JSONObject result = new JSONObject();
result.put("isLogin", Config.isLogin());
result.put("nickName", Config.getUserName());
result.put("userId", Config.getUserId());
result.put("headimgUrl", Config.getPicUrl());
/// ....
// 2,Native调用Js代码,将结果回传给JS
mJSCallBack.jsCallback(callback, result.toString());
} catch (JSONException e) {
e.printStackTrace();
}
}
/**
* 获取设备信息
*/
private void getDeviceInfo(String params) {
if (mJSCallBack == null) return;
try {
// 1,执行Native代码
JSONObject job = new JSONObject(params);
String callback = job.optString(KEY_CALLBACK);
// 从客户端获取一些信息等等
JSONObject result = new JSONObject();
result.put("os", "Android");
result.put("version", Config.getVersion());
result.put("deviceId", Config.getVersion());
///...
// 2,Native调用Js代码,将结果回传给JS
mJSCallBack.jsCallback(callback, result.toString());
} catch (JSONException e) {
e.printStackTrace();
}
}
}
复制代码