深度解密AgentWeb:WebChromeClient与WebViewClient核心实现原理

深度解密AgentWeb:WebChromeClient与WebViewClient核心实现原理

【免费下载链接】AgentWeb AgentWeb is a powerful library based on Android WebView. 【免费下载链接】AgentWeb 项目地址: https://gitcode.com/gh_mirrors/ag/AgentWeb

你是否在Android开发中遇到过WebView加载进度难以监控?JavaScript对话框样式与App风格不统一?第三方App跳转混乱等问题?本文将通过剖析AgentWeb的WebChromeClient与WebViewClient实现原理,带你彻底解决这些痛点,掌握Android WebView的高级应用技巧。

读完本文你将获得:

  • WebChromeClient与WebViewClient的协作机制
  • 进度条与标题更新的实现方案
  • 文件选择与权限请求的处理逻辑
  • URL拦截与第三方App跳转控制
  • 自定义WebView客户端的最佳实践

AgentWeb客户端架构概览

AgentWeb作为基于Android WebView的增强库,通过中间件模式对WebChromeClient和WebViewClient进行了封装,形成了灵活可扩展的客户端架构。

AgentWeb架构

核心类关系如下:

  • WebChromeClientDelegate:代理原生WebChromeClient,实现方法转发
  • WebViewClientDelegate:代理原生WebViewClient,实现方法转发
  • DefaultChromeClient:提供默认ChromeClient实现,处理进度、标题、文件选择等
  • DefaultWebClient:提供默认WebViewClient实现,处理URL加载、错误页面等

主要源码文件:

WebChromeClient实现原理

WebChromeClient主要负责浏览器界面相关的功能,如进度显示、标题更新、JavaScript对话框、文件选择等。AgentWeb通过DefaultChromeClient提供了增强实现。

进度条与标题更新机制

在DefaultChromeClient中,通过重写onProgressChanged方法实现进度条更新:

@Override
public void onProgressChanged(WebView view, int newProgress) {
    super.onProgressChanged(view, newProgress);
    if (mIndicatorController != null) {
        mIndicatorController.progress(view, newProgress);
    }
}

进度条控制器IndicatorController通过mIndicatorController.progress()方法更新UI,对应实现类为IndicatorHandler.java

JavaScript对话框处理

AgentWeb对JS对话框进行了统一处理,确保样式与App一致:

@Override
public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
    if (mAgentWebUIController.get() != null) {
        mAgentWebUIController.get().onJsAlert(view, url, message);
    }
    result.confirm(); // 默认确认
    return true; // 表示已处理
}

类似地,onJsConfirm和onJsPrompt方法也通过mAgentWebUIController将对话框展示逻辑委托给UI控制器处理。

文件选择器实现

不同Android版本的文件选择API存在差异,DefaultChromeClient通过反射适配了各种版本:

// Android >= 4.1
public void openFileChooser(ValueCallback<Uri> uploadFile, String acceptType, String capture) {
    commonRefect(this.mDelegate, "openFileChooser", 
        new Object[]{uploadFile, acceptType, capture}, 
        ValueCallback.class, String.class, String.class);
}

// Android < 3.0
public void openFileChooser(ValueCallback<Uri> valueCallback) {
    commonRefect(this.mDelegate, "openFileChooser", 
        new Object[]{valueCallback}, ValueCallback.class);
}

对于Android 5.0及以上版本,使用onShowFileChooser方法:

@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
@Override
public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, 
                               FileChooserParams fileChooserParams) {
    return openFileChooserAboveL(webView, filePathCallback, fileChooserParams);
}

权限请求处理

对于地理位置、摄像头等权限请求,DefaultChromeClient通过PermissionInterceptor接口提供了拦截机制:

@Override
public void onGeolocationPermissionsShowPrompt(String origin, GeolocationPermissions.Callback callback) {
    if (mPermissionInterceptor != null) {
        if (mPermissionInterceptor.intercept(this.mWebView.getUrl(), 
            AgentWebPermissions.LOCATION, "location")) {
            callback.invoke(origin, false, false);
            return;
        }
    }
    // 权限请求逻辑...
}

WebViewClient实现原理

WebViewClient主要负责页面加载相关的功能,如URL拦截、页面开始/结束加载、资源加载、错误处理等。AgentWeb通过DefaultWebClient提供了增强实现。

URL加载与拦截机制

shouldOverrideUrlLoading方法用于决定是否拦截URL加载:

@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
    if (url.startsWith(HTTP_SCHEME) || url.startsWith(HTTPS_SCHEME)) {
        return (webClientHelper && HAS_ALIPAY_LIB && isAlipay(view, url));
    }
    if (!webClientHelper) {
        return false;
    }
    // 处理电话、短信等通用链接
    if (handleCommonLink(url)) {
        return true;
    }
    // 处理intent scheme
    if (url.startsWith(INTENT_SCHEME)) {
        handleIntentUrl(url);
        return true;
    }
    // 微信支付
    if (url.startsWith(WEBCHAT_PAY_SCHEME)) {
        startActivity(url);
        return true;
    }
    // ...其他URL处理逻辑
    return super.shouldOverrideUrlLoading(view, url);
}

支付宝与微信支付支持

DefaultWebClient内置了支付宝和微信支付的处理逻辑:

private boolean isAlipay(final WebView view, String url) {
    try {
        Activity mActivity = mWeakReference.get();
        if (mActivity == null) return false;
        
        // 使用反射创建PayTask实例
        Class clazz = Class.forName("com.alipay.sdk.app.PayTask");
        Constructor<?> mConstructor = clazz.getConstructor(Activity.class);
        Object payTask = mConstructor.newInstance(mActivity);
        
        // 调用支付拦截方法
        Method payInterceptorWithUrl = clazz.getMethod("payInterceptorWithUrl", 
            String.class, boolean.class, H5PayCallback.class);
        return (boolean) payInterceptorWithUrl.invoke(payTask, url, true, 
            new H5PayCallback() {
                @Override
                public void onPayResult(H5PayResultModel result) {
                    // 支付结果处理
                }
            });
    } catch (Exception e) {
        // 异常处理
    }
    return false;
}

错误页面处理

当页面加载出错时,DefaultWebClient会显示自定义错误页面:

private void onMainFrameError(WebView view, int errorCode, String description, String failingUrl) {
    mErrorUrlsSet.add(failingUrl);
    if (mAgentWebUIController.get() != null) {
        mAgentWebUIController.get().onMainFrameError(view, errorCode, description, failingUrl);
    }
}

错误页面布局定义在agentweb_error_page.xml

SSL错误处理

对于SSL证书错误,提供了自定义处理机制:

@Override
public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
    if (mAgentWebUIController.get() != null) {
        mAgentWebUIController.get().onShowSslCertificateErrorDialog(view, handler, error);
    }
}

中间件设计模式的应用

AgentWeb采用中间件模式实现WebChromeClient和WebViewClient的功能扩展,通过MiddlewareWebChromeBase和MiddlewareWebClientBase实现责任链。

WebChromeClient中间件

public class MiddlewareWebChromeBase extends WebChromeClient {
    private MiddlewareWebChromeBase mMiddleWareWebChromeBase;
    
    public MiddlewareWebChromeBase(WebChromeClient webChromeClient) {
        this.mMiddlewareWebChromeBase = webChromeClient instanceof MiddlewareWebChromeBase ? 
            (MiddlewareWebChromeBase) webChromeClient : null;
    }
    
    public void enq(MiddlewareWebChromeBase middlewareWebChromeBase) {
        if (this.mMiddlewareWebChromeBase == null) {
            this.mMiddlewareWebChromeBase = middlewareWebChromeBase;
            return;
        }
        this.mMiddlewareWebChromeBase.enq(middlewareWebChromeBase);
    }
    
    // 重写WebChromeClient方法并委托给下一个中间件
    @Override
    public void onProgressChanged(WebView view, int newProgress) {
        if (this.mMiddlewareWebChromeBase != null) {
            this.mMiddlewareWebChromeBase.onProgressChanged(view, newProgress);
            return;
        }
        super.onProgressChanged(view, newProgress);
    }
    // ...其他方法
}

WebViewClient中间件

类似地,WebViewClient也通过中间件模式实现功能扩展:

public class MiddlewareWebClientBase extends WebViewClient {
    private MiddlewareWebClientBase mMiddleWareWebClientBase;
    
    public MiddlewareWebClientBase(WebViewClient webViewClient) {
        this.mMiddlewareWebClientBase = webViewClient instanceof MiddlewareWebClientBase ?
            (MiddlewareWebClientBase) webViewClient : null;
    }
    
    public void enq(MiddlewareWebClientBase middlewareWebClientBase) {
        if (this.mMiddlewareWebClientBase == null) {
            this.mMiddlewareWebClientBase = middlewareWebClientBase;
            return;
        }
        this.mMiddlewareWebClientBase.enq(middlewareWebClientBase);
    }
    
    // ...重写WebViewClient方法并委托
}

这种设计允许开发者灵活地添加自定义功能,而无需修改原有代码。

客户端配置与使用

在AgentWeb中配置自定义WebChromeClient和WebViewClient非常简单:

AgentWeb.with(this)
    .setAgentWebParent(container, new ViewGroup.LayoutParams(-1, -1))
    .useDefaultIndicator()
    .setWebChromeClient(new CustomWebChromeClient())
    .setWebViewClient(new CustomWebViewClient())
    .createAgentWeb()
    .ready()
    .go("https://www.example.com");

其中CustomWebChromeClient和CustomWebViewClient可以继承AgentWeb提供的客户端基类,实现自定义功能。

总结与最佳实践

AgentWeb通过精心设计的WebChromeClient和WebViewClient实现,解决了Android WebView开发中的诸多痛点问题。主要优势包括:

  1. 完善的进度监控:通过IndicatorController实现精确的进度条控制
  2. 统一的对话框样式:自定义JS对话框与App风格保持一致
  3. 版本兼容的文件选择:适配各Android版本的文件选择API
  4. 内置支付支持:无缝集成支付宝和微信支付
  5. 灵活的中间件扩展:通过中间件模式实现功能扩展

最佳实践建议:

  • 对于简单需求,直接使用DefaultChromeClient和DefaultWebClient
  • 需要自定义时,继承MiddlewareWebChromeBase和MiddlewareWebClientBase实现中间件
  • 处理敏感操作时,使用PermissionInterceptor进行权限控制
  • 第三方App跳转采用ASK_USER_OPEN_OTHER_PAGE模式,提升用户体验

通过深入理解AgentWeb的客户端实现原理,我们可以构建出体验更优、功能更强大的Android Web应用。AgentWeb的设计思想也为我们提供了WebView封装的优秀范例,值得在实际项目中学习和应用。

关注本项目获取更多Android WebView开发技巧,下期我们将深入探讨AgentWeb的JavaScript交互机制。

官方文档 | 更新日志 | 示例代码

【免费下载链接】AgentWeb AgentWeb is a powerful library based on Android WebView. 【免费下载链接】AgentWeb 项目地址: https://gitcode.com/gh_mirrors/ag/AgentWeb

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值