WebApp网页真机调试工具-(Android)
来源:互联网 发布:od矩阵的作用 编辑:程序博客网 时间:2024/06/05 05:03
待我年逾花甲,重新回到乡下。
池里养些鱼虾,坡上满是山茶。
不见雾霾黄沙,只有朝阳晚霞。
牛羊伴着鸡鸭,瓜田李下小麻。
孙儿承欢膝下,老伴陪与床榻。
纵是满口假牙,却也笑靥如花。
现在的移动端开发主要流行Hybrid开发方式,市面上也很多框架提供了前端访问手机硬件相关的API,但是总有不能满足的时候,所以,我们就自己做一个框架来封装提供给js的各种接口(框架不是本文重点),那么问题就来了,如何调试呢?前期开发可以通过打桩的方式来模拟,但是要发布上线必须要真枪实弹的调试通过才行。于是就输出了一个调试网页的DEMO(android/ios app),只能是通过手动输入网页地址来查看界面效果和测试接口的正确性,虽然团队没得微信那么强大开发一个桌面调试工具,但这体验和效率也确实太差了。确实不能忍,所以就写了个小玩意儿来解决这个问题。
思路:通过socket 长连接的的方式,在PC控制台输入调试的网页地址,就能立马在手机上看到网页的效果。
看看效果截图:
要实现这个小玩意儿,需要一个简单的后端程序,代码如下:
package com.lixue;import java.io.DataOutputStream;import java.io.IOException;import java.net.ServerSocket;import java.net.Socket;import java.util.Scanner;/** * * @author lh * @date 2016/12/12 11:30 */public class AppServer {public static void main(String[] args) {new ServerThread().start();}}class ServerThread extends Thread {boolean flag = false;ServerSocket ss;public void run() {try {ss = new ServerSocket(9999);// 创建服务器,并开放9999端口System.out.println("Server Listening on 9999...");flag = true;} catch (Exception e) {e.printStackTrace();}Socket sc = null;DataOutputStream outputStream = null;Scanner scanner = null;while (flag) {try {// 监听服务器端口,一旦有数据发送过来,那么就将数据封装成socket对象// 如果没有数据发送过来,那么这时处于线程阻塞状态,不会向下继续执行sc = ss.accept();System.out.println(sc.getInetAddress() + " connect...");outputStream = new DataOutputStream(sc.getOutputStream());outputStream.writeUTF("connect successful");scanner = new Scanner(System.in);while (true) {String line = scanner.nextLine();System.out.println("你输入的是:" + line);outputStream.writeUTF(line);}} catch (Exception e) {e.printStackTrace();} finally {try {if (outputStream != null) {outputStream.close();}if (sc != null) {sc.close();}} catch (IOException e) {e.printStackTrace();}}}}}
Android端代码如下:
package com.lixue.debugwebapp;import android.os.Bundle;import android.os.Handler;import android.os.Message;import android.support.v7.app.AppCompatActivity;import android.text.method.ScrollingMovementMethod;import android.view.KeyEvent;import android.webkit.WebSettings;import android.webkit.WebView;import android.webkit.WebViewClient;import android.widget.TextView;import java.io.DataInputStream;import java.io.IOException;import java.net.Socket;/** * @author lh * @version 1.0.0 * @filename MainActivity * @description -------------------------------------------------------- * @date 2016/12/12 12:00 */public class MainActivity extends AppCompatActivity { public static final int CONNECT = 99; public static final int SUCCESS = 100; public static final int ERROR = 101; public static final String KEY_CONNECT = "connect"; public static final String KEY_SUCCESS = "success"; public static final String KEY_ERROR = "error"; public static final String ADDRESS = "192.168.191.1"; public static final int PORT = 9999; private TextView tv; private WebView webView; private StringBuilder sb = new StringBuilder(); private SocketThread socketThread = null; private Handler handler = new Handler() { @Override public void handleMessage(Message msg) { String str = null; switch (msg.what) { case CONNECT: str = msg.getData().getString(KEY_CONNECT); tv.append("\n" + str); scrollToBottom(); break; case SUCCESS: str = msg.getData().getString(KEY_SUCCESS); tv.append("\n" + str); scrollToBottom(); if(isUrl(str)) { webView.loadUrl(str); }else{ tv.append("\t\t\t不合法的url"); } break; case ERROR: str = msg.getData().getString(KEY_ERROR); tv.append("\n" + str); scrollToBottom(); break; } } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); init(); connect(); } @Override protected void onDestroy() { close(); super.onDestroy(); } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if(webView.canGoBack()){ webView.goBack(); }else{ finish(); } return true; } private void init() { tv = (TextView) this.findViewById(R.id.tv_url); tv.setMovementMethod(ScrollingMovementMethod.getInstance()); webView = (WebView) this.findViewById(R.id.wv); WebSettings webSettings = webView.getSettings(); webSettings.setJavaScriptEnabled(true); webView.setWebViewClient(new WebViewClient() { @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { webView.loadUrl(url); return true; } }); } private void connect() { if (socketThread == null) { socketThread = new SocketThread(ADDRESS, PORT, handler); socketThread.start(); tv.append("发起建立连接请求"); tv.append("\n" + ADDRESS + ":" + PORT); scrollToBottom(); } } private void close() { if (socketThread != null) { socketThread.closeThread(); socketThread = null; } } /** * TV滚动到底部 */ private void scrollToBottom() { int offset = tv.getLineCount() * tv.getLineHeight(); if (offset > tv.getHeight()) { tv.scrollTo(0, offset - tv.getHeight()); } } private class SocketThread extends Thread { private String address;//ip private int port;//port >1023 private Handler handler; private DataInputStream in; private Socket socket; private boolean flag = false; public SocketThread(String address, int port, Handler handler) { this.address = address; this.port = port; this.handler = handler; } @Override public void run() { try { socket = new Socket(address, port); in = new DataInputStream(socket.getInputStream()); String content = in.readUTF(); //连接成功发送消息 sendMessage(KEY_CONNECT, content, CONNECT); while (!flag) { content = in.readUTF(); //数据传输过程发送消息 sendMessage(KEY_SUCCESS, content, SUCCESS); } } catch (IOException e) { e.printStackTrace(); //发送异常消息 sendMessage(KEY_ERROR, e.getMessage(), ERROR); } finally { try { if (in != null) { in.close(); } if (socket != null) { socket.close(); } } catch (IOException e) { e.printStackTrace(); } } } public void sendMessage(String key, String value, int code) { Bundle bundle = new Bundle(); bundle.putString(key, value); Message message = handler.obtainMessage(); message.what = code; message.setData(bundle); handler.sendMessage(message); } public void closeThread() { flag = true; } } /** * 简单的判断一下是否是网址,严谨性可以自行完善 * @param str * @return */ public static boolean isUrl(String str) { boolean isUrl = false; if (str != null) { if (str.startsWith("http://") || str.startsWith("https://") || str.startsWith("ftp://")) { isUrl = true; } } return isUrl; }}好了,整体比较简单,这只是一个简单的DEMO,但是也应该可以满足网页真机调试的需求了,另外Android的界面相关优化如IP/Port等配置可以自行实现,DEMO打印了相关地址跳转、以及连接错误和异常等信息,如果需要打印输出更多的功能信息,大家可以自行优化。
最后怕很多小白不知道怎么用,总结下使用方式:
第一步:把服务端程序AppServer跑起来;
第二步:把Android代码中的Socket地址改成你自己电脑的地址;要是觉得改来改去不方便,可以自己做一个Android端的IP/Port配置界面;
第三步:连接成功后,在后端控制台输入要调试的URL地址敲上回车就可以了。服务端我用的是Eclipse,你可以用任意的IDE或者命令行只要你喜欢!!!
第四步:经过上述操作,在手机端就能实时显示后端输入的网页了。
最后,再次说明这只是一个DEMO,纯属笔者无聊花了一小时写的,要是用着不安逸可以自己修改完善,比如Socket重连啊这些。如果要求很高可以用WebSocket,代码会更加简单,重连这些也都有实现。
Android代码地址:https://github.com/allmyson/DebugWebApp
完整附件地址:请点我。
- WebApp网页真机调试工具-(Android)
- android webApp 调试问题解决
- Android真机调试
- Android真机调试
- Android 真机调试
- android 真机调试
- Android真机调试
- Android 真机调试
- Android 真机调试
- Android真机调试
- android真机调试
- android 真机调试
- 真机调试Android
- Android真机调试
- android 真机调试
- Android真机调试
- android真机调试
- Android真机调试
- android 的语言适配
- javascript 日期操作 最后一天获取
- 关于iOS开发常用代码整理
- 杂谈
- 【Visual Studio】 VS中添加头文件和lib库的方法
- WebApp网页真机调试工具-(Android)
- HDU1003 Max Sum(DP)
- AFNetworking post和get请求笔迹
- Solr配置IK分词器自定义词库
- UGUI学习笔记1
- 查询数据库的表的数目
- caffe-ssd 学习(1)File not found: data/VOC0712/labelmap_voc.prototxt
- Android之---Android Studio开发最NB(牛逼、权威)的教程
- jquery选择器大全