使用蓝牙加密狗将字符串从PC发送到Android应用程序

时间:2014-09-15 08:41:15

标签: java android multithreading sockets bluetooth

我正在关注这个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);
            }
        }

    }
}

1 个答案:

答案 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堆栈的支持。