لتنفيذ عمليات الشبكة في تطبيقك، يجب أن يتضمّن ملف البيان الأذونات التالية:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
أفضل الممارسات لتأمين الاتصال بالشبكة
قبل إضافة وظائف الشبكات إلى تطبيقك، عليك التأكّد من أنّ البيانات والمعلومات داخل تطبيقك تظل آمنة عند نقلها عبر الشبكة. لإجراء ذلك، اتّبِع أفضل ممارسات أمان الشبكات التالية:
- قلِّل كمية بيانات المستخدمين الحساسة أو الشخصية التي تنقلها عبر الشبكة.
- أرسِل كل حركة بيانات الشبكة من تطبيقك عبر طبقة المقابس الآمنة (SSL).
- ننصحك بإنشاء إعدادات أمان الشبكة، ما يتيح لتطبيقك الوثوق بمراجع التصديق (CA) المخصّصة أو حصر مجموعة مراجع التصديق التابعة للنظام التي يثق بها من أجل الاتصال الآمن.
لمزيد من المعلومات حول كيفية تطبيق مبادئ الشبكات الآمنة، يُرجى الاطّلاع على نصائح أمان الشبكات.
اختيار عميل HTTP
تستخدم معظم التطبيقات المتصلة بالشبكة بروتوكول HTTP لإرسال البيانات واستلامها. يتضمّن نظام Android الأساسي برنامج HttpsURLConnection الذي يتيح استخدام بروتوكول أمان طبقة النقل (TLS) وعمليات التحميل والتنزيل المباشرة ومهلات قابلة للضبط وبروتوكول IPv6 وتجميع الاتصالات.
تتوفّر أيضًا مكتبات تابعة لجهات خارجية تقدّم واجهات برمجة تطبيقات ذات مستوى أعلى لعمليات الشبكات. وتتيح هذه المكتبات استخدام ميزات ملائمة مختلفة، مثل تسلسل نصوص الطلبات وإلغاء تسلسل نصوص الردود.
- Retrofit: هو عميل HTTP من Square يمنع أخطاء الكتابة في جهاز Java الافتراضي (JVM)، وهو مصمَّم على أساس OkHttp. تتيح لك Retrofit إنشاء واجهة عميل بشكل تعريفي، وتوفّر إمكانية استخدام عدة مكتبات تسلسل.
- Ktor: هو عميل HTTP من JetBrains، تم إنشاؤه بالكامل للغة Kotlin ويعمل من خلال الدوال الروتينية. يتوافق Ktor مع العديد من المحركات والمسلسلات والمنصات.
حلّ طلبات البحث لنظام أسماء النطاقات
تتضمّن الأجهزة التي تعمل بالإصدار 10 من نظام التشغيل Android (مستوى واجهة برمجة التطبيقات 29) والإصدارات الأحدث دعمًا مدمجًا لعمليات بحث نظام أسماء النطاقات المتخصّصة من خلال عمليات البحث عن النص غير المرمّز ووضع "نظام أسماء النطاقات عبر بروتوكول أمان طبقة النقل".
توفّر واجهة برمجة التطبيقات DnsResolver دقة عامة غير متزامنة تتيح لك البحث عن SRV وNAPTR وأنواع السجلات الأخرى. ويُترك تحليل الردّ للتطبيق.
على الأجهزة التي تعمل بالإصدار 9 من نظام التشغيل Android (المستوى 28 من واجهة برمجة التطبيقات) والإصدارات الأقدم، لا يتيح برنامج تعيين نظام أسماء النطاقات في النظام الأساسي سوى سجلّات A وAAAA. يتيح لك ذلك البحث عن عناوين IP المرتبطة باسم معيّن، ولكنّه لا يتيح استخدام أي أنواع سجلّات أخرى.
بالنسبة إلى التطبيقات المستندة إلى NDK، يُرجى الاطّلاع على
android_res_nsend.
تغليف عمليات الشبكة باستخدام مستودع
لتبسيط عملية تنفيذ عمليات الشبكة وتقليل تكرار الرموز البرمجية في أجزاء مختلفة من تطبيقك، يمكنك استخدام نمط تصميم المستودع. المستودع هو فئة تعالج عمليات البيانات وتوفّر تجريدًا واضحًا لواجهة برمجة التطبيقات على بعض البيانات أو الموارد المحدّدة.
يمكنك استخدام Retrofit لتعريف واجهة تحدّد طريقة HTTP وعنوان URL والوسيطات ونوع الاستجابة لعمليات الشبكة، كما في المثال التالي:
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); }
ضمن فئة المستودع، يمكن للدوال أن تتضمّن عمليات الشبكة وتعرض نتائجها. يضمن هذا التغليف أنّ المكوّنات التي تستدعي المستودع لا تحتاج إلى معرفة كيفية تخزين البيانات. أي تغييرات مستقبلية على كيفية تخزين البيانات يتم عزلها إلى فئة المستودع أيضًا. على سبيل المثال، قد يكون لديك تغيير عن بُعد مثل تحديث نقاط نهاية واجهة برمجة التطبيقات، أو قد ترغب في تنفيذ التخزين المؤقت المحلي.
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); } }
لتجنُّب إنشاء واجهة مستخدم غير مستجيبة، لا تُجرِ عمليات الشبكة على سلسلة التعليمات الرئيسية. يتطلّب منك Android تلقائيًا إجراء عمليات الشبكة على سلسلة تعليمات أخرى غير سلسلة واجهة المستخدم الرئيسية. إذا حاولت تنفيذ عمليات الشبكة
على سلسلة التعليمات الرئيسية،
سيتم طرح NetworkOnMainThreadException.
في مثال الرمز السابق، لا يتم تشغيل عملية الشبكة فعليًا. يجب أن ينفّذ المتصل بـ UserRepository
سلسلة المحادثات إما باستخدام الكوروتين أو باستخدام الدالة enqueue(). لمزيد من المعلومات، يمكنك الاطّلاع على الدرس التطبيقي حول الترميز الحصول على البيانات من الإنترنت، والذي يوضّح كيفية تنفيذ سلاسل المحادثات باستخدام وظائف Kotlin coroutines.
الاحتفاظ بالبيانات عند تغيير الإعدادات
عند حدوث تغيير في الإعدادات، مثل تدوير الشاشة، يتم تدمير الجزء أو النشاط وإعادة إنشائه. يتم فقدان أي بيانات لم يتم حفظها في حالة المثيل لنشاط الجزء، والتي يمكن أن تحتوي فقط على كميات صغيرة من البيانات. في هذه الحالة، قد تحتاج إلى إجراء طلبات الشبكة مرة أخرى.
يمكنك استخدام ViewModel للسماح
لبياناتك بالبقاء بعد تغييرات الإعدادات. تم تصميم مكوّن ViewModel لتخزين البيانات ذات الصلة بواجهة المستخدم وإدارتها بطريقة تراعي مراحل النشاط. باستخدام UserRepository السابق، يمكن لـ ViewModel إجراء طلبات الشبكة اللازمة وتقديم النتيجة إلى الجزء أو النشاط باستخدام LiveData:
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 } }); } }
الاطّلاع على الأدلة ذات الصلة
لمزيد من المعلومات حول هذا الموضوع، يُرجى الاطّلاع على الأدلة التالية ذات الصلة:
- نظرة عامة حول تقليل استنزاف البطارية بسبب الشبكة
- الحدّ من تأثير التحديثات المنتظمة
- المحتوى المستنِد إلى الويب
- أساسيات التطبيق
- دليل بنية التطبيق