android studio+webapi+easyui混合开发

近日做了个android小例子,我是个初学者,新手上路,请多多指教。

一. 创建一个H5页面,UI使用easyui

    创建assets目录,用来存放前端资源

 下载easyui资源包,复制CSS、资源和js文件。

 把easyui文件直接复制到目录下

  这个路径就是 easyuif/……,下面这一步可以查看路径

这就是要引用的路径

参考easyui demo创建h5网页

<!DOCTYPE html>
<html lang="en">
<head>
     <meta charset="UTF-8">
     <title>Title</title>
     <link rel="stylesheet" type="text/css" href="easyuif/themes/default/easyui.css" />
     <link rel="stylesheet" type="text/css" href="easyuif/themes/mobile.css" />
     <link rel="stylesheet" type="text/css" href="easyuif/themes/icon.css" />
     <link rel="stylesheet" type="text/css" href="easyuif/themes/color.css" />
     <script type="text/javascript" src="easyuif/jquery.min.js"></script>
     <script type="text/javascript" src="easyuif/jquery.easyui.min.js"></script>
     <script type="text/javascript" src="easyuif/locale/easyui-lang-zh_CN.js"></script>
     <style>
          .nihong{
              /* 要把阴影与大小配合好,一般来说大小都是偏大时采用 */
              font-family: "Arial Rounded MT Bold", "Helvetica Rounded", Arial, sans-serif;
              text-transform: uppercase;/* 全开大写 */
              font-size: 24px;
              color: orangered;
              text-shadow: 0 8px 9px #c4b59d, 0px -2px 1px #fff;
              font-weight: bold;
              letter-spacing: -4px;
              /*background: linear-gradient(to bottom, #ece4d9 0%,#e9dfd1 100%);*/
          }
     </style>
</head>
<body onload="iniatialize()">
<div style="margin:20px 0;">
     <a class="nihong" style="">RCS参数下发_测试用例</a>
</div>
<div>
     <ul class="m-list">
          <li><span style="font-size:12px;color:gray">请求编号(RequestCode:string):</span><br><input id="RequestCode" class="easyui-textbox" prompt="...(选填)" style="width:100%;height:30px"></li>
          <li><span style="font-size:12px;color:gray">任务类型(taskType:string):</span>
               <br>
               <select id="state" class="easyui-combobox" name="state" style="width:100%;height:30px">
                    <option value="AL">产线上线</option>
                    <option value="AK">立库出库</option>
                    <option value="AZ">产线下线</option>
               </select>
          </li>
          <li><span style="font-size:12px;color:gray">任务号(taskNo:string):</span><br><input id="taskNo" class="easyui-textbox" prompt="..." style="width:100%;height:30px"></li>
          <li><span style="font-size:12px;color:gray">状态(taskState:string):</span><br><input id="taskState" class="easyui-textbox" prompt="..." style="width:100%;height:30px"></li>
          <li><span style="font-size:12px;color:gray">接收位置(begin_location:string):</span><br><input id="beginlocation"  class="easyui-textbox" prompt="例如301-101" style="width:100%;height:30px"></li>
          <li><span style="font-size:12px;color:gray">送达位置(target_location:string):</span><br><input id="targetlocation"  class="easyui-textbox" prompt="例如301-103" style="width:100%;height:30px"></li>
          <li><span style="font-size:12px;color:gray">下一工序产线编码(To_Line_Code:string):</span><br><input id="ToLineCode"  class="easyui-textbox" prompt="..." style="width:100%;height:30px"></li>
          <li><span style="font-size:12px;color:gray">请求操作时间(RequestTime:string)</span><br><input id="RequestTime"  class="easyui-textbox" prompt="..." style="width:100%;height:30px"></li>
          <li><span style="font-size:12px;color:gray">托盘号(PalletCode:string):</span><br><input id="PalletCode"  class="easyui-textbox" prompt="例如:P2100056" style="width:100%;height:30px"></li>
          <li><span style="font-size:12px;color:gray">部件总数量(TotalQuantity:int):</span><br><input id="TotalQuantity"  class="easyui-textbox" prompt="请输入正整数" style="width:100%;height:30px"></li>
          <li>
               <span style="font-size:12px;color:gray">部件集合(PartSets:集合):(PartSets:ArrayList):</span>
               <br>
               <input id="PartSets" class="easyui-searchbox" data-options="prompt:'null(选填)',searcher:doSearch" style="width:100%;height:30px">
          </li>
     </ul>
     <a href="javascript:quest();" class="easyui-linkbutton c3" style="width:100%;height:40px">提交</a>
</div>
<!--弹窗 -->
<div id="win" class="easyui-window" title="部件编辑" closed="true" style="top:40%;width:90%;height:40%;">
     <form id="frm" style= "padding:1px 1px 1px 1px;">
          <table id="dg" class="easyui-datagrid" style="width:100%;height:auto"
                 data-options="iconCls: 'icon-edit',singleSelect: true,toolbar: '#tb',onClickCell: onClickCell,onEndEdit: onEndEdit">
               <thead>
               <tr>
                    <th data-options="field:'SequenceNumber',width:40,align:'center',editor:'textbox'">顺序</th>
                    <th data-options="field:'ProductionBatchCode',width:80,align:'center',editor:'textbox'">批次号</th>
                    <th data-options="field:'PartSerialNumber',width:80,align:'center',editor:'textbox'">条码号</th>
                    <th data-options="field:'TaskNumber',width:80,align:'center',editor:'textbox'">任务单</th>
                    <th data-options="field:'PartMaterialCode',width:80,align:'center',editor:'textbox'">物料号</th>
                    <th data-options="field:'status',align:'middle',width:40,align:'center',editor:{type:'checkbox',options:{on:'P',off:''}}">状态</th>
               </tr>
               </thead>
          </table>

          <div id="tb" style="height:auto">
               <a href="javascript:void(0)" class="easyui-linkbutton" data-options="iconCls:'icon-add',plain:true" onclick="append()">添加</a>
               <a href="javascript:void(0)" class="easyui-linkbutton" data-options="iconCls:'icon-remove',plain:true" onclick="removeit()">删除</a>
               <a href="javascript:void(0)" class="easyui-linkbutton" data-options="iconCls:'icon-clear',plain:true" onclick="removeall()">清空</a>
               <a href="javascript:void(0)" class="easyui-linkbutton" data-options="iconCls:'icon-cancel',plain:true" onclick="closewin2()">关闭</a>
          </div>
     </form>
</div>
<!--弹窗 -->
<div id="win2" class="easyui-window" title="系统消息" closed="true" style="top:60%;width:90%;height:30%;">
     <form id="frm2" style= "padding:10px 10px 10px 10px;">
          <div style="width:100%;height:90%">
               <div style="width:100%;height:5%">
                <p style="font-size:14px"><label id="typename">sdfsdfsdfsdg</label></p>
               </div>
               <div style="width:100%;height:95%">
                 <p style="font-size:12px;color:darkgray;padding:5px 5px 5px 5px;">
                    <label id="msgtxt" style="word-break:break-all;">asdasdasd</label>
                 </p>
               </div>
          </div>
          <div style="width:100%;top:90%;height:5%">
               <p><a href="javascript:closewin()" class="easyui-linkbutton c4" style="left:60%;width:20%;height:40px">确定</a></p>
          </div>
     </form>
</div>
<script type="text/javascript">

        function quest(){
            var RequestCode_ =$("#RequestCode").textbox('getText');
            var taskType_ =$("#state").combobox('getText');
            var taskNo_ = $("#taskNo").textbox('getText');
            var taskState_ = $("#taskState").textbox('getText');
            var beginlocation_ = $("#beginlocation").textbox('getText');
            var targetlocation_ = $("#targetlocation").textbox('getText');
            var ToLineCode_ = $("#ToLineCode").textbox('getText');
            var date = new Date();
            var datm=dateTimeToString(date).toLocaleString();
            $('#RequestTime').textbox('setValue', datm);
            var RequestTime_ = $("#RequestTime").textbox('getText');
            var PalletCode_ = $("#PalletCode").textbox('getText');
            var TotalQuantity_ = parseInt($("#TotalQuantity").textbox('getText'));
            var msginfo=getTable();
            var PartSets_;
            if(msginfo==''){
               PartSets_ = null;
               $('#PartSets').textbox('setValue', 'null');
            }else{
               PartSets_ = getTable();
               var numcou=PartSets_.length;
               $('#PartSets').textbox('setValue', 'data['+String(numcou)+']');
            }
            var datax={                       RequestCode:RequestCode_,taskType:taskType_,taskNo:taskNo_,taskState:taskState_,begin_location:beginlocation_,                    target_location:targetlocation_,To_Line_Code:ToLineCode_,RequestTime:RequestTime_,PalletCode:PalletCode_,
                         TotalQuantity:TotalQuantity_,PartSets:PartSets_
                     };
           android.showToast(JSON.stringify(datax));
        }
        function ShowMsg(str,datx){
            document.getElementById('typename').innerHTML =datx;
            document.getElementById('msgtxt').innerHTML = JSON.stringify(str);
            openmsg();
        }
        function iniatialize(){
            $('#RequestCode').textbox('setValue', 'testRCS_001');
            $('#taskState').textbox('setValue', '下发');
            $('#taskNo').textbox('setValue', 'Task001');
            var date = new Date();
            var datm=dateTimeToString(date).toLocaleString();
            $('#RequestTime').textbox('setValue', datm);
            $('#ToLineCode').textbox('setValue', '8A27A001004');
            $('#TotalQuantity').textbox('setValue', '0');
            $('#PartSets').textbox('setValue', 'null');
        }
        function dateTimeToString(date) {
            var y = date.getFullYear();
            var M = date.getMonth() + 1;
            var d = date.getDate();
            var H = date.getHours();
            var m = date.getMinutes();
            var s = date.getSeconds();
            return y + '-' + (M < 10 ? ('0' + M) : M) + '-' + (d < 10 ? ('0' + d) : d) + " " + (H < 10 ? ('0' + H) : H) + ":" + (m < 10 ? ('0' + m) : m) + ":" + (s < 10 ? ('0' + s) : s);
         }
        function getTable(){
             var list= [];
             var checkedItems = $('#dg').datagrid('getRows');
             $.each(checkedItems, function(index, item){
                 var _SequenceNumber=parseInt(item.SequenceNumber);
                 var _ProductionBatchCode=item.ProductionBatchCode==null?'':item.ProductionBatchCode;
                 var _PartSerialNumber=item.PartSerialNumber==null?'':item.PartSerialNumber;
                 var _TaskNumber=item.TaskNumber==null?'':item.TaskNumber;
                 var _PartMaterialCode=item.PartMaterialCode==null?'':item.PartMaterialCode;
                 var datax={SequenceNumber:_SequenceNumber,ProductionBatchCode:_ProductionBatchCode,PartSerialNumber:_PartSerialNumber,
                            TaskNumber:_TaskNumber,PartMaterialCode:_PartMaterialCode};
                 list.push(datax);
             });
             return list;
        }
        function doSearch(value){
            openlogin();
      }
   var editIndex = undefined;
      function endEditing(){
         if (editIndex == undefined){return true}
         if ($('#dg').datagrid('validateRow', editIndex)){
            $('#dg').datagrid('endEdit', editIndex);
            editIndex = undefined;
            return true;
         } else {
            return false;
         }
      }
      function onClickCell(index, field){
         if (editIndex != index){
            if (endEditing()){
               $('#dg').datagrid('selectRow', index)
                     .datagrid('beginEdit', index);
               var ed = $('#dg').datagrid('getEditor', {index:index,field:field});
               if (ed){
                  ($(ed.target).data('textbox') ? $(ed.target).textbox('textbox') : $(ed.target)).focus();
               }
               editIndex = index;
            } else {
               setTimeout(function(){
                  $('#dg').datagrid('selectRow', editIndex);
               },0);
            }
         }
      }
      function onEndEdit(index, row){
         var ed = $(this).datagrid('getEditor', {
            index: index,
            field: 'ProductionBatchCode'
         });
         row.ProductionBatchCode = $(ed.target).combobox('getText');
      }
      function append(){

         if (endEditing()){
            $('#dg').datagrid('appendRow',{status:'P'});
            editIndex = $('#dg').datagrid('getRows').length-1;
            $('#dg').datagrid('selectRow', editIndex)
                  .datagrid('beginEdit', editIndex);
         }
      }
      function removeit(){
         if (editIndex == undefined){return}
         $('#dg').datagrid('cancelEdit', editIndex)
               .datagrid('deleteRow', editIndex);
         editIndex = undefined;
      }
      function removeall(){

         $('#dg').datagrid('loadData',[]);
      }
      function accept(){
         if (endEditing()){
            $('#dg').datagrid('acceptChanges');
         }
      }
      function reject(){
         $('#dg').datagrid('rejectChanges');
         editIndex = undefined;
      }
      function getChanges(){
         var rows = $('#dg').datagrid('getChanges');
         alert(rows.length+' rows are changed!');
      }
    function openlogin(){

        $('#win').window('open');
    }
    function openmsg(){

        $('#win2').window('open');
    }
    (function($){
        function getParentMenu(rootMenu, menu){
            return findParent(rootMenu);
            function findParent(pmenu){
                var p = undefined;
                $(pmenu).find('.menu-item').each(function(){
                    if (!p && this.submenu){
                        if ($(this.submenu)[0] == $(menu)[0]){
                            p = pmenu;
                        } else {
                            p = findParent(this.submenu);
                        }
                    }
                });
                return p;
            }
        }
        $.extend($.fn.menubutton.methods, {
            enableNav: function(enabled){
                var curr;
                $(document).unbind('.menubutton');
                if (enabled == undefined){enabled = true;}
                if (enabled){
                    $(document).bind('keydown.menubutton', function(e){
                        var currButton = $(this).find('.m-btn-active,.m-btn-plain-active,.l-btn:focus');
                        if (!currButton.length){
                            return;
                        }
                        if (!curr || curr.button != currButton[0]){
                            curr = {
                                menu: currButton.data('menubutton') ? $(currButton.menubutton('options').menu) : $(),
                                button: currButton[0]
                            };
                        }
                        var item = curr.menu.find('.menu-active');
                        switch(e.keyCode){
                            case 13:  // enter
                                item.trigger('click');
                                break;
                            case 27:  // esc
                                currButton.trigger('mouseleave');
                                break;
                            case 38:  // up
                                var prev = !item.length ? curr.menu.find('.menu-item:last') : item.prevAll('.menu-item:first');
                                prev.trigger('mouseenter');
                                return false;
                            case 40:  // down
                                var next = !item.length ? curr.menu.find('.menu-item:first') : item.nextAll('.menu-item:first');
                                next.trigger('mouseenter');
                                return false;
                            case 37:  // left
                                var pmenu = getParentMenu(currButton.data('menubutton') ? $(currButton.menubutton('options').menu) : $(), curr.menu);
                                if (pmenu){
                                    curr.menu = pmenu;
                                    item.triggerHandler('mouseleave');
                                } else {
                                    var prev = currButton.prevAll('.l-btn:first');
                                    if (prev.length){
                                        currButton.trigger('mouseleave');
                                        prev.focus();
                                    }
                                }
                                return false;
                            case 39:  // right
                                if (item.length && item[0].submenu){
                                    curr.menu = $(item[0].submenu);
                                    curr.button = currButton[0];
                                    curr.menu.find('.menu-item:first').trigger('mouseenter');
                                } else {
                                    var next = currButton.nextAll('.l-btn:first');
                                    if (next.length){
                                        currButton.trigger('mouseleave');
                                        next.focus();
                                    }
                                }
                                return false;
                        }
                    });
                }
            }
        });
    })(jQuery);
    $(function(){
        $.fn.menubutton.methods.enableNav();
        $(document).keydown(function(e){
            if (e.altKey && e.keyCode == 87){
                $('#btn-home').focus();
            }
        })
    });
    //显示消息
    let timer;
    var inter=0;
    function clock() {
        if(inter<3) {
            $("#msginfo").css("visibility","visible");
            $("#msginfo").css("display","block");
            inter++;
        }else{
            endclock();
            $("#msginfo").css("visibility","hidden");
            $("#msginfo").css("display","none");
        }
    }
    function endclock() {
        clearInterval(timer);
    }
    function closewin() {
        $(".panel-tool-close").click();
    }
    function closewin2() {
        $(".panel-tool-close").click();
        var PartSets_ = getTable();
        var numcou=PartSets_.length;
        if(numcou==0){
           $('#PartSets').textbox('setValue', 'null');
        }else{
           $('#PartSets').textbox('setValue', 'data['+String(numcou)+']');
        }
    }
</script>
</body>
</html>
    前端网站至此创建完毕,我们继续配置android端后台。

二. 配置网络权限设置Layout布局
    
    AnddoirdManifest文件里必须开通网络权限。
<!-- 开启网络访问权限 -->
<uses-permission android:name="android.permission.INTERNET"></uses-permission> <!-- 允许访问网络状态的权限 -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <!-- 允许访问wifi状态的权限 -->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <!-- 允许修改网络状态的权限 -->
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"></uses-permission> <!-- 允许修改wifi状态的权限 -->
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
    在布局文件里修改手机UI布局。
 
    拖放webview,给他一个id,布局需要设置Margin还需要指定布局大小。
 
    我们做的是一个混合开发的APP,结合webview互操作前台与后台,原理与HbuilderX的nui和mui是一样的,也是现在开发的主流,网络api请求不指定平台,一般有idea和.net,soap+。前端其实一般前端制作工具编辑好设计好,再迁移到android studio,我用的是intellij idea,很方便测试。
编辑前端的时候我们再前端预留了2个js函数,方便android互操作。    前端按钮按下调用前端quest()。

        操作android原生后台函数android.showToast(参数)。

    ShowMsg是显示一个弹窗,当后台请求数据成功后,H5显示弹窗UI就没有违和感。

    当提交按钮提交时,后台请求webapi,返回消息,后台控制webview加载弹窗,提示一个消息。
 

 

三. 后台代码

    
    程序写三个类,MainActivity是主线程首先创建一个webapi请求的类requestApi,我们一直在纠结为什么要这么复杂使用后台,而不直接使用前台操作,js能一步到位。这个其实就是一个水很深的领域,是现存最大问题,前端有他的局限性,他会考虑跨域问题、内置浏览器端口限制问题,为了修复这个问题,需要配置浏览器还要配置API服务器支持浏览器,往往我们API来自不通领域,不仅仅是java开发的,浏览器访问需要考虑跨域问题,但是api是网络协议,不该有过多的限制,所以我们还是用后端做一些数据处理比较恰当。
package com.example.productlinetest;



import org.json.JSONException;
import org.json.JSONObject;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
public class requestApi {
    public String getSapData(String ptd) throws JSONException {
        URL wsUrl;
        int errCode=0;
        JSONObject resultJson=new JSONObject();
        String result="";
        try {
            wsUrl = new URL("http://xxx.xxx.xxx.xxx:6000/Mes/IssueTask?requestCommand=1");
            HttpURLConnection conn = (HttpURLConnection) wsUrl.openConnection();
            conn.setDoInput(true);
            conn.setDoOutput(true);
            conn.setRequestMethod("POST");
            conn.setRequestProperty("Content-Type", "application/json; charset=utf-8");
            conn.setConnectTimeout(50000);
            conn.setReadTimeout(50000);
            OutputStream os = conn.getOutputStream();
            //请求体
            String soap = ptd.trim();
            os.write(soap.getBytes());
            InputStream is = conn.getInputStream();
            byte[] b = new byte[1024];
            int len = 0;
            String s = "";
            while((len = is.read(b)) != -1){
                String ss = new String(b,0,len,"UTF-8");
                s += ss+"\r\n";
            }
            result=s;
            is.close();
            os.close();
            conn.disconnect();
        } catch (MalformedURLException e) {
            // TODO Auto-generated catch block
            System.out.println(e.toString());
            errCode=1;
        } catch (IOException e) {
            // TODO Auto-generated catch block
            System.out.println(e.toString());
            errCode=2;
        }
        resultJson.put("errCode", errCode);
        resultJson.put("data", result);
        return resultJson.toString();
    }
}
    从上面就不难看出6000端口,那是Google限制端口,跟他内部冲突。
    主线程MainActivity添加代码。
package com.example.productlinetest;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity{
    public static Handler mHandler;
    public WebView webview;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //实例化webview
        webview=this.findViewById(R.id.webviewa);
        //设置WebView属性,能够执行Javascript脚本
        webview.getSettings().setJavaScriptEnabled(true);
        //添加与js的交互接口,起的名称与js代码中的接口名称要一致
        webview.addJavascriptInterface(new JavaScriptinterface(this), "android");
        // 使WebView的网页跳转在WebView中进行,而非跳到浏览器
        webview.setWebViewClient(new WebViewClient() {
            public boolean shouldOverrideUrlLoading(WebView view, String url) {
                view.loadUrl(url);
                return true;
            }
        });
        //加载页面
        try {
            //设置打开的页面地址
            webview.loadUrl("file:///android_asset/mhx.html");
        } catch(Exception ex) {
            ex.printStackTrace();
            Toast toast=Toast.makeText(this,"加载服务器失败",Toast.LENGTH_SHORT);
            toast.show();
        }
        //订阅静态传值对象
        mHandler = new Handler(){
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                //msg.what对应子线程中msg的标签,在子线程中进行赋值
                if(msg.what==1){
                    //操作js方法,显示消息
                    String datax=msg.obj.toString();
                    String[] datm=datax.split("》");
                    webview.loadUrl("javascript:ShowMsg('"+datm[1]+"','"+datm[0]+"');");
                }
            }
        };
    }
}
    从上面代码来看,我们给webview注入了一个接口类变量。

 

    给主窗口写了一个传值跨线程对象。

 

     他是个静态对象,这里只是为了图方便,当然不建议用这种静态方法。
 

 

     JavaScriptinterface这个类继承自主线程MainAcgtivity要调用静态handler传值。内部要写一个@JavascriptInterface需要接收前端传值。
package com.example.productlinetest;
import android.content.Context;
import android.os.Message;
import android.webkit.JavascriptInterface;
import org.json.JSONException;
public class JavaScriptinterface extends MainActivity{
    Context context;
    public JavaScriptinterface(Context contextpara) {
        context= contextpara;
    }
    @JavascriptInterface
    public void showToast(String ssss) {
        requestApi req=new requestApi();
        try {
            String str=req.getSapData(ssss);
            runOnUiThread(() -> {
                Message msg = new Message();
                msg.what = 1;
                msg.obj="接口调用成功》"+str;
                mHandler.sendMessage(msg);
            });
        } catch (JSONException e) {
            runOnUiThread(() -> {
                Message msg = new Message();
                msg.what = 1;
                msg.obj="接口请求异常:》erro unlinked";
                mHandler.sendMessage(msg);
            });
        }
    }
}
    @JavascriptInterface是不能互操作后端的,需要写一个线程单独去刷新。    
    Android操作js也是要通过webview的。

        webview是主线程控件,子线程访问需要刷新handler。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值