webView 播放视频 有声音和进度条 没有画面 package com.doshare.screen.ui;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Bitmap;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.CountDownTimer;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.webkit.JavascriptInterface;
import android.webkit.JsResult;
import android.webkit.WebChromeClient;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.TextView;
import androidx.core.content.ContextCompat;
import com.doshare.commons.enums.ErrorEnum;
import com.doshare.commons.io.HttpUtils;
import com.doshare.commons.io.Log;
import com.doshare.commons.io.NetworkUtils;
import com.doshare.commons.lang.DateUtils;
import com.doshare.commons.lang.GsonUtils;
import com.doshare.commons.lang.IdUtils;
import com.doshare.commons.lang.StringUtils;
import com.doshare.screen.AppHelper;
import com.doshare.screen.Constants;
import com.doshare.screen.InitApp;
import com.doshare.screen.R;
import com.doshare.screen.ResultBean;
import com.doshare.screen.ResultEnum;
import com.doshare.screen.StringCallback;
import com.doshare.screen.storage.CacheHandler;
import com.doshare.screen.storage.FileHandler;
import com.elvishew.xlog.XLog;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
/**
* 主界面内容区-浏览器
*/
public class BrowserFragment extends BaseFragment {
private final String REQUEST_REMOTE_DATA = "getRemoteData";//请求类型
private String currentFuncId = "";//功能Id
private CommonDialogFragment commonDialog = null;//通用对话框
private Map<String, WebViewGetDataTask> webViewGetDataTaskMap = null;//浏览器获取数据异步任务
private WebView webView;//浏览器
private boolean redirectFlag = false;//重定向标识
private boolean homeShotFlag = false;//首页截屏幕标识
private boolean loadedFlag = false;//页面加载标识
private static final int MSG_LOADUI = 1;
private static final int MSG_SHOWMSG = 2;
private static final int MSG_SETPULLWEBVIEWCOMPLETE = 3;
private static final int MSG_SCREEN_SHOT = 10;//屏幕截屏
private static final String HOME_FUNC_ID = "ClassHome";
//是否门户页面
private boolean portalFlag = false;
public BrowserFragment(boolean portalFlag, String funcId){
super();
this.portalFlag = portalFlag;
this.currentFuncId = funcId;
webViewGetDataTaskMap = new HashMap<String, WebViewGetDataTask>();
}
public String getFuncId(){
return currentFuncId;
}
//region 消息处理
private final Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
switch(msg.what){
case MSG_LOADUI:
break;
case MSG_SHOWMSG:
break;
case MSG_SETPULLWEBVIEWCOMPLETE:
break;
case MSG_SCREEN_SHOT:
if (currentFuncId.contentEquals(HOME_FUNC_ID)) mainActivity.takeScreenShot();
break;
}
}
};
//endregion
//region 覆写Fragment方法
@Override
public void onCreate(Bundle savedInstanceState) {
XLog.d("BrowserFragment onCreate()...");
super.onCreate(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
XLog.d("BrowserFragment onCreateView()...");
mainActivity = (IMainActivity)getActivity();
View rootView = inflater.inflate(R.layout.fragment_browser, container, false);
webView = (WebView) rootView.findViewById(R.id.webView);
registerWebViewEvent();
handler.sendEmptyMessageDelayed(MSG_SCREEN_SHOT, 100);
return rootView;
}
@Override
public void onResume() {
XLog.d("BrowserFragment onResume()...");
super.onResume();
}
/**
* 重新加载数据
* @param forceFlag 是否强制加载
*/
public void reload(boolean forceFlag){
XLog.d("BrowserFragment reload()... " + forceFlag);
Bundle args = getArguments();
if (args != null){
String funcId = args.getString("funcId");
if (!StringUtils.isNullOrEmpty(funcId)){
String url = funcId;
if(!url.startsWith("http://") && !url.startsWith("https://") && !url.startsWith("file:///")){
if (url.startsWith("html://")){
url = StringUtils.trimStart(url, "html://");
String param = "";
if(url.contains("?")){
int i = url.indexOf("?");
String temp = url;
url = url.substring(0,i);
param = temp.substring(i);
}
String anchor = "";
if (url.indexOf("#") != -1){
int pos = url.indexOf("#");
anchor = url.substring(pos);
if(InitApp.profile.getOrientation().equals("vertical") && !anchor.contains("_v")){
anchor = anchor + "_v";
}
url = url.substring(0, pos);
}
if(!StringUtils.isNullOrEmpty(param)){
anchor = anchor + param;
}
url = "file://" + FileHandler.buildFilePath(getContext(), Environment.DIRECTORY_DOCUMENTS, Constants.RESOURCE_FILE_FOLDER + "/" + url + ".html" + anchor);
XLog.d("BrowserFragment reload() url: " + url);
}else{
url = "file:///android_asset/" + url;
XLog.d("BrowserFragment reload() url: " + url);
}
}
funcId = funcId +"?classId="+InitApp.profile.getClassId();
if (!StringUtils.equals(currentFuncId, funcId) || !loadedFlag) {
redirectFlag = false;
loadedFlag = true;
reloadFlag = false;
webView.clearView();
webView.loadUrl(url+"?classId="+InitApp.profile.getClassId());
} else if (loadedFlag && (reloadFlag || forceFlag)) {
redirectFlag = false;
reloadFlag = false;
webView.reload();
}
//巡堂页面打开60s后返回首页
if(funcId.equals("html://main#ccpatrol")){
backToPortalTimer.start();
}
}
}else if (loadedFlag && reloadFlag){
redirectFlag = false;
reloadFlag = false;
webView.reload();
}
}
/**
* 改变当前网址的hash地址
* @param hash hash地址
*/
public void changeHash(String hash){
XLog.d("BrowserFragment changeHash() hash: " + hash);
try{
webView.loadUrl("javascript:window.changeHash('"+hash+"')");
}catch (Exception e){
e.printStackTrace();
}
}
/**
* 注册浏览器事件
*/
private void registerWebViewEvent(){
XLog.d("BrowserFragment registerWebViewEvent()... ");
//webView.getSettings().setUseWideViewPort(true);
webView.getSettings().setLoadWithOverviewMode(true);
webView.getSettings().setAllowFileAccess(true);
webView.getSettings().setSupportZoom(true);
webView.getSettings().setJavaScriptEnabled(true);
webView.getSettings().setDefaultTextEncodingName("utf-8");
webView.getSettings().setLoadsImagesAutomatically(true);
webView.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);
webView.getSettings().setMediaPlaybackRequiresUserGesture(true);
webView.setBackgroundColor(ContextCompat.getColor(getContext(), android.R.color.transparent));
//webView.setBackgroundResource(R.color.transparent);
//webView.getBackground().setAlpha(0);
//webView.setLayerType(View.LAYER_TYPE_SOFTWARE,null);
webView.setWebChromeClient(new WebChromeClient(){
@Override
public boolean onJsAlert(WebView view, String url, String message, final JsResult result) {
Message msg = new Message();
msg.what = MSG_SHOWMSG;
msg.obj = message;
handler.sendMessage(msg);
return true;
}
});
webView.addJavascriptInterface(new JavaScriptInterface(), "webView");
webView.setWebViewClient(new WebViewClient(){
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
redirectFlag = true;
view.loadUrl(url);
return true;
}
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
redirectFlag = false;
super.onPageStarted(view, url, favicon);
}
@Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
if (redirectFlag) {
}
}
});
}
@Override
public void onStart() {
XLog.d("BrowserFragment onStart()... ");
super.onStart();
reload(false);
}
@Override
public void onDestroy() {
XLog.d("BrowserFragment onDestroy()... ");
if (webViewGetDataTaskMap.size() > 0){
String[] keys = new String[webViewGetDataTaskMap.size()];
webViewGetDataTaskMap.keySet().toArray(keys);
for (int i=0;i<keys.length;i++){
webViewGetDataTaskMap.get(keys[i]).cancel(true);
}
}
handler.removeCallbacksAndMessages(null);
super.onDestroy();
}
private final CountDownTimer backToPortalTimer = new CountDownTimer(60 * 1000, 60 * 1000) {
@Override
public void onTick(long millisUntilFinished) { }
@Override
public void onFinish() {
mainActivity.sendMessage(Constants.MSG_GO_PORTAL);
}
};
@Override
public void onHiddenChanged(boolean hidden) {
XLog.d("BrowserFragment onHiddenChanged()... hidden:"+ hidden);
super.onHiddenChanged(hidden);
if (!hidden) reload(false);
}
/**
* 回调
* @param callBackCode 回调代码
*/
@Override
public void callBack(String callBackCode){
XLog.d("BrowserFragment StringCallBack()... ");
}
/**
* 回调
* @param messageCode 消息代码
*/
@Override
public void callBack(int messageCode){
XLog.d("BrowserFragment StringCallBack()... messageCode:"+messageCode);
if (messageCode == MSG_SCREEN_SHOT) homeShotFlag = true;
}
//endregion
//region 对话框
//显示等待对话框
public void showWaitingDialog(){
XLog.d("BrowserFragment showWaitingDialog()...");
commonDialog = new CommonDialogFragment(CommonDialogFragment.DialogTypes.WaitingDialog);
commonDialog.show(getFragmentManager(), "CommonDialogFragment");
}
//显示等待对话框
public void showWaitingMsgDialog(String msg){
XLog.d("BrowserFragment showWaitingDialog()... msg:"+msg);
commonDialog = new CommonDialogFragment(CommonDialogFragment.DialogTypes.WaitingMsgDialog);
commonDialog.setMessage(msg);
commonDialog.show(getFragmentManager(), "CommonDialogFragment");
}
//显示消息对话框
public void showPromptDialog(String title, String msg){
XLog.d("BrowserFragment showWaitingDialog()... title:"+title+" msg:" + msg);
commonDialog = new CommonDialogFragment(CommonDialogFragment.DialogTypes.PromptDialog);
commonDialog.setTitle(title);
commonDialog.setMessage(msg);
commonDialog.setPositiveButton(getResources().getString(R.string.dialog_ok),
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
closeDialog();
}
});
commonDialog.show(getFragmentManager(), "CommonDialogFragment");
}
//显示确认对话框
public void showConfirmDialog(final String funcType, String title, String msg, final String callBackMethod){
XLog.d("BrowserFragment showWaitingDialog()... title:"+title+" msg:" + msg + " funcType" + funcType);
commonDialog = new CommonDialogFragment(CommonDialogFragment.DialogTypes.ConfirmDialog);
commonDialog.setTitle(title);
commonDialog.setMessage(msg);
commonDialog.setPositiveButton(getResources().getString(R.string.dialog_ok),
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
closeDialog();
if (webView != null && !TextUtils.isEmpty(callBackMethod)){
webView.loadUrl("javascript:" + callBackMethod + "('" + funcType + "')");
}
callBack4Confirm(funcType);
}
});
commonDialog.setNegativeButton(getResources().getString(R.string.dialog_cancel),
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
closeDialog();
}
});
commonDialog.show(getFragmentManager(), "CommonDialogFragment");
}
//关闭对话框
public void closeDialog(){
XLog.d("BrowserFragment closeDialog()... ");
androidx.fragment.app.Fragment pre = getFragmentManager().findFragmentByTag("CommonDialogFragment");
if (pre != null){
androidx.fragment.app.FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.remove(pre).commit();
}
commonDialog = null;
}
//显示提示信息(短时间)
public void showToastInShortTime(String msg){
XLog.d("BrowserFragment showToastInShortTime() ... msg:"+ msg);
CommonToast.makeText(getActivity(), msg, CommonToast.LENGTH_SHORT).show();
}
//显示提示信息(长时间)
public void showToastInLongTime(String msg){
XLog.d("BrowserFragment showToastInLongTime() ... msg:"+ msg);
CommonToast.makeText(getActivity(), msg, CommonToast.LENGTH_LONG).show();
}
//确认框回调
private void callBack4Confirm(String funcType){
XLog.d("BrowserFragment callBack4Confirm() ... funcType:"+ funcType);
}
//endregion
//region 浏览器脚本接口
final class JavaScriptInterface {
//跳转至视频播放页面
@JavascriptInterface
public void viewVideo(String message, String srcPath, String videoName){
XLog.d("BrowserFragment viewVideo() ... msg:"+ message + " srcPath:" + srcPath + " videoName:" + videoName);
//String url =
Intent intent=new Intent();
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setClass(InitApp.getContext(),ScreenVideoActivity.class);
intent.putExtra("videoUrl",message);
intent.putExtra("srcPath",srcPath);
intent.putExtra("videoName",videoName);
InitApp.getContext().startActivity(intent);
}
//显示消息对话框
@JavascriptInterface
public void showMessage(String message){
XLog.d("BrowserFragment showMessage() ... msg:"+ message);
showPromptDialog(getResources().getString(R.string.dialog_title), message);
}
//显示确认对话框
@JavascriptInterface
public void showConfirm(String funcType, String title, String message, String callBackMethod){
XLog.d("BrowserFragment showConfirm() ... msg:"+ message + " funcType:" + funcType + " title:" + title);
showConfirmDialog(funcType, TextUtils.isEmpty(title) ? getResources().getString(R.string.dialog_title) : title, message, callBackMethod);
}
//异步调用获取数据
@JavascriptInterface
public void onscreenrequest(String interfaceCode, String interface_parameters, String onComplete, boolean showLoading){
XLog.d("BrowserFragment onscreenrequest() ... interfaceCode:"+ interfaceCode + " interface_parameters:" + interface_parameters);
if (NetworkUtils.checkNetwork(getContext())){//在线异步请求
Map<String, String> params = new HashMap<>();
params.put("interface_code", interfaceCode);
params.put("interface_parameters", interface_parameters);
params.put("onComplete", onComplete);
String taskId = IdUtils.generateUUID();
WebViewGetDataTask task = new WebViewGetDataTask(taskId, showLoading);
webViewGetDataTaskMap.put(taskId, task);
task.execute(params);
}else{//本地缓存同步请求
try{
String result = CacheHandler.requestJson4Cache(interfaceCode, interface_parameters);
webView.loadUrl("javascript:window.invokeCallback('" + onComplete + "',eval('("+result+")'))");
}catch(Exception e){
e.printStackTrace();
Log.d("CacheHandler.request4Cache", String.format("%s:%s invoke error", interfaceCode, interface_parameters));
}
}
}
//获取访问令牌
@JavascriptInterface
public String getAccessToken(){
XLog.d("BrowserFragment getAccessToken() ...");
return InitApp.profile.getToken();
}
//获取后台服务地址
@JavascriptInterface
public String getRemoteUrl(){
XLog.d("BrowserFragment getRemoteUrl() ...");
return AppHelper.getUrl() + "/oauth2/resources";
}
@JavascriptInterface
public String getDeviceCode(){
XLog.d("BrowserFragment getDeviceCode() ...");
return InitApp.profile.getDeviceCode();
}
//教室
@JavascriptInterface
public String getClassRoom(){
XLog.d("BrowserFragment getClassRoom() ...");
return InitApp.profile.getClassroomName();
}
@JavascriptInterface
public String getClassRoomId(){
XLog.d("BrowserFragment getClassRoomId() ...");
return InitApp.profile.getClassroomId();
}
@JavascriptInterface
public int getYearWeek(){
XLog.d("BrowserFragment getYearWeek() ...");
Calendar c = Calendar.getInstance();
return c.get(Calendar.WEEK_OF_YEAR);
}
//当前课程和教师
@JavascriptInterface
public String getCourseAndTeacher(){
XLog.d("BrowserFragment getCourseAndTeacher() ...");
String course = "";
String teacher = "";
String nowTime = DateUtils.dateTimeToString(new Date()).split(" ")[1];
String nowTimeStr = nowTime.split(":")[0]+":"+nowTime.split(":")[1];
ListView timetableList = getActivity().findViewById(R.id.timetable_list);
if(timetableList == null){
TextView tvCourse = getActivity().findViewById(R.id.tv_course_name);
TextView tvTeacher = getActivity().findViewById(R.id.tv_teacher_name);
if(tvCourse != null && tvTeacher != null){
return tvCourse.getText() + ":" + tvTeacher.getText();
}else{
return "";
}
}
ListAdapter adapter = timetableList.getAdapter();
if(adapter != null){
for(int i = 0; i < adapter.getCount(); i++){
String s = GsonUtils.object2Json(adapter.getItem(i));
Map<String, Object> map = GsonUtils.json2Map(s);
String time = map.get("time").toString();
if(!StringUtils.isNullOrEmpty(time)){
String time1 = time.split("-")[0];
String time2 = time.split("-")[1];
if(nowTimeStr.compareTo(time1) >= 0 && nowTimeStr.compareTo(time2) <=0){
course = map.get("courseName").toString();
teacher = map.get("teacherName").toString();
}
}
}
}
return course + ":" + teacher;
}
@JavascriptInterface
public String getClassId() {
XLog.d("BrowserFragment getClassId() ...");
return InitApp.profile.getClassId();
}
//异步调用获取文本资源
@JavascriptInterface
public String onscreenloader(String name, String dataType){
XLog.d("BrowserFragment onscreenloader() ... name:" + name + " dataType:" + dataType);
String filePathName = "/" + Constants.RESOURCE_FILE_FOLDER + "/" + name;
return FileHandler.readText(getContext(), Environment.DIRECTORY_DOCUMENTS, filePathName);
}
//是否门户页所在浏览器
@JavascriptInterface
public boolean isPortalBrowser(){
XLog.d("BrowserFragment isPortalBrowser() ...");
return portalFlag;
}
@JavascriptInterface
public String getBrowserName(){
XLog.d("BrowserFragment isPortalBrowser() ...");
return portalFlag ? "portal" : "browser2";
}
//页面跳转(门户页跳转到内容页,或内容页内部跳转)
@JavascriptInterface
public void redirect(String hash){
XLog.d("BrowserFragment redirect() ... hash:"+hash);
Message msg = new Message();
msg.what = Constants.MSG_REDIRECT;
Bundle args = new Bundle();
args.putString("hash", hash);
msg.setData(args);
mainActivity.sendMessage(msg);
}
//返回门户页面(内容页面返回门户页面)
@JavascriptInterface
public void backPortal() {
XLog.d("BrowserFragment backPortal() ... ");
mainActivity.sendMessage(Constants.MSG_GO_PORTAL);
}
//改变页面地址(仅用于改变内容页浏览器地址)
@JavascriptInterface
public void changeUrl(String url){
XLog.d("BrowserFragment changeUrl() ... url:"+url);
if (!portalFlag) currentFuncId = url;
}
@JavascriptInterface
public void returnAttend(){
XLog.d("BrowserFragment returnAttend() ... ");
mainActivity.changePage("app://Attend", "考勤");
}
}
//浏览器获取数据任务内部类
//参数一:启动任务执行的输入参数类型
//参数二:后台任务执行的进度参数类型
//参数三:后台计算结果的类型
class WebViewGetDataTask extends AsyncTask<Map<String, String>, Void, ResultBean> {
private final String id;
private final boolean showWaiting;
private String callBackMehtod;
public WebViewGetDataTask(){
this(IdUtils.generateUUID(), true);
}
public WebViewGetDataTask(String id, boolean showWaiting){
this.id = id;
this.showWaiting = showWaiting;
}
//任务开始后立即执行,可在此处对UI进行标记处理
@Override
protected void onPreExecute() {
if (showWaiting){
showWaitingDialog();
}
}
//在onPreExecute()完成后立即执行,用于执行较为费时的操作
@Override
protected ResultBean doInBackground(Map<String, String>... params) {
if (!NetworkUtils.checkNetwork(getContext())){
return ResultBean.getInstance(REQUEST_REMOTE_DATA, params[0], ResultEnum.String,
ErrorEnum.NETWORK_OFFLINE);
}
try {
String interface_code = params[0].get("interface_code");
String interface_parameters = params[0].get("interface_parameters");
callBackMehtod = params[0].get("onComplete");
Map<String, String> postParams = getPostParams(interface_code, interface_parameters);
StringCallback callback = new StringCallback();
String url = AppHelper.getUrl() + "/oauth2/resources";
XLog.d("BrowserFragment WebViewGetDataTask url:" + url + " params:" + postParams);
HttpUtils.post(url, postParams, callback);
return ResultBean.getInstance(REQUEST_REMOTE_DATA, params[0], callback);
} catch (Exception e) {
XLog.e("BrowserFragment WebViewGetDataTask 异常:");
XLog.e(e);
return ResultBean.getInstance(REQUEST_REMOTE_DATA, params[0], ResultEnum.String, ErrorEnum.ERROR);
}
}
//任务结束时执行,计算结果被传递到此方法中,在此处恢复UI标记
@Override
protected void onPostExecute(final ResultBean result) {
webViewGetDataTaskMap.remove(id);
if (showWaiting) closeDialog();
if (result.isSuccess()){
XLog.d("BrowserFragment WebViewGetDataTask success:");
if (!TextUtils.isEmpty(callBackMehtod)){
String resultJson = StringUtils.replace(result.getStringResult(),"\"", "\\\"");
webView.loadUrl("javascript:window.invokeCallback('" + callBackMehtod + "',eval('("+resultJson+")'))");
}
}else{
XLog.e("BrowserFragment WebViewGetDataTask error:"+ result.getErrorCode() + ":" + result.getErrorDesc());
Map<String,Object> map = (Map<String, Object>) result.getRequestParameters();
String interface_code = map.get("interface_code").toString();
if(interface_code.equals("getClassPersonalCard")){
if(result.getErrorCode().equals("010004")){
CommonToast.makeText(getActivity(), "用户表资料缺失", CommonToast.LENGTH_SHORT).show();
}
}
}
}
//取消任务时执行
@Override
protected void onCancelled() {
XLog.d("BrowserFragment onCancelled()");
webViewGetDataTaskMap.remove(id);
if (showWaiting) closeDialog();
}
/**
* 获取post请求参数
* @param interface_code 接口代码
* @param interface_parameters 接口参数
* @return post请求参数
*/
private Map<String, String> getPostParams(String interface_code, String interface_parameters){
XLog.d("BrowserFragment getPostParams()... interface_code:" + interface_code + " interface_parameters:" + interface_parameters);
Map<String, String> params = new HashMap<>();
params.put("access_token", InitApp.profile.getToken());
params.put("classId", InitApp.profile.getClassId());
params.put("interface_code", interface_code);
params.put("interface_parameters", interface_parameters);
return params;
}
}
//endregion
}