WebApp網頁真機除錯工具-(Android)
待我年逾花甲,重新回到鄉下。
池裡養些魚蝦,坡上滿是山茶。
不見霧霾黃沙,只有朝陽晚霞。
牛羊伴著雞鴨,瓜田李下小麻。
孫兒承歡膝下,老伴陪與床榻。
縱是滿口假牙,卻也笑靨如花。
現在的移動端開發主要流行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端程式碼如下:
好了,整體比較簡單,這只是一個簡單的DEMO,但是也應該可以滿足網頁真機除錯的需求了,另外Android的介面相關優化如IP/Port等配置可以自行實現,DEMO列印了相關地址跳轉、以及連線錯誤和異常等資訊,如果需要列印輸出更多的功能資訊,大家可以自行優化。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; } }
最後怕很多小白不知道怎麼用,總結下使用方式:
第一步:把服務端程式AppServer跑起來;
第二步:把Android程式碼中的Socket地址改成你自己電腦的地址;要是覺得改來改去不方便,可以自己做一個Android端的IP/Port配置介面;
第三步:連線成功後,在後端控制檯輸入要除錯的URL地址敲上回車就可以了。服務端我用的是Eclipse,你可以用任意的IDE或者命令列只要你喜歡!!!
第四步:經過上述操作,在手機端就能實時顯示後端輸入的網頁了。
最後,再次說明這只是一個DEMO,純屬筆者無聊花了一小時寫的,要是用著不安逸可以自己修改完善,比如Socket重連啊這些。如果要求很高可以用WebSocket,程式碼會更加簡單,重連這些也都有實現。
完整附件地址:請點我。
相關推薦
WebApp網頁真機除錯工具-(Android)
待我年逾花甲,重新回到鄉下。 池裡養些魚蝦,坡上滿是山茶。 不見霧霾黃沙,只有朝陽晚霞。 牛羊伴著雞鴨,瓜田李下小麻。 孫兒承歡膝下,老伴陪與床榻。 縱是滿口假牙,卻也笑靨如花。 現在的移動端開發主要流行Hybrid開發方式,市面上也很多框架提供了前端訪問手機硬體相關的AP
微信網頁真機除錯
手機通過USB除錯連線PC,PC 的 Chrome 遠端除錯手機上的微信web 流程就幾步,網上都有 1、手機開啟開發者模式,開啟USB除錯。 2、USB用途設定為【僅限充電】 (可以測試,開啟除錯工具後。只要一切換到別的USB用途,馬上丟失連線)。 3、除錯微信裡開啟 debugx5.
網頁真機除錯之Browsersync簡介
以前的除錯方式 修改完專案檔案(html、js、css等)後儲存,在瀏覽器重新整理頁面檢視修改後的效果 本地開啟一個 tomcat 服務,修改檔案後儲存重新整理頁面,移動端或其他 pc 則需要輸入 ip + 檔案路徑進行除錯 傳統除錯頁面的缺點是每次修改完程式碼,需要在相關裝置上 F5 重新
windbg 雙機除錯配置(xp)系統
進入虛擬機器C盤 修改boot.ini檔案屬性,然後 開啟boot.ini檔案,複製一下內容到boot.ini檔案 [boot loader] timeout=5 default=multi(0)disk(0)rdisk(0)partition(1)\WINDOWS [operating syst
關於SQLite的免費視覺化工具(Android)
SQLiteStudio (推薦)開源 免費 單檔案 http://sqlitestudio.one.pl/更新及時,功能完善的sqlite2和sqlite3工具,檢視編碼支援utf8。支援匯出資料格式:csv、html、plain、sql、xml,可同時開啟多個數據庫檔案
Android新手入門2016(3)--Android真機除錯
,引用必須註明出處! 軟體開發肯定是經常需要除錯的。前文已經說過,安卓虛擬機器是很慢的,因為CPU指令不同。所以最好,最省力的方法就是真機除錯。 需要的工具--Android手機。 先說明一些東西: 手機是網際網路公司必爭之地,在兲朝,幾乎所有的PC廠商,都想往手機裡面鑽。
cordova+vue Cordova的環境搭建(android),真機測試
nod arc jdk1.8 nload 安裝 acl archive 配置環境變量 install 一、安裝node.js 去官網下載node.js(官網地址:https://nodejs.org),按默認路徑安裝。 安裝完後在命令行輸入 $ npm //(測
Android Studio 連線真機除錯
寫這篇文章主要是記錄下自己在Android 學習過程中使用android studio 碰到的一些問題以及如何解決這些問題,下面我們切入話題,我以小米5為例來介紹下怎麼在Android Studio 連線真機除錯。 【步驟一】 首先主要是對手機上的一些設定如下 1.設定手
Unity Frame Debugger連線Android真機除錯
當用Profiler分析到不是程式碼導致的效能問題,當前場景最大的效能瓶頸時渲染時,或者自己寫的Shader要除錯時,都可以用Frame Debugger進行除錯。 按下列步驟設定打包,既可以用Profiler又可以用Frame Debugger連線Android真機: ① 手機開啟開發者模式和USB除錯
告別 USB,用 wifi 進行 Android 真機除錯
--------------------- 本文來自 wdeo3601 的CSDN 部落格 ,全文地址請點選:https://blog.csdn.net/captive_rainbow_/article/details/81012704?utm_source=copy 先看
移動端螢幕適配(通俗易懂理解viewport-真機除錯)
真機vivo x5pro 除錯,體驗 當設定元標籤時,彈出螢幕寬度是320(個人理解單位就是px) 因為這個標籤指定了理想視口寬度,為裝置出廠固定的裝置獨立畫素 解析度320(重點:它是固定的) 註釋掉 彈出螢幕寬度 是視口預設的980(個人理解單位就是px) css
使用真機除錯react-native步驟(安卓機)
1、開啟 USB 除錯 2、檢查你的裝置是否能正確連線到 ADB(Android Debug Bridge),使用adb devices命令 $ adb devices List of devices attached emulator-5554 offline
用真機除錯eclipse.java語言編寫的android程式
這裡用華為手機為例。 1、首先將你的手機用資料線連線電腦,並將USB除錯(開發者模式)開啟。 2、開啟eclipse-windows-show View-Others-Devices開啟,如圖: 3、這樣就把真機連線到eclipse了,右擊工程-Run as 如果你發現它
【開發工具】iOS真機除錯抓包工具Charles安裝及使用
支援原創,更多內容請關注: iOS開發過程中,經常需要用真機來測試和後臺的網路資料傳輸,需要一個趁手的抓包工具。在Windows下用的fidder很好用,但是由於它是在.Net框架之下的,所以在Mac下需要有一個替代品,就是Charles。 一、安裝 二、
android studio關於真機除錯DDMS中的data資料夾打不開的解決方法
由於做開發的時候想開啟檢視資料庫存放的內容,在eclipse中資料庫檔案預設就在/data/data/應用包名/databases/資料庫名,而用android studio開啟DDMS下面找時發現點
Android Studio真機除錯,vvivo手機安裝失敗
vivo手機真的很麻煩,首先要確定vivo賬號密碼,允許安裝後還一直失敗。記錄下解決方案 android studio中設定 把Enable Instant。。。的勾去掉 在工程目錄的gradle.p
Mac OS X 下開發 Android 程式時使用 USB 連真機除錯
本人很早一篇 Mac OS X 下開發 Android 程式時使用 WiFi ADB 連真機除錯,手機端需要連線 WiFi, Root 許可權開啟 ADB 埠,電腦上執行 adb connect 命令來讓 Mac 連線 Android 真機進行除錯,其實用不著那麼麻煩
藍芽真機除錯Android Wear App & 真機解除安裝除錯的App
可穿戴裝置啥啥的市場、展望、分析、豬和風口等等...啥啥的官話就不羅嗦了,改天再換XX角色噴噴,今天記錄一個技術貼備份。 一、環境 作業系統:Mac OS X 10.10.1 開發環境:Android Studio 1.0.2 (Mac版) 手錶裝置:Moto 360 手
android studio 第一個真機除錯
android 開發需要使用的模擬器來測試一下應用程式的正確性,通常做法是使用模擬器,但是模擬器這個東西,太吃資源了,並且卡的太厲害了,如果有條件的話,可以使用真機來模擬測試,晚上花了點時間,用真機測試了下,遇到一些問題,記錄下來,有需要的朋友參考一下, 第一個步驟:找
如何解決android studio :nothing to show 真機除錯找不到裝置 的問題
情況是這樣的:前幾分鐘還在手機執行的程式,做了簡單的介面修改,沒有改配置檔案點選run的時候就找不到外接裝置跟模擬器了。出現nothing to show 百度了一下。得到的答案是* noting to show 沒什麼可秀的???*【黑人問號臉】。 然