android: permisos y MulticastLock para ver moviles en la misma wifi

El anuncio LAN de SSB va por UDP broadcast y Android lo filtra sin un
MulticastLock. La oficial declara ACCESS_WIFI_STATE y
CHANGE_WIFI_MULTICAST_STATE; esta no, asi que dos moviles en la misma red no
se encontraban.
This commit is contained in:
hacklab 2026-10-10 15:54:42 +02:00 • committed by oasis-bot
parent de5e8fba20
commit ba057f0092
2 changed files with 26 additions and 0 deletions

View file

@ -3,6 +3,10 @@
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!-- descubrir otros moviles en la misma wifi: el anuncio LAN de SSB va por UDP
broadcast/multicast, y Android lo filtra si no se coge un MulticastLock -->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />

View file

@ -6,6 +6,7 @@ import android.app.NotificationManager
import android.app.Service
import android.content.Context
import android.content.Intent
import android.net.wifi.WifiManager
import android.os.Build
import android.os.IBinder
import android.system.Os
@ -33,16 +34,37 @@ class NodeService : Service() {
@Volatile private var started = false
}
// Sin esto Android tira los paquetes multicast/broadcast que llegan por wifi y el
// descubrimiento LAN de SSB no ve a nadie: dos moviles en la misma red no se encuentran.
private var multicastLock: WifiManager.MulticastLock? = null
override fun onBind(intent: Intent?): IBinder? = null
override fun onCreate() {
super.onCreate()
startForeground(NOTIF_ID, buildNotification())
acquireMulticastLock()
if (started) return
started = true
Thread({ runNode() }, "node-main").start()
}
override fun onDestroy() {
try { multicastLock?.takeIf { it.isHeld }?.release() } catch (e: Throwable) { Log.w(TAG, "soltando MulticastLock", e) }
super.onDestroy()
}
private fun acquireMulticastLock() {
if (multicastLock?.isHeld == true) return
try {
val wifi = applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager
multicastLock = wifi.createMulticastLock("oasis-lan").apply { setReferenceCounted(false); acquire() }
} catch (e: Throwable) {
// sin wifi o sin permiso: los pubs siguen funcionando, solo se pierde la LAN
Log.w(TAG, "no se ha podido coger el MulticastLock; sin descubrimiento LAN", e)
}
}
private fun buildNotification(): Notification {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val ch = NotificationChannel(CHANNEL, getString(R.string.node_channel), NotificationManager.IMPORTANCE_LOW)