Browse Source

调整蓝牙设备链接逻辑

master
白凤吉 4 months ago
parent
commit
7d1b9b074b
  1. 1
      app/src/main/AndroidManifest.xml
  2. 10
      app/src/main/assets/web/asset-manifest.json
  3. 2
      app/src/main/assets/web/index.html
  4. 2
      app/src/main/assets/web/index2.html
  5. 3
      app/src/main/assets/web/static/css/main.3543332f.css
  6. 3
      app/src/main/assets/web/static/css/main.5b4e8656.css
  7. 2
      app/src/main/assets/web/static/js/main.19719279.js
  8. 0
      app/src/main/assets/web/static/js/main.19719279.js.LICENSE.txt
  9. 2
      app/src/main/assets/web/static/js/main.7d3e34ad.js
  10. 1
      app/src/main/assets/web/static/media/icon_tab2_s.d4ac46d0ffaffb862d28f1c88e5c9f01.svg
  11. 1
      app/src/main/assets/web/static/media/icon_tab2_u.93c20b90699910b5c5acebf5521a1ccc.svg
  12. 39
      app/src/main/java/com/iflytop/profilometer/MainActivity.java
  13. 10
      app/src/main/java/com/iflytop/profilometer/api/ble/BleApi.java
  14. 18
      app/src/main/java/com/iflytop/profilometer/core/bluetooth/BleManager.java
  15. 2
      app/src/main/java/com/iflytop/profilometer/server/HttpServer.kt
  16. 2
      app/src/main/res/values/strings.xml

1
app/src/main/AndroidManifest.xml

@ -24,6 +24,7 @@
tools:targetApi="31">
<activity
android:name=".MainActivity"
android:hardwareAccelerated="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

10
app/src/main/assets/web/asset-manifest.json

@ -1,12 +1,10 @@
{
"files": {
"main.css": "./static/css/main.5b4e8656.css",
"main.js": "./static/js/main.7d3e34ad.js",
"main.css": "./static/css/main.3543332f.css",
"main.js": "./static/js/main.19719279.js",
"static/js/206.d71bd05f.chunk.js": "./static/js/206.d71bd05f.chunk.js",
"static/media/icon_tab3_u.svg": "./static/media/icon_tab3_u.6d18cbd7c4dc6a54f745fdfcc7716050.svg",
"static/media/icon_tab3_s.svg": "./static/media/icon_tab3_s.b0a9cbf5ecee59829c9de63a2e9de169.svg",
"static/media/icon_tab2_s.svg": "./static/media/icon_tab2_s.d4ac46d0ffaffb862d28f1c88e5c9f01.svg",
"static/media/icon_tab2_u.svg": "./static/media/icon_tab2_u.93c20b90699910b5c5acebf5521a1ccc.svg",
"static/media/icon_tab1_u.svg": "./static/media/icon_tab1_u.242e54b7c6bc6d5751e513a1371fb444.svg",
"static/media/icon_tab1_s.svg": "./static/media/icon_tab1_s.51c4a29ff60d8149b73a6da870a0dc9d.svg",
"index.html": "./index.html",
@ -23,7 +21,7 @@
"static/media/icon_check_s_u.svg": "./static/media/icon_check_s_u.2c5e20bec088338dc1cb2161b5cba37d.svg"
},
"entrypoints": [
"static/css/main.5b4e8656.css",
"static/js/main.7d3e34ad.js"
"static/css/main.3543332f.css",
"static/js/main.19719279.js"
]
}

2
app/src/main/assets/web/index.html

@ -1 +1 @@
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="./favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=no"/><title>廓形仪</title><script defer="defer" src="./static/js/main.7d3e34ad.js"></script><link href="./static/css/main.5b4e8656.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div><script>function setupWebViewJavascriptBridge(e){if(window.WebViewJavascriptBridge)return e(WebViewJavascriptBridge);if(/android/i.test(navigator.userAgent))document.addEventListener("WebViewJavascriptBridgeReady",(function(){e(WebViewJavascriptBridge)}),!1);else{if(window.WVJBCallbacks)return window.WVJBCallbacks.push(e);window.WVJBCallbacks=[e];var i=document.createElement("iframe");i.style.display="none",i.src="https://__bridge_loaded__",document.documentElement.appendChild(i),setTimeout((function(){document.documentElement.removeChild(i)}),0)}}setupWebViewJavascriptBridge((function(e){window.bridge=e}));var SyncBridgeJS={call:function(e,i){return prompt("sync/syncBridge/"+e,i)}}</script></body></html>
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="./favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=no"/><title>廓形仪</title><script defer="defer" src="./static/js/main.19719279.js"></script><link href="./static/css/main.3543332f.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div><script>function setupWebViewJavascriptBridge(e){if(window.WebViewJavascriptBridge)return e(WebViewJavascriptBridge);if(/android/i.test(navigator.userAgent))document.addEventListener("WebViewJavascriptBridgeReady",(function(){e(WebViewJavascriptBridge)}),!1);else{if(window.WVJBCallbacks)return window.WVJBCallbacks.push(e);window.WVJBCallbacks=[e];var i=document.createElement("iframe");i.style.display="none",i.src="https://__bridge_loaded__",document.documentElement.appendChild(i),setTimeout((function(){document.documentElement.removeChild(i)}),0)}}setupWebViewJavascriptBridge((function(e){window.bridge=e}));var SyncBridgeJS={call:function(e,i){return prompt("sync/syncBridge/"+e,i)}}</script></body></html>

2
app/src/main/assets/web/index2.html

@ -37,7 +37,7 @@
<script>
// 连接到 WebSocket 服务
var ws = new WebSocket("ws://192.168.1.100:8080/ws");
var ws = new WebSocket("ws://127.0.0.1:8080/ws");
ws.onopen = function() {
document.getElementById("wsStatus").innerText = "WebSocket 状态:已连接";

3
app/src/main/assets/web/static/css/main.3543332f.css
File diff suppressed because it is too large
View File

3
app/src/main/assets/web/static/css/main.5b4e8656.css
File diff suppressed because it is too large
View File

2
app/src/main/assets/web/static/js/main.19719279.js
File diff suppressed because it is too large
View File

0
app/src/main/assets/web/static/js/main.7d3e34ad.js.LICENSE.txt → app/src/main/assets/web/static/js/main.19719279.js.LICENSE.txt

2
app/src/main/assets/web/static/js/main.7d3e34ad.js
File diff suppressed because it is too large
View File

1
app/src/main/assets/web/static/media/icon_tab2_s.d4ac46d0ffaffb862d28f1c88e5c9f01.svg

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="none" version="1.1" width="24" height="24" viewBox="0 0 24 24"><defs><clipPath id="master_svg0_2_378"><rect x="0" y="0" width="24" height="24" rx="0"/></clipPath></defs><g clip-path="url(#master_svg0_2_378)"><g><path d="M22.5362,14.4688L20.755,13.1188C20.7738,12.9313,20.7925,12.725,20.7925,12.5C20.7925,12.275,20.7738,12.0688,20.755,11.88125L22.5362,10.53125C23.0238,10.15625,23.155,9.5,22.8363,8.9375L20.8487,5.58125C20.6238,5.1875,20.1925,4.94375,19.7425,4.94375C19.5925,4.94375,19.4613,4.9625,19.3112,5.01875L17.192500000000003,5.84375C16.836199999999998,5.6,16.461199999999998,5.39375,16.086199999999998,5.225L15.7675,3.06875C15.6737,2.45,15.1487,2,14.5113,2L10.49875,2C9.86125,2,9.33625,2.45,9.2425,3.05L8.942499999999999,5.225C8.567499999999999,5.39375,8.21125,5.6,7.83625,5.84375L5.717499999999999,5.01875C5.5675,4.9625,5.4175,4.94375,5.2675,4.94375C4.8175,4.94375,4.38625,5.16875,4.18,5.5625L2.17375,8.9375C1.855,9.4625,1.9862498,10.15625,2.47375,10.53125L4.255,11.88125C4.23625,12.1063,4.217499999999999,12.3125,4.217499999999999,12.5C4.217499999999999,12.6875,4.217499999999999,12.8937,4.255,13.1188L2.47375,14.4688C1.9862499,14.8438,1.855,15.5,2.17375,16.0625L4.16125,19.4188C4.38625,19.8125,4.8175,20.0563,5.2675,20.0563C5.4175,20.0563,5.54875,20.0375,5.69875,19.9813L7.8175,19.1562C8.17375,19.4,8.54875,19.6063,8.92375,19.775L9.2425,21.9313C9.317499999999999,22.5312,9.86125,23,10.49875,23L14.5112,23C15.1487,23,15.6737,22.55,15.7675,21.95L16.086199999999998,19.775C16.461199999999998,19.6063,16.817500000000003,19.4,17.192500000000003,19.1562L19.3112,19.9813C19.4613,20.0375,19.6112,20.0563,19.7612,20.0563C20.2113,20.0563,20.6425,19.8313,20.8487,19.4375L22.855,16.043799999999997C23.155,15.5,23.0238,14.8438,22.5362,14.4688ZM17.005000000000003,12.5C17.005000000000003,14.975,14.98,17,12.505,17C10.03,17,8.004999999999999,14.975,8.004999999999999,12.5C8.004999999999999,10.025,10.03,8,12.505,8C14.98,8,17.005000000000003,10.025,17.005000000000003,12.5Z" fill="#3165D2" fill-opacity="1" style="mix-blend-mode:passthrough"/></g></g></svg>

1
app/src/main/assets/web/static/media/icon_tab2_u.93c20b90699910b5c5acebf5521a1ccc.svg

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="none" version="1.1" width="24" height="24" viewBox="0 0 24 24"><defs><clipPath id="master_svg0_2_909"><rect x="0" y="0" width="24" height="24" rx="0"/></clipPath></defs><g clip-path="url(#master_svg0_2_909)"><g><path d="M22.5362,14.4688L20.755,13.1188C20.7738,12.9313,20.7925,12.725,20.7925,12.5C20.7925,12.275,20.7738,12.0688,20.755,11.88125L22.5362,10.53125C23.0238,10.15625,23.155,9.5,22.8363,8.9375L20.8487,5.58125C20.6238,5.1875,20.1925,4.94375,19.7425,4.94375C19.5925,4.94375,19.4613,4.9625,19.3112,5.01875L17.192500000000003,5.84375C16.836199999999998,5.6,16.461199999999998,5.39375,16.086199999999998,5.225L15.7675,3.06875C15.6737,2.45,15.1487,2,14.5113,2L10.49875,2C9.86125,2,9.33625,2.45,9.2425,3.05L8.942499999999999,5.225C8.567499999999999,5.39375,8.21125,5.6,7.83625,5.84375L5.717499999999999,5.01875C5.5675,4.9625,5.4175,4.94375,5.2675,4.94375C4.8175,4.94375,4.38625,5.16875,4.18,5.5625L2.17375,8.9375C1.855,9.4625,1.9862498,10.15625,2.47375,10.53125L4.255,11.88125C4.23625,12.1063,4.217499999999999,12.3125,4.217499999999999,12.5C4.217499999999999,12.6875,4.217499999999999,12.8937,4.255,13.1188L2.47375,14.4688C1.9862499,14.8438,1.855,15.5,2.17375,16.0625L4.16125,19.4188C4.38625,19.8125,4.8175,20.0563,5.2675,20.0563C5.4175,20.0563,5.54875,20.0375,5.69875,19.9813L7.8175,19.1562C8.17375,19.4,8.54875,19.6063,8.92375,19.775L9.2425,21.9313C9.317499999999999,22.5312,9.86125,23,10.49875,23L14.5112,23C15.1487,23,15.6737,22.55,15.7675,21.95L16.086199999999998,19.775C16.461199999999998,19.6063,16.817500000000003,19.4,17.192500000000003,19.1562L19.3112,19.9813C19.4613,20.0375,19.6112,20.0563,19.7612,20.0563C20.2113,20.0563,20.6425,19.8313,20.8487,19.4375L22.855,16.043799999999997C23.155,15.5,23.0238,14.8438,22.5362,14.4688ZM17.005000000000003,12.5C17.005000000000003,14.975,14.98,17,12.505,17C10.03,17,8.004999999999999,14.975,8.004999999999999,12.5C8.004999999999999,10.025,10.03,8,12.505,8C14.98,8,17.005000000000003,10.025,17.005000000000003,12.5Z" fill="#666666" fill-opacity="1" style="mix-blend-mode:passthrough"/></g></g></svg>

39
app/src/main/java/com/iflytop/profilometer/MainActivity.java

@ -1,13 +1,19 @@
package com.iflytop.profilometer;
import android.Manifest;
import android.annotation.SuppressLint;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.view.WindowManager;
import android.webkit.WebResourceRequest;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import androidx.activity.EdgeToEdge;
import androidx.activity.OnBackPressedCallback;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.ContextCompat;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
@ -17,6 +23,7 @@ import com.iflytop.profilometer.server.HttpServer;
public class MainActivity extends AppCompatActivity {
private BleManager bleManager;
private WebView webView;
@SuppressLint({"SetJavaScriptEnabled", "MissingInflatedId"})
@Override
@ -36,14 +43,32 @@ public class MainActivity extends AppCompatActivity {
HttpServer.start(this, 8080);
// 初始化 WebView 并加载内嵌服务器提供的页面
WebView webView = findViewById(R.id.webView);
webView = findViewById(R.id.webView);
WebView.setWebContentsDebuggingEnabled(true);
webView.getSettings().setJavaScriptEnabled(true);
webView.getSettings().setDomStorageEnabled(true);
webView.getSettings().setUseWideViewPort(true);
webView.getSettings().setMediaPlaybackRequiresUserGesture(false);
// webView.loadUrl("http://127.0.0.1:8080/");
webView.loadUrl("http://192.168.1.112:3000/");
webView.loadUrl("http://127.0.0.1:8080/");
// webView.loadUrl("http://192.168.1.112:3000/");
OnBackPressedCallback callback = new OnBackPressedCallback(true) {//拦截后退
@Override
public void handleOnBackPressed() {
if (webView.canGoBack()) {
webView.goBack();
}
}
};
getOnBackPressedDispatcher().addCallback(this, callback);
webView.setWebViewClient(new WebViewClient() {//禁止启用系统浏览器
@Override
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
view.loadUrl(request.getUrl().toString());
return true;
}
});
bleManager = BleManager.getInstance(this);
// 针对 Android 12 及以上版本请求必要的运行时权限
@ -56,10 +81,18 @@ public class MainActivity extends AppCompatActivity {
}
@Override
protected void onPause() {
super.onPause();
// 停止扫描BLE设备节省资源
bleManager.stopScan();
}
@Override
protected void onDestroy() {
super.onDestroy();
// Activity 销毁时停止服务器
HttpServer.stop();
bleManager.stopScan();
}
}

10
app/src/main/java/com/iflytop/profilometer/api/ble/BleApi.java

@ -1,10 +1,10 @@
package com.iflytop.profilometer.api.ble;
import android.bluetooth.BluetoothGatt;
import android.content.Context;
import android.util.Log;
import com.iflytop.profilometer.api.ws.BleWebsocketManager;
import com.iflytop.profilometer.api.ws.DeviceStateWebsocketManager;
import com.iflytop.profilometer.common.result.Result;
import com.iflytop.profilometer.core.bluetooth.BleManager;
import com.iflytop.profilometer.core.bluetooth.BlePingManager;
@ -25,7 +25,10 @@ public class BleApi {
*/
public String start() {
try {
BleManager.getInstance().startScan();
BluetoothGatt bluetoothGatt = BleManager.getInstance().getBluetoothGatt();
if (bluetoothGatt == null) {
BleManager.getInstance().startScan();
}
BleWebsocketManager.getInstance().startWsPush();
return Result.success();
} catch (Exception e) {
@ -39,7 +42,6 @@ public class BleApi {
*/
public String stop() {
try {
BleManager.getInstance().stopScan();
BleWebsocketManager.getInstance().stopWsPush();
return Result.success();
} catch (Exception e) {
@ -53,6 +55,7 @@ public class BleApi {
*/
public String connect(String mac) {
try {
BleManager.getInstance().stopScan();//连接后停止扫描
BleManager.getInstance().connectToDevice(mac);
BlePingManager.getInstance().startPing();
return Result.success();
@ -67,6 +70,7 @@ public class BleApi {
*/
public String disconnect() {
try {
BleManager.getInstance().startScan();//断开连接后开始扫描
BleManager.getInstance().disconnect();
return Result.success();
} catch (Exception e) {

18
app/src/main/java/com/iflytop/profilometer/core/bluetooth/BleManager.java

@ -62,16 +62,16 @@ public class BleManager {
private final Context context;
//通信部分请根据你的设备替换下列 UUID
public static final UUID SERVICE_UUID = UUID.fromString("6e400001-b5a3-f393-e0a9-e50e24dcca9e");
public static final UUID WRITE_CHARACTERISTIC_UUID = UUID.fromString("6e400002-b5a3-f393-e0a9-e50e24dcca9e");
public static final UUID NOTIFY_CHARACTERISTIC_UUID = UUID.fromString("6e400003-b5a3-f393-e0a9-e50e24dcca9e");
public static final UUID SERVICE_UUID = UUID.fromString("6E8F0001-B5A3-F393-E0A9-E50E24DCCA9E");
public static final UUID WRITE_CHARACTERISTIC_UUID = UUID.fromString("6E8F0002-B5A3-F393-E0A9-E50E24DCCA9E");
public static final UUID NOTIFY_CHARACTERISTIC_UUID = UUID.fromString("6E8F0003-B5A3-F393-E0A9-E50E24DCCA9E");
public static final UUID CLIENT_CHARACTERISTIC_CONFIG_UUID = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb");
//扫描时设备实时性管理
// 超时阈值20秒内未更新则认为设备已消失
private static final long DEVICE_TIMEOUT = 20000;
// 清理间隔5秒执行一次清理任务
private static final long CLEANUP_INTERVAL = 5000;
private static final long DEVICE_TIMEOUT = 10000;
// 清理间隔2秒执行一次清理任务
private static final long CLEANUP_INTERVAL = 2000;
private final Handler cleanupHandler = new Handler(Looper.getMainLooper());
// 记录设备最后出现时间
private final Map<BluetoothDevice, Long> deviceLastSeenMap = new HashMap<>();
@ -255,8 +255,14 @@ public class BleManager {
/**
* 检查指定权限是否已授予
* 针对 Android 12 以下BLUETOOTH_SCAN BLUETOOTH_CONNECT 权限直接返回 true
*/
private boolean hasPermission(String permission) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S &&
(Manifest.permission.BLUETOOTH_SCAN.equals(permission) ||
Manifest.permission.BLUETOOTH_CONNECT.equals(permission))) {
return true;
}
return ContextCompat.checkSelfPermission(context, permission) == PackageManager.PERMISSION_GRANTED;
}

2
app/src/main/java/com/iflytop/profilometer/server/HttpServer.kt

@ -33,7 +33,7 @@ import kotlinx.serialization.json.Json
object HttpServer {
private var server: ApplicationEngine? = null
private const val MAIN_INDEX = "web/index2.html"
private const val MAIN_INDEX = "web/index.html"
@JvmStatic
fun start(context: Context, port: Int = 8080) {

2
app/src/main/res/values/strings.xml

@ -1,3 +1,3 @@
<resources>
<string name="app_name">profilometer_android</string>
<string name="app_name">廓形仪</string>
</resources>
Loading…
Cancel
Save