Deng
Deng
Android WebView渲染指定URL的H5应用(App) | odjBlog
    欢迎来到odjBlog的博客!

Android WebView渲染指定URL的H5应用(App)

技术总结及问题解决 odjbin 2个月前 (10-26) 30次浏览 0个评论

版本/工具说明

  • 开发工具:
    • IntelliJ IDEA 2022.2.5 (已安装安卓环境)
    • gradle-7.3.3

安卓应用前置条件

1.新建安卓项目

2.安装 gradle 与配置使用

  • 为了避免构建出现 gradle:Connection timed out 的报错,gradle 版本需要在 gradle-wrapper.properties 文件里查看下载(注意,版本一定不能错。)

  • 下载之后在设置里面配置 gradle 路径

  • 确定之后, IDEA 会自动构建, 构建时间可能有点长, 需耐心等待

步骤

如果你想在安卓应用中固定一个指定的 URL,并且通过 WebView 显示一个 H5 页面,可以按照以下步骤来实现:

1.添加权限

  • 确保你的应用具有访问互联网的权限,在 AndroidManifest.xml 中加入以下权限:
<uses-permission android:name="android.permission.INTERNET" />

2.创建 WebView 布局

  • 在你的 activity_main.xml 或其他布局文件中,添加一个 WebView 控件
<WebView
    android:id="@+id/webview"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

3.配置 WebView

  • 在你的 MainActivity.java 中,设置 WebView 加载指定的 URL:
package cn.odjbin.ribtest;

import android.annotation.SuppressLint;
import android.webkit.WebResourceRequest;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;

public class MainActivity extends AppCompatActivity {
private WebView webView;
    @SuppressLint("MissingInflatedId")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        webView = findViewById(R.id.webview);
        //开启 JavaScript 支持
        webView.getSettings().setJavaScriptEnabled(true);

        //设置 WebViewClient,避免点击链接时跳转到浏览器
        webView.setWebViewClient(new WebViewClient(){
            @Override
            public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
                //固定指定 URL
                //跳转到外部浏览器
                return !request.getUrl().toString().equals("http://xxx");//在 WebView 中加载
            }
        });
        //加载指定 URL
        webView.loadUrl("http://xxx");
    }

    @Override
    public void onBackPressed() {
        //让 WebView 支持返回键回退功能
        if(webView.canGoBack()){
            webView.goBack();
        }else{
            super.onBackPressed();
        }
    }
}

运行调试: 我这边选择手机的无线调试

问题 1: net:ERR_CLEARTEXT_NOT_PREMITTEN

  • net::ERR_CLEARTEXT_NOT_PERMITTED 错误通常发生在 Android 9.0(API 级别 28)及更高版本中,当你的应用尝试通过 HTTP(即非加密的清晰文本连接)访问一个 URL 时,Android 出于安全考虑会阻止这种行为。

  • 默认情况下,Android 9 及以上版本要求所有的网络请求都使用 HTTPS(加密的连接)。

解决办法:

  • 1.使用 HTTPS(推荐)

  • 2.允许 HTTP 请求(不推荐,只有在特殊情况下使用)

如果你必须通过 HTTP 访问某个 URL,可以通过以下方法修改应用的配置,允许清晰文本 HTTP 连接。

  • ①在 AndroidManifest.xml 中启用 Cleartext 支持
    在你的 AndroidManifest.xml 文件中的 <application 标签内,加入以下代码:

android:usesCleartextTraffic="true"

这会告诉系统允许应用进行 HTTP 请求。

  • ②为特定域名配置 Cleartext 支持(推荐方式)
    为了更细粒度地控制,可以在 network_security_config.xml 文件中指定哪些域名允许使用 HTTP。

首先,创建一个 res/xml/network_security_config.xml 文件(如果没有的话),并添加如下内容:

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <domain-config cleartextTrafficPermitted="true">
        <domain includeSubdomains="true">yourdomain.com</domain>
    </domain-config>
</network-security-config>

然后,确保在 AndroidManifest.xml 中<application 引用这个配置文件:

android:networkSecurityConfig="@xml/network_security_config"

这样,你只会允许 yourdomain.com 使用 HTTP,而其他域名仍然要求使用 HTTPS。

  • ③避免使用 HTTP 连接

如果是你自己控制的服务器或第三方 API,建议尽可能支持 HTTPS,这不仅能解决此问题,还能提高数据传输的安全性。

问题 2: 安卓 WebView 中加载的 H5 网页内无法进行路由切换

通常是因为 WebView 在加载页面时并未正确处理 SPA(单页应用)路由,或者是页面上的 JavaScript 路由(例如 Vue Router、React Router 等)没有正确响应 URL 路径的变化。

解决办法:

MainActivity.java

  • 开启 JavaScript 支持
webView.getSettings().setJavaScriptEnabled(true);
  • 修改 WebViewClient 的拦截逻辑
      webView.setWebViewClient(new WebViewClient() {
            @Override
            public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
                String url = request.getUrl().toString();
                // 只拦截外部链接,自己域名的放行
                if (url.startsWith("https://yourdomain.com")) {
                    return false; // 交给 WebView 内部处理
                } else {
                    // 外链交给系统浏览器处理
                    Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
                    startActivity(intent);
                    return true;
                }
            }
        });

问题 3: WebView 嵌入 url 后, 网站中 文件上传调用相册, 如何实现

在 Android 的 WebView 中实现 H5 网页调用设备的相册进行文件上传,需要正确配置 WebView 和处理文件选择的回调逻辑。

解决办法:

MainActivity.java

  • 定义全局变量和常量
    private ValueCallback<Uri[]> filePathCallback; // 文件选择回调(适用于 Android 5.0+)
    private Uri cameraUri;
  • 1.启用文件上传功能
    确保 WebView 的设置支持文件上传:
webView.getSettings().setJavaScriptEnabled(true); // 启用 JavaScript
webView.getSettings().setAllowFileAccess(true);  // 允许访问文件
webView.getSettings().setAllowContentAccess(true); // 允许内容访问

问题 3.1: 'startActivityForResult(android.content.Intent, int)' 已弃用

在 Android 11(API 30) 之后,startActivityForResult() 和 onActivityResult() 已被 弃用,
推荐使用 新的 Activity Result API (registerForActivityResult()) 来处理,比如文件选择、拍照、权限请求等

解决办法: 创建新的 Activity Result API

     private final ActivityResultLauncher<Intent> fileChooserLauncher=registerForActivityResult(new ActivityResultContracts.StartActivityForResult(),result -> {
        if(filePathCallback==null)return;
        Uri[] results = null;
        if(result.getResultCode()== Activity.RESULT_OK){
            Intent data=result.getData();
            if(data==null){
                // 拍照
                if (cameraUri != null) {
                    results = new Uri[]{cameraUri};
                }

            }else{
                Uri uriData =data.getData();
                if(uriData !=null){
                    results = new Uri[]{uriData };
                }
            }
        }
        // ✅ 必须调用,不管有没有结果,否则第二次不再触发
        filePathCallback.onReceiveValue(results);
        filePathCallback=null;
        cameraUri = null;

    });

问题 3.2: WebView 文件上传第二次点击无反应

出现的原因几乎都是:

📌 第一次回调后,没有正确调用 filePathCallback.onReceiveValue(null) 清空回调对象。
导致 WebView 认为上一个文件选择请求还没结束,从而不再触发第二次选择。

  • 2.处理文件选择回调
    通过重写 WebChromeClient,处理文件选择器的调用。
     //2. 处理文件选择回调
        webView.setWebChromeClient(new WebChromeClient() {

            //用于处理文件选择的回调
            @Override
            public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) {
               //先清理上一次残留的 callback, 防止"第二次无响应"
                if(MainActivity.this.filePathCallback!=null){
                    MainActivity.this.filePathCallback.onReceiveValue(null);
                    MainActivity.this.filePathCallback=null;
                }
                // 保存回调
                MainActivity.this.filePathCallback=filePathCallback;
                //调用系统相册或文件选择器
                Intent intent = fileChooserParams.createIntent();
                try {
                    //使用新的 Launcher 启动
                    fileChooserLauncher.launch(intent);
                } catch (ActivityNotFoundException e) {
                    MainActivity.this.filePathCallback = null;
                    Toast.makeText(MainActivity.this, "无法打开文件选择器", Toast.LENGTH_LONG).show();
                    return false;
                }
                return true;
            }
        });

问题 4: 文件上传如何支持拍照 + 相册选择?

喜欢 (0)
[]
分享 (0)
发表我的评论
取消评论
表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
已稳定运行:3年255天2小时16分