Отправка строки через Bluetooth с компьютера в качестве клиента на мобильный телефон в качестве сервера
Мне нужна помощь, перенеся строку с ПК на мобильное устройство Android через Bluetooth. Мобильное устройство Android должно выступать в качестве сервера и отображать строковое сообщение на экране устройства. ПК, который является клиентом, должен отправить строку на мобильное устройство.
Я хочу, чтобы сервер реагировал на извлеченную строку (передаваемую через Bluetooth). Это означает, что с одной стороны сервер всегда должен прослушивать поступающие новые строки, но с другой стороны все еще должен иметь возможность реагировать на эти сообщения (например, перемещаться из одного меню в другое).
Я попробовал это, используя BlueCove (2.1.1) в качестве BluetoothStack (для которого я добавляю jar из BlueCove в качестве библиотеки для обоих проектов) в сочетании с примером для связи сервер-клиент, который я нашел здесь.
Обновления:
Обновленный код с сервера благодаря user_CC, использующему RFComm
подключение к серверу:
public class RFCommServer extends Thread{
//based on java.util.UUID
private static UUID MY_UUID = UUID.fromString("446118f0-8b1e-11e2-9e96-0800200c9a66");
// The local server socket
private BluetoothServerSocket mmServerSocket;
// based on android.bluetooth.BluetoothAdapter
private BluetoothAdapter mAdapter;
private BluetoothDevice remoteDevice;
private Activity activity;
public RFCommServer(Activity activity) {
this.activity = activity;
}
public void run() {
BluetoothSocket socket = null;
mAdapter = BluetoothAdapter.getDefaultAdapter();
// Listen to the server socket if we're not connected
while (true) {
try {
// Create a new listening server socket
Log.d(this.getName(), ".....Initializing RFCOMM SERVER....");
// MY_UUID is the UUID you want to use for communication
mmServerSocket = mAdapter.listenUsingRfcommWithServiceRecord("MyService", MY_UUID);
//mmServerSocket = mAdapter.listenUsingInsecureRfcommWithServiceRecord(NAME, MY_UUID); // you can also try using In Secure connection...
// This is a blocking call and will only return on a
// successful connection or an exception
socket = mmServerSocket.accept();
} catch (Exception e) {
}
try {
Log.d(this.getName(), "Closing Server Socket.....");
mmServerSocket.close();
InputStream tmpIn = null;
OutputStream tmpOut = null;
// Get the BluetoothSocket input and output streams
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
DataInputStream mmInStream = new DataInputStream(tmpIn);
DataOutputStream mmOutStream = new DataOutputStream(tmpOut);
// here you can use the Input Stream to take the string from the client whoever is connecting
//similarly use the output stream to send the data to the client
RelativeLayout layout = (RelativeLayout) activity.findViewById(R.id.relativeLayout_Layout);
TextView text = (TextView) layout.findViewById(R.id.textView_Text);
text.setText(mmInStream.toString());
} catch (Exception e) {
//catch your exception here
}
}
}
Код Клиента SPP отсюда:
/**
* A simple SPP client that connects with an SPP server
*/
public class SampleSPPClient implements DiscoveryListener{
//object used for waiting
private static Object lock=new Object();
//vector containing the devices discovered
private static Vector vecDevices=new Vector();
private static String connectionURL=null;
public static void main(String[] args) throws IOException {
SampleSPPClient client=new SampleSPPClient();
//display local device address and name
LocalDevice localDevice = LocalDevice.getLocalDevice();
System.out.println("Address: "+localDevice.getBluetoothAddress());
System.out.println("Name: "+localDevice.getFriendlyName());
//find devices
DiscoveryAgent agent = localDevice.getDiscoveryAgent();
System.out.println("Starting device inquiry...");
agent.startInquiry(DiscoveryAgent.GIAC, client);
try {
synchronized(lock){
lock.wait();
}
}
catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Device Inquiry Completed. ");
//print all devices in vecDevices
int deviceCount=vecDevices.size();
if(deviceCount <= 0){
System.out.println("No Devices Found .");
System.exit(0);
}
else{
//print bluetooth device addresses and names in the format [ No. address (name) ]
System.out.println("Bluetooth Devices: ");
for (int i = 0; i <deviceCount; i++) {
RemoteDevice remoteDevice=(RemoteDevice)vecDevices.elementAt(i);
System.out.println((i+1)+". "+remoteDevice.getBluetoothAddress()+" ("+remoteDevice.getFriendlyName(true)+")");
}
}
System.out.print("Choose Device index: ");
BufferedReader bReader=new BufferedReader(new InputStreamReader(System.in));
String chosenIndex=bReader.readLine();
int index=Integer.parseInt(chosenIndex.trim());
//check for spp service
RemoteDevice remoteDevice=(RemoteDevice)vecDevices.elementAt(index-1);
UUID[] uuidSet = new UUID[1];
uuidSet[0]=new UUID("446118f08b1e11e29e960800200c9a66", false);
System.out.println("\nSearching for service...");
agent.searchServices(null,uuidSet,remoteDevice,client);
try {
synchronized(lock){
lock.wait();
}
}
catch (InterruptedException e) {
e.printStackTrace();
}
if(connectionURL==null){
System.out.println("Device does not support Simple SPP Service.");
System.exit(0);
}
//connect to the server and send a line of text
StreamConnection streamConnection=(StreamConnection)Connector.open(connectionURL);
//send string
OutputStream outStream=streamConnection.openOutputStream();
PrintWriter pWriter=new PrintWriter(new OutputStreamWriter(outStream));
pWriter.write("Test String from SPP Client\r\n");
pWriter.flush();
//read response
InputStream inStream=streamConnection.openInputStream();
BufferedReader bReader2=new BufferedReader(new InputStreamReader(inStream));
String lineRead=bReader2.readLine();
System.out.println(lineRead);
}//main
//methods of DiscoveryListener
public void deviceDiscovered(RemoteDevice btDevice, DeviceClass cod) {
//add the device to the vector
if(!vecDevices.contains(btDevice)){
vecDevices.addElement(btDevice);
}
}
//implement this method since services are not being discovered
public void servicesDiscovered(int transID, ServiceRecord[] servRecord) {
if(servRecord!=null && servRecord.length>0){
connectionURL=servRecord[0].getConnectionURL(0,false);
}
synchronized(lock){
lock.notify();
}
}
//implement this method since services are not being discovered
public void serviceSearchCompleted(int transID, int respCode) {
synchronized(lock){
lock.notify();
}
}
public void inquiryCompleted(int discType) {
synchronized(lock){
lock.notify();
}
}//end method
}
Для тестирования я использую Galaxy Nexus (GT-I9250) с новейшим Android API.
Благодаря user_CC клиент и сервер теперь работают без исключения. Но, к сожалению, клиент не может подключиться к серверу (см. Скриншот ниже). Это потому что connectionURL
никогда не устанавливается (таким образом, он прыгает сюда if(connectionURL==null)
по умолчанию.
Как я могу изменить код клиента, чтобы я мог соединить его с сервером? Мне нужно правильное connectionURL
в следующей строке:
StreamConnection streamConnection=(StreamConnection)Connector.open(connectionURL)
Пока я только узнал, что мне нужно как-то ServiceRecord
К сожалению, это также не описано в примере кода здесь.
2 ответа
Вам нужно будет использовать RFComm APIS, чтобы заставить коммуникацию работать. Мне удалось определить класс, который является потоком и будет действовать как сервер и прослушивать клиентские соединения. Я также разместил некоторые комментарии, чтобы вы могли понять.
private class AcceptThread extends Thread {
// The local server socket
private BluetoothServerSocket mmServerSocket;
public AcceptThread() {
}
public void run() {
BluetoothSocket socket = null;
BluetoothAdapter mAdapter = BluetoothAdapter.getDefaultAdapter();
// Listen to the server socket if we're not connected
while (true) {
try {
// Create a new listening server socket
Log.d(TAG, ".....Initializing RFCOMM SERVER....");
// MY_UUID is the UUID you want to use for communication
mmServerSocket = mAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID);
//mmServerSocket = mAdapter.listenUsingInsecureRfcommWithServiceRecord(NAME, MY_UUID); you can also try using In Secure connection...
// This is a blocking call and will only return on a
// successful connection or an exception
socket = mmServerSocket.accept();
} catch (Exception e) {
}
try {
Log.d(TAG, "Closing Server Socket.....";
mmServerSocket.close();
InputStream tmpIn = null;
OutputStream tmpOut = null;
// Get the BluetoothSocket input and output streams
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
mmInStream = new DataInputStream(tmpIn);
mmOutStream = new DataOutputStream(tmpOut);
// here you can use the Input Stream to take the string from the client whoever is connecting
//similarly use the output stream to send the data to the client
} catch (Exception e) {
//catch your exception here
}
}
}
}
надеюсь, это поможет
Для вашего другого вопроса:
Объявление javax.bluetooth.UUID на UUID-классе на стороне клиента (ПК) должно быть от javax.bluetooth.UUID
uuidSet2[0] = new UUID("446118f08b1e11e29e960800200c9a66", false);
Объявление java.util.UUID на стороне сервера (Android)
UUID MY_UUID = UUID.fromString("446118f0-8b1e-11e2-9e96-0800200c9a66");
Я не Java-разработчик, но у меня была похожая проблема с Mono для Android (C#)
UUID для SPP должен быть "00001101-0000-1000-8000-00805F9B34FB"
Это хорошо известный UID для идентификации адаптера Bluetooth SPP.
В моем коде C#, который выглядит как
private static UUID MY_UUID = UUID.FromString("00001101-0000-1000-8000-00805F9B34FB");
Я предполагаю, что вы можете обновить свой код Java на что-то вроде:
new UUID("00001101-0000-1000-8000-00805F9B34FB", true);
Хотя я не уверен, какие параметры принимает эта функция, возможно, вам придется это проверить.
Я использовал устройство Android в качестве клиента, но эта информация может быть вам полезна,
поэтому я включу свой код C# здесь, который я первоначально перевел из примеров Java,
так что вы сможете перевести его обратно:
btAdapter = BluetoothAdapter.DefaultAdapter;
btAdapter.CancelDiscovery(); //Always call CancelDiscovery before doing anything
remoteDevice = btAdapter.GetRemoteDevice(Settings["deviceaddress"].ToString());
socket = remoteDevice.CreateRfcommSocketToServiceRecord(MY_UUID);
socket.Connect();
Обычно я получаю адаптер по умолчанию, отменяю все выполняемые операции обнаружения, а затем создаю сокет для другого устройства. В вашем случае вы хотите слушать вместо подключения, но только для вашей информации.
Надеюсь, это поможет, извините, я не смог дать вам больше информации о Java.
Обновление: только что нашел небольшой пример в Java, который более или менее следует тому же методу, что и я: Проблемы с подключением Bluetooth SPP в Android?