Search code examples
androidxamarin.formsandroid-wifi

How to get list of nearby WiFi Networks in Android Xamarin.Forms?


I have searched a lot of ways on this part, on how to get a self refreshing app when getting nearby WiFi networks. But nothing has ever worked for me. So I just have tried to check this resource> How to get available wifi networks and display them in a list in android

I tried to "convert" this code into Xamarin.Forms code, but there are some issues.

  1. How to create in App.xaml a TextView, then to populate it with data from MainActivity
  2. What Content View we can set here that the app will properly work. How to set as View like Resources->Layout-> Get Main Activity (and then to create Content view). Like SetContentView(Resource.Layout.MainActivity);
using System;
using Android.App;
using Android.Content.PM;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.OS;
using Android.Content;
using System.Collections.Generic;
using Android.Net.Wifi;
using System.Text;
using Java.Lang;
using Xamarin.Forms;
using StringBuilder = System.Text.StringBuilder;
using Menu = Android.Views.Menu;

namespace MyApp.Droid
{
    [Activity(Label = "MyApp", Icon = "@mipmap/icon", Theme = "@style/MainTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation | ConfigChanges.UiMode | ConfigChanges.ScreenLayout | ConfigChanges.SmallestScreenSize)]
    public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
    {
        static TextView mainText;
        readonly Context context = Android.App.Application.Context;
        static WifiManager mainWifi;
        WifiReceiver receiverWifi;
        static List<ScanResult> wifiList;
        readonly System.Text.StringBuilder sb = new System.Text.StringBuilder();

        protected override void OnCreate(Bundle savedInstanceState)
        {
            /* Default MainActivity Data--------------------------*/
            base.OnCreate(savedInstanceState);
            TabLayoutResource = Resource.Layout.Tabbar;
            ToolbarResource = Resource.Layout.Toolbar;
            global::Xamarin.Forms.Forms.Init(context, savedInstanceState);

            /*-------------------------------------------------------*/

            SetContentView();//Here must be set the main content view ???????
            mainText = (TextView)FindViewById(Resource.Id.); // Here must get TextView Id  ???????
            mainWifi = (WifiManager)GetSystemService(Context.WifiService);

            if (mainWifi.IsWifiEnabled == false)
            {
                // If wifi disabled then enable it
                Toast.MakeText(context, "wifi is disabled..making it enabled", ToastLength.Long).Show();
                mainWifi.SetWifiEnabled(true);
            }
            receiverWifi = new WifiReceiver();
            RegisterReceiver(receiverWifi, new IntentFilter(WifiManager.ScanResultsAvailableAction));
            mainWifi.StartScan();
            char[] mine = "Starting Scan...".ToCharArray();
            int length = mine.Length;
            mainText.SetText(mine, 0, length);

            Xamarin.Essentials.Platform.Init(this, savedInstanceState);
            global::Xamarin.Forms.Forms.Init(this, savedInstanceState);

            LoadApplication(new App());
        }


        public override bool OnCreateOptionsMenu(IMenu menu)
        {
            menu.Add(0, 0, 0, "Refresh");
            return base.OnCreateOptionsMenu(menu);

        }

        public override bool OnContextItemSelected(IMenuItem item)
        {
            mainWifi.StartScan();
            char[] mine = "Starting Scan...".ToCharArray();
            int length = mine.Length;
            mainText.SetText(mine, 0, length);
            return base.OnContextItemSelected(item);

        }

        protected override void OnPause()
        {
            RegisterReceiver(receiverWifi, new IntentFilter(WifiManager.ScanResultsAvailableAction));
            base.OnPause();
        }

        protected override void OnResume()
        {
            RegisterReceiver(receiverWifi, new IntentFilter(WifiManager.ScanResultsAvailableAction));
            base.OnResume();
        }


        // Broadcast receiver class called its receive method
        // when number of wifi connections changed

        private class WifiReceiver : BroadcastReceiver
        {

            // This method call when number of wifi connections changed
            public override void OnReceive(Context context, Intent intent)
            {
                if (intent.Action.CompareTo(WifiManager.ScanResultsAvailableAction) == 0)
                {
                    var sb = new StringBuilder();
                    wifiList = (List<ScanResult>)mainWifi.ScanResults;
                    sb.Append("\n        Number Of Wifi connections :" + wifiList.Count + "\n\n");

                    for (int i = 0; i < wifiList.Count; i++)
                    {

                        sb.Append(new Integer(i + 1).ToString() + ". ");
                        sb.Append(wifiList[i].ToString());
                        sb.Append("\n\n");
                    }
                    char[] sb_t = (sb.ToString()).ToCharArray();
                    
                    mainText.SetText(sb_t,0,sb_t.Length);
                }
            }
        }

        public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Android.Content.PM.Permission[] grantResults)
        {
            Xamarin.Essentials.Platform.OnRequestPermissionsResult(requestCode, permissions, grantResults);

            base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
        }
    }
}



Solution

  • About getting Wifi list in Xamarin.forms, I do one sample using DependencyService.

    Creating interface in PCL:

     public interface IWifi
    {
        Task<IEnumerable<string>> GetAvailableNetworksAsync();
    
    }
    

    Implementing the interface on Android platform

    [assembly: Xamarin.Forms.Dependency(typeof(ListWifi.Droid.Wifi))]
    namespace ListWifi.Droid
    {
    [Activity(Label = "ListWifi", Icon = "@mipmap/icon", Theme = "@style/MainTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation | ConfigChanges.UiMode | ConfigChanges.ScreenLayout | ConfigChanges.SmallestScreenSize )]
    public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
    {
        protected override void OnCreate(Bundle savedInstanceState)
        {
            TabLayoutResource = Resource.Layout.Tabbar;
            ToolbarResource = Resource.Layout.Toolbar;
    
            base.OnCreate(savedInstanceState);
    
            Xamarin.Essentials.Platform.Init(this, savedInstanceState);
            global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
            LoadApplication(new App());
        }
        public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Android.Content.PM.Permission[] grantResults)
        {
            Xamarin.Essentials.Platform.OnRequestPermissionsResult(requestCode, permissions, grantResults);
    
            base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
        }
    }
    
    public class Wifi : IWifi
    {
        private Context context = null;
    
        public Wifi()
        {
            this.context = Android.App.Application.Context;
        }
    
        public async Task<IEnumerable<string>> GetAvailableNetworksAsync()
        {
            IEnumerable<string> availableNetworks = null;
    
            // Get a handle to the Wifi
            var wifiMgr = (WifiManager)context.GetSystemService(Context.WifiService);
            var wifiReceiver = new WifiReceiver(wifiMgr);
    
            await Task.Run(() =>
            {
                // Start a scan and register the Broadcast receiver to get the list of Wifi Networks
                context.RegisterReceiver(wifiReceiver, new IntentFilter(WifiManager.ScanResultsAvailableAction));
                availableNetworks = wifiReceiver.Scan();
            });
    
            return availableNetworks;
        }
    
     
        [BroadcastReceiver(Enabled = true, Exported = false)]
        class WifiReceiver : BroadcastReceiver
        {
            private WifiManager wifi;
            private List<string> wifiNetworks;
            private AutoResetEvent receiverARE;
            private Timer tmr;
            private const int TIMEOUT_MILLIS = 20000; // 20 seconds timeout
    
            public WifiReceiver()
            {
    
            }
            public WifiReceiver(WifiManager wifi)
            {
                this.wifi = wifi;
                wifiNetworks = new List<string>();
                receiverARE = new AutoResetEvent(false);
            }
    
            public IEnumerable<string> Scan()
            {
                tmr = new Timer(Timeout, null, TIMEOUT_MILLIS, System.Threading.Timeout.Infinite);
                wifi.StartScan();
                receiverARE.WaitOne();
                return wifiNetworks;
            }
    
            public override void OnReceive(Context context, Intent intent)
            {
                IList<ScanResult> scanwifinetworks = wifi.ScanResults;
                foreach (ScanResult wifinetwork in scanwifinetworks)
                {
                    wifiNetworks.Add(wifinetwork.Ssid);
                }
    
                receiverARE.Set();
            }
    
            private void Timeout(object sender)
            {
                // NOTE release scan, which we are using now, or we throw an error?
                receiverARE.Set();
            }
        }
    }
    
    
    }
    

    MainPage.xaml:

     <StackLayout>
        <ListView x:Name="wifilist">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <ViewCell>
                        <StackLayout>
                            <Label Text="{Binding .}" />
                        </StackLayout>
                    </ViewCell>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    
        <Button
            x:Name="btn1"
            Clicked="btn1_Clicked"
            Text="get wifi list" />
    </StackLayout>
    

    Mainpage.cs:

    private async void btn1_Clicked(object sender, EventArgs e)
        {
            _wifiService = await DependencyService.Get<IWifi>().GetAvailableNetworksAsync();
            wifilist.ItemsSource = _wifiService;
    
          
        }
    

    If you want to refresh wifi list in some time, you can use Timer to do this:

     private async void btn1_Clicked(object sender, EventArgs e)
        {
            //_wifiService = await DependencyService.Get<IWifi>().GetAvailableNetworksAsync();
            //wifilist.ItemsSource = _wifiService;
    
            Device.StartTimer(new TimeSpan(0, 0, 60), () =>
            {
                // do something every 60 seconds
                Device.BeginInvokeOnMainThread(async() =>
                {
                    _wifiService = null;
                    _wifiService = await DependencyService.Get<IWifi>().GetAvailableNetworksAsync();
                    wifilist.ItemsSource = _wifiService;
                });
                return true; // runs again, or false to stop
            });
    
        }
    

    Note: for WiFi Scanning, please permission.

    enter image description here