我正在关注这个GitHub项目https://github.com/kernl/PC-to-Android-Bluetooth-Example PC作为客户端工作,而Android应用程序作为server.Server搜索设备并将字符串发送到名为BT_的设备.While android设备侦听连接并接收字符串。
问题是它不一致..有时它正确发送字符串但有时PC客户端代码继续运行但不能发送字符串。大多数时候它不能调用“broadcastCommand”函数。它卡在这里。 它总是第一次正常工作。但它不再工作,一段时间后它再次开始工作。当我关闭Android应用程序并每次再次打开它时,它会正确接收。 请helppppp! PC客户端代码是: public class BT_Dummy extends Thread实现DiscoveryListener {
/**
* Service serial-port UUID
*/
protected UUID defaultUUID = new UUID(0x1101);
/**
* Local bluetooth device.
*/
private LocalDevice local;
/**
* Agent responsible for the discovery of bluetooth devices.
*/
private DiscoveryAgent agent;
/**
* Output stream used to send information to the bluetooth.
*/
private DataOutputStream dout;
/**
* Bluetooth Connection.
*/
private StreamConnection conn;
/**
* List of bluetooth devices of interest. (name starting with the defined token)
*/
private Vector<RemoteDevice> devices;
/**
* Services of interest (defined in UUID) of each device.
*/
private Vector<ServiceRecord> services;
public BT_Dummy() {
services = new Vector<ServiceRecord>();
}
@Override
public void run() {
findDevices();
}
/**
* Find all the discoverable devices in range.
*/
protected void findDevices(){
try{
devices = new Vector<RemoteDevice>();
LocalDevice local = LocalDevice.getLocalDevice();
DiscoveryAgent agent = local.getDiscoveryAgent();
agent.startInquiry(DiscoveryAgent.GIAC, this);
debugString("Starting device discovery...");
}catch(Exception e) {
debugString("Error initiating discovery.");
}
}
/**
* Obtains a list of services with the UUID defined from a device.
*
* @param device
* Device to obtain the service list.
*/
protected void findServices(RemoteDevice device){
try{
UUID[] uuids = new UUID[1];
uuids[0] = defaultUUID; //The UUID of the each service
local = LocalDevice.getLocalDevice();
agent = local.getDiscoveryAgent();
agent.searchServices(null, uuids, device, this);
debugString("Starting Service Discovery...");
}catch(Exception e){
debugString("Error finding services.");
}
}
/**
* Sends a message to all the devices. (using the service)
*
* @param str
* Byte array which represents a string.
*/
public void broadcastCommand(String str) {
for(ServiceRecord sr : services) {
String url = sr.getConnectionURL(ServiceRecord.NOAUTHENTICATE_NOENCRYPT, false);
conn = null;
try {
debugString("Sending command to " + url);
conn = (StreamConnection) Connector.open(url);
dout = new DataOutputStream(conn.openOutputStream());
dout.writeUTF(str);
debugString(String.format("Sending %s", str));
dout.flush();
dout.close();
conn.close();
debugString("Sent. Connection Closed.");
} catch (Exception e) {
debugString("Failed to connect to " + url);
e.printStackTrace();
}
}
}
@Override
public void deviceDiscovered(RemoteDevice arg0, DeviceClass arg1) {
try {
String name = arg0.getFriendlyName(true);
debugString("Found device: " + name);
if(name.startsWith("BT_")) {
devices.add(arg0);
}
} catch (IOException e) {
debugString("Failed to get remoteDevice Name.");
}
}
@Override
public void inquiryCompleted(int arg0) {
debugString("Inquiry Completed.");
// Start service probing
for(RemoteDevice d :devices) {
findServices(d);
}
}
@Override
public void serviceSearchCompleted(int arg0, int arg1) {
debugString("Service search completed.");
broadcastCommand(new String("Hello world!"));
}
@Override
public void servicesDiscovered(int arg0, ServiceRecord[] arg1) {
for(ServiceRecord x : arg1) {
services.add(x);
}
}
/**
* Helper to format a debug string for output.
*
* @param str
* Debug Message
*/
protected static void debugString(String str) {
System.out.println(String.format("%s :: %s", BT_Dummy.class.getName(), str));
}
}
Android代码是:
public class BT_Example extends Activity implements OnClickListener {
/**
* Default Serial-Port UUID
*/
private String defaultUUID = "00001101-0000-1000-8000-00805F9B34FB";
/**
* Default bluetooth adapter on the device.
*/
private BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
/**
* String used to identify this application in the log.
*/
private final String TAG = BT_Example.class.getName();
/**
* The prefix to identify devices of interest.
*/
private final static String PREFIX = "BT_";
/**
* The Server thread.
*/
private AcceptThread server;
/**
* Magic number used in the bluetooth enabling request.
*/
private final int REQ = 111;
private NotificationCenter mNotificationCenter;
private static final String MESSAGE_RECEIVED_INTENT = "com.almightybuserror.intent.MESSAGE_RECEIVED";
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mNotificationCenter = new NotificationCenter();
if(mBluetoothAdapter == null) {
Log.e(TAG, "No Bluetooth Adapter available. Exiting...");
this.finish();
}
this.registerReceiver(mNotificationCenter, new IntentFilter(MESSAGE_RECEIVED_INTENT));
setHandlers();
}
@Override
public void onBackPressed() {
onPause();
}
@Override
public void onPause() {
server.cancel();
restoreBTDeviceName();
super.onPause();
}
@Override
public void onClick(View v) {
Button btn = (Button) v;
if(btn.getId() == R.id.btn_start_server) {
if(!mBluetoothAdapter.getName().startsWith(PREFIX))
mBluetoothAdapter.setName(PREFIX + mBluetoothAdapter.getName());
if(mBluetoothAdapter.getScanMode() != BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE)
requestBTDiscoverable();
server = new AcceptThread();
server.start();
btn.setEnabled(false);
((Button) this.findViewById(R.id.btn_stop_server)).setEnabled(true);
} else if(btn.getId() == R.id.btn_stop_server) {
server.cancel();
btn.setEnabled(false);
((Button) this.findViewById(R.id.btn_start_server)).setEnabled(true);
restoreBTDeviceName();
}
}
/**
* Launches Discoverable Bluetooth Intent.
*/
public void requestBTDiscoverable() {
Intent i = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
i.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);
startActivityForResult(i, REQ);
int result = 0;
this.onActivityResult(REQ, result, i);
Log.i(TAG, "Bluetooth discoverability enabled");
}
/**
* Obtains the Vibrator service.
* @return
* Vibrator Object.
*/
private Vibrator getVibrator() {
return (Vibrator) getSystemService(VIBRATOR_SERVICE);
}
/**
* Removes the prefix from the device name if the prefix is present.
*/
private void restoreBTDeviceName() {
if(mBluetoothAdapter.getName().startsWith(PREFIX))
mBluetoothAdapter.setName(mBluetoothAdapter.getName().substring(PREFIX.length()));
}
/**
* Sets the interface button handlers.
*/
public void setHandlers() {
Button start_server = (Button) this.findViewById(R.id.btn_start_server);
start_server.setOnClickListener(this);
Button stop_server = (Button) this.findViewById(R.id.btn_stop_server);
stop_server.setOnClickListener(this);
}
/**
* Shows a information dialog.
* @param message
* String resource used to define the message.
* @param duration
* Dialog's TTL.
*/
private void showInformation(String message, long duration) {
final Dialog mDialog = new Dialog(this);
TextView txt = new TextView(this);
txt.setText(message);
mDialog.setContentView(txt);
mDialog.setTitle("Information");
mDialog.show();
(new Handler()).postDelayed(new Runnable() {
public void run() {
mDialog.dismiss();
}}, duration); // Close dialog after delay
}
/**
* Thread that handles an incoming connection.
* Adapted from http://developer.android.com/guide/topics/wireless/bluetooth.html
*/
class AcceptThread extends Thread {
/**
* Tag that will appear in the log.
*/
private final String ACCEPT_TAG = AcceptThread.class.getName();
/**
* The bluetooth server socket.
*/
private final BluetoothServerSocket mServerSocket;
public AcceptThread() {
BluetoothServerSocket tmp = null;
try {
tmp = mBluetoothAdapter.listenUsingRfcommWithServiceRecord(ACCEPT_TAG,
UUID.fromString(defaultUUID));
} catch (IOException e) {
e.printStackTrace();
}
mServerSocket = tmp;
}
public void run() {
BluetoothSocket socket = null;
while (true) {
try {
Log.i(ACCEPT_TAG, "Listening for a connection...");
socket = mServerSocket.accept();
Log.i(ACCEPT_TAG, "Connected to " + socket.getRemoteDevice().getName());
} catch (IOException e) {
break;
}
// If a connection was accepted
if (socket != null) {
// Do work to manage the connection (in a separate thread)
try {
// Read the incoming string.
String buffer;
DataInputStream in = new DataInputStream(socket.getInputStream());
buffer = in.readUTF();
Intent i = new Intent(MESSAGE_RECEIVED_INTENT);
i.putExtra("Message", String.format("%sn From: %s", buffer, socket.getRemoteDevice().getName()));
getBaseContext().sendBroadcast(i);
} catch (IOException e) {
Log.e(ACCEPT_TAG, "Error obtaining InputStream from socket");
e.printStackTrace();
}
try {
mServerSocket.close();
} catch (IOException e) { }
break;
}
}
}
/** Will cancel the listening socket, and cause the thread to finish */
public void cancel() {
try {
mServerSocket.close();
} catch (IOException e) { }
}
}
class NotificationCenter extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if(intent.getAction().equals(MESSAGE_RECEIVED_INTENT)) {
showInformation(intent.getExtras().getString("Message"), 5000);
getVibrator().vibrate(500);
}
}
}
}
答案 0 :(得分:0)
我使用android源代码示例完成了这个:
https://android.googlesource.com/platform/development/+/master/samples/BluetoothChat/
对于PC代码,我使用了一个简单的python服务器:
#!/usr/bin/python
from bluetooth import *
server_sock=BluetoothSocket( RFCOMM )
server_sock.bind(("",6))
#server_sock.bind(("",PORT_ANY))
server_sock.listen(1)
port = server_sock.getsockname()[1]
uuid = "8ce255c0-200a-11e0-ac64-0800200c9a66" #Insecure
#uuid = "fa87c0d0-afac-11de-8a39-0800200c9a66"
advertise_service( server_sock, "BluetoothChatInsecure",
service_id = uuid,
service_classes = [ uuid, SERIAL_PORT_CLASS ],
profiles = [ SERIAL_PORT_PROFILE ],
# protocols = [ OBEX_UUID ]
)
print "Waiting for connection on RFCOMM channel %d" % port
client_sock, client_info = server_sock.accept()
print "Accepted connection from ", client_info
try:
while True:
data = client_sock.recv(1024)
if len(data) == 0: break
print "received [%s]" % data
except IOError:
pass
print "disconnected"
client_sock.close()
server_sock.close()
print "all done"
确保Android应用内的UUID与PC服务器内的UUID相匹配。
RFCOMM不是交换数据的最新方式,GATT是一个更高级的系统,也受iOS支持。另一方面,RFCOMM更容易上手,它受Android,Windows和BlueZ堆栈的支持。