Keywords: Android Permissions | INTERNET Permission | Network Configuration
Abstract: This article provides a comprehensive analysis of network access permission configuration in Android applications, focusing on the declaration location and syntax of INTERNET permission. It also explores security practices for network operations, thread management, HTTP client selection, and user interface operations for permission management. Through code examples and architectural pattern analysis, it helps developers build secure and efficient network-functional applications.
Basic Network Permission Configuration
In Android application development, accessing internet resources is a common requirement, but it requires explicit declaration of appropriate permissions. When an application attempts to establish a network connection without proper permission configuration, the system throws a java.net.SocketException: Permission denied exception. The core solution to this problem is adding the INTERNET permission declaration in the AndroidManifest.xml file.
The permission declaration must be placed outside the application tag, typically as a direct child element of the manifest root element. The correct syntax example is as follows:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.myapp">
<uses-permission android:name="android.permission.INTERNET" />
<application
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name">
...
</application>
</manifest>This configuration allows the application to initiate outbound network connections. It is important to note that the INTERNET permission is a normal permission, automatically granted at installation time, and does not require runtime user authorization.
Network State Monitoring Permission
Beyond basic network connection permissions, applications often need to monitor network state changes to optimize user experience and functional logic. The ACCESS_NETWORK_STATE permission allows applications to query current network connection information, such as network type and availability.
It is recommended to declare both permissions in the manifest:
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />Through the ConnectivityManager system service, applications can detect network status. Example code is as follows:
// Kotlin implementation
val connectivityManager = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
val networkInfo = connectivityManager.activeNetworkInfo
val isConnected = networkInfo?.isConnected == true
// Java implementation
ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
boolean isConnected = networkInfo != null && networkInfo.isConnected();Network Security Best Practices
Network communication involves data transmission security, and developers should adhere to core security principles. First, minimize the transmission of sensitive data, sending only necessary information. Second, all network traffic should be encrypted via SSL/TLS to prevent man-in-the-middle attacks and data theft.
Android supports custom network security configurations, allowing applications to restrict trusted certificate authorities (CAs). Define the configuration in res/xml/network_security_config.xml:
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<domain-config cleartextTrafficPermitted="false">
<domain includeSubdomains="true">example.com</domain>
</domain-config>
</network-security-config>And reference it in the manifest:
<application
android:networkSecurityConfig="@xml/network_security_config"
...>
</application>HTTP Client Selection and Implementation
The Android platform offers multiple HTTP client options. The built-in HttpsURLConnection supports TLS, streaming uploads/downloads, and connection pooling, making it ideal for lightweight requirements.
For complex applications, third-party libraries like Retrofit or Ktor are recommended. Retrofit simplifies API calls through interface declarations and supports multiple serialization formats. The following is an example of defining a network interface with Retrofit:
// Kotlin interface definition
interface UserService {
@GET("/users/{id}")
suspend fun getUser(@Path("id") id: String): User
}
// Java interface definition
public interface UserService {
@GET("/user/{id}")
Call<User> getUserById(@Path("id") String id);
}Ktor, as a native Kotlin solution, fully leverages coroutine features, providing an asynchronous programming model.
Network Operation Thread Management
Android strictly prohibits network operations on the main thread; violating this rule results in a NetworkOnMainThreadException. Network requests must be moved to background threads.
Using Kotlin coroutines can elegantly handle asynchronous operations:
// In ViewModel or Repository
viewModelScope.launch {
try {
val user = userRepository.getUserById(userId)
// Update UI
} catch (error: Exception) {
// Handle error
}
}In Java environments, use the Call.enqueue() method:
Call<User> call = userService.getUserById(userId);
call.enqueue(new Callback<User>() {
@Override
public void onResponse(Call<User> call, Response<User> response) {
if (response.isSuccessful()) {
// Handle successful response
}
}
@Override
public void onFailure(Call<User> call, Throwable t) {
// Handle failure
}
});Architecture Patterns and Data Persistence
Adopting the Repository pattern encapsulates network operations, providing a unified data access interface. Combined with ViewModel, it ensures data survival during configuration changes (e.g., screen rotation).
Repository implementation example:
// Kotlin implementation
class UserRepository(private val userService: UserService) {
suspend fun getUserById(id: String): User {
return userService.getUser(id)
}
}
// Java implementation
class UserRepository {
private UserService userService;
public UserRepository(UserService userService) {
this.userService = userService;
}
public Call<User> getUserById(String id) {
return userService.getUserById(id);
}
}Using LiveData in ViewModel to expose data:
// Kotlin ViewModel
class MainViewModel(
savedStateHandle: SavedStateHandle,
private val userRepository: UserRepository
) : ViewModel() {
private val _user = MutableLiveData<User>()
val user: LiveData<User> = _user
init {
viewModelScope.launch {
try {
val user = userRepository.getUserById(userId)
_user.value = user
} catch (error: Exception) {
// Error handling
}
}
}
}Advanced DNS Resolution
Android 10 and higher versions extend DNS resolution capabilities, supporting queries for record types like SRV and NAPTR. The DnsResolver API provides asynchronous resolution functionality, enhancing network service discovery.
Lower version devices only support A and AAAA record queries, requiring developers to choose implementation schemes based on target API levels.
User Permission Management Interface
From the user perspective, network permission management is handled through system settings. In Android 11 and higher, users can finely control permission grant timing: always allow, allow only while using, ask every time, or deny.
Permission management path: Settings → Apps → Select app → Permissions. Users can view and modify granted permissions, including network access permissions.
For sensitive permissions like location, camera, and microphone, the system provides more granular control options, but the INTERNET permission, as a normal permission, is not included in this category.
Permission Trust and Security Considerations
Granting an application network permission implies trust in its data handling behavior. Users should examine the reasonableness of an app's functionality and permission requirements—it is reasonable for a weather app to need network permissions, but suspicious for a flashlight app to request the same.
From a developer responsibility perspective, clear data collection and usage policies should be established to avoid permission abuse. Technically, there is no guarantee that data is sent only to intended servers, making code review and third-party library audits crucial.
Security scanning tools like Google Play Protect provide an additional layer of protection, but ultimate trust is based on overall assessment of the developer and application ecosystem.