简体   繁体   English

使用蓝牙加密狗从PC向Android应用发送字符串

[英]Sending string from PC to android app using bluetooth Dongle

I am following this GitHub project https://github.com/kernl/PC-to-Android-Bluetooth-Example PC is working as a client while android app as a server.Server searches for the devices and send a string to the device named BT_ .While android device listens for the connection and receive the string. 我正在关注这个GitHub项目https://github.com/kernl/PC-to-Android-Bluetooth-Example PC正在作为客户端运行,而android app作为服务器正在运行.Server搜索设备并将字符串发送到设备名为BT_。而android设备会监听连接并接收字符串。

The problem is its not consistent..Sometimes it sends the string correctly but sometimes PC client code keeps running but can't send the string.most of the times it can't call "broadcastCommand" function.It stucks here. 问题是不一致。有时它会正确发送字符串,但有时PC客户端代码会继续运行,但无法发送字符串。大多数情况下,它无法调用“ broadcastCommand”功能。 It always work fine for the first time.But it does not work again and after some time it starts working again.When I close the android app and open it again every time,it receives properly. 第一次总是可以正常工作。但是一段时间后它又无法正常工作了。当我关闭android应用并每次再次打开它时,它都能正常接收。 Please helppppp ! 请helppppp! PC client code is: public class BT_Dummy extends Thread implements DiscoveryListener { PC客户端代码为:公共类BT_Dummy扩展线程实现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 code is: 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);
            }
        }

    }
}

I've accomplished this using the android source example: 我已经使用android源示例完成了此操作:

https://android.googlesource.com/platform/development/+/master/samples/BluetoothChat/ https://android.googlesource.com/platform/development/+/master/samples/BluetoothChat/

For the PC code I used a simple python server: 对于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"

Ensure that the UUID inside your android app matches the one inside your PC server. 确保您的android应用中的UUID与PC服务器中的UUID相匹配。

RFCOMM isn't the newest way to exchange data, GATT is a more advanced system which is also supported by iOS. RFCOMM并不是交换数据的最新方式,GATT是一种更高级的系统,iOS也支持。 RFCOMM on the other hand is easier to get started, its supported by Android, Windows, and BlueZ stacks. 另一方面,RFCOMM较容易上手,它受到Android,Windows和BlueZ堆栈的支持。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM