Ağa bağlanma

Uygulamanızda ağ işlemleri gerçekleştirmek için manifest dosyanızda aşağıdaki izinler bulunmalıdır:

<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ğ işlevi eklemeden önce, ağ üzerinden veri ve bilgi aktarırken uygulamanızdaki verilerin ve bilgilerin güvende kalmasını sağlamanız gerekir. Bunun için aşağıdaki ağ güvenliğiyle ilgili en iyi uygulamalardan yararlanın:

  • Ağ üzerinden ilettiğiniz hassas veya kişisel kullanıcı verilerinin 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 veya güvenli iletişim için güvendiği sistem CA'ları grubunu kısıtlamasını sağlayan bir ağ güvenliği yapılandırması oluşturabilirsiniz.

Güvenli ağ ilkelerinin nasıl uygulanacağı hakkında daha fazla bilgi için ağ güvenliği ipuçları başlıklı makaleyi inceleyin.

HTTP istemcisi seçme

Ağa bağlı uygulamaların çoğu, veri göndermek ve almak için HTTP kullanır. Android platformu; TLS, akış yüklemeleri ve indirmeleri, yapılandırılabilir zaman aşımları, IPv6 ve bağlantı havuzu oluşturmayı destekleyen HttpsURLConnection istemcisini içerir.

Ağ işlemleri için daha üst düzey API'ler sunan üçüncü taraf kitaplıkları da mevcuttur. Bu kitaplıklar, istek gövdelerinin serileştirilmesi ve yanıt gövdelerinin serileştirmenin kaldırılması gibi çeşitli kolaylık özellikleri sunar.

  • Retrofit: Square tarafından JVM için geliştirilen, OkHttp tabanlı, tip güvenli bir HTTP istemcisidir. Retrofit, istemci arayüzünü bildirimli olarak oluşturmanıza olanak tanır ve çeşitli serileştirme kitaplıklarını destekler.
  • Ktor: JetBrains'in tamamen Kotlin için oluşturulmuş ve eş yordamlarla desteklenen bir HTTP istemcisidir. Ktor çeşitli motorları, serileştiricileri ve platformları destekler.

DNS sorgularını çözme

Android 10 (API düzeyi 29) ve sonraki sürümleri çalıştıran cihazlar, hem şifresiz metin aramaları hem de TLS üzerinden DNS modu aracılığıyla özel DNS aramaları için yerleşik desteğe sahiptir. DnsResolver API'si, SRV, NAPTR ve diğer kayıt türlerini aramanıza olanak tanıyan genel, eşzamansız çözümleme sağlar. Yanıtın ayrıştırılması uygulamaya bırakılır.

Android 9 (API düzeyi 28) ve önceki sürümlerin yüklü olduğu cihazlarda platform DNS çözümleyicisi yalnızca A ve AAAA kayıtlarını destekler. Bu sayede, bir adla ilişkili IP adreslerini arayabilirsiniz ancak diğer kayıt türleri desteklenmez.

NDK tabanlı uygulamalar için android_res_nsend sayfasına bakın.

Ağ işlemlerini bir depo ile kapsülleme

Ağ işlemlerini gerçekleştirme sürecini basitleştirmek ve uygulamanızın çeşitli bölümlerinde kod kopyalamayı azaltmak için depo tasarım desenini kullanabilirsiniz. Depo, veri işlemlerini yöneten ve belirli bir veri veya kaynak ü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 için 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);
}

Bir 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 depolanma biçiminde gelecekte yapılacak değişiklikler de depo sınıfından ayrı tutulur. Örneğin, API uç noktalarında güncelleme gibi uzaktan bir değişiklik yapmanız gerekebilir veya yerel önbelleğe alma özelliğini 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şturmamak için ana iş parçacığında ağ işlemleri gerçekleştirmeyin. Android, varsayılan olarak ağ işlemlerini ana kullanıcı arayüzü iş parçacığı dışında bir iş parçacığında gerçekleştirmenizi gerektirir. Ana iş parçacığında ağ işlemleri gerçekleştirmeye çalışırsanız NetworkOnMainThreadException hatası verilir.

Önceki kod örneğinde ağ işlemi aslında tetiklenmez. UserRepository işlevini çağıran, iş parçacığı oluşturma işlemini eş yordamlar veya enqueue() işleviyle uygulamalıdır. Daha fazla bilgi için Kotlin eş yordamlarını kullanarak iş parçacığı oluşturmayı gösteren İnternetten veri alma codelab'ine bakın.

Yapılandırma değişikliklerini koruma

Ekran döndürme gibi bir yapılandırma değişikliği olduğunda fragment'ınız veya etkinliğiniz yok edilir ve yeniden oluşturulur. Yalnızca küçük miktarlarda veri tutabilen fragment etkinliğinizin örnek durumuna kaydedilmeyen tüm veriler kaybolur. Bu durumda, ağ isteklerinizi tekrar yapmanız gerekebilir.

Verilerinizin yapılandırma değişikliklerinden etkilenmemesi için ViewModel kullanabilirsiniz. ViewModel bileşeni, kullanıcı arayüzüyle ilgili verileri yaşam döngüsüne duyarlı bir şekilde depolamak ve yönetmek için tasarlanmıştır. Önceki UserRepository kullanılarak 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 konu hakkında daha fazla bilgi edinmek için aşağıdaki ilgili kılavuzları inceleyin: