Android 使用WebView总结

WebView 专题

第一个WebView程序:加载远程网址

  1. Layout添加WebView组件;
xml 复制代码
<WebView
                android:id="@+id/webView_first"
                android:layout_width="match_parent"
                android:layout_height="match_parent"/>
  1. 初始化组件,加载Url;

    java 复制代码
    public class FirstWebViewActivity extends AppCompatActivity{
    
        private WebView webView_first;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_first_web_view);
            webView_first=findViewById(R.id.webView_first);
            webView_first.loadUrl("https://www.baidu.com/");
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            webView_first.removeAllViews();
            webView_first.destroy();
        }
    }
  2. Manifest文件添加网络访问权限

    xml 复制代码
    <uses-permission android:name="android.permission.INTERNET" />
  3. 出现错误:

    sql 复制代码
    NetworkSecurityConfig   com.hymy.webviewstarter              D  No Network Security Config specified, using platform default
    Denied starting an intent without a user gesture, URI

    解决方法:

    res/xml下添加 network_security_config.xml 文件:

    xml 复制代码
    <?xml version="1.0" encoding="utf-8"?>
    <network-security-config> //默认配置:允许明文通信
        <base-config cleartextTrafficPermitted="true" />
    </network-security-config>

    在AndroidManifest.xml中引用

    xml 复制代码
    <application
            android:networkSecurityConfig="@xml/network_security_config"
            ...
  4. 出现错误:

    访问bing.com无法加载封面图片:

    vbnet 复制代码
    The resource xxx was preloaded using link preload but not used within a few seconds from the window's load event. Please make sure it has an appropriate `as` value and it is preloaded intentionally.

    解决方法:

    ini 复制代码
    webView_first=findViewById(R.id.webView_first);
    //启用JavaScript
    WebSettings webSettings = webView_first.getSettings();
    webSettings.setJavaScriptEnabled(true);
    webView_first.loadUrl("https://cn.bing.com/?mkt=zh-CN");
  5. 下载:在bing搜索网站首页,好看的壁纸,点击可以下载图片,将图片下载到 SD 卡下的Downloader目录下

    参考:cloud.tencent.com/developer/a...

  6. 将 JavaScript代码绑定到Android代码

    js调用Android代码中的方法

    新建 WebAppInterface 类

    java 复制代码
    /**
     * @Author : alex
     * @Date : on 2023/11/14 09:21.
     * @Description :描述
     */
    public class WebAppInterface {
        Context mContext;
    
        /**
         * 初始化接口,并设置context
         * @param c
         */
        WebAppInterface(Context c){
            mContext=c;
        }
    
        /**
         * 在Web页面显示消息提示
         * @param toast
         */
        @JavascriptInterface
        public void showToast(String toast){
            Toast.makeText(mContext,toast,Toast.LENGTH_SHORT).show();
        }
    }

    webview 绑定接口:

    arduino 复制代码
     webView_first.addJavascriptInterface(new WebAppInterface(this),"Android");

    html代码示例:

    xml 复制代码
    <!doctype html>
    <html lang="en">
      <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Bootstrap demo</title>
        <link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/5.3.1/css/bootstrap.min.css" rel="stylesheet">
      </head>
      <body>
        <h1>Hello, world!</h1>
        <input type="button" value="Say hello" onClick="showAndroidToast('Hello Android!')" />
        <script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/5.3.1/js/bootstrap.bundle.min.js"></script>
        <script type="text/javascript">
          function showAndroidToast(toast) {
                Android.showToast(toast);
          }
        </script>
      </body>
    </html>
  7. webview中的跳转连接

    参考:www.digitalocean.com/community/t...

    当 html 中有跳转链接的时候,可以直接阻止、选择性阻止在我们的App跳转、或者可以打开系统浏览器,加载外部链接。

    java 复制代码
    webView_first.setWebViewClient(new MyWebViewClient());
    
    private class MyWebViewClient extends WebViewClient {
        @Override
        public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
            Log.i("FirstWebViewActivity",request.getUrl().getHost());
            if ("192.168.96.108".equals(request.getUrl().getHost())) {
                // This is my website, so do not override; let my WebView load the page
                return false;
            }
            // Otherwise, the link is not for a page on my site, so launch another Activity that handles URLs
            Intent intent = new Intent(Intent.ACTION_VIEW, request.getUrl());
            startActivity(intent);
            return true;
        }
    }
  8. webview加载本地网页,实现 sqlite 数据库增删改查

    使用的库 gson:

    groovy 复制代码
    implementation 'com.google.code.gson:gson:2.8.5'

    首先新建assets文件夹,android默认工程没有创建。

编写 DBHelper ,定义数据库名,在 onCreate 中初始化数据库:

java 复制代码
    public class MyDatabaseHelper extends SQLiteOpenHelper {
        public static final String DATABASE_NAME = "student.db";
        public static final int DATABASE_VERSION =1;

        public MyDatabaseHelper(Context context){
            super(context,DATABASE_NAME,null,DATABASE_VERSION);
        }

        @Override
        public void onCreate(SQLiteDatabase db) {
            // 数据库首次创建时调用,执行创建表等语句
            // 创建student表
            db.execSQL("CREATE TABLE student (" +
                    "id INTEGER PRIMARY KEY AUTOINCREMENT," +
                    "name TEXT," +
                    "age INTEGER," +
                    "birth TEXT)");
            // 如果需要初始化数据可以在这里插入:
            db.execSQL("INSERT INTO student (name, age, birth) " +
                    "VALUES ('张三', 18, '1980-01-01')");
        }

        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
            // 数据库版本更新时调用

        }
    }

然后定义 MyApplication,在程序启动的时候初始化数据库:

java 复制代码
    public class MyApplication extends Application {
        @Override
        public void onCreate() {
            super.onCreate();
            //检测数据库是否存在,不存在则创建数据库
            Context context = getApplicationContext();
            MyDatabaseHelper dbHelper = new MyDatabaseHelper(context);
            SQLiteDatabase db = dbHelper.getWritableDatabase();
        }
    }

定义数据增、查接口类,供H5中调用:

java 复制代码
    public class JsDBInterface {
        private SQLiteDatabase db;
        public JsDBInterface(Context context){
            // 在构造函数中打开数据库
            MyDatabaseHelper helper = new MyDatabaseHelper(context);
            db = helper.getWritableDatabase();
        }

        /**
         * 插入数据
         * @param name
         * @param age
         * @param birth
         */
        @JavascriptInterface
        public void insertData(String name,int age,String birth){
            //检查参数
            if(name==null||name.isEmpty()){
                return;
            }
            //插入数据
            ContentValues values = new ContentValues();
            values.put("name",name);
            values.put("age",age);
            values.put("birth",birth);
            db.insert("student",null,values);
            Log.i("插入数据",name);
        }

        /**
         * 查询数据
         * @return
         */
        @JavascriptInterface
        public String getAllStudents(){
            List<Student> students = new ArrayList<>();
            //查询数据库中的所有学生
            Cursor cursor = db.query("student",null,null,null,null,null,null);
            //获取所有列
    //        String[] cols = cursor.getColumnNames();
    //        int nameIndex=-1;
            while (cursor.moveToNext()){
                int columnIndex1=cursor.getColumnIndex("id");
                int columnIndex2=cursor.getColumnIndex("name");
                int columnIndex3=cursor.getColumnIndex("age");
                int columnIndex4=cursor.getColumnIndex("birth");
                int id=0;String name="null";int age=0;String birth="0000-00-00";
                if(columnIndex1>=0){
                    id = cursor.getInt(columnIndex1);
                }
                if(columnIndex2>=0){
                    name=cursor.getString(columnIndex2);
                }
                if(columnIndex3>=0){
                    age = cursor.getInt(columnIndex3);
                }
                if(columnIndex4>=0){
                    birth=cursor.getString(columnIndex4);
                }

                Student stu = new Student(id,name,age,birth);
                students.add(stu);
            }
            cursor.close();
            Gson gson = new Gson();
            String json = gson.toJson(students);
            return json;
        }
    }

数据实体类:

java 复制代码
    public class Student {
        private int id;
        private String name;
        private int age;
        private String birth;

        public int getId() {
            return id;
        }

        public Student(int id,String name, int age, String birth) {
            this.id=id;
            this.name = name;
            this.age = age;
            this.birth = birth;
        }

        public void setId(int id) {
            this.id = id;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public int getAge() {
            return age;
        }

        public void setAge(int age) {
            this.age = age;
        }

        public String getBirth() {
            return birth;
        }

        public void setBirth(String birth) {
            this.birth = birth;
        }
    }

在 Activity 中注册接口:

java 复制代码
webView.addJavascriptInterface(new JsDBInterface(MainActivity.this),"JsDBInterface");

加载本地网页:
private String localUrl="file:///android_asset/index.html";
webView_first.loadUrl(localUrl);

HTML 使用了vue,调用代码如下:

html 复制代码
<!DOCTYPE html>
        <html lang="en">
        <head>
            <meta charset="UTF-8">
            <meta name="viewport" content="width=device-width, initial-scale=1.0">
            <title>Document</title>
            <script src="./vue.min.js"></script>
        </head>
        <body>
            <div id="app">
                <h2>{{message}}</h2>
                <ul>
                    <li v-for="user in users" :key="user.id">{{user.name}}</li>
                </ul>
                <button id="btnInsertStudent" onclick="addStudent()">新增学生</button>
                <button id="btnGetAllStudents" onclick="getAllStudent()">查询所有学生</button>
                <ul id='studentList'></ul>
            </div>
            <script>
                var app = new Vue({
                    el:'#app',
                    data(){
                        return {
                            message:'Hello Vue!'
                        }
                    },
                    mounted(){
                    }
                })
                function addStudent(){
                    JsDBInterface.insertData("小明",18,"2010-01-01");
                    alert('添加成功')
                }
                function getAllStudent(){
                    var data = JsDBInterface.getAllStudents();
                    var students = JSON.parse(data);
                    var studentTxt='';
                    for(var i = 0; i < students.length; i++) {
                        var stu = students[i];
                        studentTxt += '<li>' + stu.name + ',' + stu.age + ',' + stu.birth + '</li>';
                      }
                      var ul = document.getElementById('studentList');
                      ul.innerHTML = studentTxt;
                }
            </script>
        </body>
        </html>

结果:

  1. webview h5 alert 不运行

    参考:copyprogramming.com/howto/modif...

    最简单的处理方法是:添加下面的代码

java 复制代码
webView_first.setWebChromeClient(new WebChromeClient());

但是上面的标题会显示网址,可以用下面的方法进行修改:

java 复制代码
webView_first.setWebChromeClient(new WebChromeClient(){
    @Override
    public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
        AlertDialog dialog = new AlertDialog.Builder(view.getContext())
            .setTitle("提示")
            .setMessage(message)
            .setPositiveButton("确定", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    // do nothing
                }
            }).create();
        dialog.show();
        result.confirm();
        return true;
    }
});

修改后:

此外如果对 alert, prompt, confirm统一进行修改,可以使用下面代码:

java 复制代码
webView_first.setWebChromeClient(new WebChromeClient(){
    @Override
    public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
        new AlertDialog.Builder(view.getContext())
            .setTitle("alert")
            .setMessage(message)
            .setPositiveButton("确定", (DialogInterface dialog, int which) -> result.confirm())
            .setOnDismissListener((DialogInterface dialog) -> result.confirm())
            .create()
            .show();
        return true;
    }

    @Override
    public boolean onJsConfirm(WebView view, String url, String message, JsResult result) {
        new AlertDialog.Builder(view.getContext())
            .setTitle("confirm")
            .setMessage(message)
            .setPositiveButton("确定", (DialogInterface dialog, int which) -> result.confirm())
            .setNegativeButton("取消", (DialogInterface dialog, int which) -> result.cancel())
            .setOnDismissListener((DialogInterface dialog) -> result.cancel())
            .create()
            .show();
        return true;
    }

    @Override
    public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {
        final EditText input = new EditText(view.getContext());
        input.setInputType(InputType.TYPE_CLASS_TEXT);
        input.setText(defaultValue);
        new AlertDialog.Builder(view.getContext())
            .setTitle("prompt")
            .setMessage(message)
            .setView(input)
            .setPositiveButton("确定", (DialogInterface dialog, int which) -> result.confirm(input.getText().toString()))
            .setNegativeButton("取消", (DialogInterface dialog, int which) -> result.cancel())
            .setOnDismissListener((DialogInterface dialog) -> result.cancel())
            .create()
            .show();
        return true;
    }
});
相关推荐
刚刚好ā6 天前
uni-app跳转外部链接方式汇总--超全
前端·vue.js·uni-app·vue·webview
李先静8 天前
AWTK-WIDGET-WEB-VIEW 实现笔记 (3) - MacOS
macos·webview·awtk
李先静8 天前
AWTK-WIDGET-WEB-VIEW 实现笔记 (2) - Windows
webview·awtk
小双1 个月前
Android WebView加载不到cookie
android·webview
捂心1 个月前
uniapp打包的h5与小程序web-view间的通讯、跳转
小程序·uni-app·html5·webview·postmessage
我是ed.2 个月前
Cocos 2 使用 webview 嵌入页面,摄像头调用没权限问题
webview·cocos2d·摄像头
盛书强2 个月前
iOS H5 黑边解决方案
ios·webview
帅次2 个月前
解决 Android WebView 无法加载 H5 页面常见问题的实用指南
android·okhttp·gradle·binder·webview·retrofit·appcompat
余生H2 个月前
拿下奇怪的前端报错:某些多摄手机拉取部分摄像头视频流会导致应用崩溃,该如何改善呢?
前端·javascript·webrtc·html5·webview·相机
技术无疆2 个月前
跨平台开发新视角:利用Android WebView实现Web内容的原生体验
android·java·前端·ios·react·web·webview