Android使用WebView交互

Android使用webView细节



前言

android中使用WebView细节繁多,特此记录一个天气可视化折线图,android端使用WebView加载前端H5页面,可视化工具使用Echarts ,api使用聚合天气


一、android端与WebView交互

1.android调用前端方法

编写布局 ProgressBar为进度条,可省略

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical">
    <ProgressBar android:layout_width="match_parent" style="@style/Widget.AppCompat.ProgressBar.Horizontal" android:id="@+id/chart_bar" android:layout_height="10dp"/>
<WebView android:layout_width="match_parent" android:id="@+id/fragment_webview" android:layout_height="match_parent"/>

</LinearLayout>

H5中编写一个测试方法供android端调用

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
</body>
<script> /* 无参调用 */ function notParamFun() {
     alert("网页方法被调用"); } /* 有参调用 */ function haveParamtestFun(data) {
     alert("接收到android端的数据:" + data); } </script>
</html>

注意:编写好的HTML网页需要放入android 项目中的assets中,assets需要手动新建。


android 中java代码,注意loadUrl中是asset,且发送数据必须等待网页加载完(newProgress =100)才能进行交互并且只能传输字符串形式。
且需要加入单引号

 	private ProgressBar chartBar;
    private WebView fragmentWebview;
    
   @Override
    protected void onCreate(Bundle savedInstanceState) {
   
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);
         chartBar = (ProgressBar) view.findViewById(R.id.chart_bar);
        fragmentWebview = (WebView) view.findViewById(R.id.fragment_webview);


        /*前端接口*/
        fragmentWebview.addJavascriptInterface(this, "myWebView");
        fragmentWebview.loadUrl("file:///android_asset/myWebView.html");
        fragmentWebview.setWebChromeClient(new WebChromeClient() {
   
            @Override
            public void onProgressChanged(WebView view, int newProgress) {
   
// 当进度达到100时调用H5接口
                if (newProgress == 100) {
   
                       fragmentWebview.loadUrl("javascript:notParamFun()");
                    fragmentWebview.loadUrl("javascript:haveParamtestFun('"+ "发送String数据" +"')");
                    chartBar.setVisibility(View.GONE);

                } else {
   
                    chartBar.setVisibility(View.VISIBLE);
                    chartBar.setProgress(newProgress);
                }
            }

        });
    }
        /*前端调用的接口方法*/
    @JavascriptInterface
    public void getData(String title) {
   
        new AlertDialog.Builder(getContext())
                .setTitle(title)
                .setMessage("前端调用")
                .setPositiveButton("OK", null)
                .create()
                .show();

    }


2. 前端H5调用android方法

在android已经写好网页端调用接口对象myWebView,且有一个共前端调用的方法为getData

        /*前端接口对象*/
fragmentWebview.addJavascriptInterface(this, "myWebView");

    /*前端调用的接口方法*/
    @JavascriptInterface
    public void getData(String title) {
   
        new AlertDialog.Builder(getContext())
                .setTitle(title)
                .setMessage("前端调用")
                .setPositiveButton("OK", null)
                .create()
                .show();

    }

只需在前端加入一行调用代码

<script> //调用android方法,无参也需要写上() javascript: myWebView.getData("我是前端的title"); /* 无参调用 */ function notParamFun() {
     alert("网页方法被调用"); } /* 有参调用 */ function haveParamtestFun(data) {
     alert("接收到android端的数据:" + data); } </script>

保存重新启动模拟器

二、编写写天气可视化Demo

1、前端引入Echarts,编写前端布局

注意:stack加上会有堆叠显示问题,最后去掉stack解决堆叠问题

<!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="https://cdn.staticfile.org/echarts/4.7.0/echarts.min.js"></script>

</head>

<body>
    <div id="myChartPie" style="width: 100%; height: 400px; "></div>
    <div></div>
</body>
<script> var echartsPie = echarts.init(document.getElementById("myChartPie")); var option = {
     title: {
     text: '武汉天气预报' }, tooltip: {
     trigger: 'axis' }, legend: {
     data: ['最低温度', '最高温度'] }, grid: {
     left: '3%', right: '4%', bottom: '3%', containLabel: true }, toolbox: {
     feature: {
     saveAsImage: {
    } } }, xAxis: {
     type: 'category', boundaryGap: false, data: [], }, yAxis: {
     type: 'value' }, series: [{
     name: '最低温度', type: 'line', data: [], itemStyle: {
     normal: {
     color: 'black', borderColor: 'black', //拐点边框颜色 } }, }, {
     name: '最高温度', type: 'line', data: [], itemStyle: {
     normal: {
     color: 'red', borderColor: 'red', //拐点边框颜色 } }, } ] }; echartsPie.setOption(option); function javacalljs(data) {
     /* 将JSON数据转换为对象 */ data = JSON.parse(data); var weather = data.result.future; //时间数组 var dateArr = []; //最低气温数组 var temLowerArr = []; //最高气温数组 var temHightArr = []; //循环遍历添加数据 weather.forEach(function(item) {
     var tem = item.temperature.toString().replace("℃", "").split("/"); dateArr.push(item.date); temLowerArr.push(tem[0]); temHightArr.push(tem[1]); }); option.xAxis.data = dateArr; option.series[0].data = temLowerArr; option.series[1].data = temHightArr; //最后要更新图表 echartsPie.setOption(option); } </script>

</html>

2.android 端编写布局及交互代码

布局仍然使用上次的xml文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical">
    <ProgressBar android:layout_width="match_parent" style="@style/Widget.AppCompat.ProgressBar.Horizontal" android:id="@+id/chart_bar" android:layout_height="10dp"/>
<WebView android:layout_width="match_parent" android:id="@+id/fragment_webview" android:layout_height="match_parent"/>

</LinearLayout>

java 交互代码,api选用聚合天气api,网络框架使用OKHttp



    private ProgressBar chartBar;
    private WebView fragmentWebview;
	private String apiData = "";
	//请求聚合天气API的url
   private final String url = "http://apis.juhe.cn/simpleWeather/query";
 @Override
    protected void onCreate(Bundle savedInstanceState) {
   
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        chartBar = (ProgressBar) view.findViewById(R.id.chart_bar);
        fragmentWebview = (WebView) view.findViewById(R.id.fragment_webview);
         RequestBody body =new FormBody.Builder()
                .add("key", "你申请的key")
                .add("city", "武汉")
                .build();
                    
 OkHttpClient client = new OkHttpClient();

        Request request = new Request.Builder()
                    .url(url)
                    .post(body)
                    .build();



        client.newCall(request).enqueue(new Callback() {
   
            /*请求失败时的回调*/
            @Override
            public void onFailure(Call call, IOException e) {
   
                Log.e("onFailure: ", e.getMessage());
            }
            /*请求成功时的回调*/
            @Override
            public void onResponse(Call call, Response response) throws IOException {
   
					apiData = response.body().string();
            }
        });
		
        fragmentWebview.loadUrl("file:///android_asset/myWebView.html");
        fragmentWebview.setWebChromeClient(new WebChromeClient() {
   
            @Override
            public void onProgressChanged(WebView view, int newProgress) {
   
			// 当进度达到100时发送数据
                if (newProgress == 100) {
   
                    fragmentWebview.loadUrl("javascript:javacalljs('"+ apiData +"')");

                    chartBar.setVisibility(View.GONE);

                } else {
   
                    chartBar.setVisibility(View.VISIBLE);
                    chartBar.setProgress(newProgress);
                }
            }

        });
        
    }