Ağa bağlanma

Uygulamanızda ağ işlemleri gerçekleştirmek için manifest dosyanız aşağıdaki izinleri içermelidir:

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

Güvenli ağ iletişimi için en iyi uygulamalar

Uygulamanıza ağ iletişimi işlevi eklemeden önce, ağ üzerinden aktarım yaparken uygulamanızdaki verilerin ve bilgilerin güvende olduğundan emin olmanız gerekir. Bunu yapmak için ağ güvenliğiyle ilgili şu en iyi uygulamaları izleyin:

  • Ağ üzerinden ilettiğiniz hassas veya kişisel kullanıcı verisi miktarını en aza indirin.
  • Uygulamanızdan gelen tüm ağ trafiğini SSL üzerinden gönderin.
  • Uygulamanızın özel sertifika yetkililerine (CA) güvenmesini sağlayan veya güvenli iletişim için güvendiği sistem CA'larını kısıtlayan bir ağ güvenliği yapılandırması oluşturabilirsiniz.

Güvenli ağ iletişimi ilkelerini uygulama hakkında daha fazla bilgi için ağ iletişimi güvenlik ipuçlarına bakın.

HTTP istemcisi seçin

Ağa bağlı uygulamaların çoğu veri gönderip almak için HTTP kullanır. Android platformu; TLS'yi, yükleme ve indirme işlemlerini, yapılandırılabilir zaman aşımlarını, IPv6'yı ve bağlantı havuzlamayı destekleyen HttpsURLConnection istemcisini içerir.

Ağ iletişimi işlemleri için üst düzey API'ler sunan üçüncü taraf kitaplıkları da kullanabilirsiniz. Bunlar, istek gövdelerinin serileştirilmesi ve yanıt gövdelerinin seri durumdan çıkarılması gibi çeşitli kolaylık özelliklerini destekler.

  • Retrofit: OkHttp tabanlı, Square'den JVM için tür güvenli bir HTTP istemcisi. Retrofit, bildirimli şekilde bir istemci arayüzü oluşturmanıza olanak tanır ve çeşitli serileştirme kitaplıklarını destekler.
  • Ktor: JetBrains'den tamamen Kotlin için oluşturulmuş ve eş yordamlarla desteklenen bir HTTP istemcisidir. Ktor çeşitli motorları, seri izleyicileri ve platformları destekler.

DNS sorgularını çözme

Android 10 (API düzeyi 29) ve sonraki sürümleri çalıştıran cihazlar, hem düz metin aramaları hem de TLS üzerinden DNS modu aracılığıyla özel DNS aramaları için yerleşik desteğe sahiptir. DnsResolver API, SRV, NAPTR ve diğer kayıt türlerini arayabilmenizi sağlayan genel, eşzamansız çözünürlük sağlar. Yanıtın ayrıştırılması işlemi gerçekleştirmek için uygulamaya bırakılır.

Android 9 (API düzeyi 28) ve önceki sürümleri çalıştıran cihazlarda platform DNS çözümleyici yalnızca A ve AAAA kayıtlarını destekler. Bu işlem, bir adla ilişkilendirilmiş IP adreslerini arayabilmenizi sağlar ancak diğer kayıt türlerini desteklemez.

NDK tabanlı uygulamalar için android_res_nsend bölümüne bakın.

Ağ işlemlerini bir depoyla kapsama

Ağ işlemleri gerçekleştirme sürecini basitleştirmek ve uygulamanızın çeşitli bölümlerinde kod yinelemesini azaltmak için depo tasarımı kalıbını kullanabilirsiniz. Depo, veri işlemlerini işleyen ve bazı belirli veri veya kaynaklar üzerinde temiz bir API soyutlaması sağlayan bir sınıftır.

Aşağıdaki örnekte olduğu gibi, ağ işlemleri için HTTP yöntemini, URL'yi, bağımsız değişkenleri ve yanıt türünü belirten bir arayüz tanımlamak üzere Retrofit'i kullanabilirsiniz:

Kotlin

interface UserService {
    @GET("/users/{id}")
    suspend fun getUser(@Path("id") id: String): User
}

Java

public interface UserService {
    @GET("/user/{id}")
    Call<User> getUserById(@Path("id") String id);
}

Depo sınıfında, işlevler ağ işlemlerini kapsayabilir ve sonuçlarını gösterebilir. Bu kapsülleme, depoyu çağıran bileşenlerin, verilerin nasıl depolandığını bilmesine gerek kalmamasını sağlar. Verilerin depolanmasıyla ilgili gelecekte yapılacak değişiklikler de depo sınıfında izole edilir. Örneğin, API uç noktalarında güncelleme gibi uzaktan bir değişikliğiniz olabilir veya yerel önbelleğe almayı uygulamak isteyebilirsiniz.

Kotlin

class UserRepository constructor(
    private val userService: UserService
) {
    suspend fun getUserById(id: String): User {
        return userService.getUser(id)
    }
}

Java

class UserRepository {
    private UserService userService;

    public UserRepository(
            UserService userService
    ) {
        this.userService = userService;
    }

    public Call<User> getUserById(String id) {
        return userService.getUser(id);
    }
}

Yanıt vermeyen bir kullanıcı arayüzü oluşturmaktan kaçınmak için ana iş parçacığında ağ işlemleri gerçekleştirmeyin. Android, varsayılan olarak ana kullanıcı arayüzü iş parçacığı dışında bir iş parçacığı üzerinde ağ işlemleri gerçekleştirmenizi gerektirir. Ana iş parçacığında ağ işlemleri gerçekleştirmeye çalışırsanız NetworkOnMainThreadException hatası gönderilir.

Önceki kod örneğinde, ağ işlemi aslında tetiklenmez. UserRepository çağrısını yapan kişi, eş yordamları veya enqueue() işlevini kullanarak iş parçacıklarını uygulamalıdır. Daha fazla bilgi için Kotlin eş yordamlarını kullanarak iş parçacıklarının nasıl uygulanacağını gösteren İnternetten veri alma adlı codelab'e bakın.

Yapılandırma değişikliklerinden kurtulun

Ekran döndürme gibi bir yapılandırma değişikliği gerçekleştiğinde, parçanız veya etkinliğiniz kaldırılır ve yeniden oluşturulur. Çok az miktarda veri depolayabilen, parça etkinliğiniz için örnek durumuna kaydedilmemiş tüm veriler kaybolur. Bu durumda, ağ isteklerinizi tekrar göndermeniz gerekebilir.

Verilerinizin yapılandırma değişikliklerinden etkilenmemesi için ViewModel kullanabilirsiniz. ViewModel bileşeni, kullanıcı arayüzü ile ilgili verileri yaşam döngüsüne duyarlı bir şekilde depolamak ve yönetmek için tasarlanmıştır. Önceki UserRepository ile ViewModel, gerekli ağ isteklerini yapabilir ve LiveData kullanarak sonucu parçanıza veya etkinliğinize sağlayabilir:

Kotlin

class MainViewModel constructor(
    savedStateHandle: SavedStateHandle,
    userRepository: UserRepository
) : ViewModel() {
    private val userId: String = savedStateHandle["uid"] ?:
        throw IllegalArgumentException("Missing user ID")

    private val _user = MutableLiveData<User>()
    val user = _user as LiveData<User>

    init {
        viewModelScope.launch {
            try {
                // Calling the repository is safe as it moves execution off
                // the main thread
                val user = userRepository.getUserById(userId)
                _user.value = user
            } catch (error: Exception) {
                // Show error message to user
            }

        }
    }
}

Java

class MainViewModel extends ViewModel {

    private final MutableLiveData<User> _user = new MutableLiveData<>();
    LiveData<User> user = (LiveData<User>) _user;

    public MainViewModel(
            SavedStateHandle savedStateHandle,
            UserRepository userRepository
    ) {
        String userId = savedStateHandle.get("uid");
        Call<User> userCall = userRepository.getUserById(userId);
        userCall.enqueue(new Callback<User>() {
            @Override
            public void onResponse(Call<User> call, Response<User> response) {
                if (response.isSuccessful()) {
                    _user.setValue(response.body());
                }
            }

            @Override
            public void onFailure(Call<User> call, Throwable t) {
                // Show error message to user
            }
        });
    }
}

Bu konuyla ilgili daha fazla bilgi edinmek için aşağıdaki ilgili kılavuzlara bakın: