I created a test Xamarin.Forms project, tabbed app, with support for iOS, Android, and UWP. The app with the boilerplate starter code builds and and runs correctly on all 3 platforms.
Am trying to test receiving UDP broadcast in the app. The UDP broadcast is being sent from another machine on the same subnet (have tested broadcasting from another machine and from the same machine, results are the same). If I run a standalone, unmanaged UDP listener test tool on this machine (one we wrote internally), I can see all the messages coming through from the other machine.
I added the code (shown below) to the Xamarin.Forms project and ran the UWP build on this machine. What I'm seeing is that in the debug output I get the "started receiving" message, then nothing else. I'm not actually receiving the messages (or at least, the callback is not being invoked). I checked netstat and can see that when my Xamarin.Forms app is running, it is bound to the specified UDP port. But my OnUdpDataReceived never gets called.
EDIT: I double-clicked the UWP project's Package.appxmanifest file in solution explorer which brought up a UI and in that I checked "Capabilities >> Internet (Client & Server)" thinking it was a permissions thing, but this did not help.
EDIT: I verified connectivity by creating two console projects, a sender and a receiver. The sender just loops forever sending a test UDP broadcast each second. The receiver uses the same code shown here. These projects work as expected. So the same receiver code is working in the console project, but not in the Xamarin.Forms project.
First, a simple UDP receiver class.
public class BaseUdpReceiver
{
private UdpClient _udpClient;
public BaseUdpReceiver()
{
}
public void Start()
{
_udpClient = new UdpClient()
{
ExclusiveAddressUse = false,
EnableBroadcast = true
};
_udpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
_udpClient.Client.Bind(new IPEndPoint(IPAddress.Any, Constants.Network.SOME_CONSTANT_PORT_INTEGER));
_udpClient.BeginReceive(OnUdpDataReceived, _udpClient);
Debug.WriteLine($">>> started receiving");
}
private static void OnUdpDataReceived(IAsyncResult result)
{
Debug.WriteLine($">>> in receive");
var udpClient = result.AsyncState as UdpClient;
if (udpClient == null)
return;
IPEndPoint remoteAddr = null;
var recvBuffer = udpClient.EndReceive(result, ref remoteAddr);
Debug.WriteLine($"MESSAGE FROM: {remoteAddr.Address}:{remoteAddr.Port}, MESSAGE SIZE: {recvBuffer?.Length ?? 0}");
udpClient.BeginReceive(OnUdpDataReceived, udpClient);
}
}
Then, the code in App.xaml.cs which uses this class.
public partial class App : Application
{
private BaseUdpReceiver _udpReceiver;
public App()
{
InitializeComponent();
DependencyService.Register<MockDataStore>();
MainPage = new MainPage();
_udpReceiver = new BaseUdpReceiver();
_udpReceiver.Start();
}
protected override void OnStart()
{
}
protected override void OnSleep()
{
}
protected override void OnResume()
{
}
}
version info
Visual Studio 2019 Enterprise v16.4.5
Xamarin 16.4.000.322 (d16-4#ddfd842)
Windows 10 64-bit v1909 (OS Build 18363.657)
Microsoft.NETCore.UniversalWindowsPlatform, v6.2.9
NETStandard.Library, v2.0.3
Xamarin.Essentials, v1.5.0
Xamarin.Forms, v4.5.0.356
Got it working for both UWP and Android with help from MS support.
Note that the code provided in the original post is correct and works, given the following considerations.
UWP
Due to network isolation with UWP, you can't broadcast and receive on the same machine, while this works fine with the console apps, it doesn't work with Xamarin.Forms UWP, so the trick is you just have to broadcast from a different machine
Need to adjust Package.appxmanifest >> Capabilities settings
On 2 machines (a wifi laptop and wired desktop), I found it was sufficient to have "Internet (Client)" and "Internet (Client & Server)" checked
On a 3rd desktop machine with 2 NICs, one plugged in and one unplugged, it still didn't work with the above options, it was necessary to also check the "Private Networks (Client & Server)"
Android
The emulator appears to create its own subnet, you can see this by checking the emulator's network settings, it clearly isn't on the same subnet as the desktop machine on which its running
As a result, you can't get UDP broadcasts in the Android emulator in an easy way (aside from some sort of forwarding scheme which I did not experiment with)
Verified that with a physical Android tablet (tested with Samsung Galaxy Tab A 8"), it works and I'm able to receive UDP broadcasts
Note that on Android I didn't have to change any permissions from the defaults as with UWP, it worked without issue
iOS
As of yet, have not tested on a physical iOS device, I have an iPhone, but I'm using a cloud Mac build server so can't test on my device
When it comes time to deal with iOS, it looks like I'll probably need to get a local Mac
Related
I am trying scan the Bluetooth devices using 32feet.NET library using the following code.
private void Button_Click(object sender, RoutedEventArgs e)
{
BluetoothClient client = new BluetoothClient();
foreach (BluetoothDeviceInfo bdi in client.DiscoverDevices())
{
System.Diagnostics.Debug.WriteLine(bdi.DeviceName + " " + bdi.DeviceAddress);
}
}
The above code returns list of available Bluetooth devices in WPF application. But when I use the same code in UWP application I am getting the following exception.
System.Runtime.InteropServices.COMException: 'A method was called at an unexpected time.
When I tried to use the async/await as per the suggestion given here to fix this exception, I am not able to use async/await in collections. So I used Task.FromResult method as below then also the exception is not fixed.
private async void Button_Click(object sender, RoutedEventArgs e)
{
BluetoothClient client = new BluetoothClient();
var dev = await Task.FromResult(client.DiscoverDevices());
foreach (BluetoothDeviceInfo bdi in dev)
{
System.Diagnostics.Debug.WriteLine(bdi.DeviceName + " " + bdi.DeviceAddress);
}
}
Can someone help me why the same code works in WPF application but not in UWP application?
Unable to Discover Bluetooth Devices in UWP application but works in WPF application
I'm afraid the third part library does not support UWP platform, if you want to discover Bluetooth device in UWP platform, we suggest you use DeviceWatcher class to enumerate all Bluetooth device.
Here is official code sample that you could refer and here is official document.
UWP applications are containerised (sandboxed). This means that UWP applications cannot communicate with the kernel and other parts of the operating system directly. The only way a UWP application can communicate with the operating system is through Windows 10/11 API calls. Example: await Windows.System.Launcher.LaunchUriAsync(new Uri("ms-settings"));
There exist a couple of workarounds, one notable example is to download the UWP SDK in a WPF application and use UWP libraries within that respective WPF application.
Look here: https://www.thomasclaudiushuber.com/2019/04/26/calling-windows-10-apis-from-your-wpf-application/
getting NETWORK_COMMUNICATION when calling coreRouter.calculateRoute
not sure what url is't trying to reach ,
so can not test connection issue.
coreRouter.calculateRoute(routePlan, new CoreRouter.Listener() {
#Override
public void onCalculateRouteFinished(List<RouteResult> list,
RoutingError routingError) {
the routingError returns NETWORK_COMMUNICATION .
Using phone to test and am connected to the wifi network and can view webpages via the chrome browser
NETWORK_COMMUNICATION with SDK usually indicates a connectivity issue with HERE Servers, the connectivity issue could occur
if there are issues accessing HERE Servers by the SDK, make sure all *here.com are whitelisting if you device is using any proxy or
The map data on the device is very old and it is not being maintained anymore and make sure the device map is updated using the corresponding method in SDK MapLoader.checkForMapDataUpdate() and MapLoader.performMapDataUpdate()
using GoogleApiClient I am able to get location in this way:
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
#Override
public void onConnected(Bundle connectionHint) {
mLastLocation = LocationServices.FusedLocationApi.getLastLocation(
mGoogleApiClient);
if (mLastLocation != null) {
mLatitudeText = String.valueOf(mLastLocation.getLatitude());
Log.d("the lat is",mLatitudeText);
mLongitudeText = String.valueOf(mLastLocation.getLongitude());
Log.d("the lon is",mLongitudeText);
}
}
but this does not work for android TV application. Neither onConnected nor onConnectionFailed is called. I did not find any documentation too.
The Android developer documentation on handling TV hardware states:
TVs have a different purpose from other devices, and so they do not have hardware features that other Android-powered devices often have. For this reason, the Android system does not support the following features for a TV device:
GPS - android.hardware.location.gps
That might be tripping you up.
The documentation offers some hints on solutions:
TVs are stationary, indoor devices, and do not have built-in global positioning system (GPS) receivers. If your app uses location information, you can still allow users to search for a location, or use a static location provider such as a zip code configured during the TV device setup.
I am trying to create a QT based application that scan and connect WiFi networks. I am using this example as a reference code.
Is it possible to assign static IP for the WiFi connection using QNetworkConfiguration or any related class ?
How to authenticate the networks that are password protected ?
thanks in advance......
I have created a net work session using the below code set..
void BearerMonitor::createNewSessionFromQml(QString ssid)
{
QList<QNetworkConfiguration> allConfigurations = manager.allConfigurations();
while (!allConfigurations.isEmpty()) {
QNetworkConfiguration config = allConfigurations.takeFirst();
if(config.name()==ssid)
createSessionFor(config);
}
}
SessionWidget::SessionWidget(const QNetworkConfiguration &config, QObject *parent):QObject(parent)
{
session = new QNetworkSession(config, this);
session->open();
}
No you can't. At least not with just Qt APIs.
Please read this and in particular this. QNetworkConfiguration is just a facility to manage network configurations. Editing such configurations is demanded to native code / OS interactions. From the second link:
Note that the QNetworkConfiguration object only provides limited information about the configuration details themselves. It's main purpose is to act as a configuration identifier through which link layer connections can be created, destroyed and monitored.
Even the "start/stop network interfaces" claim is not entirely true since such a feature is available only in certain OSs (not the mobile ones). See the "Platform capabilities" section of the second link for more details about that.
The same reasoning applies to the password question. Once a network is registed in the OS with the corresponding password (because of native code or the user physically registering it) a new configuration is available to the NetworkConfigurationManager, granted that the list of configurations is updated via updateConfigurations(). The new configuration contains the password but you can't edit it from Qt APIs.
Native code is the only solution, as said. Still, Apple does not want you to mess up with WiFi programatically since private APIs for that cannot be used in iOS > 5.1 (the oldest version supported by Qt as for Qt 5.4).
I've been asked if I can read the weight from a scale, connected via RS232, and dump it into a web application. Reading the weight of the scale from the local machine isn't bad (this SO question gives an explanation: RS232 question - how to read weight to PC), but...
How do I then get that data to paste into a box in my web application...? Ideas?
I'm running into a similar-but-reverse situation with Fedex and UPS labels. I can get the label data within the web application, but I need to send that data via a raw printer socket (i.e. I can't just File > Print) to the local printer... how?
FedEx and UPS now how Zebra printers that can be network attached. Printing to them is easy via .NET and the standard Windows Spooler using the UNC path to the printer. The trick is how to expose the printer to your web application. If you web application is on the same network as your printer (intranet), the answer is simple. Send the data to the printer via the Windows Spooler from your web server in a server side call from your web app clients. If your web application is hosted outside of your local network, stand up a web service and write a web service to receive the ZPL (Zebra Printer Language) from your web app. The web service would also use the windows spooler to send to the printer on the same network.
Usually web applications are unable to communicate directly with a PC unless there's a full trust between the server and the client. Even then, web pages lack the ability to talk to peripheral devices for myriad security reasons. For a problem like this, you'd almost have to run some kind of client/service background application on the PC.
For the print from web app functionality, QZ Tray is a little java app that does the heavy lifting for you. You can snakeoil a cert, too, instead of paying for their custom cert for their silent printing.
I've been asked if I can read the weight from a scale, connected via RS232, and dump it into a web application.
Although this can't be done directly through JavaScript, a custom client-side or server-side solution can help. There are some server-side and desktop products which expose this functionality to a webpage (RS232 scales, USB scales)
To elaborate specifically on Gordon's recommended QZ Tray approach (assumes the PC has QZ Tray installed; assumes the page has been configured to use QZ Tray), here's a technique which will work for a serial port connected to a Mettler Toledo scale. The commands vary between scale suppliers, so adapt as needed.
Disclaimer, we're the authors of QZ Tray.
Connect to COM1, send command, disconnect
// MT = Mettler Toledo. Change as needed.
var port = 'COM1'; // <-- COM1, '/dev/ttyUSB0', etc
var cmd = 'W\n'; // <--- MT Weight command
var baud = {
baudRate: 9600,
dataBits: 7, // <--- MT Changed from 8
stopBits: 1,
parity: 'EVEN', // <--- MT Changed from NONE
flowControl: 'NONE'
};
var delims = {
begin: '\x02', // <--- MT start of message
end: '\x0D', // <--- MT end of message
width: null // <--- MT doesn't use width
};
qz.serial.openPort(port, delims).then(function() {
return qz.serial.sendData(port, cmd, baud);
}).catch(function(err) { console.error(err); } );
qz.serial.setSerialCallbacks(function(evt) {
if (evt.type !== 'ERROR') {
console.log('Serial', evt.portName, 'received output', evt.output);
} else {
console.error(evt.exception);
}
// Close port
return qz.serial.closePort(evt.portName);
});
I'm running into a similar-but-reverse situation with Fedex and UPS labels. I can get the label data within the web application, but I need to send that data via a raw printer socket (i.e. I can't just File > Print) to the local printer... how?
Duplicate of https://stackoverflow.com/a/28783269/3196753.