কম্পিউটার টিউটোরিয়াল

অ্যান্ড্রয়েডে উপলব্ধ ওয়াইফাই নেটওয়ার্ক স্ক্যান করে লিস্টভিউতে দেখানোর পদ্ধতি

অ্যান্ড্রয়েডে ওয়াইফাই স্ক্যানিং করার জন্য WifiManager এবং BroadcastReceiver ব্যবহার করা হয়। Android 6.0 (Marshmallow, API 23) থেকে লোকেশন পারমিশন (`ACCESS_COARSE_LOCATION` বা `ACCESS_FINE_LOCATION`) বাধ্যতামূলক হয়েছে ওয়াইফাই স্ক্যান রেজাল্ট পাওয়ার জন্য। এই টিউটোরিয়ালে একটি সম্পূর্ণ ওয়াইফাই স্ক্যানার অ্যাপ বানানো দেখানো হলো।

প্রয়োজনীয় পারমিশনস (AndroidManifest.xml)

<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<!-- Android 13+ এর জন্য -->
<uses-permission android:name="android.permission.NEARBY_WIFI_DEVICES" 
    android:usesPermissionFlags="neverForLocation" />

১. activity_main.xml (লেআউট)

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="https://schemas.android.com/apk/res/android"
    xmlns:tools="https://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_margin="16dp"
    tools:context=".MainActivity">

    <ListView
        android:id="@+id/wifiList"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_above="@+id/scanBtn"
        android:divider="@android:color/darker_gray"
        android:dividerHeight="1dp" />

    <Button
        android:id="@+id/scanBtn"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:layout_alignParentBottom="true"
        android:layout_margin="15dp"
        android:text="Scan WiFi"
        android:textSize="16sp"
        android:backgroundTint="@color/colorPrimary"
        android:textColor="@android:color/white" />
</RelativeLayout>

২. MainActivity.java

package com.example.wifiscanner;

import android.Manifest;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiManager;
import android.os.Build;
import android.os.Bundle;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {

    private ListView wifiListView;
    private WifiManager wifiManager;
    private Button scanButton;
    private WifiScanReceiver wifiReceiver;
    private static final int LOCATION_PERMISSION_REQUEST_CODE = 1001;
    private ArrayAdapter adapter;
    private List wifiNetworkList = new ArrayList<>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        wifiListView = findViewById(R.id.wifiList);
        scanButton = findViewById(R.id.scanBtn);
        wifiManager = (WifiManager) getApplicationContext().getSystemService(WIFI_SERVICE);

        // অ্যাডাপ্টার ইনিশিয়ালাইজ
        adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, wifiNetworkList);
        wifiListView.setAdapter(adapter);

        // ওয়াইফাই অফ থাকলে অন করা
        if (wifiManager != null && !wifiManager.isWifiEnabled()) {
            Toast.makeText(this, "WiFi চালু করা হচ্ছে...", Toast.LENGTH_SHORT).show();
            wifiManager.setWifiEnabled(true);
        }

        scanButton.setOnClickListener(v -> requestPermissionAndScan());
    }

    private void requestPermissionAndScan() {
        // Android 13+ (API 33) NEARBY_WIFI_DEVICES পারমিশন চেক
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
            if (ContextCompat.checkSelfPermission(this, Manifest.permission.NEARBY_WIFI_DEVICES) 
                    != PackageManager.PERMISSION_GRANTED) {
                ActivityCompat.requestPermissions(this, 
                    new String[]{Manifest.permission.NEARBY_WIFI_DEVICES}, 
                    LOCATION_PERMISSION_REQUEST_CODE);
                return;
            }
        } 
        // Android 6.0 - 12: ACCESS_COARSE_LOCATION বা ACCESS_FINE_LOCATION
        else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) 
                    != PackageManager.PERMISSION_GRANTED) {
                ActivityCompat.requestPermissions(this, 
                    new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, 
                    LOCATION_PERMISSION_REQUEST_CODE);
                return;
            }
        }
        // পারমিশন আছে, স্ক্যান শুরু
        startWifiScan();
    }

    private void startWifiScan() {
        if (wifiManager != null) {
            boolean success = wifiManager.startScan();
            if (!success) {
                Toast.makeText(this, "স্ক্যান শুরু হয়নি, আবার চেষ্টা করুন", Toast.LENGTH_SHORT).show();
            }
        }
    }

    @Override
    protected void onResume() {
        super.onResume();
        // ব্রডকাস্ট রিসিভার রেজিস্টার
        wifiReceiver = new WifiScanReceiver();
        IntentFilter filter = new IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
        registerReceiver(wifiReceiver, filter);
    }

    @Override
    protected void onPause() {
        super.onPause();
        // লিক এড়াতে অনরেজিস্টার
        if (wifiReceiver != null) {
            unregisterReceiver(wifiReceiver);
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == LOCATION_PERMISSION_REQUEST_CODE) {
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                Toast.makeText(this, "পারমিশন মঞ্জুর", Toast.LENGTH_SHORT).show();
                startWifiScan();
            } else {
                Toast.makeText(this, "পারমিশন অনুমতінहीं দেওয়া হয়েছে। সেটিংস থেকে দিন।", Toast.LENGTH_LONG).show();
            }
        }
    }

    // ইনার ক্লাস: ব্রডকাস্ট রিসিভার
    private class WifiScanReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (WifiManager.SCAN_RESULTS_AVAILABLE_ACTION.equals(action)) {
                if (wifiManager != null) {
                    List results = wifiManager.getScanResults();
                    wifiNetworkList.clear();
                    
                    for (ScanResult result : results) {
                        // SSID + সিকিউরিটি টাইপ (WPA2, WEP, Open ইত্যাদি)
                        String item = result.SSID + " | " + getSecurityType(result.capabilities) 
                                    + " | Signal: " + result.level + " dBm";
                        wifiNetworkList.add(item);
                    }
                    adapter.notifyDataSetChanged();
                    
                    if (results.isEmpty()) {
                        Toast.makeText(context, "কোনো নেটওয়ার্ক পাওয়া যায়নি", Toast.LENGTH_SHORT).show();
                    }
                }
            }
        }

        private String getSecurityType(String capabilities) {
            if (capabilities.contains("WPA3")) return "WPA3";
            if (capabilities.contains("WPA2")) return "WPA2";
            if (capabilities.contains("WPA")) return "WPA";
            if (capabilities.contains("WEP")) return "WEP";
            return "Open";
        }
    }
}

৩. AndroidManifest.xml (সম্পূর্ণ)

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="https://schemas.android.com/apk/res/android"
    package="com.example.wifiscanner">

    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.NEARBY_WIFI_DEVICES" 
        android:usesPermissionFlags="neverForLocation" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.WiFiScanner">

        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>

চলানোর নির্দেশনা

  1. প্রজেক্ট তৈরি করুন এবং উপরের কোডগুলো যোগ করুন।
  2. ডিভাইসে অ্যাপ ইনস্টল করুন (এমুলেটরে ওয়াইফাই স্ক্যান সাপোর্ট নেই, রিয়েল ডিভাইস দরকার)।
  3. অ্যাপ খুললে প্রথমবারের মতো লোকেশন/ওয়াইফাই পারমিশন মাগবে — Allow দিন।
  4. Scan WiFi বাটনে ক্লিক করুন।
  5. কয়েক সেকেন্ডের মধ্যে লিস্টে আশেপাশের ওয়াইফাই নেটওয়ার্কগুলো SSID, সিকিউরিটি টাইপ এবং সিগন্যাল স্ট্রেংথসহ দেখাবে।

মডার্ন অ্যান্ড্রয়েড (API 29+) এ গুরুত্বপূর্ণ পরিবর্তন

API লেভেলপরিবর্তন
API 23 (6.0)লোকেশন পারমিশন বাধ্যতামূলক
API 29 (10)নন-সিস্টেম অ্যাপের জন্য স্ক্যান থ্রটলিং (৪টি/২ মিনিট)
API 31 (12)WifiManager.startScan() ডিপ্রিকেইটেড (কনটেক্সট-বেসড)
API 33 (13)NEARBY_WIFI_DEVICES পারমিশন (লোকেশন ছাড়া)

সেরা অনুশীলন ও টিপস

  • RecyclerView ব্যবহার করুন: ListView পুরনো, RecyclerView + ViewHolder প্যাটার্ন ব্যবহার করুন।
  • করআউট ফিল্টার: হিডেন SSID বা ডুপ্লিকেট ফিল্টার করুন।
  • সিগন্যাল স্ট্রেংথ সর্ট: `result.level` অনুযায়ী ডেসেন্ডিং অর্ডারে সর্ট করুন।
  • ইন্টারনেট কানেক্টিভিটি চেক: স্ক্যানের পর কানেক্ট করার চেষ্টা করলে `NetworkCallback` ব্যবহার করুন।
  • Jetpack Compose: নये প্রজেক্টে Compose + `WifiManager` + `rememberCoroutineScope` ব্যবহার করুন।

সীমাবদ্ধতা

  • এমুলেটরে ওয়াইফাই স্ক্যান কাজ করে না (রিয়েল ডিভাইস দরকার)।
  • অ্যান্ড্রয়েড ১০+ তে ব্যাকগ্রাউন্ড স্ক্যান সীমাবদ্ধ।
  • চাইনিয়াস OEM-এ (MIUI, OneUI, ColorOS) এক্সট্রা ব্যাটারি অপ্টিমাইজেশন সেটিংস হতে পারে।

এই উদাহরণটি একটি ফাংশনাল ওয়াইফাই স্ক্যানারের বেসিক বিন্যাস দেয়। প্রোডাকশন অ্যাপে আপনি UI উন্নতি, ফিল্টার, সর্ট, কানেকশন ম্যানেজমেন্ট ইত্যাদি যোগ করতে পারেন।

  1. অ্যান্ড্রয়েড অ্যাপে ImageView-এ ছবি লোড ও প্রদর্শন করার পদ্ধতি

  2. Android-এ ইনস্টল করা অ্যাপ্লিকেশনগুলির তালিকা পাওয়ার পদ্ধতি

  3. ৫টি সবচেয়ে বিপদজনক অ্যান্ড্রয়েড ভাইরাস এবং তাদের মুছে ফেলার উপায়

  4. এন্ড্রয়েড P-র Ambient Display-এ আবহাওয়া দেখান: ধাপে ধাপে গাইড