Request local network permissions on Android
Learn how to declare and request Android local area network permissions before opening Dart sockets in Flutter.
Starting in Android 17 (API level 37), Android blocks local network access
by default. Apps targeting Android 17 or higher that discover, scan,
or connect to devices on the local area network must declare and request
the ACCESS_LOCAL_NETWORK runtime permission.
Understand the impact on Dart sockets
#
The standard dart:io library provides low-level socket networking,
including Socket,
RawSocket,
and ServerSocket.
These socket classes operate at the system level
and do not interact with Android's application framework UI.
Because Dart sockets cannot display an Android permission prompt,
any attempt to connect to a local IP address without the required permission
fails and throws a SocketException.
To prevent connection failures,
request the runtime permission in Flutter
before you initialize or connect your Dart socket.
Declare the permission in Android
#Before you can request the permission at runtime, declare it in your Android manifest.
- Open
android/app/src/main/AndroidManifest.xml. - Add the
ACCESS_LOCAL_NETWORKpermission inside the<manifest>tag:
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.ACCESS_LOCAL_NETWORK" />
<application
...
</application>
</manifest>
Add the permission_handler package
#
To request Android runtime permissions from Dart,
use the permission_handler
plugin from pub.dev.
Add permission_handler to your Flutter project dependencies:
flutter pub add permission_handler
Request permission before connecting a socket
#
Call Permission.accessLocalNetwork.request()
before opening a Dart socket connection.
The following example demonstrates how to check the platform, request local network permission, and open a socket connection:
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:permission_handler/permission_handler.dart';
Future<void> connectToLocalDevice({
required String host,
required int port,
}) async {
// Check and request runtime permission on Android.
if (Platform.isAndroid) {
final status = await Permission.accessLocalNetwork.request();
if (status.isPermanentlyDenied) {
// The user opted not to grant permission and checked "Don't ask again".
// In a real app, show an explanation dialog before calling openAppSettings().
debugPrint('Permission permanently denied. Please enable it in settings.');
return;
}
if (!status.isGranted) {
// Handle the case where the user denied permission.
debugPrint('Local network permission was denied.');
return;
}
}
// Connect the Dart socket after the permission is granted.
try {
final socket = await Socket.connect(
host,
port,
timeout: const Duration(seconds: 5),
);
debugPrint(
'Connected to ${socket.remoteAddress.address}:${socket.remotePort}',
);
// Use the socket...
await socket.close();
} on SocketException catch (e) {
debugPrint('Failed to connect: $e');
}
}
Handle permission status
#
The Permission.accessLocalNetwork.request() method
returns a PermissionStatus enum that indicates the outcome:
-
PermissionStatus.granted: The user granted local network access. You can proceed to connect your Dart sockets. -
PermissionStatus.denied: The user denied permission for this request. Prompt the user with an explanation before requesting permission again. -
PermissionStatus.permanentlyDenied: The user denied permission permanently. CallopenAppSettings()to help the user enable permission in the system settings.
More information
#To learn more about local network permissions and socket programming, consult the following resources:
- Android developer guide on Local network permission
-
permission_handlerpackage on pub.dev -
Dart
Socketclass documentation - Issue #184859 on GitHub
Unless stated otherwise, the documentation on this site reflects Flutter 3.44.7. Page last updated on 2026-08-25. View source or report an issue.