Android 熱點?
一、前言
熱點開發屬于系統級功能開發,涉及的核心 API 多為系統簽名權限保護(如android.permission.TETHER_PRIVILEGED
),通常僅系統應用(如 Settings)可正常調用。
實際開發中,除基礎的開關、配置功能外,可能需要擴展自定義信道設置、頻段切換等 Settings 未涵蓋的功能。本文總結熱點開發的核心流程、調試技巧及版本適配要點
二、熱點開發
1、開關和默認配置
(1)核心 API(分版本)
Android 13 及以上:推薦使用
ConnectivityManager
與TetheringManager
的公開 API,支持回調監聽狀態:// 開啟熱點 ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); TetheringManager tetheringManager = connectivityManager.getTetheringManager(); tetheringManager.startTethering(TetheringManager.TETHERING_WIFI,ContextCompat.getMainExecutor(context),new TetheringManager.StartTetheringCallback() {@Overridepublic void onTetheringStarted() { /* 開啟成功 */ }@Overridepublic void onTetheringFailed() { /* 開啟失敗 */ }} );// 關閉熱點 tetheringManager.stopTethering(TetheringManager.TETHERING_WIFI);
Android 11-12:可使用
WifiManager
的startTetheredHotspot
(需系統簽名):WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); // 開啟(使用現有配置) wifiManager.startTetheredHotspot(null); // 關閉 wifiManager.stopTetheredHotspot();
(2)配置信息設置
通過SoftApConfiguration
配置熱點參數(SSID、密碼、頻段、信道等),需注意配置修改后需重啟熱點才能生效:
private SoftApConfiguration buildConfig() {SoftApConfiguration.Builder builder = new SoftApConfiguration.Builder();builder.setSsid("MyHotspot"); // 熱點名稱// 加密類型:0=無密碼(OPEN),1=WPA2-PSKbuilder.setPassphrase("12345678", SoftApConfiguration.SECURITY_TYPE_WPA2_PSK); // 頻段與信道(必須匹配,否則開啟失敗)// 2.4G頻段(band=1):信道1-14;5G頻段(band=2):信道36-165builder.setChannel(6, 1); // 2.4G信道6return builder.build();
}// 應用配置
WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
wifiManager.setSoftApConfiguration(buildConfig());
2、主要流程
熱點開啟的核心調用鏈
1. ConnectivityManager.startTethering() → 觸發 tethering 服務請求
2. TetheringManager.startTethering() → 管理 tethering 狀態與權限校驗
3. TetheringService.startTethering() → 系統服務層處理請求
4. WifiManager.startTetheredHotspot() → 調用WiFi服務開啟熱點
5. WifiServiceImpl.startTetheredHotspot() → 實現熱點啟動邏輯
6. ActiveModeWarden.startSoftAp() → 管理活躍模式(AP模式)
7. SoftApManager.start() → 構建AP配置并調用底層
8. WifiNative.startSoftAp() → 與WiFi HAL交互
9. HostapdHal.addAccessPoint() → 調用硬件抽象層接口,啟動hostapd進程
關鍵節點:SoftApManager
負責 AP 配置轉換,HostapdHal
對接硬件驅動,若某環節日志缺失,需重點排查對應層問題(如權限、硬件支持)。
3、相關日志
調試熱點問題時,需重點關注以下日志關鍵字和過濾命令:
日志類型 | 關鍵字 / 進程名 | 過濾命令示例 | ||
---|---|---|---|---|
Framework 層 | SoftApManager 、WifiService | `logcat | grep -iE "SoftApManager | WifiService"` |
底層服務 | hostapd 、wpa_supplicant | `logcat | grep -i hostapd` | |
HAL 與驅動交互 | WifiNative 、WifiHAL | `logcat | grep -i WifiNative` | |
網絡接口 | wlan 、ap0 (接口名) | `logcat | grep -i wlan1` |
常見錯誤日志分析:
Failed to start softap: invalid channel
:信道與頻段不匹配(如 5G 頻段用了 2.4G 信道)。SecurityException: Not allowed to start tethering
:缺少系統簽名或TETHER_PRIVILEGED
權限。hostapd: Failed to set channel
:硬件不支持該信道(需檢查設備支持的頻段范圍)。
4、相關廣播
熱點狀態變化的核心廣播為WifiManager.WIFI_AP_STATE_CHANGED_ACTION
,可監聽開關過程:
private BroadcastReceiver hotspotReceiver = new BroadcastReceiver() {@Overridepublic void onReceive(Context context, Intent intent) {if (WifiManager.WIFI_AP_STATE_CHANGED_ACTION.equals(intent.getAction())) {int state = intent.getIntExtra(WifiManager.EXTRA_WIFI_AP_STATE, -1);switch (state) {case WifiManager.WIFI_AP_STATE_ENABLED:Log.d(TAG, "熱點已開啟");// 可在此處獲取熱點IP(通過NetworkInterface)break;case WifiManager.WIFI_AP_STATE_FAILED:Log.e(TAG, "熱點開啟失敗");break;// 其他狀態:開啟中(WIFI_AP_STATE_ENABLING)、關閉中(WIFI_AP_STATE_DISABLING)、已關閉(WIFI_AP_STATE_DISABLED)}}}
};// 注冊廣播
IntentFilter filter = new IntentFilter(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
context.registerReceiver(hotspotReceiver, filter);
三、其他
1、Android 熱點開發調試小結
- 權限依賴:必須為系統應用(安裝在
/system/priv-app
)并使用系統簽名,還需要導入framwork包; - 硬件限制:頻段和信道支持依賴 WiFi 芯片,需通過
WifiManager.getConfiguredNetworks()
或底層日志確認設備能力。
// 依賴ZXing庫:implementation 'com.google.zxing:core:3.5.0'
private Bitmap generateHotspotQrCode(String ssid, String password) {// 二維碼內容格式:WIFI:S:熱點名;T:加密類型(WPA/WEP/OPEN);P:密碼;;String content = "WIFI:S:" + ssid + ";T:WPA;P:" + password + ";;";MultiFormatWriter writer = new MultiFormatWriter();try {BitMatrix matrix = writer.encode(content, BarcodeFormat.QR_CODE, 300, 300, // 二維碼寬高new HashMap<>());// 轉換BitMatrix為Bitmapint width = matrix.getWidth();int height = matrix.getHeight();Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);for (int x = 0; x < width; x++) {for (int y = 0; y < height; y++) {bitmap.setPixel(x, y, matrix[x][y] ? Color.BLACK : Color.WHITE);}}return bitmap;} catch (WriterException e) {e.printStackTrace();return null;}
}