# Android 局域网寻址极简 SDK 接入指南

本模块提供了一个极致精简、无 UI 侵入的 UDP 服务自动寻址工具，仅含一个独立文件，旨在方便其他业务线项目无缝集成。

## 一、集成方式

由于是极简化设计，无需配置 Gradle 依赖池，只需将以下代码文件复制到目标项目的源码目录下：

* **源码路径**: `android/UdpDiscoveryClient.kt`

> *注意：复制过去后，别忘了把首行的 `package com.yourcompany...` 修改为你项目的实际包名。*

## 二、运行前置准备

### 1. 确保已引入 Kotlin 协程
目标项目必须支持基础的 Kotlin 协程（现代 Android 项目默认支持）。
```gradle
// app/build.gradle
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.x"
```

### 2. 检查网络权限
请确保目标项目的 `AndroidManifest.xml` 中已被授予了联网权限（默认肯定都有）：
```xml
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
```

---

## 三、如何使用（最佳实践）

我们的 SDK 并**不干涉**目标项目的 UI 长什么样。目标项目拿到返回的结果数据后，自己决定是弹窗提醒还是填充到 EditText 里。

以下是在目标项目某个 Activity/Fragment 或 ViewModel 中发起寻找的典型代码：

### 示例：配合用户的手动输入框

假设目标项目有一个“服务器设置页面”，里面有两个输入框：`ipEditText` 和 `portEditText`。

```kotlin
import androidx.lifecycle.lifecycleScope    // 或者使用 viewModelScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext

// 场景：当用户点击了【自动获取局域网设备】这个按钮时

autoDiscoverBtn.setOnClickListener {
    // 假设你有某种全局 Loading 弹窗，可以在这里展示
    // showLoadingDialog("正在寻找设备...")
    
    // 启动协程
    lifecycleScope.launch {
        
        // 默认会使用：
        // magicWord = DISCOVER_STANDARD_EDITION
        // targetPort = 8888
        // responsePrefix = SERVER_IP:
        val result = UdpDiscoveryClient.discover()
        
        // 隐藏 Loading
        // hideLoadingDialog()
        
        // 检测结果
        if (result != null) {
            // ✅ 找到了！
            // 不干预 UI，直接把拿到的 ip 和 port 填入该项目的输入框里
            ipEditText.setText(result.ip)
            portEditText.setText(result.port.toString())
            
            Toast.makeText(this@ConfigActivity, "自动获取成功！", Toast.LENGTH_SHORT).show()
        } else {
            // ❌ 没找到 (超时，或者对方没开程序，或者不在同一个局域网)
            // 提示用户找不到，让用户继续自己手动填
            Toast.makeText(this@ConfigActivity, "未发现可用设备，请手动填写IP", Toast.LENGTH_LONG).show()
        }
    }
}
```

### 自定义参数示例

如果下一个 Android 项目的 UDP 协议不完全一样，可以只改几个外露参数：

```kotlin
val result = UdpDiscoveryClient.discover(
    magicWord = "DISCOVER_MY_APP",
    timeoutMs = 3_000L,
    targetPort = 9999,
    broadcastIp = "255.255.255.255",
    responsePrefix = "MY_SERVER:"
)
```

### Java 调用示例

```java
UdpDiscoveryClient.discoverFromJava(
    LifecycleOwnerKt.getLifecycleScope(this),
    "DISCOVER_MY_APP",
    3000L,
    9999,
    "255.255.255.255",
    "MY_SERVER:",
    result -> {
        if (result != null) {
            ipEditText.setText(result.getIp());
            portEditText.setText(String.valueOf(result.getPort()));
        }
    }
);
```

## 四、核心原理与优势
* **单文件**：完全没有乱七八糟的库文件或复杂的依赖图。
* **参数可外露**：暗号、UDP 端口、广播地址、返回前缀都可以按项目差异直接覆盖。
* **绝对挂起**：内部底层代码已经切换到 `Dispatchers.IO`。你就算在主线程 `scope.launch` 里直接调，也绝不用担心 `NetworkOnMainThreadException` 或界面卡死。
* **原生解析**：收到诸如 `SERVER_IP:192.168.1.100:8080` 的报文后，会自动拆出 `ip` 和 `port` 返回给上层业务。
