欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android开发:通过 webview 将网页打包成安卓应用

程序员文章站 2022-07-06 12:37:11
商业转载请联系作者获得授权,非商业转载请注明出处。 For commercial use, please contact the author for authorization. For non commercial use, please indicate the source. 协议(Lice ......

商业转载请联系作者获得授权,非商业转载请注明出处。

for commercial use, please contact the author for authorization. for non-commercial use, please indicate the source.

协议(license):署名-非商业性使用-相同方式共享 4.0 国际 (cc by-nc-sa 4.0)

作者(author):

链接(url):

来源(source):搬砖少年

近期团队接到一个新的项目,企业内部的一个掌上超市项目,最初考虑通过公众号或者小程序来做,后面说是部署在企业内网,就考虑到做网站应用,由于需要通过运营商分配的apn连接企业内网,所以在打开应用之前需要检测一下网络,如果是web端的话,那就没法检测网络了,所以考虑使用安卓的 webview 封装一下h5的应用。
1、配置网络连接权限

在androidmanifest.xml文件中加上以下配置信息

<uses-permission android:name="android.permission.internet"/>

注: 从android 9.0(api级别28)开始,默认情况下禁用明文支持。因此http的url均无法在webview中加载 ,所以只配置以上信息可能会导致net::err_cleartext_not_permitted报错,还需要在配置文件的 application中加入下面的配置。参照文章: net::err_cleartext_not_permitted

android:usescleartexttraffic="true"

webview 网络配置异常
net::err_cleartext_not_permitted 配置
2、创建layout文件
使用idea的话,会自动创建mainactivity和对应的layout文件,直接在文件的基础上修改即可,使用webview控件,如果需要使用进度条的话,可以将progressbar 的配置打开即可。

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.constraintlayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context="com.ctjsoft.jxf.shop.mainactivity">
    <webview android:id="@+id/webview" android:layout_width="match_parent" android:layout_height="match_parent"/>
    <!--<progressbar android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/progressbar"
                 style="@android:style/widget.progressbar.horizontal" android:max="100" android:progress="0"
                 android:visibility="gone"/>-->
</androidx.constraintlayout.widget.constraintlayout>

3、修改 mainactivity 文件
重写oncreate方法:

protected void oncreate(@nullable bundle savedinstancestate) {
        super.oncreate(savedinstancestate);
        setcontentview(r.layout.activity_main);
        //progressbar = (progressbar) findviewbyid(r.id.progressbar);//进度条
 
        webview = (webview) findviewbyid(r.id.webview);
        webview.getsettings().setallowuniversalaccessfromfileurls(true);
        webview.getsettings().setallowfileaccessfromfileurls(true);
        // webview的设置中添加如下代码
        try {
            if (build.version.sdk_int >= 16) {
                class<?> clazz = webview.getsettings().getclass();
                method method = clazz.getmethod("setallowuniversalaccessfromfileurls", boolean.class);
                if (method != null) {
                    method.invoke(webview.getsettings(), true);
                }
            }
        } catch (illegalargumentexception e) {
            e.printstacktrace();
        } catch (nosuchmethodexception e) {
            e.printstacktrace();
        } catch (illegalaccessexception e) {
            e.printstacktrace();
        } catch (invocationtargetexception e) {
            e.printstacktrace();
        }
        //webview.loadurl("http://172.17.1.176:8082/");//加载url
        webview.loadurl(api);
 
        //使用webview显示html代码
//        webview.loaddatawithbaseurl(null,"<html><head><title> 欢迎您 </title></head>" +
//                "<body><h2>使用webview显示 html代码</h2></body></html>", "text/html" , "utf-8", null);
 
        webview.addjavascriptinterface(this, "android");//添加js监听 这样html就能调用客户端
        webview.setwebchromeclient(webchromeclient);
        webview.setwebviewclient(webviewclient);
        websettings websettings = webview.getsettings();
        /**
         * load_cache_only: 不使用网络,只读取本地缓存数据
         * load_default: (默认)根据cache-control决定是否从网络上取数据。
         * load_no_cache: 不使用缓存,只从网络获取数据.
         * load_cache_else_network,只要本地有,无论是否过期,或者no-cache,都使用缓存中的数据。
         */
        websettings.setcachemode(websettings.load_default);//不使用缓存,只从网络获取数据.
        webview.getsettings().settextzoom(100);
webview.getsettings().setjavascriptcanopenwindowsautomatically(true);//设置js可以直接打开窗口,如window.open(),默认为false
        webview.getsettings().setjavascriptenabled(true);//是否允许执行js,默认为false。设置true时,会提醒可能造成xss漏洞
        webview.getsettings().setsupportzoom(true);//是否可以缩放,默认
        webview.getsettings().setbuiltinzoomcontrols(true);//是否显示缩放按钮,默认false
        webview.getsettings().setusewideviewport(true);//设置此属性,可任意比例缩放。大视图模式
        webview.getsettings().setloadwithoverviewmode(true);//和setusewideviewport(true)一起解决网页自适应问题
        webview.getsettings().setappcacheenabled(true);//是否使用缓存
        webview.getsettings().setdomstorageenabled(true);//dom storage
    }
		```
配置webviewclient
//webviewclient主要帮助webview处理各种通知、请求事件
private webviewclient webviewclient = new webviewclient() {
    @override
    public void onpagefinished(webview view, string url) {//页面加载完成
        //progressbar.setvisibility(view.gone);
    }

    public void onpagestarted(webview view, string url, bitmap favicon) {//页面开始加载
        //progressbar.setvisibility(view.visible);
    }

    @requiresapi(api = build.version_codes.lollipop)
    @override
    public boolean shouldoverrideurlloading(webview view, webresourcerequest request) {
        log.i("ansen", "拦截url:" + request.geturl());
        return super.shouldoverrideurlloading(view, request);
    }

};

//webchromeclient主要辅助webview处理javascript的对话框、网站图标、网站title、加载进度等
private webchromeclient webchromeclient = new webchromeclient() {
    //不支持js的alert弹窗,需要自己监听然后通过dialog弹窗
    public boolean onjsalert(webview webview, string url, string message, jsresult result) {
        alertdialog.builder localbuilder = new alertdialog.builder(webview.getcontext());
        localbuilder.setmessage(message).setpositivebutton("确定", null);
        localbuilder.setcancelable(false);
        localbuilder.create().show();

        //注意:
        //必须要这一句代码:result.confirm()表示:
        //处理结果为确定状态同时唤醒webcore线程
        //否则不能继续点击按钮
        result.confirm();
        return true;
    }

    //获取网页标题
    @override
    public void onreceivedtitle(webview view, string title) {
        super.onreceivedtitle(view, title);
        log.i("ansen", "网页标题:" + title);
    }

    //加载进度回调
    @override
    public void onprogresschanged(webview view, int newprogress) {
        // progressbar.setprogress(newprogress);
    }
};

@override
public boolean onkeydown(int keycode, keyevent event) {
    log.i("ansen", "是否有上一个页面:" + webview.cangoback());
    if (webview.cangoback() && keycode == keyevent.keycode_back) {//点击返回按钮的时候判断有没有上一页
        webview.goback(); // goback()表示返回webview的上一页面
        return true;
    }
    return super.onkeydown(keycode, event);
}

/**
 * js调用android的方法
 *
 * @param str
 * @return
 */
@javascriptinterface //仍然必不可少
public void getclient(string str) {
    log.i("ansen", "html调用客户端:" + str);
}

@override
protected void ondestroy() {
    super.ondestroy();

    //释放资源
    webview.destroy();
    webview = null;
}
	```