I'm trying to connect and send a file from android device to a PC or another smartphone with Xamarin.Android via Bluetooth.
Connection is estabilished, but it doesn't send the file. It doesn't seems to work since there are no exceptions.
int bufferSize = (int)sourceStream.Length;
byte[] byteArray=File.ReadAllBytes("/sdcard/test.txt");
BluetoothSocket socket = device.CreateInsecureRfcommSocketToServiceRecord(UUID.FromString("00001105-0000-1000-8000-00805f9b34fb"));
try
{
await socket.ConnectAsync();
Stream oStream = socket.OutputStream;
oStream.Write(byteArray, 0, bufferSize);
}
catch (Exception ex)
{
//some catching
}
Beside that, do you know any tutorial out there?
I do not know what your receiving code looks like, but you can use the built-in Android BlueTooth Intent.ActionSend Sharing app to start the transfer:
var photoAsset = Assets.OpenFd ("BusinessCard.png");
var javaIOFile = new Java.IO.File (photoAsset.ToString ());
var sendIntent = new Intent (Intent.ActionSend);
sendIntent.SetType ("image/*");
sendIntent.SetComponent (new ComponentName ("com.android.bluetooth", "com.android.bluetooth.opp.BluetoothOppLauncherActivity"));
sendIntent.PutExtra (Intent.ExtraStream, Android.Net.Uri.FromFile (javaIOFile));
StartActivity (sendIntent);
Of course the receiver would have to have their BlueTooth on and accept the connection/transfer.
Related
I am creating a BLE app where I am successfully connecting to a BLE device. I am able to read the GATT characteristics as well. But when I try to do write operation I get exception
Device xxx disconnected while writing characteristic with yyy
This is my code
private async Task<string> ProcessDeviceInformationService(IService deviceInfoService)
{
try
{
await adapter.ConnectToDeviceAsync(device);
var sb = new StringBuilder("Getting information from Device Information service: \n");
var characteristics = await deviceInfoService.GetCharacteristicsAsync();
var characteristic = await deviceInfoService.GetCharacteristicAsync(Guid.Parse("00002b0f-0000-1000-8000-00805f9b34fb"));
//{
try
{
deviceInfoService.GetCharacteristicAsync(GattCharacteristicIdentifiers.DataExchange);
if (characteristic != null)
{
var sbnew = new StringBuilder("BLE Characteristics\n");
byte[] senddata = Encoding.UTF8.GetBytes(string.IsNullOrEmpty(SendMessageLabel.Text) ? "0x21" : SendMessageLabel.Text);
await Task.Delay(300);
var newbytes = await characteristic.WriteAsync(senddata);
byte[] characteristicsvalue = characteristic.Value;
var str = Encoding.UTF8.GetString(characteristicsvalue);
sbnew.AppendLine($"Characteristics found on this device: {string.Join(", ", str.ToString())}");
CharactericsLabel.Text = sbnew.ToString();
}
}
catch (Exception ex)
{
return ex.Message;
}
return CharactericsLabel.Text;
}
catch (Exception ex)
{
return ex.ToString();
}
}
After some search I found that I need to pass hexadecimal value.Even I tried sending hexadecimal value as you can see in code but it's not working. For android its working fine but for iOS it is still showing this exception.I'm using device Iphone 8 plus and OS version of Iphone is 13.5.1.The write operation works in Light Blue app which I downloaded from App store for iOS. My write type is set to default which is write with response. But it is giving exception in my xamarin app only for the iOS part. I'm using latest stable version 2.1.1 of Plugin.BLE. I have no clue how to fix this any suggestions?
I fixed this exception by getting write without response for characteristic from the peripheral side.
I'm trying to code a proof of concept, with Xamarin android.
A sort of EMM tool, i.e. an application which will be in charge of installing other applications and managing the device.
So Android Marshmallow is a good place to start with android for work features.
My app is a Device Owner, therefore it should have no problem silently installing other applications. It can download an apk from a website without any problem. But when I try to install it, it throws a "Files still open" exception despite calling all Close() methods.
I have taken my code from the excellent android-testdpc github example here.
I have changed it to work in C# with Xamarin.
Here is my code:
public static bool InstallPackage(Context context, Handler handler, InputStream input, String packageName)
{
try
{
PackageInstaller packageInstaller = context.PackageManager.PackageInstaller;
PackageInstaller.SessionParams param = new PackageInstaller.SessionParams(PackageInstallMode.FullInstall);
param.SetAppPackageName(packageName);
// set params
int sessionId = packageInstaller.CreateSession(param);
PackageInstaller.Session session = packageInstaller.OpenSession(sessionId);
using (System.IO.Stream output = session.OpenWrite("COSU", 0, -1))
{
byte[] buffer = new byte[65536];
int c;
while ((c = input.Read(buffer)) != -1)
{
output.Write(buffer, 0, c);
}
session.Fsync(output);
input.Close();
output.Close();
}
session.Commit(createIntentSender(context, sessionId)); // this line throws exception 'Files stil open'
return true;
}
catch (Exception ex)
{
Log.Error(TAG, "Error installing package: " + packageName, ex);
handler.SendMessage(handler.ObtainMessage(Common.MSG_INSTALL_FAIL,
packageName));
return false;
}
}
I'm stuck with this for the moment. If I have the time, I will try to install Android Studio and test my code in Java to see if the problem comes from Xamarin.
If someone has any clue for my problem, I will greatly appreciate the help.
SecurityException : if streams opened through openWrite(String, long, long) are still open.
The Java peer object is not closed yet, this is how I force it for the PackageInstaller.Session.Commit:
var input = Assets.Open(packageName);
var packageInstaller = PackageManager.PackageInstaller;
var sessionParams = new PackageInstaller.SessionParams(PackageInstallMode.FullInstall);
sessionParams.SetAppPackageName(packageName);
int sessionId = packageInstaller.CreateSession(sessionParams);
var session = packageInstaller.OpenSession(sessionId);
using (var output = session.OpenWrite(packageName, 0, -1))
{
input.CopyTo(output);
session.Fsync(output);
foreach (var name in session.GetNames())
Log.Debug("Installer", name);
output.Close();
output.Dispose();
input.Close();
input.Dispose();
GC.Collect();
}
var pendingIntent = PendingIntent.GetBroadcast(BaseContext, sessionId, new Intent(Intent.ActionInstallPackage), 0);
session.Commit(pendingIntent.IntentSender);
I have a bluetooth button from Radius networks. The builtin - "add a bluetooth device" finds it every time.
I need the api or a stack that I can use to do from my app. I am doing this in c#. the library 32 feet is not compatible
To enumerate RFCOMM Bluetooth devices attached to a device, do:
var DEVICE_ID = new Guid("{00000000-0000-0000-0000-000000000000}"); //Enter your device's RFCOMM service id (try to find it on manufactorer's website
var services = await Windows.Devices.Enumeration.DeviceInformation.FindAllAsync(
RfcommDeviceService.GetDeviceSelector(
RfcommServiceId.FromUuid(DEVICE_ID)));
To connect to a the first available device, do:
if (services.Count > 0)
{
var service = await RfcommDeviceService.FromIdAsync(services[0].Id);
//Open a socket to the bluetooth device for communication. Use the socket to communicate using the device's API
var socket = new StreamSocket();
await socket.ConnectAsync(service.ConnectionHostName, service.ConnectionServiceName, SocketProtectionLevel
.BluetoothEncryptionAllowNullAuthentication); //Substitue real BluetoothEncryption
}
To send data to the device and read data back, do:
var BYTE_NUM = 64 as UInt32; //Read this many bytes
IInputStream input = socket.InputStream;
IOutputStream output = socket.OutputStream;
var inputBuffer = new Buffer();
var operation = input.ReadAsync(inputBuffer, BYTE_NUM, InputStreamOptions.none);
while (!operation.Completed) Thread.Sleep(200);
inputBuffer = operation.GetResults();
var resultReader = DataReader.FromBuffer(inputBuffer);
byte[] result = new byte[BYTE_NUM];
resultReader.ReadBytes(result);
resultReader.Dispose();
//Do something with the bytes retrieved. If the Bluetooth device has an api, it will likely specify what bytes will be sent from the device
//Now time to give some data to the device
byte[] outputData = Encoding.ASCII.GetBytes("Hello, Bluetooth Device. Here's some data! LALALALALA");
IBuffer outputBuffer = outputData.AsBuffer(); //Neat method, remember to include System.Runtime.InteropServices.WindowsRuntime
operation = output.WriteAsync(outputBuffer);
while (!operation.Completed) Thread.Sleep(200);
await output.FlushAsync(); //Now the data has really been written
This will work for all RFCOMM (normal) bluetooth devices, if your device uses Bluetooth Low Energy please use the corresponding GATT classes.
I have been working with Monodroid for a few days and still can't figure out how to send a command through Bluetooth.
This is my scenario: I have a Tablet/Cellphone working with Android 2.1+ and need to send and receive data to a Bluetooth printer (in bytes).
What i managed so far:
using Android.Bluetooth; // library necessary
BluetoothAdapter bth = BluetoothAdapter.DefaultAdapter;
if (!bth.IsEnabled)
bth.Enable();
ICollection<BluetoothDevice> bthD = bth.BondedDevices;
foreach (BluetoothDevice d in bthD)
{
if (d.Name == "DPP-350")
{
Java.Util.UUID UUID = Java.Util.UUID.FromString("00001101-0000-1000-8000-00805F9B34FB");
// Get the BLuetoothDevice object
BluetoothSocket s = d.CreateRfcommSocketToServiceRecord(UUID);
s.Connect();
// Try to send command
...
s.Close()
}
}
The program asks for the pairing info, with is done correctly.
I have tried many ways to send the command:
// the command
// Self_Test = Chr(27) + Chr(84) = ESC T
byte[] dBytes = System.Text.Encoding.GetEncoding(1252).GetBytes(Self_Test);
// wont work
new Java.IO.ObjectOutputStream(s.OutputStream).Write(dBytes);
// wont work
System.IO.Stream st = s.OutputStream;
if (st.CanWrite)
{
st.Write(dBytes, 0, dBytes.Length);
st.Flush();
}
// wonk work
s.OutputStream.Write(dBytes, 0, dBytes.Length);
s.OutputStream.Flush();
No error is raised. I'm running out of options here...
Thanks in advance!
I know this is a very old thread, but I wanted to post a reply so others will know the answer. I too searched hard with no luck.
s.OutputStream.BeginWrite(buffer, 0, buffer.Length,new AsyncCallback(delegate {}), State.Connected);
Thanks.
Im attempting to write a push server for the iPhone in C#. I have the following code:
// Create a TCP/IP client socket.
using (TcpClient client = new TcpClient())
{
client.Connect("gateway.sandbox.push.apple.com", 2195);
using (NetworkStream networkStream = client.GetStream())
{
Console.WriteLine("Client connected.");
X509Certificate clientCertificate = new X509Certificate(#"certfile.p12", passwordHere);
X509CertificateCollection clientCertificateCollection = new X509CertificateCollection(new X509Certificate[1] { clientCertificate });
// Create an SSL stream that will close the client's stream.
SslStream sslStream = new SslStream(
client.GetStream(),
false,
new RemoteCertificateValidationCallback(ValidateServerCertificate),
null
);
try
{
sslStream.AuthenticateAsClient("gateway.sandbox.push.apple.com");
}
catch (AuthenticationException e)
{
Console.WriteLine("Exception: {0}", e.Message);
if (e.InnerException != null)
{
Console.WriteLine("Inner exception: {0}", e.InnerException.Message);
}
Console.WriteLine("Authentication failed - closing the connection.");
client.Close();
return;
}
}
ect....
Only I keep receiving a exception:
"A call to SSPI failed, see Inner exception"
Inner Exception -> "The message received was unexpected or badly formatted."
Does anyone have any idea whats going wrong here?
Figured it out. Replaced sslStream.AuthenticateAsClient("gateway.sandbox.push.apple.com"); with sslStream.AuthenticateAsClient("gateway.sandbox.push.apple.com", clientCertificateCollection, SslProtocols.Default, false); And registered the certificates on the PC.
Edit: Here is the code for creating a payload as requested:
private static byte[] GeneratePayload(byte [] deviceToken, string message, string sound)
{
MemoryStream memoryStream = new MemoryStream();
// Command
memoryStream.WriteByte(0);
byte[] tokenLength = BitConverter.GetBytes((Int16)32);
Array.Reverse(tokenLength);
// device token length
memoryStream.Write(tokenLength, 0, 2);
// Token
memoryStream.Write(deviceToken, 0, 32);
// String length
string apnMessage = string.Format ( "{{\"aps\":{{\"alert\":{{\"body\":\"{0}\",\"action-loc-key\":null}},\"sound\":\"{1}\"}}}}",
message,
sound);
byte [] apnMessageLength = BitConverter.GetBytes((Int16)apnMessage.Length);
Array.Reverse ( apnMessageLength );
// message length
memoryStream.Write(apnMessageLength, 0, 2);
// Write the message
memoryStream.Write(System.Text.ASCIIEncoding.ASCII.GetBytes(apnMessage), 0, apnMessage.Length);
return memoryStream.ToArray();
} // End of GeneratePayload
From Zenox's comment:
use a different version of AuthenticateAsClient
sslStream.AuthenticateAsClient("gateway.sandbox.push.apple.com", clientCertificateCollection, SslProtocols.Default, false);
Other way is just to use X509Certificate2 and X509CertificateCollection2 classes.
I recently used Growl For Windows to push messages to the Prowl client on the IPhone from .Net code. So you might get your functionatlity without writing a push server yourself.
The "The message received was unexpected or badly formatted." error usually comes when you did not register the p12 certificate in Windows. (Under Vista, just double click on the p12 file and the import wizard will open)
In my case I had to delete all the certificate from my windows 8 and then re-install them in order to send push notifications to apple device.
I do not know why my certificates stop working, I am searching for the correct reason and will update here soon.