久久亚洲成a人片熟女精品色一区二区三区|国产精品视频第一精品视频|av天堂热无码手机版|亚洲?v无码久久无遮挡|国产精品偷伦视频免费观看国产|麻豆国产自产精品丰满熟妇|av无码av不卡一区二区|久久亚洲精品中文字

ARTICLE DETAIL

資訊詳情

深耕商務(wù)建站與企業(yè)官網(wǎng)運(yùn)營的一線實(shí)戰(zhàn)洞察。

Android藍(lán)牙開發(fā)源碼全解析:從掃描到連接的避坑實(shí)戰(zhàn)指南

Android藍(lán)牙開發(fā)源碼全解析:從掃描到連接的避坑實(shí)戰(zhàn)指南 簡介這是一份面向Android開發(fā)者的藍(lán)牙開發(fā)源碼工程包涵蓋藍(lán)牙適配器初始化、BLE設(shè)備掃描、Gatt連接及數(shù)據(jù)讀寫等核心流程適用于初學(xué)藍(lán)牙通信或需快速搭建設(shè)備互聯(lián)功能的開發(fā)者。壓縮包共23個(gè)文件包含Java源碼、AndroidManifest.xml、資源文件以及編譯生成的apk、dex、class等既可直接閱讀源碼也可運(yùn)行包內(nèi)APK驗(yàn)證效果整體僅91KB輕量便于下載。已有209人學(xué)習(xí)瀏覽這份工程包具有一定參考價(jià)值。通過分析源碼可掌握BluetoothManager與BluetoothAdapter的獲取方式、ScanCallback掃描回調(diào)處理、BluetoothGatt與BluetoothGattCallback的用法還能理解Android不同版本對掃描權(quán)限、掃描模式的要求從而減少實(shí)際開發(fā)中的兼容性問題。1. Android 藍(lán)牙開發(fā)源碼從能掃到設(shè)備到能順利交付的完整路徑搜“android 藍(lán)牙開發(fā)源碼”結(jié)果基本分兩種要么是幾年前的 Demo 工程要么是封裝得看不出調(diào)用邏輯的框架代碼。實(shí)際上 Android 藍(lán)牙開發(fā)屬于“看起來不難、跑起來全是細(xì)節(jié)”的模塊——權(quán)限、掃描、配對、連接、服務(wù)發(fā)現(xiàn)、數(shù)據(jù)收發(fā)每一環(huán)都可能因?yàn)樵O(shè)備兼容性翻車而且一旦翻車報(bào)錯(cuò)信息常常讓你摸不著頭腦。這篇文章不打算給你一份虛構(gòu)的全家桶源碼包而是把一條可復(fù)現(xiàn)的開發(fā)路徑拆開講透先搞懂選型再跑通最小工程接著調(diào)關(guān)鍵參數(shù)最后落在一份能用的避坑清單上。不管你是新接手藍(lán)牙功能還是已經(jīng)寫了兩天還卡在連接階段按這個(gè)順序走一遍對自己手上的源碼該看哪里、改哪里、為什么這么改會(huì)有清晰的方向感。2. 先選型再讀碼經(jīng)典藍(lán)牙與 BLE 的源碼結(jié)構(gòu)差異2.1 經(jīng)典藍(lán)牙與 BLE協(xié)議棧差異決定了代碼走向Android 的藍(lán)牙技術(shù)棧從 API 層面分兩條路線。經(jīng)典藍(lán)牙走 BluetoothSocket適合音頻、文件傳輸這類持續(xù)大流量場景低功耗藍(lán)牙BLE走 BluetoothGatt適合傳感器數(shù)據(jù)、遙控器、智能硬件這類小包低頻場景。兩者的源碼結(jié)構(gòu)差異很大經(jīng)典藍(lán)牙的核心是BluetoothDevice.createRfcommSocketToServiceRecord()BLE 的核心是BluetoothGattCallback里那一堆異步回調(diào)。選型選錯(cuò)了后面的代碼幾乎等于白寫。實(shí)際項(xiàng)目里“android 藍(lán)牙開發(fā)源碼”的需求大部分落在 BLE 上。原因無非三點(diǎn)功耗低、協(xié)議靈活、手機(jī)兼容性好。但如果你要接的是車載藍(lán)牙、藍(lán)牙音箱、老式藍(lán)牙串口模塊那就繞不開經(jīng)典藍(lán)牙的 Socket 路線。我的習(xí)慣是先問自己三個(gè)問題數(shù)據(jù)量多大傳輸頻率多高對端設(shè)備是什么數(shù)據(jù)量超過每秒幾十 KB、且要求穩(wěn)定流式傳輸就選經(jīng)典藍(lán)牙否則優(yōu)先 BLE。這個(gè)決定直接決定了你手上那份源碼的代碼組織方式。兩條路線在連接流程上的差異也要清楚這會(huì)影響你排查問題的方向。經(jīng)典藍(lán)牙需要先配對再創(chuàng)建 Socket連接后走輸入輸出流BLE 不需要配對直接連接 GATT 服務(wù)然后通過特征值Characteristic讀寫。配對失敗的報(bào)錯(cuò)在經(jīng)典藍(lán)牙里非常常見而 BLE 里根本沒有“配對”這個(gè)概念取而代之的是連接參數(shù)協(xié)商和 MTU 協(xié)商。如果你拿到的源碼是 BLE 的卻在翻“配對回調(diào)”說明你還沒把協(xié)議模型轉(zhuǎn)換過來。2.2 一份可用的藍(lán)牙源碼工程里該有哪些模塊拿到一套藍(lán)牙源碼不用急著逐行讀。先看它有沒有把功能拆成模塊。一個(gè)可維護(hù)的藍(lán)牙工程至少應(yīng)該包含初始化、掃描、連接、數(shù)據(jù)收發(fā)、服務(wù)解析、狀態(tài)回調(diào)這六個(gè)部分。我習(xí)慣把它們列成一張對照表來快速對號入座模塊職責(zé)關(guān)鍵類初始化檢查硬件、權(quán)限、藍(lán)牙開關(guān)狀態(tài)BluetoothAdapter, BluetoothManager掃描發(fā)現(xiàn)周邊設(shè)備區(qū)分經(jīng)典藍(lán)牙與 BLEBluetoothAdapter.startDiscovery / BluetoothLeScanner連接管理建立并維護(hù)連接持有連接狀態(tài)BluetoothSocket / BluetoothGatt數(shù)據(jù)收發(fā)收發(fā)數(shù)據(jù)處理粘包與分包InputStream / OutputStream / GattCallback服務(wù)解析解析 BLE 服務(wù)與特征值BluetoothGattService / BluetoothGattCharacteristic狀態(tài)回調(diào)向 UI 層通知連接狀態(tài)變化Handler / LiveData / 接口回調(diào)如果一份源碼里找不到獨(dú)立的掃描模塊多半是把掃描邏輯直接塞進(jìn)了 Activity這種結(jié)構(gòu)改起來成本很高設(shè)備一多就亂成一鍋粥。我更在意的其實(shí)不是它的包名是否華麗而是掃描、連接、收發(fā)這三件事有沒有解耦。三者獨(dú)立之后后面你想從經(jīng)典藍(lán)牙切到 BLE或者換一個(gè)對端設(shè)備型號改動(dòng)范圍能被限制在一個(gè)模塊內(nèi)。模塊劃分還有一個(gè)現(xiàn)實(shí)價(jià)值藍(lán)牙連接經(jīng)常是異步的回調(diào)滿天飛。如果所有邏輯都堆在 Activity 里配置變更旋轉(zhuǎn)屏幕時(shí)回調(diào)就會(huì)崩或泄漏。把連接和掃描放到 ViewModel 或獨(dú)立的單例管理器里持有 ApplicationContext是規(guī)避這類問題的常見且有效做法。2.3 拿到一份源碼后先看哪幾個(gè)文件按下面這個(gè)順序讀半小時(shí)內(nèi)基本能判斷一套源碼靠不靠譜。首先打開 AndroidManifest.xml看藍(lán)牙相關(guān)權(quán)限是否齊全是否適配了 Android 12API 31之后的運(yùn)行時(shí)權(quán)限拆分。很多老源碼在高版本設(shè)備上直接崩就是因?yàn)闆]適配 BLUETOOTH_SCAN 和 BLUETOOTH_CONNECT 的動(dòng)態(tài)申請。接著看藍(lán)牙適配器的初始化位置。最規(guī)范的寫法是通過 BluetoothManager 拿 BluetoothAdapter這樣能準(zhǔn)確拿到系統(tǒng)藍(lán)牙服務(wù)的狀態(tài)。如果源碼里直接用BluetoothAdapter.getDefaultAdapter()也不是不行但你在新設(shè)備上要留意這個(gè)接口是否被系統(tǒng)標(biāo)記為過時(shí)或受限。再看設(shè)備掃描的回調(diào)實(shí)現(xiàn)。經(jīng)典藍(lán)牙用的是 BroadcastReceiver 接收 ACTION_FOUNDBLE 用的是 ScanCallback。重點(diǎn)看回調(diào)里是按設(shè)備名做字符串匹配還是結(jié)合信號強(qiáng)度做過濾。直接拿設(shè)備名做模糊匹配的源碼在設(shè)備密集的環(huán)境里基本不能用。最后看連接的建立與斷開邏輯。經(jīng)典藍(lán)牙看 Socket 是否在子線程創(chuàng)建、是否有超時(shí)控制BLE 看 onConnectionStateChange 里的斷線處理是否完整。很多源碼只寫了連接成功和失敗沒有重連邏輯這種工程連上線都會(huì)斷交付時(shí)必被挑戰(zhàn)。3. 把藍(lán)牙源碼跑通最小工程與調(diào)用鏈拆解3.1 權(quán)限聲明與藍(lán)牙適配器初始化權(quán)限是第一道門檻也是翻車率最高的地方。Android 12API 31之后藍(lán)牙權(quán)限被拆成 BLUETOOTH_SCAN、BLUETOOTH_CONNECT、BLUETOOTH_ADVERTISE 三個(gè)運(yùn)行時(shí)權(quán)限而 Android 11 及以下用的是 BLUETOOTH 和 BLUETOOTH_ADMIN另外定位權(quán)限對 BLE 掃描結(jié)果有直接影響。下面這段 Manifest 聲明是我在新項(xiàng)目里一直沿用的兼容寫法!-- Android 12 -- uses-permission android:nameandroid.permission.BLUETOOTH_SCAN android:usesPermissionFlagsneverForLocation / uses-permission android:nameandroid.permission.BLUETOOTH_CONNECT / uses-permission android:nameandroid.permission.BLUETOOTH_ADVERTISE / !-- Android 11 及以下 -- uses-permission android:nameandroid.permission.BLUETOOTH android:maxSdkVersion30 / uses-permission android:nameandroid.permission.BLUETOOTH_ADMIN android:maxSdkVersion30 / uses-permission android:nameandroid.permission.ACCESS_FINE_LOCATION android:maxSdkVersion30 /usesPermissionFlagsneverForLocation表示不會(huì)用藍(lán)牙掃描結(jié)果做定位這在應(yīng)用市場審核時(shí)能降低權(quán)限敏感度。但如果你的應(yīng)用確實(shí)需要根據(jù)藍(lán)牙信號推算位置這句就不要加否則功能會(huì)受限。maxSdkVersion30的作用是讓舊權(quán)限只在 Android 11 及以下生效避免高版本系統(tǒng)重復(fù)請求舊權(quán)限。適配器初始化我推薦用 BluetoothManager 的方式代碼更穩(wěn)// BluetoothManager 方式獲取適配器兼容性更好 BluetoothManager manager (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE); BluetoothAdapter adapter manager.getAdapter(); if (adapter null) { // 設(shè)備不支持藍(lán)牙直接停止后續(xù)流程 return; } if (!adapter.isEnabled()) { // 先發(fā)系統(tǒng) Intent 請求用戶打開藍(lán)牙而不是強(qiáng)制 enable Intent enableBtIntent new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT); }manager.getAdapter()在系統(tǒng)藍(lán)牙服務(wù)異常重啟后能重新拿到有效實(shí)例而getDefaultAdapter()在某些定制 ROM 上會(huì)返回一個(gè)不可用的空殼對象。這里沒有直接用adapter.enable()是因?yàn)槟鞘欠瓷湎到y(tǒng)接口部分廠商 ROM 會(huì)攔截而且系統(tǒng)會(huì)彈權(quán)限確認(rèn)框不做用戶確認(rèn)直接開藍(lán)牙不符合交互規(guī)范。運(yùn)行時(shí)權(quán)限請求建議把三個(gè)藍(lán)牙權(quán)限和定位權(quán)限放在一次請求里完成用戶只需要做一次授權(quán)操作體驗(yàn)會(huì)好很多。注意Android 13 及以上即使動(dòng)態(tài)權(quán)限都給了系統(tǒng)設(shè)置里“附近設(shè)備”權(quán)限開關(guān)如果被用戶手動(dòng)關(guān)閉BLE 掃描仍然會(huì)靜默失敗。這個(gè)開關(guān)藏得很深遇到掃描不到設(shè)備時(shí)要去檢查。3.2 設(shè)備掃描回調(diào)、過濾與掃描周期BLE 掃描的推薦做法是用 BluetoothLeScanner掃描回調(diào)的觸發(fā)頻率可以很高必須做過濾和去重。下面是一個(gè)帶信號強(qiáng)度過濾的掃描實(shí)現(xiàn)能有效避免掃描列表被遠(yuǎn)處設(shè)備刷屏private MapString, BluetoothDevice deviceMap new HashMap(); private ListBluetoothDevice deviceList new ArrayList(); private ScanCallback scanCallback new ScanCallback() { Override public void onScanResult(int callbackType, ScanResult result) { BluetoothDevice device result.getDevice(); String name device.getName(); int rssi result.getRssi(); // 信號強(qiáng)度低于 -85dBm 的設(shè)備直接忽略減少列表干擾 if (rssi -85) { return; } // 按設(shè)備地址去重避免同一設(shè)備在回調(diào)中反復(fù)出現(xiàn) if (!deviceMap.containsKey(device.getAddress())) { deviceMap.put(device.getAddress(), device); deviceList.add(device); // 回到主線程更新 UI 列表 runOnUiThread(() - adapter.notifyItemInserted(deviceList.size() - 1)); } } }; private void startBleScan() { BluetoothLeScanner scanner BluetoothAdapter.getDefaultAdapter().getBluetoothLeScanner(); if (scanner null) { // 當(dāng)前設(shè)備不支持 BLE 掃描提示用戶換設(shè)備 return; } ScanFilter filter new ScanFilter.Builder() .setDeviceName(MyDevice) // 按廣播名精確過濾 .build(); ScanSettings settings new ScanSettings.Builder() .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY) // 高頻率掃描 .setReportDelay(0) // 實(shí)時(shí)上報(bào)不做批量延遲 .build(); scanner.startScan(filter, settings, scanCallback); }ScanFilter能按設(shè)備名或服務(wù) UUID 過濾能顯著減少回調(diào)次數(shù)。但按設(shè)備名過濾的前提是廣播名穩(wěn)定有些設(shè)備會(huì)在名稱后面加隨機(jī)后綴用setDeviceName就會(huì)漏掉。遇到這種對端我建議要么去掉過濾器要么按服務(wù) UUID 過濾。setScanMode有兩檔最常用LOW_LATENCY 延遲最低但耗電高適合用戶停留在掃描頁的場景LOW_POWER 適合后臺掃描但發(fā)現(xiàn)速度慢很多。setReportDelay(0)表示實(shí)時(shí)回調(diào)如果設(shè)成大于 0 的值系統(tǒng)會(huì)積攢一批結(jié)果一起返回這個(gè)對 UI 列表刷新并不友好。經(jīng)典藍(lán)牙掃描走的是startDiscovery加廣播接收器。需要注意的是startDiscovery是全局掃描會(huì)掃描所有經(jīng)典藍(lán)牙設(shè)備而且掃描期間會(huì)干擾已經(jīng)建立的藍(lán)牙連接在低端設(shè)備上尤其明顯。我的習(xí)慣是只在用戶主動(dòng)點(diǎn)擊“搜索”時(shí)啟動(dòng)掃描到目標(biāo)設(shè)備立刻cancelDiscovery()不要讓掃描在后臺持續(xù)運(yùn)行。3.3 建立連接與數(shù)據(jù)收發(fā)Socket 與 GATT 兩條路線經(jīng)典藍(lán)牙的連接必須在子線程里做connect()是阻塞調(diào)用而且沒有內(nèi)置超時(shí)。部分設(shè)備響應(yīng)慢連接可能拖十幾秒。下面這段代碼把連接放到單線程池并依賴外層做超時(shí)控制private void connectClassic(BluetoothDevice device) { ExecutorService executor Executors.newSingleThreadExecutor(); executor.execute(() - { try { // 創(chuàng)建 Socket使用 SPP 服務(wù) UUID經(jīng)典藍(lán)牙串口通用值 BluetoothSocket socket device.createRfcommSocketToServiceRecord( UUID.fromString(00001101-0000-1000-8000-00805F9B34FB)); // 連接前主動(dòng)取消掃描避免掃描干擾連接建立 bluetoothAdapter.cancelDiscovery(); // 阻塞調(diào)用建議用 Future.get(timeout) 包裝做超時(shí) socket.connect(); InputStream in socket.getInputStream(); OutputStream out socket.getOutputStream(); // 啟動(dòng)獨(dú)立讀線程持續(xù)讀取對端數(shù)據(jù) readLoop(in); } catch (IOException e) { // 連接失敗記錄日志并觸發(fā)重試或提示用戶 e.printStackTrace(); } }); }createRfcommSocketToServiceRecord的第一個(gè)參數(shù)是服務(wù) UUID。SPP 的通用 UUID 是00001101-0000-1000-8000-00805F9B34FB絕大多數(shù)藍(lán)牙串口設(shè)備都認(rèn)這個(gè)值。但如果你的對端是定制硬件就需要查閱設(shè)備文檔確認(rèn) UUID 是否不同。connect()成功后讀寫操作都在各自的線程里完成不能把讀線程和 UI 線程混在一起。BLE 的代碼風(fēng)格完全相反。Gatt 是異步的連接結(jié)果、服務(wù)發(fā)現(xiàn)結(jié)果、數(shù)據(jù)通知全部通過BluetoothGattCallback回調(diào)返回。下面是連接加訂閱通知的完整流程private BluetoothGatt gatt; private final BluetoothGattCallback gattCallback new BluetoothGattCallback() { Override public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { if (newState BluetoothProfile.STATE_CONNECTED) { // 連接成功開始發(fā)現(xiàn)服務(wù) gatt.discoverServices(); } else if (newState BluetoothProfile.STATE_DISCONNECTED) { // 連接斷開在這里做重連或通知上層 } } Override public void onServicesDiscovered(BluetoothGatt gatt, int status) { if (status ! BluetoothGatt.GATT_SUCCESS) { // 服務(wù)發(fā)現(xiàn)失敗關(guān)閉連接并重試 gatt.disconnect(); gatt.close(); return; } // 按協(xié)議文檔里的 UUID 查找服務(wù)和特征值 BluetoothGattService service gatt.getService(serviceUuid); if (service null) { return; } BluetoothGattCharacteristic characteristic service.getCharacteristic(charUuid); // 啟用通知讓設(shè)備可以主動(dòng)推送數(shù)據(jù) gatt.setCharacteristicNotification(characteristic, true); // 有些設(shè)備還必須寫描述符 CCCD 才能收到通知 BluetoothGattDescriptor descriptor characteristic.getDescriptor( UUID.fromString(00002902-0000-1000-8000-00805F9B34FB)); if (descriptor ! null) { descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE); gatt.writeDescriptor(descriptor); } } Override public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) { byte[] data characteristic.getValue(); // 對端設(shè)備推送的數(shù)據(jù)在這里處理不能做耗時(shí)操作 } }; private void connectBle(BluetoothDevice device) { // autoConnect 用 false主動(dòng)連接速度更快 gatt device.connectGatt(context, false, gattCallback); }connectGatt的autoConnect參數(shù)值得單獨(dú)說。false是主動(dòng)連接速度快適合用戶點(diǎn)擊連接按鈕的場景true是讓系統(tǒng)在后臺監(jiān)測到設(shè)備可用時(shí)自動(dòng)連接適合“靠近就自動(dòng)連”的場景但首次連接很慢部分設(shè)備固件還不支持。我?guī)缀跞胒alse然后自己做重連策略這樣時(shí)序是可控的。setCharacteristicNotification之后很多設(shè)備還必須寫描述符 0x2902CCCD否則數(shù)據(jù)不會(huì)推送上來。這是 BLE 開發(fā)里最容易漏掉的一步漏掉的表現(xiàn)就是連接正常、服務(wù)發(fā)現(xiàn)正常但onCharacteristicChanged永遠(yuǎn)不觸發(fā)。3.4 數(shù)據(jù)收發(fā)緩沖與線程模型藍(lán)牙數(shù)據(jù)沒有理想的包邊界。經(jīng)典藍(lán)牙的 InputStream 是字節(jié)流你不知道一幀數(shù)據(jù)在哪里結(jié)束BLE 的onCharacteristicChanged每次回調(diào)是一個(gè)特征值的數(shù)據(jù)包但如果特征值超過 MTU對端會(huì)把它拆成多個(gè)包依次推送。應(yīng)用層必須自己維護(hù)一個(gè)累積緩沖來做粘包和分包處理。常用的做法是維護(hù)一個(gè) ByteArrayOutputStream把每個(gè) chunk 寫入再按自定義的幀協(xié)議去判斷哪些是完整的包、哪些還差數(shù)據(jù)。幀協(xié)議一般就是包頭、長度、負(fù)載、校驗(yàn)這個(gè)套路。比如你規(guī)定幀以 0xAA 0x55 開頭以 0x0D 0x0A 結(jié)尾那應(yīng)用層的處理邏輯就是先把數(shù)據(jù)塞進(jìn) buffer然后循環(huán)檢查 buffer 里是否有完整的幀有就提取出來處理剩下的殘留在 buffer 里等下一個(gè) chunk 湊齊。沒有協(xié)議文檔的話可以抓一段對端的日志統(tǒng)計(jì)一組完整數(shù)據(jù)的長度和起止標(biāo)志用啟發(fā)式方式找邊界。這個(gè)過程是藍(lán)牙開發(fā)里最耗時(shí)、也最容易讓開發(fā)者產(chǎn)生“數(shù)據(jù)對不對得上”困惑的地方值得多投入時(shí)間驗(yàn)證。線程模型方面原則只有一條藍(lán)牙回調(diào)線程不碰 UI。經(jīng)典藍(lán)牙的讀線程在子線程BLE 的回調(diào)運(yùn)行在系統(tǒng) Binder 線程都不能直接更新界面。用 Handler 或 LiveData 把數(shù)據(jù)切到主線程。另外onCharacteristicChanged回調(diào)頻率可能很高如果在這里做耗時(shí)的業(yè)務(wù)處理會(huì)拖慢整個(gè)藍(lán)牙消息隊(duì)列導(dǎo)致后續(xù)數(shù)據(jù)包丟失這點(diǎn)在高頻推送場景下尤其要留心。4. 源碼改造時(shí)最容易翻車的配置項(xiàng)UUID、掃描周期與重連策略4.1 UUID 不一致連接失敗的第一大原因UUID 是藍(lán)牙開發(fā)里出問題最多的配置項(xiàng)。經(jīng)典藍(lán)牙里創(chuàng)建 Socket 用的 UUID 必須與對端設(shè)備監(jiān)聽的服務(wù) UUID 一致BLE 里GATT 服務(wù) UUID、特征值 UUID 必須與設(shè)備廣播的完全一致。UUID 是 128 位的十六進(jìn)制字符串形如00001101-0000-1000-8000-00805F9B34FB但不同設(shè)備文檔的寫法差別很大有的省略前導(dǎo)零有的把廠商自定義段放在中間一不留神就配錯(cuò)。我的經(jīng)驗(yàn)是拿到設(shè)備文檔后先把所有 UUID 整理到一個(gè)常量類里逐個(gè)對照格式補(bǔ)全成完整的 128 位字符串。BIG 需要注意的是大小寫不敏感但連字符位置必須正確有些框架層會(huì)做格式化但你自己手寫的字符串不一致就會(huì)失敗。另外一個(gè)常用手段是先用成熟的 BLE 調(diào)試工具連接設(shè)備查看它實(shí)際廣播的服務(wù)和特征值列表再和源碼里的常量逐個(gè)比對能快速定位寫錯(cuò)的位置。注意調(diào)試工具連過的設(shè)備會(huì)在系統(tǒng)層留下緩存同一臺設(shè)備在應(yīng)用里連接時(shí)可能被系統(tǒng)返回舊緩存遇到這種情況要把設(shè)備從系統(tǒng)藍(lán)牙設(shè)置里移除再測試。4.2 掃描周期與服務(wù)發(fā)現(xiàn)時(shí)序回調(diào)沒觸發(fā)時(shí)先看時(shí)序掃描周期的設(shè)置直接影響兩個(gè)體驗(yàn)設(shè)備出現(xiàn)速度和耗電。持續(xù)以 LOW_LATENCY 模式掃描手機(jī)發(fā)熱和耗電都會(huì)明顯上升尤其在掃描列表頁面長時(shí)間停留的場景。我一般把掃描拆成“掃描 6 秒、停 3 秒”的循環(huán)來平衡功耗和發(fā)現(xiàn)速度。注意停掃描時(shí)要傳入同一個(gè)scanCallback實(shí)例不要傳 null傳 null 是全局停止會(huì)把其他模塊發(fā)起的掃描也停掉。服務(wù)發(fā)現(xiàn)時(shí)序的問題也很典型。很多源碼在onConnectionStateChange里調(diào)用discoverServices()之后就立刻去getService()但onServicesDiscovered可能幾百毫秒后才回調(diào)。這時(shí)拿到的 service 是 null代碼就崩了或者靜默失敗。正確做法是在onServicesDiscovered回調(diào)里去獲取服務(wù)和特征值而不是在連接成功的回調(diào)里急著取。還有一類廠商設(shè)備的行為比較特殊連接成功后不會(huì)立刻響應(yīng)服務(wù)發(fā)現(xiàn)需要先往某個(gè)特征值寫一個(gè)喚醒命令然后等 200 毫秒左右再調(diào)discoverServices()才會(huì)正常完成服務(wù)枚舉。如果你發(fā)現(xiàn)設(shè)備用通用工具一切正常、自己的代碼卻卡在服務(wù)發(fā)現(xiàn)階段可以先試試延遲觸發(fā)discoverServices()這個(gè)經(jīng)驗(yàn)我在實(shí)際項(xiàng)目里驗(yàn)證過多次。4.3 重連策略與系統(tǒng)藍(lán)牙緩存斷線重連不是簡單重調(diào) connect很多人在連接斷開后直接調(diào)用之前的connectGatt或socket.connect()結(jié)果要么連不上要么連上后行為異常。這個(gè)問題多半落在系統(tǒng)藍(lán)牙緩存和資源未清理上。BLE 斷線重連的正確姿勢是private void reconnectBle(BluetoothDevice device) { if (gatt ! null) { // 先斷開再關(guān)閉釋放底層資源 gatt.disconnect(); gatt.close(); gatt null; } // 必須用新的 connectGatt 重新建立連接 gatt device.connectGatt(context, false, gattCallback); }gatt.disconnect()和gatt.close()的順序不能反。先斷開連接再釋放資源。如果跳過close()系統(tǒng)底層會(huì)保留一個(gè) GATT 客戶端實(shí)例下一次connectGatt很容易失敗或串線。這是 BLE 資源管理里最重要的一步。經(jīng)典藍(lán)牙的 Socket 也一樣一個(gè)BluetoothSocket對象成功connect()一次之后再斷開不能復(fù)用第二次。重連時(shí)必須重新createRfcommSocketToServiceRecord()創(chuàng)建新 Socket舊對象直接close()。如果代碼里復(fù)用了同一個(gè) Socket 對象第二次連接大概率拋異常或卡死。經(jīng)典藍(lán)牙的重連流程必須是“新建 Socket → 連接 → 使用 → 關(guān)閉 → 新建”沒有捷徑。系統(tǒng)藍(lán)牙緩存的另外一個(gè)表現(xiàn)是設(shè)備改了廣播名或服務(wù) UUID但手機(jī)掃到的還是舊的。這是系統(tǒng)級緩存應(yīng)用層控制不了只能引導(dǎo)用戶在系統(tǒng)藍(lán)牙設(shè)置里取消配對后重新掃描。你的代碼里能做的就是盡量保持設(shè)備端廣播的 UUID 和名稱穩(wěn)定從源頭減少緩存導(dǎo)致的幽靈數(shù)據(jù)問題。5. Android 藍(lán)牙開發(fā)避坑指南五條高頻踩坑記錄5.1 坑一權(quán)限聲明了但一啟動(dòng)就崩潰現(xiàn)象AndroidManifest.xml 里權(quán)限一個(gè)不少運(yùn)行在 Android 12 以上設(shè)備仍然崩潰日志報(bào) SecurityException 或 MissingPermission。原因targetSdkVersion 在 31 以上時(shí)BLUETOOTH_SCAN 和 BLUETOOTH_CONNECT 屬于運(yùn)行時(shí)權(quán)限必須在代碼里動(dòng)態(tài)申請。只寫在 Manifest 里等于沒寫。另一個(gè)隱蔽點(diǎn)部分廠商 ROM 在 targetSdkVersion 30 及以下也會(huì)強(qiáng)制要求動(dòng)態(tài)申請否則直接不給權(quán)限。解決在啟動(dòng)流程中先判斷 SDK 版本31 及以上請求三個(gè)藍(lán)牙權(quán)限30 及以下請求定位權(quán)限。用ActivityResultContracts.RequestMultiplePermissions統(tǒng)一管理授權(quán)結(jié)果。同時(shí)檢查系統(tǒng)設(shè)置里“附近設(shè)備”權(quán)限開關(guān)是否開啟這個(gè)開關(guān)與運(yùn)行時(shí)權(quán)限是獨(dú)立的用戶關(guān)掉后任何掃描和連接 API 都會(huì)靜默失敗。5.2 坑二掃描回調(diào)一直不觸發(fā)掃描列表永遠(yuǎn)為空現(xiàn)象代碼完全照著官方文檔寫但onScanResult一次都沒被調(diào)用?;蛘邟呙璧搅嗽O(shè)備但列表里只出現(xiàn)一兩個(gè)離得近的設(shè)備反而不出現(xiàn)。原因最常見的是系統(tǒng)“附近設(shè)備”權(quán)限被關(guān)閉掃描 API 被靜默攔截不報(bào)任何錯(cuò)誤。其次是 ScanFilter 配置過嚴(yán)比如setDeviceName拼錯(cuò)、服務(wù) UUID 和設(shè)備廣播不一致過濾后把目標(biāo)設(shè)備也濾掉了。還有一種情況是上一次stopScan沒正常執(zhí)行新的startScan不會(huì)有回調(diào)。解決先用最寬松的方式測試不傳任何 Filter直接scanner.startScan(callback)?;卣{(diào)能觸發(fā)就說明過濾條件有問題逐個(gè)把條件加回去排查?;卣{(diào)仍不觸發(fā)就去檢查系統(tǒng)權(quán)限和位置服務(wù)開關(guān)。另外 Android 13 以上定位服務(wù)開關(guān)關(guān)閉也會(huì)導(dǎo)致 BLE 掃描不到設(shè)備這個(gè)要準(zhǔn)備在文檔里寫清楚否則用戶會(huì)認(rèn)為軟件有問題。5.3 坑三BLE 連接成功后立刻斷連狀態(tài)碼是 133現(xiàn)象onConnectionStateChange先收到 STATE_CONNECTED不到一秒又收到 STATE_DISCONNECTEDstatus 值是 133GATT_ERROR。原因133 表示底層 GATT 連接出錯(cuò)。常見原因有上一次連接沒有close()舊實(shí)例還占著資源兩個(gè)應(yīng)用同時(shí)連接同一臺 BLE 設(shè)備設(shè)備端主動(dòng)斷開。還有一個(gè)容易被低估的原因是 MTU 協(xié)商不成功部分老固件不支持高 MTU超出范圍會(huì)直接斷開連接。解決先檢查代碼里是否在每次連接前都調(diào)用了close()處理舊連接。然后排除多應(yīng)用干擾把系統(tǒng)藍(lán)牙設(shè)置里所有配對設(shè)備取消關(guān)掉其他使用藍(lán)牙的應(yīng)用再測試。MTU 問題用gatt.requestMtu(247)時(shí)注意捕獲結(jié)果回調(diào)不要假設(shè)一定成功。如果設(shè)備固件不支持高 MTU應(yīng)用層仍要按 20 字節(jié)分包處理數(shù)據(jù)。5.4 坑四多設(shè)備并發(fā)連接時(shí)數(shù)據(jù)竄了現(xiàn)象同時(shí)連接多臺設(shè)備A 設(shè)備的數(shù)據(jù)跑到了 B 設(shè)備的回調(diào)里斷開 A 設(shè)備后 B 設(shè)備也跟著斷了。原因如果多個(gè)連接共用一個(gè)BluetoothGattCallback所有設(shè)備的回調(diào)都會(huì)進(jìn)同一個(gè)實(shí)例?;卣{(diào)方法里的gatt參數(shù)能區(qū)分設(shè)備但很多源碼直接忽略這個(gè)參數(shù)數(shù)據(jù)自然就竄了。還有更糟的情況多個(gè)連接共用一個(gè)BluetoothGatt實(shí)例系統(tǒng)會(huì)返回同一個(gè)已存在的對象設(shè)備之間互相干擾。解決每個(gè)設(shè)備使用獨(dú)立的BluetoothGatt實(shí)例回調(diào)里用gatt.getDevice().getAddress()區(qū)分設(shè)備維護(hù)一個(gè)MapdeviceAddress, BluetoothGatt。處理數(shù)據(jù)時(shí)始終攜帶設(shè)備地址上下文不要只把 byte[] 傳給上層。并發(fā)連接數(shù)也有限制手機(jī)硬件雖然支持多個(gè) BLE 連接但實(shí)際項(xiàng)目中連接超過三個(gè)就會(huì)出現(xiàn)不穩(wěn)定不要設(shè)計(jì)成大規(guī)模一對多并發(fā)。5.5 坑五設(shè)備端固件不支持 MTU 協(xié)商數(shù)據(jù)包被靜默吞掉現(xiàn)象連接一切正常服務(wù)發(fā)現(xiàn)也成功應(yīng)用寫入大塊數(shù)據(jù)也不報(bào)錯(cuò)但對端就是沒有響應(yīng)。日志里看不到任何異常似乎數(shù)據(jù)發(fā)出去就消失了。原因應(yīng)用主動(dòng)requestMtu(247)但設(shè)備固件協(xié)商失敗后靜默退回默認(rèn) MTU一般是 23 字節(jié)。應(yīng)用層還按照擴(kuò)展 MTU 一次性寫入了超過 20 字節(jié)的數(shù)據(jù)包底層把超長部分丟掉造成數(shù)據(jù)靜默丟失。解決在onMtuChanged回調(diào)里確認(rèn)協(xié)商結(jié)果拿到實(shí)際 MTU 值再根據(jù)實(shí)際值調(diào)整每次寫入的字節(jié)數(shù)。不需要強(qiáng)行追求大包應(yīng)用層可以按 20 字節(jié)分包寫入或者等 MTU 協(xié)商成功后再切大包模式。這個(gè)排查動(dòng)作我很早就應(yīng)該做結(jié)果在一個(gè)項(xiàng)目里耗了快一周最后靠協(xié)議日志才發(fā)現(xiàn)設(shè)備端拒絕了 MTU 協(xié)商。6. 強(qiáng)化你的調(diào)試習(xí)慣先抓藍(lán)牙協(xié)議日志再動(dòng)代碼調(diào)試藍(lán)牙源碼光靠 Logcat 里的應(yīng)用日志遠(yuǎn)遠(yuǎn)不夠。很多連接層的異常發(fā)生在系統(tǒng)協(xié)議棧內(nèi)部應(yīng)用層只能看到狀態(tài)的跳變看不到原因。這時(shí)候必須抓系統(tǒng)藍(lán)牙 HCI 日志。開啟方法是在開發(fā)者選項(xiàng)里打開“藍(lán)牙 HCI 信息收集日志”Bluetooth HCI snoop log復(fù)現(xiàn)問題后日志文件會(huì)記錄系統(tǒng)藍(lán)牙協(xié)議棧收發(fā)的所有 HCI 數(shù)據(jù)包。文件通常保存在/data/misc/bluetooth/logs/可以用 adb 導(dǎo)出然后用 Wireshark 的解析工具查看。日志里能看到完整的 ATT/GATT 數(shù)據(jù)包來回記錄比如某個(gè)特征值寫入是否被設(shè)備拒收、連接斷開前底層發(fā)生了什么事件。我的排查習(xí)慣是先看應(yīng)用日志確認(rèn)在哪個(gè)回調(diào)卡住再?zèng)Q定要不要抓 HCI 日志。比如連接斷開在 state133HCI 日志會(huì)顯示底層是否有 Link Loss 事件onCharacteristicChanged收不到數(shù)據(jù)HCI 日志能看出設(shè)備到底有沒有主動(dòng)發(fā) Notification——如果日志里根本沒有設(shè)備發(fā)來的包那問題在對端如果有包但應(yīng)用沒收到那問題在訂閱 Descriptor 或者 MTU 協(xié)商上。這種定位方式能避免“盲目改代碼然后反復(fù)試”的死循環(huán)。還有一個(gè)更省錢的前置手段在 Logcat 里過濾系統(tǒng)藍(lán)牙日志關(guān)鍵字包括 BluetoothGatt、bt_btif、bt_gatt。系統(tǒng)層很多關(guān)鍵狀態(tài)變化會(huì)打點(diǎn)在這里。配合 Debug.startMethodTracing可以查看藍(lán)牙回調(diào)線程上的耗時(shí)操作。把回調(diào)里的耗時(shí)控制在一毫秒以內(nèi)是避免背靠背數(shù)據(jù)包丟失的前提這在大量數(shù)據(jù)連續(xù)推送時(shí)尤其重要?;仡^再看我調(diào)試過的藍(lán)牙項(xiàng)目花時(shí)間最多的往往不是寫代碼而是定位“誰沒按協(xié)議走”。一開始遇到連接異常就悶頭改業(yè)務(wù)代碼改了兩天發(fā)現(xiàn)根本沒用后來養(yǎng)成先看協(xié)議日志、再動(dòng)代碼的習(xí)慣很多問題一眼就能看到癥結(jié)。如果這篇文章能讓你少走這個(gè)彎路那投入的方向就是對的。希望你也能養(yǎng)成這個(gè)習(xí)慣——遇到藍(lán)牙異常先抓日志再下結(jié)論。希望幫到你。本文還有配套的精品資源點(diǎn)擊獲取
返回列表
PREV
查看更多資訊
NEXT
返回資訊列表
狠狠干狠狠干| 日韩伦理视频| 久久久无码视频| 欧美色997| 色综合久久久久| 婷婷干黄色| 亚洲日韩资源| 欧洲精品区| 日韩乱码av| 秋霞影音一区二区三区| 亚洲密乳AV| 天天夜夜rb| 丝袜翘臀后入欧美校园亚洲自拍另类小说一区中文字幕少妇诱惑 | 粉嫩av平台| 97超碰超| 亚洲欧美综合区自拍另类| 人人妻人人爽人人精品| 日韩射图| 欧美亚州综合网图片| 极品AV网站在线观看| 日本一二三高清| 欧美色婷婷| 欧美强奸乱能| 肉嘟嘟www视频在线观看高清| 麻豆成人影音在线| 亚洲色婷婷综合久久久久中文| 日韩精品99久久久久久中文字幕| 美日韩一卡二卡三卡免费人妻精品| 睡产熟女乱伦| 欧美十八禁在线看| 曰韩av中文字幕专区| 亚洲αv一区二区三区| 伊人网青青| 亚洲精品九九九| 91情色在线| 91 国产丝袜在线播放-百度| 超碰69| 一直超碰| 欧美午夜视频| 激情综合网一盗摄| 亚洲日韩久久精品一区| 天天躁日日躁狠狠狠躁| 午夜一区| 黄色香蕉视频网站一区| 精品一区二区国产日韩| 国内亚洲高清无码| 日本三级日本三级三级人妇四虎| 国产 日韩 另类 视频一区爱| 亚洲精品国产无码高清| 国产亚洲精品美女久久久久久2021| 无码直播久久久| 亚洲97成人在线观看| 蜜臀一区二区三区亚洲最新章节在线观看 - 高清蜜臀一区二区三区亚洲全集播放 | 精品天堂| 乱操乱伦AV| 国模私拍一区二区三区神乳| 欧洲熟妇xxXx欧美老妇裸体| 色色五月婷| 丁香五月综合| 熟女一区二区三区| 大香蕉懂9| 亚洲在线91| av毛片aaaaa免费看| 一个人免费视频观看在线WWW | 精品国产网站| J?P?NESEHD熟女熟妇伦| 国产又黄又粗的视频| 最新岛国大片| 欧美后进式| 神马久久网| 亚洲精品蜜桃久久久| 久久久久久久91| 国产午夜福利电影免费在线观看 | 99热最新网址| 欧美 亚洲 大香| 人妻熟妇久草在线| 久久久久九九九| 一起草欧美| 99操| 久久婷婷亚洲欧| 999热日韩精品| 日韩性爱小视频| 日韩成人精品视频自拍| 91网亚洲| 97在线/亚洲| 国产精品熟女九色九色蜜臀| 蜜臀av一区二区三区免费观看| 色婷婷综合久久久久中文一区二区 | 国产精品久久久久久久久久二区三区| 欧美日本成人一区二区| 中文字幕在线高清男人的天堂| 91久青| 日本孕妇孕交| 91丨九色丨国产丨人妻在线| 女同在线视频一区| 性色亚洲| 国产成人+综合亚洲+天堂| 久久人妻四季| 日产操逼| 大香蕉碰| 亚洲资源站| 国精精品无码一二三区水多多| 欧美午夜精品久久久久久超碰| 午夜精品人妻二区三区| 精品国产乱码| 99蜜桃臀亚洲成人在线观看| 午夜a成v人电影| 日本久久久久久久久| 亚洲drav色图| 久久亚洲精品成人av| 欧美性爱一区| 最新av中文字幕高清| 色99色| 情色大香蕉| 精品国产一区二区三区四区在线看| 青青草中文-久久青草精品一区二区三| 青青草国产一区二区三区| 老熟女搡BBBB搡BBBB视频| 国产欧美第五页| 日韩欧美中文字幕搭讪巨乳美人妻视频| 国产亚洲精品激情| 亚洲涩涩| 亚洲成A∨人影院在线欢看| 日韩人妻丝袜美腿中文| 99热最新网址| 天久久久噜噜噜久久国产精品爽爽 | 亚洲αv一区二区三区| 久久精品天美| 超碰在线观看av不卡| 午夜天堂精品久久| 熟女色综合久久| 亚欧高清| 亚洲一二三四区在线免费看视频| 激情看片网站| 国产又粗又大硬免费色网视频| 亚洲中文制服诱惑| 免费无码国产精品v片在线观看| 伊人久久国产免费观看视频| 6080YYY午夜理论片在线观看| 天天日日本| 国产亚洲精品美女久久久久久2021| 亚洲性猛| 日本在线一二 | 探花精品视频| 欧美性天天| 久都青青视频| 新久久AV| 美女91网| 中文有码第五页| 欧美日韩日产免费网站看| 二三四区精品| 五月激情在线| 日韩亚洲Av人人夜夜澡人人爽| 亚洲综合色在线| 99爱爱| 操东北女人| 成人综合网 欧美| 亚洲无码国产精品久久| 情色图区| 亚洲av热热色| 99综合视频| 欧美人体性爱互联网第一页婷婷日本| 国产1727欧美| 天天干2019| 久久五十路熟女人妻| 91美女视频直播| 神马视频久久久久久| 日本成人A片免费看| 91欧美丝袜| 亚洲精品97在线| 熟女精品va中文字幕| 麻豆熟妇乱妇熟色A片在线看| juliaann丝袜大战黑鬼| 天天综合精品| 93人人操人人| 综合影院永久入口国产| 欧美伊人电影| 日韩日韩日韩-国产乱码精品一区二区| 992这里有精品| 久久一级无码精品毛片6| 久久男人的天堂| 久草线上视频免费看| 欧美欲色| 精品超碰中文在线| 麻豆伊人网| 中日高清无码操逼视频| 久久毛卡| 精品人妻av在线播放| 91日韩| 超碰久久综合| 97se综合| 亚洲欧美在线综合| 天天天天做夜夜夜夜做| 国产熟妇一区二区| 欧美日韩婷婷中文| 美女让帅哥通她小鸡鸡| 日韩精品作爱导航| 97精品在线| 青青草十区九区爱夜| 丁香六月啪啪| 激情综合五| 女人被添高潮免费视频| 精品亚洲国产成人AV制服丝袜 | 精品一久久久| 99久久综合| 日韩三级网址| 三级片大波波| 超碰97男人| 97干在线看| 国产精品久久久亚洲一区| 99性爱| 五月综合激情网| 日本污ww视频网站| 99超级碰免费视频| 久久久啊啊| 国产不卡精品91| 蜜臀AV成人精品蜜臀AV久久| 麻豆天美制片厂网站视频| 亚洲最大的黄色电影网站。| 日韩激情视频| 加勒比av官网在线| 亚洲成人AB| 97操97干| 97干97色| 亚洲国产成人福利在线观看| 大香蕉啪啪网| 天天摸天天碰天天添青青| 美女淫穴| 亚洲十八禁止| 日韩啊V| 欧美一级美片在线观看免费| 为用户提供免费看黄网址在线观看| 久久久久亚洲三级电影| www网站黄| 日本99热| 成人网欧美风情| 超碰午夜| 亚洲资源站| 欧美日韩插逼视频| 五月婷婷无码| 青青草手机在线免费观看| 色老牛| 国产精品97超碰| 国产99热| 久草免费在线一区二区| 诱惑人妻欧美一区在线播放| 午夜啊啊| 午夜偷拍久久熟女| 亚洲天堂中文字幕无码男同| 亚洲永久AV无码精品秋霞| 亚欧美综合| 欧美精品宗合| 99久久久无码国产精品性男| 91精品电影18| 99这里只有精品| 日韩欧美加勒比| 无码WWW免费视频网站| 亚洲操操| 欧洲精品一二三在线| 欧美宗合网| 中文字幕国产| 淫淫总合网| 青青伊人久久| 97视频免费在线观看| 青娱乐国产精品| 人人妻人人操人人乐| 中文字幕无码不卡啪啪| 午夜男人av| 国语人妻精彩刺激| 欧美色乱| 婷婷五月天成人| 97视频在线视频| 日本东京热久久久电影| 丁香五月电影| aV中文麻| 国产自偷自拍一区| 中文字幕免费看| 日韩操逼性鲍| 91美女视频在线| 天美传媒AV在线播放| 日韩黄色成人性爱| 青青草在线视频播放器| 国产亚洲精品自在线亚洲情侣| 亚洲美欧999| 手机在线大香蕉| 天天色播亚洲综合网站| 曰本特级特黄特色黄色A级网站高清在线免费看 | 欧美亚洲首页| 亚洲色图大香| 天天天肏屄肏屄肏屄欧美欧美| 亚洲国产尤物yw在线观看| 夫妻四区五区六区| 色婷婷激一区二区三区| 色老牛| 久久久久久亚洲Av无码精| 亚洲欧美精品一区天堂久久 | 女生看匆91网站| 日韩激情中文字幕有码| 欧美色交| 日本在线一二| av网站在线看| 国产传媒美日韩av| 亚洲精品白浆高清久久久久久| 国产性感在线观看| 26UUU欧美激情一区二区| AV在线资源| 国产成年免费大片黄在线观看| 久久水蜜臀亚洲AV无码精品| 天天干天天燥| 亚洲人妻色图| 麻豆 欧美 日韩| 亚洲中文字幕精品一区| 色网在线| 亚洲综合另类| 免费观看网黄| 桑老女人九区| 性爱动态120秒| 性爱综合一区二区| 成人精品水蜜桃久久久久久久| 日韩在线观看字幕精品| 91免费看中出视频| 情色五月天久久久| 国产强上视频在线观看| 精品国产a∨一区天美传媒| 操一区| 极品销魂美女一区二区| 午夜福利在线合集| 青青草操逼逼视频| www.伪伪| 中文字幕一区二区无码成人| 天堂日本亚洲欧美| 干婷婷综合网| 张柏芝国产一区在线观看| 九九热这里只有在线精品视 伊人草 成人菠萝蜜视频在线观看 | 狠狠操夜夜操蜜桃视频三区| 17c在线成人免费A片观看| 欧美日本不卡| 极品粉嫩一区二区| 人妻中文在线| 五月婷网站| 欧美97在线欧| 美女上床网站| 99精品热| 国产少妇肉丝在线观看| 欧美一级国产一级| 日韩成年人性爱视频| 色婷婷一区二区三区久久| 99自拍B亚洲 | 国产精品高潮久久AV| 国产成人自拍视频在线| 五十路六十路素人熟女| 免费视频一二三区| 亚洲风情综合网| 很黄很污的免费网站| 亚洲AV无码国产成人| av毛片aaaaa免费看| 久久伊人网视频一区二区三区| 青娱乐欧美激情一区二区| 操一对老熟妇爽上天视频| 有码色中文字幕在线观看| 日韩av乱伦| 国产亚洲精品久久久久小| 免费在线视频97| 亚洲大色堂| 九九AV| 色综合久久88色综合久久天天| 精品一区二区三区国产| 亚洲不卡三级手机播放| 夜夜爽夜夜高潮夜夜爽| 亚洲脚交| 高清不卡 中文 人妻| 丰满少妇高潮无码| 嗯嗯嗯啊啊啊操的我好爽| 中文字幕 码 自拍 视频 区| 婷婷丁香熟妇综合网| 午夜120视频在线观看| 日韩字幕一区| 丰满人妻一区二区三区性色| 岛国免费视频在线| 日韩精品色呦呦| A级毛片在线看免费| 日韩欧美大片免费高清啪啪| 激情五月天中文字幕色| 一级性爱网| 欧美裸体美女日麻屄| rion磁力链接| 久久专区| 黄色人人| 自拍偷拍 日韩无码| WWW黄片COM| 伦理片秋霞免费影院| 亚洲强奸乱伦影视网| 日本人人操人人操| 日韩黄色成人性爱| 久久久久成人蜜桃精品| 99r九九| 久久大香蕉手机高清| 九九热男人天堂| 国产精品久久发布| 草久久久| 超碰社区97| 黄色交缠性感爆操91国产精品免费一区二区三区| 91无码人妻| 91欧美巨乳| 国际精品久久久| 日韩性色| 欧美Aⅴ| 中文字幕91页| 超碰99在线| 啊啊啊啊视频免费| 97视频www| 天天操狠狠日夜夜干超大胆开放com大香蕉视频在线观看 | 国产久久av| 一区| 嗯嗯啊啊的视频| 欧美在线|亚洲| 热热色综合网| 97综合国产| 久久久久久久久久久免费精品| 波多野42部无码喷潮在线观看| 大色综合网| 色色热| 欧美精品 - 91爱爱| 国产AV人人夜夜澡人人爽麻豆| nuu12国产麻豆精品| 97免费在线| 奇米狠999| 亚洲欧美精品一区天堂久久 | 天天干18禁| 在线a亚洲视频播放在线| 一线黄色免费性爱片| 综合色播| 亚洲污污网站| 日本精品一级二级三级| www久| 热久久99999| 超碰色97| 大伊香蕉在线视频免费| 欧美性暴力猛交XXXX| 色欧美色交综合| 日韩熟女无码| 亚洲另类综合欧美| 一二三四区电影| 天天谢天天干| 97这里都是精品| 东京热综合久久一区二区| 天天摸夜夜添无码小视频| 亚洲天堂综合AV| 人人摸人人舔一区二区| 黑人美精品 A片| 色爱综合网欧美| 国产精品久久久久婷婷二区次| 国产成年免费大片黄在线观看| 国产高清1234区| 亚洲少妇综合| 青青操轻轻| 色欧洲97| 日韩乱伦影音先锋| 99热日| 国产女人和拘做爰视频| 成人综合视频久久| 国产91av在线播放| 综合激情97| 超碰97人妻免费在线| 午夜免费视频1000| 亚洲色图A| 探花精品视频| 激情欧美97| 色色操| 人妻91少妇| 99精品无码| 欧美色图综合网| 小泽玛利亚一二三| 神马九九| 人人污日韩一区二区| 操逼无码操逼| 亚洲欧洲久久天堂| 欧日a| 国产吹潮女在线观看| 蜜乳AV网址| 欧美 日韩第一性色| 亚洲精品无码少妇久久| 97国产精品一区| 国产精品交换一区二区| 91P0RNY大屁股人妻| 精品无人区麻豆乱码久久久| 强奸乱伦亚洲第一页| 欧美综合 站| 欧美性爱伊人| 亚洲毛片基地专区| 99色婷婷中文字幕乱色| 特级丰满少妇一级AAAA爱毛片| 久久r精品| 26uuu欧美| 少妇熟女1区2区3区| 99色骚| 三级三级三级a级全黄三| 中精品一区二区三区| 9久精品| 国产强奸无码乱伦| 狠狠躁日日躁夜夜躁A| 久久久久9| 乱伦一二三| 欧美激情亚洲情色| 97WW精品| 粉嫩粉嫩一区性色AV片| 国色综合天| 久久久久密臀一区二区| 亚洲乱熟女一区二区三区大香蕉| 综合网91| 色偷偷综合91久久噜噜| 蜜桃精品一区二区三区ww| 人人操人人插人人摸人人干| 亚洲天堂资源在线| 欧美大战久久久伊人| 99精品在线| 一区不卡在线观看av| 麻豆天天躁天天揉揉AV| 蜜桃久久久久久久久久久久| 97天天爽| 国产AV高清AV无码| 91东京热男人的天堂| 久久精品国产99久久,亚洲日韩久久日本一区一区三区 | 蜜臀久久久99久久久久 | 久久久啊啊| 96久久精品一二三区色欲| 国产高清成人免费视频| 久久久草草精品| 欧美在线啊啊啊| 天天干,天天日| 免费精品人妻一区二区三| 野狼福利社区| 日1区2区3区2020| 都市激情人妻一区二区青青操视频| 国模一区二区三区| 中文字幕一区日韩精| 亚洲精品一二区| 久久永久无码人妻视频| 国产免费内射视频| 欧洲自拍第一页| 青青草国产盗摄一二三区| 日韩女优中文字幕| 欧美另类色图片| 操人91| 国产亚洲精品玖玖玖在线观看| 黑人精品一区二区在线播放| 大JI巴好深好爽又大又粗视频| 亚洲少妇视频| 熟人人妻少妇精品久久| 在线电影亚洲色图| 青青操视频在线| 人妻 制服 日韩 中文 在线| 亚洲91网。| 超碰在线人妻不卡| 日韩国产十八禁| 91伊人影视综合| 91色综合激情| 久久精品视频在线观看| 久久久∴| 夜夜爽爽夜夜精品视频| 欧美性天天影院| a人片中文字幕一区二区| 欧美日韩婷婷中文| 伊人久久蜜月| 国产精品午夜精品| 人妻精品一区二区三区| 日韩9区| 91丝袜在线观看| 精品国模无码| A 在线网址| 操逼片中文| 一块操欧美| 成人欧美一区二区三区黑人一| 91超级碰| 国内精品久久国产,www香蕉久久五月丁香,亚洲欧美日韩精品永久在线,日本精品一 | 国产精品96久久久久久| 精品视频在线观看| .精品人妻一区二区三| 国产精品视频自拍在线| 欧美成人一级免费电影| 国产99 中文字幕日韩小视频| 国产1769在线| 日韩有码一区三区| 性性欧美| 午夜视频久久久| 青青久草| 欧美日韩插逼视频| 岛国黄| 国产视频一区二区免费| 志村玲子视频一区二区| 青青操在线亚洲视频观看欧美在线| 极品粉嫩少妇视频| 欧美线天码中字| 亚洲国产熟妇综合色专区| 男人天堂网址| 黄页网站免费高清在线观看| 日本久久天堂| 岛国小电影| 欧美激色| 日韩视频中文字幕| 国产精品69人妻无码久久久| 婷婷亚洲综合| 91丝袜在线视频| 欧美激情内射| 777AV电影| 狠狠操狠狠| 2000亚洲男人天堂| 91精品91久久久中77777| 色视频蜜乳| 大香蕉乱伦视频网| 精品一区二区三区四区女| 欧美同性恋 的搜索结果 - 91n| 少妇被c 黄 免费观看| 黄骗免费| 91最新综合| 久久高潮妇女视频| 免费伦费视频在线观看| 夜夜操天天肏| 欧美在线天堂| 在线国产一区二区av| 久久久穴999| 99999国产| 亚洲一卡2卡3卡4卡乱码网站| 96AV精品| 97伊人| 中文字幕性感少妇av| 9久精品视频在线观看| 国产无码一二三区| 国产青视频| 天天操夜夜操| 亚洲一区二区麻豆影院| 国产精品另类| 欧美成va视频网站| 亚洲青青草| 91在线超高颜值国产| 超碰久久中文| 视频二区美腿制服人妻欧美| 亚欧成人中文字幕一区| 青女在线| 高清在线不卡一区二区 视频| av天堂影视中文在字幕在线中文| 97超级色碰碰| 国产精品女生av| 一区麻豆 高清中文字幕| 亚洲丝袜少妇在线| 120分钟婬片免费看| 蜜桃臀一区二区三区久久| 天天躁日日躁xxxxx| 后入 亚洲 美女 射| 992视频一区| 婷婷色五月激情| 91岛国动作片| 亚洲AV无码天美传媒一区| 青青草毛片| 91人人爽人人爽| 在线亚洲 欧美 日本专区| 亚洲高清内射| 国产免a费看黄片在线| 激情欧美日韩女同久久| 台湾成人无码AV| 色哟哟精品1精品2| 亚洲成人综合在线| 酒色综合网| 蜜桃久久久久久久| 欧美成人四级在线播放| 蜜臀一二三区| 天天看综合网| AV天堂国产| 亚洲和欧美裸体美女双飞视频| 日本操大逼| 有码专区最新中文字幕有码| 夜夜中出国产| 国产三级资源在线观看| 青青操视频在线| 欧美久热| 亚洲97成人在线观看| AV中文字幕剧情1区2区3| 人、人、摸,人、人、草| 操一对老熟妇爽上天视频| 天天日老熟妇| 国产精品成人无码a v毛片| 天天躁夜夜躁狠狠躁AV| 黄污污污污| 日韩在线欧美精品一区二区| 色一区二区三区综合| 啊啊啊好爽快点啊啊啊嗯嗯| 亚洲小电影免费涩涩成人在线高清| 蜜臀久久99'精品久久久| 啊啊啊不要好疼视频| 欧美日韩另类在线| 日韩欧美女求操每天更新| 啊啊啊好舒服好爽啊啊啊视频| 亚洲中文日韩欧美大香蕉视频| 花花AV导航| 五月开心久久AV官网| 五月天开心网| 乱伦图一区| 激情小说亚洲| 亚洲不卡一| 欧美曰韩国产精品| 国产成人+综合亚洲+天堂| 秋霞成人做爱| 日本色日夜干| 91模特在线观看| 久久久性爱视频| 亚洲中文字幕97久久精品少妇| 日韩中文字幕人妻视频| 91综合网| av2014 日韩在线中文字幕| 久久爽爽精品| 精品免费一区二区三区在线亚洲人成| 天天精品| 综合久久久久久久综合网| 嗯嗯啊啊操我| 国产精品伦理| 久久久熟女一区| 91精品国久久久久久无码| 九九毛片这里只有精品| 色婷五月| 在线国产一区二区av| 国产精品女生av| 国产精品成久久久久午夜午夜| 欧美操逼录像国产黄色国产| 男人的天堂日韩| 国产久久一区二区| 夜夜国产一区| 欧美色图私拍91| 97在线视频观看免费| 亚洲限制级| 老熟女区| 久久精品老司| juliaann丝袜大战黑鬼| 中文字幕亚洲欧美在线不卡| 99丝袜福利在线播放| 嗯啊不要在线| 天天色香欲综合网| 国产日本熟女顶级一区二区三区视频 | 女优视频第10页| 激情网五月天| 91麻豆天美国产欧美| 色色亚洲| 国内精品999| 人妻久热在线| 色五月69夫妻| 少妇三P| 精品中文日韩字幕视频| 亚洲色悠悠久久88| 五月天欧美色图| 骚货 中文字幕 av| 欧美日综合| 97超碰超| 永久电影三级在线观看| 91一区二区三区蜜桃| 夜夜操美女| 一级aaaaa欧美中文字幕录像片| 少妇xx精品| 国产无码一二三区| 五月天激情小说| 97资源超碰| aaa淫乱视频| 色五月AV在线| 嗯嗯不要视频| 欧美 精品国产制服第一页| 久久性爱精品一区| 全球成人中文在线| 亚洲熟妇自偷自拍另欧美| 老女人日韩美91| 亚洲一二三| 在线啊啊啊| 久久专区| 欧美日韩操逼动图| 色婷婷激情| 欧美熟妇操操视频| 综合自拍| 手机在线免费看的av| 婷婷影院入口| 亚殴在线| 97久久天天综合色天天综合色电影| 亚洲综合在线91| 92性色国产午夜福利在线661| 福利在线观看一区二区| 91oumei| 精国久久一区二区三区98| 变态综合色| 天天草夜夜草高潮片| 亚洲五月婷| 97超碰逼| 天啪| 国产精品美女久久久久AⅤ国产馆| 插欧洲美女欧美精品| 青青草吊丝| 久久精品国产97欧美精品亚洲 | 亚州伊人色综台| 天天操人人操骚逼网站| 色香AV| 日韩性爱视频免费在线| 中日韩久久人妻一区二区| 东北女人性交| 天天色天天干天天射| 人妻激情另类| 久久久月天| 黄色片,com| 国产不卡精品91| 9久9久9久9久视频网站| 中文字幕一区二区日韩网| 天天日老熟妇| 欧美日韩制服| 亚洲成人福利电影免费| 国产超碰在线一区| 亚州综合| 五月天激情国产综合婷婷婷| 激情婷婷丁香| 日韩激情啪啪啪| 狠插 制服 自拍| 神马久久久久久久| 五月天激情小说网| 欧洲一区二区| 欧美一级黄片免费播放| 91美女视频在线免费观看| 国产免费一区2区3区| 五月婷婷激情| 99久久99九九99九九九| 色牛牛AV| 国产av色网| 人妻中文字幕日韩电影| 欧美成人一区二区| 人人 操人人 操人人| 亚洲综合888| 中文字幕精品探花视频| 亚洲不卡AV在线| 久久久久久久久久9| 色九月| 欧美激情精品| 91欧美高清| 亚洲福利中文字幕在线| 中文字幕第23区| 操逼免费视频无码国产| 天美传媒Av在线| 国产精品爽爽v| 91丨精品丨国产丨丝袜| av无线看| 国产风韵犹存熟妇三区| 欧美视频边做饭边橾| 天天干1区2区在线| 女人爽到高潮潮喷18禁网站| 51一区二区三区| 91超级碰碰碰| 精品人妻一区二区三区鲁大师| 九九热在线视频| TS人妖另类精品视频系列| 色呦呦、国产精品| 国产精品一区二区亚洲人成毛片| 99热导航| 国产中文字幕曰本毛片| 亚洲午夜精品久久久中文影院| 亚洲综合五月天| 97亚洲综合| 欧美伦乱爱| 色噜噜人妻丝袜a∨先锋影| 东北女人性交| 日本天天吊| 91露脸熟女专区| 大香蕉伊然在亚洲91| 色五月网址| 国产无码久久高清| 国产精品国产| 色蜜AV| 天天激情综合站| 久久久久久99999国产精品| 日本 欧美 亚中文字幕| 日本操逼视频不卡直接放| 中文一区二区| 国产精品老熟女一区二区| 日韩中文字幕国产| 精品无av| 东北女人被操| 九九亚洲视频| 17c在线成人免费A片观看| av日韩中文字幕| 九九热男人天堂| 成人aⅴ一区二区三区| 啊啊啊水好多| 国产熟妇一区二区| 丁香五月综合| 亚洲中文一区二区三区| 麻豆熟妇乱妇熟色A片在线看| 97玖玖人妻| 蜜臀操逼黄色视频操的好爽| 亚洲国产综合视频| 久欲AV| 久久伊人网视频一区二区三区| 亚欧性爱ab| 亚洲av国产av综合av卡| 久久久无码精品人妻二区| 91欧美偷拍| 久久久A∨| 成人美女av| 尤物视频视频官网| 高颜值美女口爆高潮浪叫| 躁躁日曰躁2020| 欧美有码激情视频一区二区三区| 亚洲成人av电影在线| 久操视频在线观看| 暴力av在线| 日韩精品大香蕉伊人在线| 欧美不卡在线美女| 色九九综合| 全球成人中文在线| 精品中文字幕第一页| 91在线免费精品视频| 日韩欧美中文字幕搭讪巨乳美人妻视频| 91成人国产综合久久精品蜜月| 人妻少妇精品一区二区三区| 强奸乱伦动态污图免费| 国产毛片久久久久久久| 国产品精品自在在线午夜免费| 舔人妻中文免费视频| 亚洲综合校园春色| 色综和网| 嫩草伊人久久精品| 欧美亚州手机在线| 欧美日韩999| 欧美久久伊人| 乱伦av国产| 人妻一区视频| 亚洲精品人妻在线| 人妻一二三区| 亚欧免费| 干干干天天| 亚洲日韩美国人妻| 视频国产精品未满十八禁止在线观看| 操婢日韩| 免费人成在线观看网站品爱网| 不卡中文字幕aⅴ在线| 国产精品美女视频诱惑| 色香AV| 91麻豆天美| 亚洲熟妇一,二,三期| 国产精品99999| 操一操摸一摸| 国产精品第一区第一页| 亚洲国产精品成人综合| 青娱乐二区免费| 午夜男女爽爽大片免费观看| 超碰在线人妻中文字幕| 亚洲国产精品成人综合| 91搞逼视频| 久久久久亚洲AV无码专区少妇| 国产日韩在线播放av| 国产精品999zyz| 在线视频日韩欧美国产| 99久re热视频精品98| 中文字幕五区| 有码人妻系列| 三上悠亚在线毛片91| 1769一区| 欧美αv.com| wwwcaobibi| 涩涩五月天| 欧洲乱码一区二区| 国产一区二区在线播放,久久亚洲精品中文字幕第一区,亚洲精品在线中文字幕视频 | 无码自拍SM| 裸体美女免费看网站青草| 嗯嗯,啊啊,国产精品| 欧美亚洲美少妇一区二区| 亚洲精品白丝| 无人区高清电影免费观看一区二区三 www.qmcai2.com | 欧美 传媒 麻豆 日韩 偷拍| 狠狠躁天天躁日日躁| 日日嗷| 97在线视频免费观看| 翔田千里Av在线| 天天日天天干天天整| 夜夜操狠狠操| 人妻社区男人天堂| 国内外毛片在线观看| 亚洲日韩电影| 一区操逼日比视频| 天天干天天拍| 国产在线精品电影观看| 青青草一区二区高清无码视频| 无遮挡又黄又刺激的视频| 国产一级作爱毛片| 国产丝袜美女诱惑| 欧美最大综合网| 国产强奸乱伦无码视频| JIZZJIZZ国产精品喷水| 人妻天天爽夜夜爽爽| 大屁股熟女一区二区三区| 亚洲天堂一区| 亚卅熟女乱色| 99www.bibizy香蕉资源国产一区二区三区高清 | AV天堂电影网| 天天干人妻视频| 亚洲图片色图欧美另类| 色欧美天天| 麻豆区久久久久亚| 亚洲成人性爱在线观看| 亚洲 暴爽 AV人人爽日日碰| 国产精品 午夜福利| 操B视频日韩无码| 日本岛国黄色网址| 91黑丝美女| 老鸭窝成人免费毛片视频| 日韩欧美aⅴ综合网站发布| 欧美激情总合网| 久久久青草青青国产亚洲免观精品高清完整版_97久久综合区小说区图片区,国精品 | 国产少妇高潮| 精品性爱| 91人妻爽爽人人做人人澡| 99热99re6国产在线播放| 久久久久久99AV无码免费网站| 97在线精品| 精品无码产区一区二| 亚洲成人性爱网站在线播放| 91在线欧色| 91亚洲综合在线| 亚洲国产欧美中日韩成人综合视频| 国产传媒一区日韩| 亚洲色婷婷久久91| 欧美午夜精品久久久久久超碰| 国产一区二区在线看| 亚洲AV无码黄色强奸| 国产乱弄免费在线视频。 | 国产男人又猛又粗又爽| 久久一二三四不卡 | 精品久| 91操人视频| 一区二区三区四区五区久久久久久| 亚洲欧美日韩二区视频| 九九久久国产精品| 中文字幕黄片在线| 97超碰天天爱天天爱| 国产精品美女久久久久久网站| 欧美性天天影视| 日韩欧美日韩| 美女啊啊啊啊pc| 亚洲一区二区在线观看91| 激激五月| 看日韩黄片| 91偷拍欧美亚洲| 无码免费在线观看黄色片| 91色噜噜狠狠| 91香蕉视频在线观看免费| 日本人妻天堂网站在线播放| 搞中出久久| 国产欧美后入| 国产福利av精彩对白| 哑洲在线| 婷婷久草| 午夜精品久久久| 亚洲AV资源| 天天懆天天日| 久久久久无码一妻区| 操比国产| 一本久道久久综合狠狠爱一密臀精 | 清纯唯美激情四射| 老外又粗又长一晚做五次| 大香蕉欧美日韩| 老司机老司机午夜影院| 新91视频.cmp| 国产欧美美女免费观看视频| 综合伊人网12色| 青娱乐手机日韩在线视频| 亚洲欧美国产其他二区| 青草地一本线一区二区三区| 天天欧美欧美亚洲网| 无码操逼视频一下| 大香蕉日亚洲日本亚大| 亚洲中文字幕97久久精品少妇| 日韩免费簧片| 欧美在线|亚洲| 中文啪啪视频| 家庭乱伦性爱av| 人妻丝袜一区二区三区在线| 欧美精品丝袜久久久中文字幕| 国产精品欧美日韩久久| 4虎在线观看| 日韩情色AV| 丁香六月激情综合| 久久欲| 国产搭汕a级片| 欧美精品双插| 综合激情五月丁香| 欧美一区二区福利在线| 日韩无码第3页| 青青操少妇| 五月丁香综合激情| 日逼逼免费看| 久久东京热久久| 亚洲男人综合网| 好淫网一二三视区| 欧亚性爱视频免费看| 五月亭亭六月丁香| 久久中久文96| av午夜玫瑰| 久久久无码国精品无码三区三区| 中文精品一区二去| 97aiaiai| 五月天精品| 天美传媒AV国产在线| 男人的天堂亚洲| 亚洲精品一区二区三区在线播放| 国产无码成人无码| 小电影欧美91| 久久久久元码视频| 欧美97日韩精品| 日本熟妇色熟妇在线视频播放| 国产精品秘 福利姬在线观看| 蜜乳AV免费观看| 青青操在线视频| 亚洲熟久久| 婷婷五月天久久精品视频一区二区三区| 亚洲精品a人片在线观看视| 成 人 A V免费视频在线观看| 超碰吊日色| 亚洲综合大片| 国产又大又粗又色生活片亚洲国产精品成人久久久综合免费 | 久久婷婷色| 啊啊啊操一区| 夜夜草网站| 日本一区二区不卡精品| 天天爽夜夜爽夜夜爽精| 不卡日本一区二区| 亚洲欧美清纯| 97色欧洲| 日本97久久| 亚洲一区制服诱惑| 天天综合网1| 懂色AV中文| 天天日日本| 亚洲国产剧情少妇激情| 欧美嗯啊……在线观看视频免费| 伊人久久婷婷| 国产亚洲在线观看| 五月色网| 大香蕉啪啪啪| 日韩三级一区 | 97视频免费在线观看| 欧美 亚洲 在线| 欧美人妻少妇| 亚洲久久久久| 国产色产精品在线观看| 日韩综合无码一区久久92| 青青草国产欧美非洲黑人| 亚洲国产熟妇综合色专区| 大香蕉中文在线| 92一区二区| 亚洲乱码精品一区二区| 欧亚无码视频| 久久久久久久久久va| 午夜操逼不卡| 日逼国产| 99色天堂| 日韩AV电影网站| 91色五月俺来也| 1204金沙人妻懂旧版免费| 2019午夜福利视频| 欧美啪啪天堂| 91网站18禁|