Trouble with connecting to wifi in code in Xamarin - xamarin

I've been trying to connect to a specific wifi through code, but with no succcess.
This is what i've come up with:
public void ConnectToWifi(string ssid, string password)
{
WifiManager wifiManager = (WifiManager)Android.App.Application.Context.GetSystemService(Context.WifiService);
if (!wifiManager.IsWifiEnabled)
{
wifiManager.SetWifiEnabled(true);
}
string formattedSsid = $"\"{ssid}\"";
string formattedPassword = $"\"{password}\"";
WifiConfiguration wifiConfig = new WifiConfiguration
{
Ssid = formattedSsid,
PreSharedKey = formattedPassword
};
var addNetwork = wifiManager.AddNetwork(wifiConfig);
WifiConfiguration network = wifiManager.ConfiguredNetworks.FirstOrDefault(n => n.Ssid == ssid);
if (network == null)
{
Console.WriteLine($"Cannot connect to network: {ssid}");
return;
}
wifiManager.Disconnect();
bool enableNetwork = wifiManager.EnableNetwork(network.NetworkId, true);
}
I've added permissions.
When testing it does turn the wifi on atleast, so i know it works until that point. What seems not to be working is the AddNetwork part.
I appreciate any help i can get!

You are missing one key method - reconnect(). You can read more about it in the WifiManager's docs here
The important part of the documentation is:
Reconnect to the currently active access point, if we are currently disconnected.
So, what you need to do it after you have disconnected and enabled your new network, call in the end this and you will be good to go:
wifiManager.Disconnect();
wifiManager.EnableNetwork(network.NetworkId, true);
wifiManager.Reconnect(); // This is the missing method
NB: Keep in mind that most of the WifiManager's code that you are using is being obsolete starting Android 10. So, if you want to target Android 10, then you will need to write an additional code for the connectivity for devices with Android 10+.

Related

Using libVLCsharp to stream pw protected IP Camera Video but video not playing

I am trying to construct a UI for Onvif complaint devices. I've been beating my head against the wall for sometime now. I believe I have the custom URI correctly constructed. According to the ONVIF Programmers Guide we need to Get Profiles, GetStreamURI, Request Streaming. http://www.openipcam.com/files/ONVIF/ONVIF_WG-APG-Application_Programmer's_Guide.pdf
Using Wireshark I believe I see HTTP packets being sent (showing the appropriate requests), and what I believe are appropriate responses. The final GetStreamURI gets a successful response from the camera. Then when I try to call _mp.Play I see a few packets over HTTP and a few TCP packets back back from the camera. After this communication stops.
using System;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using LibVLCSharp.Shared;
using LibVLCSharp;
using System.ServiceModel.Channels;
using Lib_vlc_CSharp_Onvif.OnvifDevice;
using System.ServiceModel;
using Lib_vlc_CSharp_Onvif.OnvifMedia;
namespace Lib_vlc_CSharp_Onvif
{
public partial class Form1 : Form
{
public LibVLC _libVLC;
public LibVLCSharp.Shared.MediaPlayer _mp;
public LibVLCSharp.Shared.Media media;
//ToDO... make screen size adjustable
public System.Drawing.Size VidSize;
public System.Drawing.Size FormSize;
public System.Drawing.Point OldVidLoc;
//Create Onvif Media Profiles through service references
OnvifMedia.Media2Client Onvif_media;
OnvifMedia.MediaProfile[] profiles;
//Custom URI variable
UriBuilder deviceUri;
public Form1()
{
InitializeComponent();
//LibVLCSharp Specific
Core.Initialize();
this.KeyPreview = true;
//Just controlling the size. TODO: Imp controls
VidSize = videoView.Size;
FormSize = this.Size;
OldVidLoc = videoView.Location;
//Vlc Specific
//Set up the Vlc Lib and then connect the Form1 media window player to the media player of the library.
//videoVew is vlcsharp item in Form1.
_libVLC = new LibVLC();
_mp = new MediaPlayer(_libVLC);
videoView.MediaPlayer = _mp;
}
private void button1_Click(object sender, EventArgs e)
{
//Set up device to get profiles (Onvif Specific)
//Required a custom URI and binding.
deviceUri = new UriBuilder("Http:/onvif/device_service");
System.ServiceModel.Channels.Binding binding;
HttpTransportBindingElement httpTransport = new HttpTransportBindingElement();
httpTransport.AuthenticationScheme = System.Net.AuthenticationSchemes.Digest;
binding = new CustomBinding(new TextMessageEncodingBindingElement(MessageVersion.Soap12, Encoding.UTF8), httpTransport);
//Assign IP Address to device URI. TODO: This eventually will be pulled from user entered value in an text box.
deviceUri.Host = "xxx.xxx.x.x";
DeviceClient Onvif_Device = new DeviceClient(binding, new EndpointAddress(deviceUri.ToString()));
OnvifDevice.Service[] service = Onvif_Device.GetServices(false);
//Check if they contain media and that we have made contact TODO wrap in a try catch block
OnvifDevice.Service xmedia = service.FirstOrDefault(s => s.Namespace == "http://www.onvif.org/ver20/media/wsdl");
if (xmedia != null)
{
Onvif_media = new Media2Client(binding, new EndpointAddress(deviceUri.ToString()));
Onvif_media.ClientCredentials.HttpDigest.ClientCredential.UserName = "admin";
Onvif_media.ClientCredentials.HttpDigest.ClientCredential.Password = "admin";
Onvif_media.ClientCredentials.HttpDigest.AllowedImpersonationLevel = System.Security.Principal.TokenImpersonationLevel.Impersonation;
//Get camera Profiles.
profiles = Onvif_media.GetProfiles(null, null);
if (profiles != null)
{
foreach (var p in profiles)
{
listBox.Items.Add(p.Name);
//Profiles listed in box match profiles setup on camera.
}
}
}
//Eventually add a selection option on the list box.
//listBox.SelectedINdexChanged += OnSelectionChanged
//If we have profiles build a custom URI to past to the vlc boject
if (profiles != null)
{
//Building URI to pass to VLCSharp VideoView Item.
//https://www.onvif.org/ver20/media/wsdl/media.wsdl
//GetSreamUri and define RtspUnicast.
//http://www.openipcam.com/files/ONVIF/ONVIF_WG-APG-Application_Programmer's_Guide.pdf on page 57&58
UriBuilder local_uri = new UriBuilder(Onvif_media.GetStreamUri("RtspUnicast", profiles[0].token));
//ToDO: Build list box to allow user to switch between profiles. Just past main profile for now.
local_uri.Host = deviceUri.Host;
local_uri.Port = deviceUri.Port;
local_uri.Scheme = "rtsp";
//List full URI info.
infoBox.Text = local_uri.Host + local_uri.Port + local_uri.Path;
//Past it to VideoView and start playing video.
_mp.Play(new Media(_libVLC, local_uri.Uri));
}
}
}
}
Update: I believe my issue is the URI I have built requires validation. When I take this URI and put it into a web browser I get a 401 Error. I'm not sure why I don't see this error on wire-shark. I assign the user name and password into URI object but when I check "IsWellFormedURIString" I get an "invalid Port Error."
Did you try --rtsp-user and --rtsp-pwd ? you could also set the RTSP password with the dialog API.
If that doesn't work, please share your full logs.
You should be able to copy/paste the URL from Onvif Device Manager right into VLC and see it play (provided that you entered the correct credentials). If it doesn't, that's already an issue on its own.
You can still assign the Password and Username password.
MyUri.UserName = MyName
MyUri.Password = password
You run into problems when your password has characters like "#"
While I haven't figured out a workaround on this, for the time being keeping the password simple like "MyPassword" instead of "MyPassword#1234" will allow you to use the URI with the name and password built into the string.

PostAsync hanging in Xamarin Forms works on emulator but hangs on actual Mobile phone

I have Xamarin Forms project where I'm trying to POST and GET data to/from a Web API but when I'm making an async/await call, it works on the emulator (not without its original problems!) but when I try it on my actual phone mobile (Samsung S8+), it just hangs indefinitely.
Note that I'm only concentrating on the Android part right now, not iOS, not that the problem should make any difference in either.
This is the code I'm using:
IDataService.cs
Task<TResponse> PostDataAsync<TRequest, TResponse>(string uri, TRequest data)
where TRequest : class
where TResponse : class;
DataService.cs:
public async Task<TResponse> PostDataAsync<TRequest, TResponse>(string
additionalUri, TRequest data)
where TRequest : class
where TResponse : class
{
return await WebClient
.PostData<TRequest, TResponse>
(string.Concat(this.Uri, additionalUri), data);
}
WebClient.cs
using (var client = new HttpClient())
{
var jsonData = JsonConvert.SerializeObject(data);
using (var response = await client.PostAsync(
uri,
new StringContent(jsonData,
Encoding.UTF8,
"application/json" )))
{
if (response.IsSuccessStatusCode)
{
var content = await response.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<TResponse>(content);
}
}
}
Method 1:
LoginPageViewModel.cs
public DelegateCommand SignInCommand => _signInCommand ??
(this._signInCommand = new DelegateCommand(SignInCommandAction));
private async void SignInCommandAction()
{
try
{
....
var user = await this._dataService
.PostDataAsync<LoginRequestDto,
LoginResponseDto>(#"Accounts/Login", loginRequestDto);
....
}
...
}
Method2:
LoginPageViewModel.cs
public DelegateCommand SignInCommand => _signInCommand ??
(this._signInCommand =
new DelegateCommand(async () => await SignInCommandAction()));
private async Task SignInCommandAction()
{
try
{
....
var user = await this._dataService
.PostDataAsync<LoginRequestDto,
LoginResponseDto>(#"Accounts/Login", loginRequestDto);
....
}
...
}
The PostDataAsync works with both methods when I call my local web API i.e. http://10.0.2.2/MyApp/api/ but both methods still hangs when calling external my web service from web provider i.e. http://myapp-123-site.atempurl.com/api/ which is a temp url for testing purpose.
The same apply to my GetDataAsync which is not demonstrated in question but I just thought I'd mention it.
Based on the above, you would think that my async/await code is correct since it works when calling the local web api but then what's causing it to hang when calling the remote web api.
As mentioned, I did enable my INTERNET permission in the manifest.
Any suggestions welcomed?
Thanks.
UPDATE-1:
Note that I've just tried to call a GET opertation within the same function and this is working in the emulator but hanging with the actual mobile.
using (var client = new HttpClient())
{
using (var response = await client.GetAsync(uri))
{
if (response.IsSuccessStatusCode)
{
var content = await response.Content.ReadAsStringAsync();
return Newtonsoft.Json.JsonConvert
.DeserializeObject<TResponse>(content);
}
}
}
UPDATE-2:
This is somehow working and I have no idea why! The only thing that comes to mind is that I upgraded my libraries. This included PRISM which may have been at the source of the problem but I have no idea.
Sorry I can't provide more details. I could role back my code and try to see if it's hanging again but I just don't have the time to go and experiment some more considering the amount of time I've already spent on this. Sorry.
The requested url is an IP or a domain name.
If it is ip, only the IP of the public network can be accessed by devices on multiple network segments.
If it is a domain name, it needs to support the domain name resolution service.
If you do not have these environments for a while, you need the IP of the device and the IP of the server on the same network segment.
The PostDataAsync works with both methods when I call my local web API i.e. http://10.0.2.2/MyApp/api/ but both methods still hangs when calling external my web service from web provider i.e. http://myapp-123-site.atempurl.com/api/ which is a temp url for testing purpose.
From this phenomenon , the reason should be the temp url. From this domain name (myapp-123-site.atempurl.com) can not find the right local IP (10.0.2.2).And when you test in local network , I guess this will work.However the network of actual mobile can be not the same with local network , such as using 3G/4G network , then this will not working.

Detect network changes in Xamarin Forms

I want to detect when the user is online or offline.
I am using CrossConnectivity package to detect connectivity changes.
I have to connect to VPN (Sonic Wall to be exact) in order to connect to my server.
My problem is this: When I am connecting to my server, I need to switch apps in order for me to connect to my server. When I switch back to my app the function SyncFunction.SyncUser(host, database, contact, ipaddress, pingipaddress) is not executing. The connectivity changed function is not on my App.xaml.cs it is on my Main Menu Content page because I need the sync function to be executed in my main menu not the whole app. How can I fix this?
CrossConnectivity.Current.ConnectivityChanged += async (sender, args) =>
{
var appdate = Preferences.Get("appdatetime", String.Empty, "private_prefs");
if (string.IsNullOrEmpty(appdate))
{
Preferences.Set("appdatetime", DateTime.Now.ToString(), "private_prefs");
}
else
{
if (DateTime.Now >= DateTime.Parse(Preferences.Get("appdatetime", String.Empty, "private_prefs")))
{
Preferences.Set("appdatetime", DateTime.Now.ToString(), "private_prefs");
if (CrossConnectivity.Current.IsConnected)
{
var ping = new Ping();
var reply = ping.Send(new IPAddress(pingipaddress), 5000);
if (reply.Status == IPStatus.Success)
{
lblStatus.Text = "Syncing data to server";
lblStatus.BackgroundColor = Color.FromHex("#2bcbba");
await Task.Delay(5000);
SyncFunction.SyncUser(host, database, contact, ipaddress, pingipaddress);
lblStatus.Text = "Online - Connected to server";
lblStatus.BackgroundColor = Color.FromHex("#2ecc71");
}
else
{
lblStatus.Text = "Online - Server unreachable. Connect to VPN";
lblStatus.BackgroundColor = Color.FromHex("#e67e22");
}
}
else
{
lblStatus.Text = "Offline - Connect to internet";
lblStatus.BackgroundColor = Color.FromHex("#e74c3c");
}
}
else
{
await DisplayAlert("Application Error", "It appears you change the time/date of your phone. Please restore the correct time/date", "Got it");
await Navigation.PopToRootAsync();
}
}
};
Detecting connectivity change across a VPN is not easy.
A workaround solution is to use a webservice as ping.
If you have a backend with API, this "ping" can be executed regularly to ensure the network AND the API are accessible.
This solution is to be used in addition to the connectivity check
Subscribe to connectivity changed
When conectivity looks OK, check the "ping service"
Typically in a mob app, this "ping endpoint" can be something like "/about".
Moreover, this specific service can be use to perform the compatibility version check beetween App Mob version and API version.
(look also Xamarin.Essentials to replace CrossConnectivity by Xamarin.Essentials: Connectivity, https://learn.microsoft.com/fr-fr/xamarin/essentials/connectivity?context=xamarin%2Fxamarin-forms&tabs=android)

PNRP stops working windows 10 1803

I had some code that uses PNRP to discover peers on network. Everything works fine since Windows 10 update 1803.
public void Init()
{
try
{
_ServiceUrl = Dns.GetHostAddresses(Dns.GetHostName()).Where(address => address.AddressFamily == AddressFamily.InterNetwork).Select(address => _Address = address).Select(address => $"net.tcp://{address}:{Port}/SiemensVR").FirstOrDefault();
if (string.IsNullOrEmpty(_ServiceUrl)) return;
_LocalProxy = new PeerProxy(_EventAggregator, this);
_Host = new ServiceHost(_LocalProxy, new Uri(_ServiceUrl));
var binding = new NetTcpBinding();
binding.Security.Mode = SecurityMode.None;
_Host.AddServiceEndpoint(typeof(IPeerContract), binding, new Uri(_ServiceUrl));
_Host.Open();
_PeerName = new PeerName(PEER_NAME_ID, PeerNameType.Unsecured);
_PeerNameRegistration = new PeerNameRegistration(_PeerName, Port) { Cloud = Cloud.AllLinkLocal };
_PeerNameRegistration.Comment = _UserId.ToString();
_PeerNameRegistration.Start();
ResolvePeers();
}
finally { }
}
private async void ResolvePeers()
{
var resolver = new PeerNameResolver();
resolver.ResolveProgressChanged += OnResolveProgressChanged;
resolver.ResolveCompleted += (s, e) =>
{
Console.WriteLine("Completed");
};
resolver.ResolveAsync(_PeerName, this);
await Task.Delay(1000);
resolver.ResolveAsyncCancel(this);
}
Does MS have replace PNRP by something ?
I already tested to activate pnrp services, reinstall teredo tunneling and more.
Microsoft has deprecated and is in the process of removing PNRP.
You're out of luck, since its service and client APIs are being removed completely.
See https://learn.microsoft.com/en-us/windows/deployment/planning/windows-10-deprecated-features
Having the same issue here... Let me know if you find any resolution.
Previously, our application works fine, but on 1803 it doesn't work anymore. I can see the cloud start to synchronize and then each peer just ends up going to status alone.
Same issue, I found a Microsoft note to set the following services to Automatic Delayed Start:
Computer Browser (Browser) <- Set to Automatic, not delayed start
Function Discovery Provider Host (FDPHost)
Function Discovery Resource Publication (FDResPub)
Network Connections (NetMan)
UPnP Device Host (UPnPHost)
Peer Name Resolution Protocol (PNRPSvc)
Peer Networking Grouping (P2PSvc)
Peer Networking Identity Manager (P2PIMSvc)
But it didn't resolve the issue.
Any progress in resolving this?

Getting current IP of windows phone 7

I am building a windows phone 7.1 app. I need to find out if the phone is connected to any Wifi and if so, what is its current IP in the local network (ie. 192.168.0.100 like this).
I've been trying to find out these information for some time now. Please help.
I've managed to get the local IP on my console app by using the following code
public void ScanIP()
{
IPHostEntry host = Dns.GetHostEntry(Dns.GetHostName());
foreach (IPAddress ip in host.AddressList)
{
if (ip.AddressFamily == AddressFamily.InterNetwork)
{
String localIP = ip.ToString();
Console.WriteLine(localIP);
}
}
Console.ReadKey();
}
However, I need similar thing done for windows mobile 7 app. Any idea ? Please share.
Do a multicast and listen for replies. Once you identify your multicast message, you can get the IP of the sender (which is yourself). You can use UdpAnySourceMulticastClient to do the multicasting. In case you're not in a wifi network, you will get a socket failure in the EndJoinGroup call. You should handle the exception and pass a specific value indicating you're not in a wifi network.
More info in this blog post by Andy Pennell.
it will provide you the ip address of the phone ...
public static IPAddress Find()
{
List<string> ipAddresses = new List<string>();
var hostnames = NetworkInformation.GetHostNames();
foreach (var hn in hostnames)
{
if (hn.IPInformation != null)
{
string ipAddress = hn.DisplayName;
ipAddresses.Add(ipAddress);
}
}
IPAddress address = IPAddress.Parse(ipAddresses[0]);
return address;
}

Resources