package com.ydl.webview; import android.annotation.SuppressLint; import android.annotation.TargetApi; import android.app.Activity; import android.content.ClipData; import android.content.Context; import android.content.Intent; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.Color; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.text.TextUtils; import android.util.Log; import android.view.KeyEvent; import android.view.View; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.PopupWindow; import com.alibaba.android.arouter.facade.annotation.Route; import com.alibaba.android.arouter.launcher.ARouter; import com.tencent.smtt.export.external.interfaces.JsResult; import com.tencent.smtt.export.external.interfaces.SslError; import com.tencent.smtt.export.external.interfaces.SslErrorHandler; import com.tencent.smtt.sdk.CookieSyncManager; import com.tencent.smtt.sdk.ValueCallback; import com.tencent.smtt.sdk.WebChromeClient; import com.tencent.smtt.sdk.WebSettings; import com.tencent.smtt.sdk.WebView; import com.tencent.smtt.sdk.WebViewClient; import com.umeng.socialize.UMShareAPI; import com.umeng.socialize.bean.SHARE_MEDIA; import com.ydl.utils.PopUtils; import com.ydl.utils.ProxyCheckUtils; import com.ydl.utils.WebUrlParamsUtils; import com.ydl.view.ArticleDialogFragment; import com.ydl.view.ShareMeditationDialog; import com.ydl.ydl_router.manager.YDLRouterManager; import com.ydl.ydlcommon.base.BaseActivity; import com.ydl.ydlcommon.base.BaseApp; import com.ydl.ydlcommon.bean.ShareData; import com.ydl.ydlcommon.bean.StatusBarOptions; import com.ydl.ydlcommon.event.MeditationEvent; import com.ydl.ydlcommon.modular.ModularServiceManager; import com.ydl.ydlcommon.ui.LogoLoadingView; import com.ydl.ydlcommon.utils.ActivityManager; import com.ydl.ydlcommon.utils.BuryPointUtils; import com.ydl.ydlcommon.utils.LogUtil; import com.ydl.ydlcommon.utils.NetWorkSpeedUtils; import com.ydl.ydlcommon.utils.StatusBarUtils; import com.ydl.ydlcommon.utils.URLUtils; import com.ydl.ydlcommon.utils.actionutil.ActionCountUtils; import com.ydl.ydlcommon.utils.log.AliYunLogConfig; import com.ydl.ydlcommon.utils.log.AliYunRichLogsHelper; import com.ydl.ydlcommon.view.TitleBar; import com.ydl.ydlcommon.view.dialog.YDLCommonDialog; import com.ydl.ydlcommon.view.dialog.YDLShareDialog; import com.yidianling.common.tools.RxDeviceTool; import com.yidianling.common.tools.RxImageTool; import com.yidianling.common.tools.ToastUtil; import com.yidianling.dynamic.api.IDynamicService; import com.yidianling.user.api.event.UserBindPhoneEvent; import com.yidianling.user.api.event.UserLoginEvent; import com.yidianling.user.api.service.IAppService; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.json.JSONException; import org.json.JSONObject; import java.net.URI; import java.util.HashMap; import java.util.Map; import de.greenrobot.event.EventBus; import in.srain.cube.views.ptr.PtrDefaultHandler; import in.srain.cube.views.ptr.PtrFrameLayout; import in.srain.cube.views.ptr.PtrHandler; import in.srain.cube.views.ptr.header.MaterialHeader; import io.reactivex.Observable; import io.reactivex.android.schedulers.AndroidSchedulers; import static android.view.View.GONE; import static android.view.View.VISIBLE; /** * 通用h5显示页面 * 跳转此h5页面,请使用唯一参数 H5ParamsBaseActivity */ @Route(path = "/new_h5/h5") public class NewH5Activity extends BaseActivity implements PtrHandler { public static final String PARAMS = "h5Params"; /*** 路由传递过来的参数*/ public static final String ROUTER_PARAMS = "routerParam"; /***下单选择时间请求吗*/ public static final int ORDER_TIME_REQUEST_CODE = 110; /***启动类型 0正常模式 1从下至上打开页面*/ private int startType = 0; /***右侧按钮文字*/ private String rightText = ""; protected TitleBar tb_title; protected View tb_title_cover_v; protected ImageView backgroundView; protected ProgressWebView wv_content; protected PtrFrameLayout store_house_ptr_frame; protected SafeTipView safeTipView; /***接收参数*/ private H5Params h5Params; /***分享到发布需要的url*/ protected String purl; protected String shareUrl; protected String shareTitle; protected String shareDesc; private String cover; private String miniId; private String miniPath; // 评价2.0新增字段 区分评价列表 private H5JsBean.H5JsCmd.Params paramsForCommentList; private boolean isShareCommentList; private boolean isDarkMode = false; private ShareMeditationDialog shareMeditationDialog; private ArticleDialogFragment commentArticleDialog; protected PopupWindow popupWindow; protected ValueCallback<Uri> uploadMessage; protected ValueCallback<Uri[]> uploadMessageAboveL; private boolean shouldClearHistory = false; /***要分享出去的url*/ private String shareToUrl; /*** 拍照/选择文件请求码*/ protected final static int FILE_CHOOSER_RESULT_CODE = 10000; protected IJavascriptHandler jtoJHandle; private boolean loadFailed; private LinearLayout llWebView; /***加载url开始的时间*/ private long loadStartTime = 0; /***webview初始化开始的时间*/ private long initStartTime = 0; /***webview初始化耗时*/ private long initDuration = 0; /***加载url耗时*/ private long loadDuration = 0; private NetWorkSpeedUtils workSpeedUtils; /***部分机型中webview加载完成回调方法会调用多次,增加本地标识符*/ private boolean hasLoad = false; /***是否跳转到动态*/ private boolean isToTrend = false; private LogoLoadingView v_loading; /***是否超时*/ private boolean isTimeOut = false; /***超时处理handler*/ private Handler mTimeOutHandler = null; /***超时限定时间*/ private int timeOutLong = 15000; /***超时消息*/ private int TIME_OUT_TYPE = 0x1000; /** * 设置微信 H5 支付调用 loadDataWithBaseURL 的标记位,避免循环调用, * 再次进入微信 H5 支付流程时记得重置此标记位状态 */ boolean firstVisitWXH5PayUrl = true; private String WX_H5_PAY_HOST = "http://testnewm.ydl.com"; /*** 当前页面类型*/ private int selfPageType = -1; /***测评题页面*/ private int TEST_QUESTIONS_PAGE_TYPE = 1000001; private YDLCommonDialog testQuestionsPageReturnDialog = null; /*** 标题栏是否被覆盖隐藏*/ private boolean isTitleBarCover = false; private static IWebRightClickListener webRightClickListener = null; /** * 设置当前h5页面类型 * * @param pageType */ public void setSelfPageType(int pageType) { selfPageType = pageType; // 如果是测试题页面 if (selfPageType == TEST_QUESTIONS_PAGE_TYPE) { if (null != tb_title) { tb_title.setImageListener(v -> { if (!isTitleBarCover) { showTestQuestionPageReturnDialog(); } }); tb_title.setOnLeftTextClick((view, isActive) -> { if (!isTitleBarCover) { showTestQuestionPageReturnDialog(); } }); } } } public static void start(Context context, H5Params h5Params1) { if (null == context) { return; } Intent intent = new Intent(context, NewH5Activity.class); if (!(context instanceof Activity)) { intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); } intent.putExtra(PARAMS, h5Params1); context.startActivity(intent); } public static void start(Context context, H5Params h5Params1, String rightText, IWebRightClickListener listener) { if (null == context) { return; } webRightClickListener = listener; Intent intent = new Intent(context, NewH5Activity.class); if (!(context instanceof Activity)) { intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); } intent.putExtra("rightText", rightText); intent.putExtra(PARAMS, h5Params1); context.startActivity(intent); } public static void start(Context context, H5Params h5Params, TellData tellData) { if (null == context) { return; } Intent intent = new Intent(context, NewH5Activity.class); intent.putExtra(PARAMS, h5Params); intent.putExtra("tell_data", tellData); context.startActivity(intent); } public static void start(Activity context, H5Params h5Params1, int startType, String rightText) { if (null == context) { return; } Intent intent = new Intent(context, NewH5Activity.class); intent.putExtra("startType", startType); intent.putExtra("rightText", rightText); intent.putExtra(PARAMS, h5Params1); context.startActivity(intent); } public static void startForResult(Activity context, H5Params h5Params1, int requestCode) { if (null == context) { return; } WebModularServiceUtils.Companion.getUserService().isLogin(); Intent intent = new Intent(context, NewH5Activity.class); intent.putExtra(PARAMS, h5Params1); context.startActivityForResult(intent, requestCode); } public static void startForResult(Activity context, H5Params h5Params1, int requestCode, int startType, String rightText) { if (null == context) { return; } Intent intent = new Intent(context, NewH5Activity.class); intent.putExtra(PARAMS, h5Params1); intent.putExtra("startType", startType); intent.putExtra("rightText", rightText); context.startActivityForResult(intent, requestCode); } @Override protected int layoutResId() { return R.layout.web_activity_h5_new; } public String successPage; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { initStartTime = System.currentTimeMillis(); super.onCreate(savedInstanceState); overridePendingTransition(R.anim.platform_activity_anim_in, R.anim.platform_activity_anim_out); } private void initTimeOutHandler() { mTimeOutHandler = new Handler(msg -> { if (wv_content.getProgress() < 100) { isTimeOut = true; llWebView.setVisibility(View.GONE); v_loading.setVisibility(View.VISIBLE); v_loading.setViewType(LogoLoadingView.TYPE_NET_LOSS, null); } return false; }); sendNetLossMessage(); } /** * 15秒后发送一条消息通知展示无网络页面 */ private void sendNetLossMessage() { if (null != mTimeOutHandler) { mTimeOutHandler.sendEmptyMessageDelayed(TIME_OUT_TYPE, timeOutLong); } } /** * 取消预定15秒后发送的消息 */ private void cancelSendNetLossMessage() { if (null != mTimeOutHandler) { mTimeOutHandler.removeMessages(TIME_OUT_TYPE); } } private void initLoadingView() { wv_content.setBackgroundColor(0); wv_content.getBackground().setAlpha(0); v_loading = findViewById(R.id.v_loading); v_loading.setListener(new LogoLoadingView.LogoLoadingListener() { @Override public void onDataResetClick() { sendNetLossMessage(); isTimeOut = false; llWebView.setVisibility(View.VISIBLE); v_loading.setVisibility(View.VISIBLE); v_loading.setViewType(LogoLoadingView.TYPE_LOADING, null); loadUrl(h5Params.getUrl()); shouldClearHistory = true; } @Override public void onBackClick() { finish(); } }); } private void getParam() { if (null != getIntent()) { //正常获取入参 h5Params = (H5Params) getIntent().getSerializableExtra(PARAMS); //路由传递的入参 if (getIntent().hasExtra(ROUTER_PARAMS)) { String json = getIntent().getStringExtra(ROUTER_PARAMS); try { JSONObject jsonObject = new JSONObject(json); h5Params = new H5Params(jsonObject.getString("url"), ""); } catch (JSONException e) { e.printStackTrace(); } } } } @NotNull @Override public StatusBarOptions getStatusViewOptions() { return new StatusBarOptions(true, true); } @Override protected void initDataAndEvent() { getParam(); TellData tellData = (TellData) getIntent().getSerializableExtra("tell_data"); if (tellData == null) { tellData = new TellData(); } initView(); if (!BaseApp.instance.getGlobalConfig().getAppDebug()&& ProxyCheckUtils.INSTANCE.isWifiProxy(this)){ ToastUtil.toastShort("网络设置错误"); return; } startType = getIntent().getIntExtra("startType", 0); rightText = getIntent().getStringExtra("rightText"); if (h5Params == null) { ToastUtil.toastShort("参数错误"); AliYunRichLogsHelper.Companion.getInstance().sendRichLog(AliYunLogConfig.WEB, "参数错误 Params == null"); finish(); return; } setUrlHeightParams(); EventBus.getDefault().register(this); jtoJHandle = WebModularServiceUtils.Companion.getWebService().getJavascripHandler(this, wv_content, tellData); init(); if (startType == 1) { tb_title.setImageVis(0); tb_title.setLeftTextVisible(View.GONE); tb_title.setmRightText(rightText); tb_title.setOnRightTextClick((view, isActive) -> { finish(); }); } else if (!TextUtils.isEmpty(rightText) && webRightClickListener != null) { tb_title.setmRightText(rightText); tb_title.setOnRightTextClick((view, isActive) -> { webRightClickListener.onCLick(view); }); } llWebView = findViewById(R.id.ll_web_view); initLoadingView(); initTimeOutHandler(); } /** * 专家详情页改版 需要url后面拼接状态栏高度 并且隐藏导航栏 */ private void setUrlHeightParams() { String url = h5Params.getUrl(); //兼容课程详情页url if (!TextUtils.isEmpty(url) && url.contains("course/Detail/") && !url.contains("course/Detail/v2/")) { url = url.replace("course/Detail/", "course/Detail/v2/"); //再次替换 方哥那边解决不了域名的问题 app中强行匹配修改 if (url.contains("fe-app-yidianling")) { int index = url.indexOf("course/Detail"); String newUrl = url.substring(index, url.length()); if (url.contains("test")) { newUrl = "https://testnewm.ydl.com/" + newUrl; } else { newUrl = "https://m.ydl.com/" + newUrl; } url = newUrl; } } url = pinjie(url); h5Params.setUrl(url); } /** * 专家详情页改版 需要url后面拼接状态栏高度 并且隐藏导航栏 * * @param url * @return */ private String setUrlHeightParams(String url) { String resultUrl = url; try { Uri uri = Uri.parse(url); String host = uri.getHost(); if (!TextUtils.isEmpty(host) && host.contains("nodeapi.ydl")) { //马亮的需求,在nodeapi.ydl.com 地址后面拼上公共参数,用于判断是否为app String uriAppendSuffix = jtoJHandle.getUriAppendSuffix(); resultUrl = WebUrlParamsUtils.getSuffix(url, uriAppendSuffix); } } catch (Exception e) { e.printStackTrace(); } return pinjie(resultUrl); } private String pinjie(String jumpUrl) { if (jumpUrl.contains("hideNavBar=1")) { hideJavaTitleBar(); return jumpUrl; } else if (jumpUrl.contains("hideNavBar=2")) { showTitleBar(); return jumpUrl; } String useUrl = new StringBuffer().append(jumpUrl).toString(); Resources res = getResources(); String[] doctorUrlArray = res.getStringArray(R.array.platform_doctorUrls); for (String url : doctorUrlArray) { if (useUrl.contains(url)) { String lastUrl = useUrl.replaceAll(url, ""); if (lastUrl.contains("?")) { lastUrl = lastUrl.substring(0, lastUrl.indexOf("?")); } try { //不报错就说明可以转成long,就说明是专家详情页地址 Long.parseLong(lastUrl); if (!lastUrl.contains("/")) { if (useUrl.endsWith("?")) { useUrl = useUrl.substring(0, useUrl.indexOf("?")); } if (!useUrl.contains("barHeight")) { String paramsStr = useUrl.contains("?") ? "&barHeight=" + String.valueOf(StatusBarUtils.Companion.getStatusBarHeight(NewH5Activity.this)) : "?barHeight=" + String.valueOf(StatusBarUtils.Companion.getStatusBarHeight(NewH5Activity.this)); useUrl = new StringBuffer().append(useUrl).append(paramsStr).toString(); } hideJavaTitleBar(); } } catch (NumberFormatException e) { e.printStackTrace(); } } } return useUrl; } public void hasShowDownRefresh(boolean isVisible) { store_house_ptr_frame.post(() -> store_house_ptr_frame.setEnabled(isVisible)); } public void refresh() { store_house_ptr_frame.autoRefresh(); } public void showShareMenu(H5JsBean.H5JsCmd.Params params) { LogUtil.d("showShareMenu"); if (params.getShare() != null) { LogUtil.d("params.getShare() not null"); purl = params.getShare().getUrl(); shareUrl = params.getShare().getShare_url(); shareTitle = params.getShare().getTitle(); shareDesc = params.getShare().getDesc(); cover = params.getShare().getCover(); paramsForCommentList = params; LogUtil.d("title: " + shareTitle + " url: " + shareUrl + " desc: " + shareDesc + " cover: " + cover); new Handler(getMainLooper()).post(() -> initShareMenu()); } } public void openRightTopMenu() { popupWindow = PopUtils.showMoreItem(this, tb_title.getRootView(), jtoJHandle); } public void openShareMenu(H5JsBean.H5JsCmd.Params params) { if (params.getShare() != null) { if ("Meditation".equals(params.getShare().getType())){ shareUrl = params.getShare().getShare_url(); shareTitle = params.getShare().getTitle(); shareDesc = params.getShare().getDesc(); cover = params.getShare().getCover(); miniId = params.getShare().getMinProgramId(); miniPath = params.getShare().getMinProgramPath(); isDarkMode = params.getShare().isDarkMode(); if (shareMeditationDialog == null) { shareMeditationDialog = ShareMeditationDialog.Companion.newInstance(isDarkMode, shareUrl, shareTitle, shareDesc, cover, miniId, miniPath); } if (shareMeditationDialog != null && !shareMeditationDialog.isAdded()) { shareMeditationDialog.show(getSupportFragmentManager(), "share_meditation"); } }else { purl = params.getShare().getUrl(); shareUrl = params.getShare().getShare_url(); shareTitle = params.getShare().getTitle(); shareDesc = params.getShare().getDesc(); cover = params.getShare().getCover(); LogUtil.d("title: " + shareTitle + " url: " + shareUrl + " desc: " + shareDesc + " cover: " + cover); String base64DataStr = params.getImageBase64(); share(base64DataStr, params); } } } private void initView() { tb_title = (TitleBar) findViewById(R.id.tb_title); tb_title_cover_v = (View) findViewById(R.id.tb_title_cover_v); tb_title.setPaddingLeft(10); wv_content = (ProgressWebView) findViewById(R.id.wv_content); backgroundView = findViewById(R.id.iv_background); store_house_ptr_frame = (PtrFrameLayout) findViewById(R.id.store_house_ptr_frame); safeTipView = (SafeTipView) findViewById(R.id.safe_tip_view); if (h5Params != null && h5Params.isControlBack()) { store_house_ptr_frame.setEnabled(false); } else { store_house_ptr_frame.setEnabled(true); } } //js修改UI的操作需要放在UI线程中更新 public void hideJavaTitleBar() { runOnUiThread(() -> { tb_title.setVisibility(View.GONE); if (null != getStatusView()) { if (selfPageType == TEST_QUESTIONS_PAGE_TYPE) { //测评题隐藏标题的时候,不隐藏状态栏 } else { getStatusView().setVisibility(View.GONE); } } }); } public void setBottomViewColor(String color) { runOnUiThread(() -> { setBottomColor(color); }); } public void showTitleBar() { runOnUiThread(() -> { tb_title.setVisibility(VISIBLE); if (null != getStatusView()) { getStatusView().setVisibility(VISIBLE); } }); } //js修改UI的操作需要放在UI线程中更新,覆盖标题 public void coverJavaTitleBar() { isTitleBarCover = true; runOnUiThread(() -> { tb_title_cover_v.setVisibility(VISIBLE); }); } public void notCoverTitleBar() { isTitleBarCover = false; runOnUiThread(() -> { tb_title_cover_v.setVisibility(GONE); }); } public void closeWebKit() { finish(); } @SuppressLint({"WrongConstant", "AddJavascriptInterface", "SetJavaScriptEnabled"}) void init() { final Intent intent = getIntent(); purl = intent.getStringExtra("purl"); //要加"more"按钮 if (h5Params.isShowMenu()) { tb_title.setRightImageListener(v -> popupWindow = PopUtils.showMoreItem(this, tb_title.getRootView(), jtoJHandle)); tb_title.setRightImageIfShouldSee(); } else { tb_title.setRightImageIfNoSee(); } if (h5Params.getShareData() != null && h5Params.getShareData().getShare_url() != null) { shareUrl = h5Params.getShareData().getShare_url(); shareTitle = h5Params.getShareData().getTitle(); shareDesc = h5Params.getShareData().getDesc(); cover = h5Params.getShareData().getCover(); initShareMenu(); } if (!TextUtils.isEmpty(h5Params.getTitle()) && !h5Params.getShowUrlTitle()) { tb_title.setTitle(h5Params.getTitle()); } tb_title.setImage(getResources().getDrawable(R.drawable.web_common_back)); WebSettings setting = wv_content.getSettings(); //支持js setting.setJavaScriptEnabled(true); //设置字符编码 setting.setDefaultTextEncodingName("GBK"); setting.setDomStorageEnabled(true); String appCachePath = getApplicationContext().getCacheDir().getAbsolutePath(); setting.setAppCachePath(appCachePath); setting.setAllowFileAccessFromFileURLs(true); setting.setAppCacheEnabled(true); setting.setAllowFileAccess(true); // 解决图片不显示 setting.setBlockNetworkImage(false); //设置自动缩放 degmi的测试题不能设置 不然界面展示有问题 if (h5Params.getUrl().contains("l.yidianling.com") || h5Params.getUrl().contains("l.ydl.com")) { //l.yidianling.com 这个域名 只有云凤蝶使用 这个平台需要设置自适应 不然显示有问题 setting.setUseWideViewPort(true); setting.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NARROW_COLUMNS); setting.setLoadWithOverviewMode(true); } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { setting.setMixedContentMode(WebSettings.LOAD_NORMAL); } wv_content.setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY);//滚动条风格,为0指滚动条不占用空间,直接覆盖在网页上 tb_title.setImageListener(v -> { if (h5Params.isSplash()) { WebModularServiceUtils.Companion.startMain(NewH5Activity.this); finish(); } else { if (ActivityManager.Companion.getInstance().getActivitys().size() == 1) { WebModularServiceUtils.Companion.startMain(NewH5Activity.this); } finish(); } }); if (startType != 1) { tb_title.setImageVis(1); } wv_content.addJavascriptInterface(jtoJHandle, "javascriptHandler"); //noinspection unused wv_content.setWebChromeClient(new WebChromeClient() { @Override public boolean onJsAlert(WebView webView, String s, String s1, JsResult jsResult) { return super.onJsAlert(webView, s, s1, jsResult); } @Override public void onProgressChanged(WebView view, int newProgress) { if (newProgress == 100) { wv_content.getProgressbar().setVisibility(GONE); } else { if (wv_content.getProgressbar().getVisibility() == GONE) { wv_content.getProgressbar().setVisibility(VISIBLE); } wv_content.getProgressbar().setProgress(newProgress); } super.onProgressChanged(view, newProgress); } @Override public void onReceivedTitle(WebView view, String title) { super.onReceivedTitle(view, title); if (TextUtils.isEmpty(h5Params.getTitle())){ tb_title.setTitle(title); } wv_content.setTitle(title); if ("我的订单".equals(title)) { safeTipView.setVisibility(View.VISIBLE); safeTipView.updateVisibility(); safeTipView.setLocation("orderList"); } if (title.contains("404") || title.contains("500") || title.contains("Error")) { AliYunRichLogsHelper.Companion.getInstance() .sendRichLog(AliYunLogConfig.WEB, "页面错误 : url:" + view.getUrl() + "title:" + title); } } // For Android < 3.0 public void openFileChooser(ValueCallback<Uri> valueCallback) { uploadMessage = valueCallback; openImageChooserActivity(); } // For Android >= 3.0 public void openFileChooser(ValueCallback valueCallback, String acceptType) { uploadMessage = valueCallback; openImageChooserActivity(); } //For Android >= 4.1 @Override public void openFileChooser(ValueCallback<Uri> valueCallback, String acceptType, String capture) { uploadMessage = valueCallback; openImageChooserActivity(); } // For Android >= 5.0 @Override public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, WebChromeClient.FileChooserParams fileChooserParams) { uploadMessageAboveL = filePathCallback; openImageChooserActivity(); return true; } }); if (h5Params.getShowUrlTitle()) { wv_content.setWebViewClient(new WebViewClient() { @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { Boolean overridePayUrl = shouldOverridePayUrl(view, url); if (overridePayUrl != null) { return overridePayUrl; } if (!TextUtils.isEmpty(url) && url.endsWith(".apk")) { Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); startActivity(intent); } else if (url.startsWith("tel://")){ Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); startActivity(intent); } else if (!TextUtils.isEmpty(url) && url.startsWith("http")) { loadUrl(setUrlHeightParams(url)); } else { if (!YDLRouterManager.Companion.router(url)) { loadUrl(setUrlHeightParams(url)); } } return true; } @Override public void onPageStarted(WebView view, String url, Bitmap favicon) { super.onPageStarted(view, url, favicon); } @Override public void onPageFinished(WebView view, String url) { if (!hasLoad) { hasLoad = true; loadDuration = System.currentTimeMillis() - loadStartTime; LogUtil.e("initDuration:" + initDuration + ",loadDuration:" + loadDuration); // UploadWebViewTimeUtils.Companion.uploadWebViewTime(h5Params.getUrl(), initDuration + "", loadDuration + "", workSpeedUtils.getNetSpeed()); } if (shouldClearHistory) { wv_content.clearHistory(); shouldClearHistory = false; } back("top"); if (!loadFailed) { v_loading.setVisibility(View.GONE); } cancelSendNetLossMessage(); } @Override public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) { onReceivedSslErrorHandle(handler); } @Override public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) { super.onReceivedError(view, errorCode, description, failingUrl); AliYunRichLogsHelper.Companion.getInstance() .sendRichLog(AliYunLogConfig.WEB, "onReceivedError---- errorCode: " + errorCode + "----failingUrl:" + failingUrl); LogUtil.e("webviewErrorCode:" + errorCode + "description:" + description); loadFailed = true; tb_title.setTitle("加载中"); if (wv_content != null) { wv_content.loadDataWithBaseURL(null, "<!doctype html>\n" + "<html>\n" + "<head>\n" + "<meta charset=\"utf-8\">\n" + "<title></title>\n" + "</head>\n" + "\n" + "<body>\n" + "\t<p></p>\n" + "</body>\n" + "<ml>", "text/html", "utf-8", null); } llWebView.setVisibility(View.GONE); v_loading.setVisibility(View.VISIBLE); v_loading.setViewType(LogoLoadingView.TYPE_NET_LOSS, "哎呦,网络开小差了"); } }); } else { wv_content.setWebViewClient(new WebViewClient() { @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { Boolean overridePayUrl = shouldOverridePayUrl(view, url); if (overridePayUrl != null) { return overridePayUrl; } if (!TextUtils.isEmpty(url) && url.endsWith(".apk")) { Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); startActivity(intent); }else if (url.startsWith("tel://")){ Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); startActivity(intent); } else if (!TextUtils.isEmpty(url) && url.startsWith("http")) { loadUrl(setUrlHeightParams(url)); } else { if (!YDLRouterManager.Companion.router(url)) { loadUrl(setUrlHeightParams(url)); } } return true; } @Override public void onPageStarted(WebView view, String url, Bitmap favicon) { super.onPageStarted(view, url, favicon); } @Override public void onPageFinished(WebView view, String url) { if (!hasLoad) { hasLoad = true; loadDuration = System.currentTimeMillis() - loadStartTime; LogUtil.e("initDuration:" + initDuration + ",loadDuration:" + loadDuration); //UploadWebViewTimeUtils.Companion.uploadWebViewTime(h5Params.getUrl(), initDuration + "", loadDuration + "", workSpeedUtils.getNetSpeed()); } if (shouldClearHistory) { wv_content.clearHistory(); shouldClearHistory = false; } if (wv_content.canGoBack()) { setTitle(wv_content.getTitle()); tb_title.setmLeftText("关闭"); tb_title.setImageListener(v -> { if (wv_content.canGoBack()) { wv_content.goBack(); } else { finish(); } }); if (startType != 1) { tb_title.setImageVis(1); } } else { tb_title.setImage(getResources().getDrawable(R.drawable.web_common_back)); tb_title.setmLeftText(""); tb_title.setImageListener(v -> { if (h5Params.getShowUrlTitle()) { WebModularServiceUtils.Companion.startMain(NewH5Activity.this); finish(); } else { if (ActivityManager.Companion.getInstance().getActivitys().size() == 1) { WebModularServiceUtils.Companion.startMain(NewH5Activity.this); } finish(); } }); if (startType != 1) { tb_title.setImageVis(1); } } if (!loadFailed) { v_loading.setVisibility(View.GONE); } cancelSendNetLossMessage(); } @Override public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) { onReceivedSslErrorHandle(handler); } @Override public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) { super.onReceivedError(view, errorCode, description, failingUrl); AliYunRichLogsHelper.Companion.getInstance() .sendRichLog(AliYunLogConfig.WEB, "onReceivedError---- errorCode: " + errorCode + "----failingUrl:" + failingUrl); tb_title.setTitle("加载中"); loadFailed = true; if (wv_content != null) { wv_content.loadDataWithBaseURL(null, "<!doctype html>\n" + "<html>\n" + "<head>\n" + "<meta charset=\"utf-8\">\n" + "<title></title>\n" + "</head>\n" + "\n" + "<body>\n" + "\t<p></p>\n" + "</body>\n" + "<ml>", "text/html", "utf-8", null); } llWebView.setVisibility(View.GONE); v_loading.setVisibility(View.VISIBLE); v_loading.setViewType(LogoLoadingView.TYPE_NET_LOSS, "哎呦,网络开小差了"); } }); } wv_content.setDownloadListener((url, userAgent, contentDisposition, mimetype, contentLength) -> { if (url != null && url.startsWith("http://")) { startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(url))); } }); initDuration = System.currentTimeMillis() - initStartTime; workSpeedUtils = new NetWorkSpeedUtils(this); workSpeedUtils.startNetSpeed(); loadStartTime = System.currentTimeMillis(); loadUrl(h5Params.getUrl()); LogUtil.d(h5Params.getUrl()); initHead(); } private Boolean shouldOverridePayUrl(WebView view, String url) { if (url.startsWith("weixin://")) { try { startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(url))); return true; } catch (Exception e) { // 防止手机没有安装处理某个 scheme 开头的 url 的 APP 导致 crash ToastUtil.toastShort("该手机没有安装微信"); return true; } } else if (url.startsWith("alipays://") || url.startsWith("alipay")) { try { startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(url))); return true; } catch (Exception e) { // 防止手机没有安装处理某个 scheme 开头的 url 的 APP 导致 crash // 启动支付宝 App 失败,会自行跳转支付宝网页支付 return true; } } // 处理普通 http 请求跳转 // if (!(url.startsWith("http") || url.startsWith("https"))) { // return true; // } // 处理微信 H5 支付跳转时验证请求头 referer 失效 // 验证不通过会出现“商家参数格式有误,请联系商家解决” if (url.contains("wx.tenpay.com")) { // 申请微信 H5 支付时填写的域名 // 比如经常用来测试网络连通性的 http://www.baidu.com Uri parse = Uri.parse(url); //从url 中获取 域名信息 String redirectUrlStr = parse.getQueryParameter("redirect_url"); Uri redirectUrl = Uri.parse(redirectUrlStr); // 申请微信 H5 支付时填写的域名 String referer = redirectUrl.getScheme() + "://" + redirectUrl.getHost(); // 兼容 Android 4.4.3 和 4.4.4 两个系统版本设置 referer 无效的问题 if (("4.4.3".equals(Build.VERSION.RELEASE)) || ("4.4.4".equals(Build.VERSION.RELEASE))) { if (firstVisitWXH5PayUrl) { view.loadDataWithBaseURL(referer, "<script>window.location.href=\"" + url + "\";</script>", "text/html", "utf-8", null); // 修改标记位状态,避免循环调用 // 再次进入微信H5支付流程时记得重置状态 firstVisitWXH5PayUrl = true firstVisitWXH5PayUrl = false; } // 返回 false 由系统 WebView 自己处理该 url return false; } else { // HashMap 指定容量初始化,避免不必要的内存消耗 HashMap<String, String> map = new HashMap<>(1); map.put("Referer", referer); view.loadUrl(url, map); return true; } } else if (url.contains("alipay")) { return false; } return null; } private void onReceivedSslErrorHandle(SslErrorHandler handler) { if (BaseApp.instance.getGlobalConfig().getAppDebug()) { handler.proceed(); return; } ToastUtil.toastShort("SSL 证书验证错误"); handler.cancel(); } private void initShareMenu() { tb_title.setRightIcon(getResources().getDrawable(R.drawable.web_common_share)); tb_title.setOnRightTextClick((view, isActive) -> { ShareData shareData = paramsForCommentList.getShare(); if (shareData != null && "commentList".equals(shareData.getType())) { isShareCommentList = true; ActionCountUtils.Companion.record("experts_comment_list_page", "comment_share_click"); share(shareData.getImageBase64(), paramsForCommentList); } else { share(null, null); } }); LogUtil.d("setSeccessful"); } public void onEvent(RefreshWebEvent event) { if (event.isClearHistory) { wv_content.clearCache(true); wv_content.clearHistory(); loadUrl(h5Params.getUrl()); } else { //刷新页面 loadUrl(h5Params.getUrl()); shouldClearHistory = true; } } public void onEvent(UserBindPhoneEvent event) { //刷新页面 loadUrl(h5Params.getUrl()); shouldClearHistory = true; } public void onEvent(UserLoginEvent event) { if (!TextUtils.isEmpty(successPage)) { if (!TextUtils.isEmpty(event.getUid())) { String subText = "uid=" + event.getUid(); URI uri = URI.create(successPage); String query = uri.getQuery(); if (TextUtils.isEmpty(query)) { successPage = successPage + "?" + subText; } else { Map<String, String> queryMap = URLUtils.queryStr2Map(successPage); if (queryMap != null && queryMap.containsKey("uid")) { queryMap.put("uid", event.getUid()); successPage = successPage.substring(0, successPage.indexOf("?")) + "?" + URLUtils.map2QueryStr(queryMap); } else { successPage += "&" + subText; } } } h5Params.setUrl(successPage); } //刷新页面 loadUrl(h5Params.getUrl()); shouldClearHistory = true; if (isToTrend) { isToTrend = false; //分享到心事动态 toTrend(shareToUrl); } } @SuppressWarnings("unused") public void callJSFunc(String funcName) { final StringBuffer sb = new StringBuffer("javascript:"); sb.append(funcName); wv_content.post(() -> { try { wv_content.loadUrl(sb.toString()); } catch (Exception e) { e.printStackTrace(); } }); } public void loadUrl(String url) { if (TextUtils.isEmpty(url)) { return; } String resultUrl = h5Params.getSuffix() ? WebUrlParamsUtils.getSuffix(url, jtoJHandle.getUriAppendSuffix()) : url; Log.e("AAAA", resultUrl); wv_content.loadUrl(resultUrl); pointBI(resultUrl); } /** * 埋点 * * @param url */ private void pointBI(String url) { } private void initHead() { // header final MaterialHeader header = new MaterialHeader(this); int[] colors = new int[]{getResources().getColor(R.color.platform_main_theme)}; header.setColorSchemeColors(colors); header.setLayoutParams(new PtrFrameLayout.LayoutParams(-1, -2)); int padding = (int) getResources().getDimension(R.dimen.platform_default_dis_size); header.setPadding(0, padding, 0, padding); header.setPtrFrameLayout(store_house_ptr_frame); store_house_ptr_frame.setHeaderView(header); store_house_ptr_frame.setPtrHandler(this); store_house_ptr_frame.addPtrUIHandler(header); } @Override public boolean checkCanDoRefresh(PtrFrameLayout frame, View content, View header) { return PtrDefaultHandler.checkContentCanBePulledDown(frame, wv_content, header); } @Override public void onRefreshBegin(PtrFrameLayout frame) { frame.postDelayed(() -> { store_house_ptr_frame.refreshComplete(); if (loadFailed) { loadFailed = false; wv_content.goBack(); } else { wv_content.reload(); } }, 1800); } public void goBack() { finish(); } public void back(String type) { if (wv_content.canGoBack()) { tb_title.setmLeftText("关闭"); tb_title.setLeftTextVisible(VISIBLE); if ("top".equals(type)) { setTitle(wv_content.getTitle()); tb_title.setImageListener(v -> wv_content.goBack() ); } else { wv_content.goBack(); } if (startType != 1) { tb_title.setImageVis(1); } } else { tb_title.setImage(getResources().getDrawable(R.drawable.web_common_back)); tb_title.setmLeftText(""); if ("top".equals(type)) { setTitle(wv_content.getTitle()); tb_title.setImageListener(v -> { if (h5Params.isSplash()) { WebModularServiceUtils.Companion.startMain(NewH5Activity.this); finish(); } else { if (ActivityManager.Companion.getInstance().getActivitys().size() == 1) { WebModularServiceUtils.Companion.startMain(NewH5Activity.this); } finish(); } }); } else { if (h5Params.isSplash()) { WebModularServiceUtils.Companion.startMain(NewH5Activity.this); finish(); } else { if (startType == 1) { // overridePendingTransition(0, R.anim.activity_open_down); } finish(); } } if (startType != 1) { tb_title.setImageVis(1); } } } public void setWebViewTitle(String title) { Observable.just(1) .observeOn(AndroidSchedulers.mainThread()) .subscribe(next -> { tb_title.setTitle(title); }); } private void setTitle(String title) { /** * 高级题跳转第三方h5页面,需要特殊处理:不能使用页面自带的title */ if (!h5Params.isControlBack()) { tb_title.setTitle(title); } } @Override public void finish() { super.finish(); CookieSyncManager.createInstance(this); CookieSyncManager.getInstance().startSync(); //CookieManager.getInstance().removeSessionCookie(); } private void openImageChooserActivity() { Intent i = new Intent(Intent.ACTION_GET_CONTENT); i.addCategory(Intent.CATEGORY_OPENABLE); i.setType("image/*"); startActivityForResult(Intent.createChooser(i, "Image Chooser"), FILE_CHOOSER_RESULT_CODE); } /** * 最后在OnActivityResult中接受返回的结果 */ @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == FILE_CHOOSER_RESULT_CODE) { if (null == uploadMessage && null == uploadMessageAboveL) { return; } Uri result = data == null || resultCode != RESULT_OK ? null : data.getData(); if (uploadMessageAboveL != null) { onActivityResultAboveL(requestCode, resultCode, data); } else if (uploadMessage != null) { uploadMessage.onReceiveValue(result); uploadMessage = null; } } else if (requestCode == 33 && resultCode == RESULT_OK) { //专家收款 支付成功 跟新历史收款消息 if (!TextUtils.isEmpty(successPage)) { NewH5Activity.start(this, new H5Params(successPage, "")); } if (h5Params.isSplash()) { WebModularServiceUtils.Companion.startMain(NewH5Activity.this); finish(); } else { finish(); } } else if (requestCode == 55 && resultCode == RESULT_OK) { //购买课程成功 ToastUtil.toastShort(getString(R.string.platform_attend_course_success)); wv_content.reload(); } else if (requestCode == 44) { //测试题 支付成功 refresh(); } UMShareAPI.get(this).onActivityResult(requestCode, resultCode, data); super.onActivityResult(requestCode, resultCode, data); } @TargetApi(Build.VERSION_CODES.LOLLIPOP) private void onActivityResultAboveL(int requestCode, int resultCode, Intent intent) { if (requestCode != FILE_CHOOSER_RESULT_CODE || uploadMessageAboveL == null) { return; } Uri[] results = null; if (resultCode == Activity.RESULT_OK) { if (intent != null) { String dataString = intent.getDataString(); ClipData clipData = intent.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)}; } } } uploadMessageAboveL.onReceiveValue(results); uploadMessageAboveL = null; } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { /** * 判断是否是测评题页面,如果是,则走测评题页面的返回逻辑 */ if (keyCode == KeyEvent.KEYCODE_BACK) { /** * 是否是测评题目页面 */ if (selfPageType == TEST_QUESTIONS_PAGE_TYPE) { showTestQuestionPageReturnDialog(); return false; } /** * 新用户侧滑按钮限制 */ if (h5Params.getBackLimit() != null && h5Params.getBackLimit() == H5Params.BackLimit.NEW_USER_PAGE) { ModularServiceManager.INSTANCE.provide(IAppService.class).mainIntent(this); return true; } /** * 增加逻辑:在高级题测试页面,按物理返回键直接finish当前页面,不走webview.goback()逻辑 */ if (h5Params.isControlBack()) { finish(); } back("key"); return true; } return super.onKeyDown(keyCode, event); } /** * 测评题返回的时候,弹窗提示用户 */ public void showTestQuestionPageReturnDialog() { if (null == testQuestionsPageReturnDialog) { testQuestionsPageReturnDialog = new YDLCommonDialog(this, new YDLCommonDialog.OnYDLCommonDialogListener() { @Override public void onCancel() { finish(); } @Override public void onSure() { coverJavaTitleBar(); testQuestionsPageReturnDialog.dismiss(); } }).setTitle("你确定要退出测试吗?") .setDesc("98%的人都说结果很有用哦") .setCancelText("退出") .setSureText("继续测试"); } testQuestionsPageReturnDialog.show(); } @Override protected void onDestroy() { super.onDestroy(); cancelSendNetLossMessage(); EventBus.getDefault().unregister(this); if (wv_content != null) { wv_content.destroy(); } } @Override protected void onResume() { super.onResume(); if ("我的订单".equals(tb_title.getTitle())) { safeTipView.updateVisibility(); } if (h5Params.isShowMenu()) { try { if (WebModularServiceUtils.Companion.getImService().isHasUnread()) { tb_title.setImage_right(getResources().getDrawable(R.drawable.web_common_notice_more_en)); } else { tb_title.setImage_right(getResources().getDrawable(R.drawable.web_common_notice_more_un)); } } catch (Exception e) { e.printStackTrace(); } } if (backgroundView.getVisibility() == View.VISIBLE) { backgroundView.setVisibility(View.GONE); } } /** * 分享 */ private void share(String base64DataStr, H5JsBean.H5JsCmd.Params params) { shareToUrl = !TextUtils.isEmpty(purl) ? purl : shareUrl; if (TextUtils.isEmpty(shareToUrl)) { return; } if (!TextUtils.isEmpty(base64DataStr) && TextUtils.isEmpty(shareDesc)) { shareDesc = "壹点灵,温暖而有力地爱着你"; } String minPath = ""; String minId = ""; if (params != null && params.getShare() != null) { minPath = params.getShare().getMinProgramPath(); minId = params.getShare().getMinProgramId(); } YDLShareDialog dialog; if (params != null && !TextUtils.isEmpty(params.getCourse_id())) { dialog = YDLShareDialog.Companion.style5(this, shareTitle, shareUrl, shareDesc, cover); } else { if (!H5RouterUtils.INSTANCE.isDependByClz(IDynamicService.class)) { //如果未引入动态模块的话,隐藏分享至动态按钮 dialog = YDLShareDialog.Companion.style4(this, shareTitle, shareUrl, shareDesc, cover); } else { if (isShareCommentList){ dialog = YDLShareDialog.Companion.style7(this, shareTitle, shareUrl, shareDesc, cover, minPath, minId); }else { dialog = YDLShareDialog.Companion.style1(this, shareTitle, shareUrl, shareDesc, cover, minPath, minId); } } } dialog.setCallBack(type -> { if (1 == type) { if (!WebModularServiceUtils.Companion.getUserService().loginByOneKeyLogin(NewH5Activity.this, true)) { isToTrend = true; } else { //分享到心事动态 toTrend(shareToUrl); } } if (type == 5) { //生成海报 ARouter.getInstance().build("/course/poster") .withString("course_id", params.getCourse_id()) .navigation(); new Handler(getMainLooper()).postDelayed(() -> { backgroundView.setImageBitmap(RxImageTool.fastBlur(RxDeviceTool.captureWithStatusBar(NewH5Activity.this), 0.5f, 12, true)); backgroundView.setVisibility(View.VISIBLE); }, 500); } }); if (!TextUtils.isEmpty(base64DataStr)) { dialog.setPosterPicture(base64DataStr); } if ("文章详情".equals(tb_title.getTitle())) { dialog.setShareCallBack(new YDLShareDialog.IShareCallBack() { @Override public void onShareSuccessed(@NotNull SHARE_MEDIA share_media) { String params = getIntent().getStringExtra("articalParams"); BuryPointUtils.getInstance().createMap() .put("share_where", share_media.toString()) .put("share_what", shareTitle + "," + params) .put("share_succeed", true) .burryPoint("Share"); } @Override public void onShareFailed(@NotNull SHARE_MEDIA share_media, @NotNull Throwable throwable) { String params = getIntent().getStringExtra("articalParams"); BuryPointUtils.getInstance().createMap() .put("share_where", share_media.toString()) .put("share_what", shareTitle + "," + params) .put("share_succeed", false) .burryPoint("Share"); } }); } dialog.show(getFragmentManager(), "lose"); } private void toTrend(String url) { this.startActivity(WebModularServiceUtils.Companion.getDynamicService().publishArticleToTrend(NewH5Activity.this, url, cover, shareTitle)); } public void switchSound(int mediaId, long meditationId, int meditationType, int businessType, String buried, String mediaUrl, String mediaCoverUrl, String title, String desc, int status){ MeditationEvent event = new MeditationEvent( mediaId,meditationId,meditationType,businessType, status,buried,mediaUrl,mediaCoverUrl,title,desc); EventBus.getDefault().post(event); } public void setBG(String color,String alpha){ try { store_house_ptr_frame.setBackgroundColor(Color.parseColor(color)); int a = Integer.valueOf(alpha); store_house_ptr_frame.getBackground().setAlpha(a); }catch (Exception ex){ } } public void showCommentArticleDialog(String title){ if (commentArticleDialog == null) { String titleStr = title==null?wv_content.getTitle():title; commentArticleDialog = ArticleDialogFragment.newInstance(titleStr); commentArticleDialog.setOnPublishListener(comment -> { callJSFunc("sendComment('"+comment+"')"); }); } if (commentArticleDialog != null && !commentArticleDialog.isAdded()) { commentArticleDialog.show(getSupportFragmentManager(), "article_comment"); } } }