88package com.facebook.react.devsupport
99
1010import android.app.Activity
11- import android.content.Context
1211import android.content.pm.PackageManager
12+ import com.facebook.react.common.build.ReactBuildConfig
1313import com.facebook.react.modules.core.PermissionAwareActivity
14- import com.facebook.react.modules.systeminfo.AndroidInfoHelpers
1514import com.facebook.react.util.AndroidVersion
1615
1716/* *
1817 * Debug-only helper to request the runtime `ACCESS_LOCAL_NETWORK` permission needed to reach Metro
1918 * on Android 17 (SDK 37) devices, which gate local-network addresses (the emulator's `10.0.2.2`
20- * alias, a device's Wi-Fi/LAN IP) for any app that declares the permission, regardless of targetSdk.
21- * Loopback via `adb reverse` (`localhost`) is exempt .
19+ * alias, a device's Wi-Fi/LAN IP). Requested only in debuggable builds, and always (like iOS), since
20+ * the dev-server host can change at runtime (e.g. switching from `adb reverse` to a LAN IP) .
2221 */
2322internal object LocalNetworkPermissionUtil {
2423 private const val PERMISSION = " android.permission.ACCESS_LOCAL_NETWORK"
@@ -42,28 +41,8 @@ internal object LocalNetworkPermissionUtil {
4241
4342 /* * Whether the `ACCESS_LOCAL_NETWORK` prompt must be shown before reaching the dev server. */
4443 private fun needsLocalNetworkPrompt (activity : Activity ): Boolean {
44+ if (! ReactBuildConfig .DEBUG ) return false // dev-server only; never prompt in release builds
4545 if (! AndroidVersion .isAtLeastSdk37()) return false // enforced by the device, not app targetSdk
46- if (! isPermissionDeclared(activity)) return false // debug manifest only
47- if (activity.checkSelfPermission(PERMISSION ) == PackageManager .PERMISSION_GRANTED ) return false
48- return ! isExemptDevServerHost(activity) // loopback needs no permission
46+ return activity.checkSelfPermission(PERMISSION ) != PackageManager .PERMISSION_GRANTED
4947 }
50-
51- /* *
52- * True for loopback dev servers (`localhost` / `127.x` / `::1`, e.g. USB + `adb reverse`), which
53- * are exempt. The emulator's `10.0.2.2` is not loopback here and does need the permission.
54- */
55- private fun isExemptDevServerHost (context : Context ): Boolean {
56- val host = AndroidInfoHelpers .getServerHost(context).substringBeforeLast(' :' ).trim(' [' , ' ]' )
57- return host == " localhost" || host == " ::1" || host.startsWith(" 127." )
58- }
59-
60- private fun isPermissionDeclared (activity : Activity ): Boolean =
61- try {
62- activity.packageManager
63- .getPackageInfo(activity.packageName, PackageManager .GET_PERMISSIONS )
64- .requestedPermissions
65- ?.contains(PERMISSION ) == true
66- } catch (_: PackageManager .NameNotFoundException ) {
67- false
68- }
6948}
0 commit comments