নেটওয়ার্কে সংযোগ করুন

আপনার অ্যাপ্লিকেশনে নেটওয়ার্ক ক্রিয়াকলাপ সম্পাদন করতে, আপনার ম্যানিফেস্টে নিম্নলিখিত অনুমতিগুলি অন্তর্ভুক্ত করতে হবে:

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

নিরাপদ নেটওয়ার্ক যোগাযোগের জন্য সর্বোত্তম অনুশীলন

আপনি আপনার অ্যাপে নেটওয়ার্কিং কার্যকারিতা যোগ করার আগে, আপনাকে নিশ্চিত করতে হবে যে আপনার অ্যাপের মধ্যে থাকা ডেটা এবং তথ্য যখন আপনি একটি নেটওয়ার্কের মাধ্যমে ট্রান্সমিট করছেন তখন নিরাপদ থাকবে৷ এটি করতে, এই নেটওয়ার্কিং নিরাপত্তা সর্বোত্তম অনুশীলনগুলি অনুসরণ করুন:

  • সংবেদনশীল বা ব্যক্তিগত ব্যবহারকারীর ডেটার পরিমাণ কম করুন যা আপনি নেটওয়ার্কে প্রেরণ করেন।
  • SSL এর মাধ্যমে আপনার অ্যাপ থেকে সমস্ত নেটওয়ার্ক ট্রাফিক পাঠান।
  • একটি নেটওয়ার্ক নিরাপত্তা কনফিগারেশন তৈরি করার কথা বিবেচনা করুন, যা আপনার অ্যাপকে কাস্টম সার্টিফিকেট কর্তৃপক্ষ (CAs) বিশ্বাস করতে দেয় বা নিরাপদ যোগাযোগের জন্য এটি বিশ্বাস করে এমন সিস্টেম CA-এর সেটকে সীমাবদ্ধ করতে দেয়।

নিরাপদ নেটওয়ার্কিং নীতিগুলি কীভাবে প্রয়োগ করবেন সে সম্পর্কে আরও তথ্যের জন্য, নেটওয়ার্কিং নিরাপত্তা টিপস দেখুন।

একটি HTTP ক্লায়েন্ট চয়ন করুন

বেশিরভাগ নেটওয়ার্ক-সংযুক্ত অ্যাপ ডেটা পাঠাতে এবং গ্রহণ করতে HTTP ব্যবহার করে। অ্যান্ড্রয়েড প্ল্যাটফর্মে HttpsURLConnection ক্লায়েন্ট রয়েছে, যা TLS, স্ট্রিমিং আপলোড এবং ডাউনলোড, কনফিগারযোগ্য টাইমআউট, IPv6 এবং সংযোগ পুলিং সমর্থন করে।

থার্ড-পার্টি লাইব্রেরি যা নেটওয়ার্কিং অপারেশনের জন্য উচ্চ-স্তরের API অফার করে। এগুলি বিভিন্ন সুবিধার বৈশিষ্ট্যগুলিকে সমর্থন করে, যেমন অনুরোধ সংস্থাগুলির ক্রমিককরণ এবং প্রতিক্রিয়া সংস্থাগুলির ডিসিরিয়ালাইজেশন৷

  • Retrofit : স্কোয়ার থেকে JVM-এর জন্য একটি টাইপ-নিরাপদ HTTP ক্লায়েন্ট, OkHttp-এর উপরে নির্মিত। রেট্রোফিট আপনাকে ঘোষণামূলকভাবে একটি ক্লায়েন্ট ইন্টারফেস তৈরি করতে দেয় এবং বেশ কয়েকটি সিরিয়ালাইজেশন লাইব্রেরির জন্য সমর্থন রয়েছে।
  • Ktor : JetBrains থেকে একটি HTTP ক্লায়েন্ট, সম্পূর্ণরূপে Kotlin এর জন্য নির্মিত এবং coroutines দ্বারা চালিত। Ktor বিভিন্ন ইঞ্জিন, সিরিয়ালাইজার এবং প্ল্যাটফর্ম সমর্থন করে।

DNS প্রশ্নের সমাধান করুন

যে ডিভাইসগুলি Android 10 (API স্তর 29) এবং উচ্চতর চালায় সেগুলিতে ক্লিয়ারটেক্সট লুকআপ এবং DNS-ওভার-TLS মোড উভয়ের মাধ্যমে বিশেষায়িত DNS লুকআপের জন্য অন্তর্নির্মিত সমর্থন রয়েছে। DnsResolver API জেনেরিক, অ্যাসিঙ্ক্রোনাস রেজোলিউশন প্রদান করে, যা আপনাকে SRV , NAPTR এবং অন্যান্য রেকর্ডের ধরন দেখতে দেয়। প্রতিক্রিয়া পার্সিং সঞ্চালনের জন্য অ্যাপে ছেড়ে দেওয়া হয়।

যে ডিভাইসগুলিতে Android 9 (API লেভেল 28) এবং তার নিচে চলে, প্ল্যাটফর্ম DNS সমাধানকারী শুধুমাত্র A এবং AAAA রেকর্ড সমর্থন করে। এটি আপনাকে একটি নামের সাথে সম্পর্কিত IP ঠিকানাগুলি সন্ধান করতে দেয় তবে অন্য কোনও রেকর্ডের ধরন সমর্থন করে না।

NDK-ভিত্তিক অ্যাপগুলির জন্য, android_res_nsend দেখুন।

একটি সংগ্রহস্থলের সাথে নেটওয়ার্ক ক্রিয়াকলাপগুলিকে এনক্যাপসুলেট করুন৷

নেটওয়ার্ক ক্রিয়াকলাপ সম্পাদনের প্রক্রিয়া সহজ করতে এবং আপনার অ্যাপের বিভিন্ন অংশে কোড সদৃশতা কমাতে, আপনি সংগ্রহস্থল ডিজাইন প্যাটার্ন ব্যবহার করতে পারেন। একটি সংগ্রহস্থল হল একটি শ্রেণী যা ডেটা অপারেশন পরিচালনা করে এবং কিছু নির্দিষ্ট ডেটা বা সংস্থানের উপর একটি পরিষ্কার API বিমূর্ততা প্রদান করে।

আপনি একটি ইন্টারফেস ঘোষণা করতে Retrofit ব্যবহার করতে পারেন যা HTTP পদ্ধতি, URL, আর্গুমেন্ট এবং নেটওয়ার্ক ক্রিয়াকলাপের জন্য প্রতিক্রিয়ার ধরন নির্দিষ্ট করে, যেমন নিম্নলিখিত উদাহরণে:

কোটলিন

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

জাভা

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

একটি রিপোজিটরি ক্লাসের মধ্যে, ফাংশনগুলি নেটওয়ার্ক অপারেশনগুলিকে এনক্যাপসুলেট করতে পারে এবং তাদের ফলাফল প্রকাশ করতে পারে। এই এনক্যাপসুলেশন নিশ্চিত করে যে উপাদানগুলি যেগুলি সংগ্রহস্থলকে কল করে তাদের ডেটা কীভাবে সংরক্ষণ করা হয় তা জানতে হবে না। ডেটা কীভাবে সংরক্ষণ করা হয় তার ভবিষ্যতের যে কোনও পরিবর্তনগুলি সংগ্রহস্থল শ্রেণিতেও বিচ্ছিন্ন হয়। উদাহরণস্বরূপ, আপনার কাছে একটি দূরবর্তী পরিবর্তন হতে পারে যেমন API এন্ডপয়েন্টে একটি আপডেট, অথবা আপনি স্থানীয় ক্যাশিং প্রয়োগ করতে চাইতে পারেন।

কোটলিন

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

জাভা

class UserRepository {
    private UserService userService;

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

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

একটি অপ্রতিক্রিয়াশীল UI তৈরি করা এড়াতে, প্রধান থ্রেডে নেটওয়ার্ক ক্রিয়াকলাপগুলি সম্পাদন করবেন না৷ ডিফল্টরূপে, Android এর জন্য আপনাকে প্রধান UI থ্রেড ছাড়া অন্য কোনো থ্রেডে নেটওয়ার্ক অপারেশন করতে হবে। আপনি যদি প্রধান থ্রেডে নেটওয়ার্ক অপারেশন করার চেষ্টা করেন, একটি NetworkOnMainThreadException নিক্ষেপ করা হয়।

পূর্ববর্তী কোড উদাহরণে, নেটওয়ার্ক অপারেশন আসলে ট্রিগার হয় না। UserRepository এর কলারকে অবশ্যই coroutines ব্যবহার করে অথবা enqueue() ফাংশন ব্যবহার করে থ্রেডিং বাস্তবায়ন করতে হবে। আরও তথ্যের জন্য, কোডল্যাব দেখুন ইন্টারনেট থেকে ডেটা পান , যা কোটলিন কোরোটিন ব্যবহার করে থ্রেডিং কীভাবে প্রয়োগ করতে হয় তা প্রদর্শন করে।

কনফিগারেশন পরিবর্তন বাঁচা

যখন একটি কনফিগারেশন পরিবর্তন ঘটে, যেমন একটি স্ক্রীন ঘূর্ণন, আপনার খণ্ড বা কার্যকলাপ ধ্বংস এবং পুনরায় তৈরি করা হয়। আপনার টুকরো কার্যকলাপের জন্য ইনস্ট্যান্স অবস্থায় সংরক্ষিত না হওয়া কোনো ডেটা, যা শুধুমাত্র অল্প পরিমাণে ডেটা ধারণ করতে পারে, হারিয়ে গেছে। যদি এটি ঘটে, তাহলে আপনাকে আবার আপনার নেটওয়ার্ক অনুরোধ করতে হতে পারে।

আপনার ডেটা কনফিগারেশন পরিবর্তনগুলিকে বাঁচতে দেওয়ার জন্য আপনি একটি ViewModel ব্যবহার করতে পারেন৷ ViewModel উপাদানটি জীবনচক্র-সচেতন উপায়ে UI- সম্পর্কিত ডেটা সংরক্ষণ এবং পরিচালনা করার জন্য ডিজাইন করা হয়েছে। পূর্ববর্তী UserRepository ব্যবহার করে, ViewModel প্রয়োজনীয় নেটওয়ার্ক অনুরোধ করতে পারে এবং LiveData ব্যবহার করে আপনার খণ্ড বা কার্যকলাপের ফলাফল প্রদান করতে পারে:

কোটলিন

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
            }

        }
    }
}

জাভা

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
            }
        });
    }
}

এই বিষয় সম্পর্কে আরও জানতে, নিম্নলিখিত সম্পর্কিত নির্দেশিকাগুলি দেখুন: