整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

c#使用webView2 访问本地静态html资源跨

c#使用webView2 访问本地静态html资源跨域Cors问题

使用 WebView2 控件时,如果你尝试从 WebView2 加载的页面访问本地静态 HTML 资源,并且遇到了跨域资源共享(CORS)问题,这通常是因为 WebView2 遵循同源策略,这意味着默认情况下,它不允许从一个源加载的页面访问另一个源的资源。

解决此问题的方法取决于你的具体场景和需求。下面是一些可能的解决方案:

1. 使用allow-local-file-access属性

对于本地开发或测试,你可以在 WebView2 控件上设置 allow-local-file-access 属性为 true,这将允许 WebView2 加载的页面访问本地文件系统上的资源。

csharpawait webView2.CoreWebView2.Settings.PutBoolean("allowLocalFileAccess", true);

请注意,这只应该在受信任的环境中使用,因为启用本地文件访问可能会引入安全风险。

2. 设置 CORS 头部

如果你正在尝试从 WebView2 加载的页面访问本地服务器上托管的资源,并且该服务器支持 CORS,你可以配置服务器以发送适当的 CORS 响应头。这允许跨源请求。

例如,在 ASP.NET Core 中,你可以使用 CORS 中间件来配置 CORS 策略。

csharppublic void ConfigureServices(IServiceCollection services)
{
    services.AddCors(options=>
    {
        options.AddPolicy("MyCorsPolicy", builder=>
        {
            builder.WithOrigins("http://example.com", "http://www.example.com")
                    .AllowAnyHeader()
                    .AllowAnyMethod();
        });
    });

    // ... 其他服务配置 ...
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    // ... 其他中间件配置 ...

    app.UseCors("MyCorsPolicy");

    // ... 其他中间件配置 ...
}

3. 使用代理服务器

如果你无法修改资源服务器的 CORS 配置,你可以设置一个代理服务器来绕过 CORS 限制。代理服务器会接收来自 WebView2 的请求,然后转发到目标资源服务器,并将响应返回给 WebView2。代理服务器可以设置适当的 CORS 响应头来允许跨源请求。

4. 部署到相同源

如果可能的话,将你的静态 HTML 资源和 WebView2 控件部署到相同的源(即相同的域名、端口和协议)。这样,同源策略就不会阻止它们之间的交互。

5. 使用 Web 服务器

对于本地文件,你可以使用一个简单的 Web 服务器(如 IIS Express、Kestrel 或其他任何服务器)来托管这些文件,并通过 HTTP 访问它们,而不是直接通过文件系统。这样,你就可以通过配置服务器来处理 CORS 请求。

注意事项

  • 启用本地文件访问或绕过 CORS 限制可能会引入安全风险,特别是在生产环境中。确保你了解这些风险,并采取适当的安全措施。
  • 如果你的应用程序是面向用户的,最好避免使用可能降低安全性的解决方案,并寻找更安全的替代方案。

者:Mino



1.针对加载webView中的资源时加快加载的速度优化(主要是针对图片)

原因:html代码下载到WebView后,webkit开始解析网页各个节点,发现有外部样式文件或者外部脚本文件时,会异步发起网络请求下载文件,但如果在这之前也有解析到image节点,那势必也会发起网络请求下载相应的图片。在网络情况较差的情况下,过多的网络请求就会造成带宽紧张,影响到css或js文件加载完成的时间,造成页面空白loading过久。

解决方法:告诉WebView先不要自动加载图片,等页面finish后再发起图片加载。

//设置是否开启密码保存功能,不建议开启,默认已经做了处理,存在盗取密码的危险
WebView.setSavePassword(false);


2.WebView硬件加速导致页面渲染闪烁

原因:4.0以上的系统我们开启硬件加速后,WebView渲染页面更加快速,拖动也更加顺滑。但有个副作用就是,当WebView视图被整体遮住一块,然后突然恢复时(比如使用SlideMenu将WebView从侧边滑出来时),这个过渡期会出现白块同时界面闪烁。

解决方法:是在过渡期前将WebView的硬件加速临时关闭,过渡期后再开启。

/**
 * 请求网络出现error
 * @param view                              view
 * @param errorCode                         错误
 * @param description                       description
 * @param failingUrl                        失败链接
 */
@Override
public void onReceivedError(WebView view, int errorCode, String description, String
        failingUrl) {
    super.onReceivedError(view, errorCode, description, failingUrl);
    if (errorCode==404) {
        //用javascript隐藏系统定义的404页面信息
        String data="Page NO FOUND!";
        view.loadUrl("javascript:document.body.innerHTML=\"" + data + "\"");
    } else {
        if (webListener!=null){
            webListener.showErrorView();
        }
    }
}

// 向主机应用程序报告Web资源加载错误。这些错误通常表明无法连接到服务器。
// 值得注意的是,不同的是过时的版本的回调,新的版本将被称为任何资源(iframe,图像等)
// 不仅为主页。因此,建议在回调过程中执行最低要求的工作。
// 6.0 之后
@Override
public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
    super.onReceivedError(view, request, error);
    if (Build.VERSION.SDK_INT >=Build.VERSION_CODES.M) {
        X5WebUtils.log("服务器异常"+error.getDescription().toString());
    }
    //ToastUtils.showToast("服务器异常6.0之后");
    //当加载错误时,就让它加载本地错误网页文件
    //mWebView.loadUrl("file:///android_asset/errorpage/error.html");
    if (webListener!=null){
        webListener.showErrorView();
    }
}

/**
 * 这个方法主要是监听标题变化操作的
 * @param view  view
 * @param title 标题
 */
@Override
public void onReceivedTitle(WebView view, String title) {
    super.onReceivedTitle(view, title);
    if (title.contains("404") || title.contains("网页无法打开")){
        if (webListener!=null){
            webListener.showErrorView();
        }
    } else {
        // 设置title
    }
}


3.可以提前显示加载进度条

原因:WebView.loadUrl("url") 不会立马就回调 onPageStarted 或者 onProgressChanged 因为在这一时间段,WebView 有可能在初始化内核,也有可能在与服务器建立连接,这个时间段容易出现白屏,白屏用户体验是很糟糕的。

解决方法:提前显示进度条虽然不是提升性能 , 但是对用户体验来说也是很重要的一点。

/**
 * 在加载资源时通知主机应用程序发生SSL错误
 * 作用:处理https请求
 * @param view   view
 * @param handler  handler
 * @param error   error
 */
@Override
public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
    super.onReceivedSslError(view, handler, error);
    if (error!=null){
        String url=error.getUrl();
    }
    //https忽略证书问题
    if (handler!=null){
        //表示等待证书响应
        handler.proceed();
        // handler.cancel();      //表示挂起连接,为默认方式
        // handler.handleMessage(null);    //可做其他处理
    }
}


4.WebView密码明文存储漏洞优化

原因:WebView 默认开启密码保存功能 mWebView.setSavePassword(true),如果该功能未关闭,在用户输入密码时,会弹出提示框,询问用户是否保存密码,如果选择”是”,密码会被明文保到 /data/data/com.package.name/databases/webview.db 中,这样就有被盗取密码的危险。

解决方法:通过 WebSettings.setSavePassword(false) 关闭密码保存提醒功能。

@Override
protected void onDestroy() {
    try {
        //有音频播放的web页面的销毁逻辑
        //在关闭了Activity时,如果Webview的音乐或视频,还在播放。就必须销毁Webview
        //但是注意:webview调用destory时,webview仍绑定在Activity上
        //这是由于自定义webview构建时传入了该Activity的context对象
        //因此需要先从父容器中移除webview,然后再销毁webview:
        if (webView !=null) {
            ViewGroup parent=(ViewGroup) webView.getParent();
            if (parent !=null) {
                parent.removeView(webView);
            }
            webView.removeAllViews();
            webView.destroy();
            webView=null;
        }
    } catch (Exception e) {

    }
    super.onDestroy();
}


5.自定义加载异常error的状态页面,比如下面这些方法中可能会出现error

原因:当WebView加载页面出错时(一般为404 NOT FOUND,Android WebView会默认显示一个出错界面。当WebView加载出错时,会在WebViewClient实例中的onReceivedError(),还有onReceivedTitle方法接收到错误。

解决方法:自定义错误页面样式。

@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
    super.onPageStarted(view, url, favicon);
    String host=Uri.parse(url).getHost();
    if (!BuildConfig.IS_DEBUG) {
        if (Arrays.binarySearch(domainList, host) < 0) {
            //不在白名单内,非法网址,这个时候给用户强烈而明显的提示
        } else {
            //合法网址
        }
    }
}


6. WebView加载证书错误

原因:webView加载一些别人的url时候,有时候会发生证书认证错误的情况。

解决方法:要将正常的呈现页面给用户,我们需要忽略证书错误,需要调用WebViewClient类的onReceivedSslError方法,调用handler.proceed()来忽略该证书错误。

 //在onResume里面设置setJavaScriptEnabled(true)。
    @Override
    protected void onResume() {
        super.onResume();
        if (mWebView !=null) {
        mWebView.getSettings().setJavaScriptEnabled(true);
        }
    }
//在onStop里面设置setJavaScriptEnabled(false);
    @Override
    protected void onStop() {
        super.onStop();
        if (mWebView !=null) {
        mWebView.getSettings().setJavaScriptEnabled(false)
       }
  }


7.WebView音频播放销毁后还有声音

原因:WebView页面中播放了音频,退出Activity后音频仍然在播放。

解决方法:需要在Activity的onDestory()中从父容器中移除WebView。

@Override
protected void onDestroy() {
    try {
        //有音频播放的web页面的销毁逻辑
        //在关闭了Activity时,如果Webview的音乐或视频,还在播放。就必须销毁Webview
        //但是注意:webview调用destory时,webview仍绑定在Activity上
        //这是由于自定义webview构建时传入了该Activity的context对象
        //因此需要先从父容器中移除webview,然后再销毁webview:
        if (webView !=null) {
            ViewGroup parent=(ViewGroup) webView.getParent();
            if (parent !=null) {
                parent.removeView(webView);
            }
            webView.removeAllViews();
            webView.destroy();
            webView=null;
        }
    } catch (Exception e) {

    }
    super.onDestroy();
}


8.如何设置白名单操作

原因:客户端内的WebView都是可以通过客户端的某个schema打开的,而要打开页面的URL很多都并不写在客户端内,而是可以由URL中的参数传递过去的。上面4.0.5 使用scheme协议打开链接风险已经说明了scheme使用的危险性。

解决方法:设置运行访问的白名单,或者当用户打开外部链接前给用户强烈而明显的提示。设置白名单操作其实和过滤广告是一个意思,这里你可以放一些合法的网址允许访问。

@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
    super.onPageStarted(view, url, favicon);
    String host=Uri.parse(url).getHost();
    if (!BuildConfig.IS_DEBUG) {
        if (Arrays.binarySearch(domainList, host) < 0) {
            //不在白名单内,非法网址,这个时候给用户强烈而明显的提示
        } else {
            //合法网址
        }
    }
}


9.Android后台无法释放js导致发热耗电

原因:有些手机你如果webView加载的html里,有一些js一直在执行比如动画之类的东西,如果此刻webView 挂在了后台这些资源是不会被释放用户也无法感知。导致一直占有cpu 耗电特别快。

解决方法:WebView在后台的时候,会调用onStop方法,即此时关闭js交互,回到前台调用onResume再开启js交互。

 //在onResume里面设置setJavaScriptEnabled(true)。
    @Override
    protected void onResume() {
        super.onResume();
        if (mWebView !=null) {
        mWebView.getSettings().setJavaScriptEnabled(true);
        }
    }
//在onStop里面设置setJavaScriptEnabled(false);
    @Override
    protected void onStop() {
        super.onStop();
        if (mWebView !=null) {
        mWebView.getSettings().setJavaScriptEnabled(false)
       }
  }


10.WebView加载网页不显示图片

原因:WebView从Lollipop(5.0)开始webView默认不允许混合模式, https当中不能加载http资源, 而开发的时候可能使用的是https的链接,但是链接中的图片可能是http的,所以显示图片失败。

解决方案:需要设置开启。

天在调试android webview加载本地html文件时,对三种不同位置html的加载方式总结如下:

1.//打开本包内asset目录下的index.html文件

wView.loadUrl(" file:///android_asset/index.html ");

2.//打开本地sd卡内的index.html文件

wView.loadUrl("content://com.android.htmlfileprovider/sdcard/index.html");

3.//打开指定URL的html文件

wView.loadUrl(" http://m.oschina.net");

今天就分享这一个知识点,祝大家好运!