码迷,mamicode.com
首页 > 移动开发 > 详细

Android 实现蓝牙客户端与服务器端通信

时间:2016-06-03 10:11:48      阅读:374      评论:0      收藏:0      [点我收藏+]

标签:

一、首先说明:蓝牙通信必须用手机测试,因为avd里没有相关的硬件,会报错!
好了,看看最后的效果图:
技术分享
技术分享

二、概述:
1.判断是否支持Bluetooth

BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if(bluetoothAdapter == null) {
    //the device doesn‘t support bluetooth
} else {
    //the device support bluetooth
}

2.如果支持,打开Bluetooth

if(!bluetoothAdapter.isEnable()) {
    Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
    startActivityForResult(enableIntent,REQUEST_ENABLE_BT);
}

3.监视Bluetooth打开状态

BroadcastReceiver bluetoothState = new BroadcastReceiver() {
    public void onReceive(Context context, Intent intent) {
    String stateExtra = BluetoothAdapter.EXTRA_STATE;
       int state = intent.getIntExtra(stateExtra, -1);
       switch(state) {
    case BluetoothAdapter.STATE_TURNING_ON:
        break;
    case BluetoothAdapter.STATE_ON:
        break;
    case BluetoothAdapter.STATE_TURNING_OFF:
        break;
    case BluetoothAdapter.STATE_OFF:
        break;
    }
    }
}

registerReceiver(bluetoothState,new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED));

4.设置本地设备可以被其它设备搜索

Intent discoveryIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
startActivityForResult(discoveryIntent,REQUEST_DISCOVERY);

BroadcastReceiver discovery = new BroadcastReceiver() {
    @Override
    public void onRecevie(Content context, Intent intent) {
        String scanMode = BluetoothAdapter.EXTRA_SCAN_MODE;
        String preScanMode = BluetoothAdapter.EXTRA_PREVIOUS_SCAN_MODE;
        int mode = intent.getIntExtra(scanMode);
    }
}

registerReceiver(discovery,new IntentFilter(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED);

5.搜索设备
开始搜索 bluetoothAdapter.startDiscovery();
停止搜索 bluetoothAdapter.cancelDiscovery();

当发现一个设备时,系统会发出ACTION_FOUND广播消息,我们可以实现接收这个消息的BroadcastReceiver

BroadcastReceiver deviceFound = new BroadcastReceiver() {
    @Override
    public void onReceiver(Content content, Intent intent) {
        String remoteDeviceName = intent.getStringExtra(BluetoothAdapter.EXTRA_NAME);
        BluetoothDevice remoteDevice = intent.getParcelableExtra(BluetoothAdapter.EXTRA_DEVICE);
    }
}
registerReceiver(deviceFound, new IntentFilter(BluetoothAdapter.ACTION_FOUND);

6.连接设备

连接两个蓝牙设备要分别实现服务器端(BluetoothServerSocket)和客户端(BluetoothSocket),这点与J2SE中的

ServerSocket和Socket很类似。

BluetoothServerSocket在服务器端调用方法accept()监听,当有客户端请求到来时,accept()方法返回BluetoothSocket,客户端得到后,两端便可以通信。通过InputStream和OutputStream来实现数据的传输。

accept方法是阻塞的,所以不能放在UI线程中,当用到BluetoothServerSocket和BluetoothSocket时,通常把它们放在各自的新线程中。

三、如何实现
以下是开发中的几个关键步骤:
1)首先开启蓝牙
2)搜索可用设备
3)创建蓝牙socket,获取输入输出流
4)读取和写入数据
5)断开连接关闭蓝牙

1、因为有页面切换,这里我使用了TabHost,但原来的效果不好,没有动画,那只好自己复写了

/**
 * 带有动画效果的TabHost
 * 
 * @Project App_Bluetooth
 * @Package com.android.bluetooth
 * @author chenlin
 * @version 1.0
 * @Date 2013年6月2日
 * @Note TODO
 */
public class AnimationTabHost extends TabHost {

    private int mCurrentTabID = 0;//当前的tabId
    private final long mDuration = 400;//动画时间

    public AnimationTabHost(Context context) {
        this(context, null);
    }

    public AnimationTabHost(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    /**
     * 切换动画
     */
    @Override
    public void setCurrentTab(int index) {
        //向右平移 
        if (index > mCurrentTabID) {
            TranslateAnimation translateAnimation = new TranslateAnimation(Animation.RELATIVE_TO_SELF, 0f, Animation.RELATIVE_TO_SELF,
                    -1.0f, Animation.RELATIVE_TO_SELF, 0f, Animation.RELATIVE_TO_SELF, 0f);
            translateAnimation.setDuration(mDuration);
            getCurrentView().startAnimation(translateAnimation);
            //向左平移
        } else if (index < mCurrentTabID) {
            TranslateAnimation translateAnimation = new TranslateAnimation(
                    Animation.RELATIVE_TO_SELF, 0f, Animation.RELATIVE_TO_SELF, 1.0f, Animation.RELATIVE_TO_SELF, 0f,
                    Animation.RELATIVE_TO_SELF, 0f);
            translateAnimation.setDuration(mDuration);
            getCurrentView().startAnimation(translateAnimation);
        } 

        super.setCurrentTab(index);

        //-----方向平移------------------------------
        if (index > mCurrentTabID) {
            TranslateAnimation translateAnimation = new TranslateAnimation( //
                    Animation.RELATIVE_TO_PARENT, 1.0f,// RELATIVE_TO_SELF
                    Animation.RELATIVE_TO_PARENT, 0f, Animation.RELATIVE_TO_PARENT, 0f, Animation.RELATIVE_TO_PARENT, 0f);
            translateAnimation.setDuration(mDuration);
            getCurrentView().startAnimation(translateAnimation);
        } else if (index < mCurrentTabID) {
            TranslateAnimation translateAnimation = new TranslateAnimation(
                    Animation.RELATIVE_TO_PARENT, -1.0f, Animation.RELATIVE_TO_PARENT, 0f, Animation.RELATIVE_TO_PARENT, 0f,
                    Animation.RELATIVE_TO_PARENT, 0f);
            translateAnimation.setDuration(mDuration);
            getCurrentView().startAnimation(translateAnimation);
        }
        mCurrentTabID = index;
    }
}

2、先搭建好主页,使用复写的TabHost滑动,如何滑动,根据状态,有三种状态

/**
 * 主页
 * 
 * @Project App_Bluetooth
 * @Package com.android.bluetooth
 * @author chenlin
 * @version 1.0
 * @Date 2013年6月2日
 */
@SuppressWarnings("deprecation")
public class BluetoothActivity extends TabActivity {
    static AnimationTabHost mTabHost;//动画tabhost
    static String BlueToothAddress;//蓝牙地址
    static Type mType = Type.NONE;//类型
    static boolean isOpen = false;

    //类型:
    enum Type {
        NONE, SERVICE, CILENT
    };

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        initTab();
    }

    private void initTab() {
        //初始化
        mTabHost = (AnimationTabHost) getTabHost();
        //添加tab
        mTabHost.addTab(mTabHost.newTabSpec("Tab1").setIndicator("设备列表", getResources().getDrawable(android.R.drawable.ic_menu_add))
                .setContent(new Intent(this, DeviceActivity.class)));
        mTabHost.addTab(mTabHost.newTabSpec("Tab2").setIndicator("会话列表", getResources().getDrawable(android.R.drawable.ic_menu_add))
                .setContent(new Intent(this, ChatActivity.class)));
        //添加监听
        mTabHost.setOnTabChangedListener(new OnTabChangeListener() {
            public void onTabChanged(String tabId) {
                if (tabId.equals("Tab1")) {
                    //TODO
                }
            }
        });
        //默认在第一个tabhost上面
        mTabHost.setCurrentTab(0);
    }

    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        Toast.makeText(this, "address:", Toast.LENGTH_SHORT).show();
    }

}

3、有了主页,就开始分别实现两个列表页面,一个是寻找设备页面DeviceActivity.java,另一个是会话页面ChatActivity.java
1)设备页面DeviceActivity.java

/**
 * 发现的设备列表
 * @Project    App_Bluetooth
 * @Package    com.android.bluetooth
 * @author     chenlin
 * @version    1.0
 * @Date       2013年6月2日
 * @Note       TODO
 */
public class DeviceActivity extends Activity {
    private ListView mListView;
    //数据
    private ArrayList<DeviceBean> mDatas;
    private Button mBtnSearch, mBtnService;
    private ChatListAdapter mAdapter;
    //蓝牙适配器
    private BluetoothAdapter mBtAdapter;


    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.devices);
        initDatas();
        initViews();
        registerBroadcast();
        init();
    }

    private void initDatas() {
        mDatas = new ArrayList<DeviceBean>();
        mAdapter = new ChatListAdapter(this, mDatas);
        mBtAdapter = BluetoothAdapter.getDefaultAdapter();
    }

    /**
     * 列出所有的蓝牙设备
     */
    private void init() {
        Log.i("tag", "mBtAdapter=="+ mBtAdapter);
        //根据适配器得到所有的设备信息
        Set<BluetoothDevice> deviceSet = mBtAdapter.getBondedDevices();
        if (deviceSet.size() > 0) {
            for (BluetoothDevice device : deviceSet) {
                mDatas.add(new DeviceBean(device.getName() + "\n" + device.getAddress(), true));
                mAdapter.notifyDataSetChanged();
                mListView.setSelection(mDatas.size() - 1);
            }
        } else {
            mDatas.add(new DeviceBean("没有配对的设备", true));
            mAdapter.notifyDataSetChanged();
            mListView.setSelection(mDatas.size() - 1);
        }
    }

    /**
     * 注册广播
     */
    private void registerBroadcast() {
        //设备被发现广播
        IntentFilter discoveryFilter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
        this.registerReceiver(mReceiver, discoveryFilter);

        // 设备发现完成
        IntentFilter foundFilter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
        this.registerReceiver(mReceiver, foundFilter);
    }

    /**
     * 初始化视图
     */
    private void initViews() {
        mListView = (ListView) findViewById(R.id.list);
        mListView.setAdapter(mAdapter);
        mListView.setFastScrollEnabled(true);


        mListView.setOnItemClickListener(mDeviceClickListener);

        mBtnSearch = (Button) findViewById(R.id.start_seach);
        mBtnSearch.setOnClickListener(mSearchListener);


        mBtnService = (Button) findViewById(R.id.start_service);
        mBtnService.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View arg0) {
                BluetoothActivity.mType = Type.SERVICE;
                BluetoothActivity.mTabHost.setCurrentTab(1);
            }
        });

    }


    /**
     * 搜索监听
     */
    private OnClickListener mSearchListener = new OnClickListener() {
        @Override
        public void onClick(View arg0) {
            if (mBtAdapter.isDiscovering()) {
                mBtAdapter.cancelDiscovery();
                mBtnSearch.setText("重新搜索");
            } else {
                mDatas.clear();
                mAdapter.notifyDataSetChanged();

                init();

                /* 开始搜索 */
                mBtAdapter.startDiscovery();
                mBtnSearch.setText("??停止搜索");
            }
        }
    };

    /**
     * 点击设备监听
     */
    private OnItemClickListener mDeviceClickListener = new OnItemClickListener() {
        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {

            DeviceBean bean = mDatas.get(position);
            String info = bean.message;
            String address = info.substring(info.length() - 17);
            BluetoothActivity.BlueToothAddress = address;

            AlertDialog.Builder stopDialog = new AlertDialog.Builder(DeviceActivity.this);
            stopDialog.setTitle("连接");//标题
            stopDialog.setMessage(bean.message);
            stopDialog.setPositiveButton("连接", new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int which) {
                    mBtAdapter.cancelDiscovery();
                    mBtnSearch.setText("重新搜索");

                    BluetoothActivity.mType = Type.CILENT;
                    BluetoothActivity.mTabHost.setCurrentTab(1);

                    dialog.cancel();
                }
            });
            stopDialog.setNegativeButton("取消", new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int which) {
                    BluetoothActivity.BlueToothAddress = null;
                    dialog.cancel();
                }
            });
            stopDialog.show();
        }
    };

    /**
     * 发现设备广播
     */
    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();

            if (BluetoothDevice.ACTION_FOUND.equals(action)) {
                // 获得设备信息
                BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                // 如果绑定的状态不一样
                if (device.getBondState() != BluetoothDevice.BOND_BONDED) {
                    mDatas.add(new DeviceBean(device.getName() + "\n" + device.getAddress(), false));
                    mAdapter.notifyDataSetChanged();
                    mListView.setSelection(mDatas.size() - 1);
                }
                // 如果搜索完成了
            } else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {
                setProgressBarIndeterminateVisibility(false);
                if (mListView.getCount() == 0) {
                    mDatas.add(new DeviceBean("?没有发现蓝牙设备", false));
                    mAdapter.notifyDataSetChanged();
                    mListView.setSelection(mDatas.size() - 1);
                }
                mBtnSearch.setText("重新搜索");
            }
        }
    };

    @Override
    public void onStart() {
        super.onStart();
        if (!mBtAdapter.isEnabled()) {
            Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
            startActivityForResult(enableIntent, 3);
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mBtAdapter != null) {
            mBtAdapter.cancelDiscovery();
        }
        this.unregisterReceiver(mReceiver);
    }
}

2)会话页面ChatActivity.java

/**
 * 会话界面
 * 
 * @Project App_Bluetooth
 * @Package com.android.bluetooth
 * @author chenlin
 * @version 1.0
 * @Date 2013年3月2日
 * @Note TODO
 */
public class ChatActivity extends Activity implements OnItemClickListener, OnClickListener {
    private static final int STATUS_CONNECT = 0x11;

    private ListView mListView;
    private ArrayList<DeviceBean> mDatas;
    private Button mBtnSend;// 发送按钮
    private Button mBtnDisconn;// 断开连接
    private EditText mEtMsg;
    private DeviceListAdapter mAdapter;

    /* 一些常量,代表服务器的名称 */
    public static final String PROTOCOL_SCHEME_L2CAP = "btl2cap";
    public static final String PROTOCOL_SCHEME_RFCOMM = "btspp";
    public static final String PROTOCOL_SCHEME_BT_OBEX = "btgoep";
    public static final String PROTOCOL_SCHEME_TCP_OBEX = "tcpobex";

    // 蓝牙服务端socket
    private BluetoothServerSocket mServerSocket;
    // 蓝牙客户端socket
    private BluetoothSocket mSocket;
    // 设备
    private BluetoothDevice mDevice;
    private BluetoothAdapter mBluetoothAdapter;

    // --线程类-----------------
    private ServerThread mServerThread;
    private ClientThread mClientThread;
    private ReadThread mReadThread;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.chat);
        initDatas();
        initViews();
        initEvents();
    }

    private void initEvents() {
        mListView.setOnItemClickListener(this);

        // 发送信息
        mBtnSend.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View arg0) {
                String text = mEtMsg.getText().toString();
                if (!TextUtils.isEmpty(text)) {
                    // 发送信息
                    sendMessageHandle(text);

                    mEtMsg.setText("");
                    mEtMsg.clearFocus();
                    // 隐藏软键盘
                    InputMethodManager manager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
                    manager.hideSoftInputFromWindow(mEtMsg.getWindowToken(), 0);
                } else
                    Toast.makeText(ChatActivity.this, "发送内容不能为空!", Toast.LENGTH_SHORT).show();
            }
        });

        // 关闭会话
        mBtnDisconn.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View view) {
                if (BluetoothActivity.mType == Type.CILENT) {
                    shutdownClient();
                } else if (BluetoothActivity.mType == Type.SERVICE) {
                    shutdownServer();
                }
                BluetoothActivity.isOpen = false;
                BluetoothActivity.mType = Type.NONE;
                Toast.makeText(ChatActivity.this, "已断开连接!", Toast.LENGTH_SHORT).show();
            }
        });
    }

    private void initViews() {
        mListView = (ListView) findViewById(R.id.list);
        mListView.setAdapter(mAdapter);
        mListView.setFastScrollEnabled(true);

        mEtMsg = (EditText) findViewById(R.id.MessageText);
        mEtMsg.clearFocus();

        mBtnSend = (Button) findViewById(R.id.btn_msg_send);
        mBtnDisconn = (Button) findViewById(R.id.btn_disconnect);
    }

    private void initDatas() {
        mDatas = new ArrayList<DeviceBean>();
        mAdapter = new DeviceListAdapter(this, mDatas);
        mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
    }

    /**
     * 信息处理
     */
    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            String info = (String) msg.obj;
            switch (msg.what) {
            case STATUS_CONNECT:
                Toast.makeText(ChatActivity.this, info, 0).show();
                break;
            }

            if (msg.what == 1) {
                mDatas.add(new DeviceBean(info, true));
                mAdapter.notifyDataSetChanged();
                mListView.setSelection(mDatas.size() - 1);
            }else {
                mDatas.add(new DeviceBean(info, false));
                mAdapter.notifyDataSetChanged();
                mListView.setSelection(mDatas.size() - 1);
            }
        }

    };

    @Override
    public void onResume() {
        super.onResume();
        if (BluetoothActivity.isOpen) {
            Toast.makeText(this, "连接已经打开,可以通信。如果要再建立连接,请先断开", Toast.LENGTH_SHORT).show();
            return;
        }
        if (BluetoothActivity.mType == Type.CILENT) {
            String address = BluetoothActivity.BlueToothAddress;
            if (!"".equals(address)) {
                mDevice = mBluetoothAdapter.getRemoteDevice(address);
                mClientThread = new ClientThread();
                mClientThread.start();
                BluetoothActivity.isOpen = true;
            } else {
                Toast.makeText(this, "address is null !", Toast.LENGTH_SHORT).show();
            }
        } else if (BluetoothActivity.mType == Type.SERVICE) {
            mServerThread = new ServerThread();
            mServerThread.start();
            BluetoothActivity.isOpen = true;
        }
    }

    // 客户端线程
    private class ClientThread extends Thread {
        public void run() {
            try {
                mSocket = mDevice.createRfcommSocketToServiceRecord(UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"));
                Message msg = new Message();
                msg.obj = "请稍候,正在连接服务器:" + BluetoothActivity.BlueToothAddress;
                msg.what = STATUS_CONNECT;
                mHandler.sendMessage(msg);

                mSocket.connect();

                msg = new Message();
                msg.obj = "已经连接上服务端!可以发送信息。";
                msg.what = STATUS_CONNECT;
                mHandler.sendMessage(msg);
                // 启动接受数据
                mReadThread = new ReadThread();
                mReadThread.start();
            } catch (IOException e) {
                Message msg = new Message();
                msg.obj = "连接服务端异常!断开连接重新试一试。";
                msg.what = STATUS_CONNECT;
                mHandler.sendMessage(msg);
            }
        }
    };

    // 开启服务器
    private class ServerThread extends Thread {
        public void run() {
            try {
                // 创建一个蓝牙服务器 参数分别:服务器名称、UUID
                mServerSocket = mBluetoothAdapter.listenUsingRfcommWithServiceRecord(PROTOCOL_SCHEME_RFCOMM,
                        UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"));

                Message msg = new Message();
                msg.obj = "请稍候,正在等待客户端的连接...";
                msg.what = STATUS_CONNECT;
                mHandler.sendMessage(msg);

                /* 接受客户端的连接请求 */
                mSocket = mServerSocket.accept();

                msg = new Message();
                msg.obj = "客户端已经连接上!可以发送信息。";
                msg.what = STATUS_CONNECT;
                mHandler.sendMessage(msg);
                // 启动接受数据
                mReadThread = new ReadThread();
                mReadThread.start();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    };

    /* 停止服务器 */
    private void shutdownServer() {
        new Thread() {
            public void run() {
                if (mServerThread != null) {
                    mServerThread.interrupt();
                    mServerThread = null;
                }
                if (mReadThread != null) {
                    mReadThread.interrupt();
                    mReadThread = null;
                }
                try {
                    if (mSocket != null) {
                        mSocket.close();
                        mSocket = null;
                    }
                    if (mServerSocket != null) {
                        mServerSocket.close();
                        mServerSocket = null;
                    }
                } catch (IOException e) {
                    Log.e("server", "mserverSocket.close()", e);
                }
            };
        }.start();
    }

    /* ?停止客户端连接 */
    private void shutdownClient() {
        new Thread() {
            public void run() {
                if (mClientThread != null) {
                    mClientThread.interrupt();
                    mClientThread = null;
                }
                if (mReadThread != null) {
                    mReadThread.interrupt();
                    mReadThread = null;
                }
                if (mSocket != null) {
                    try {
                        mSocket.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                    mSocket = null;
                }
            };
        }.start();
    }

    // 发送数据
    private void sendMessageHandle(String msg) {
        if (mSocket == null) {
            Toast.makeText(this, "没有连接", Toast.LENGTH_SHORT).show();
            return;
        }
        try {
            OutputStream os = mSocket.getOutputStream();
            os.write(msg.getBytes());

            mDatas.add(new DeviceBean(msg, false));
            mAdapter.notifyDataSetChanged();
            mListView.setSelection(mDatas.size() - 1);

        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    // 读取数据
    private class ReadThread extends Thread {
        public void run() {
            byte[] buffer = new byte[1024];
            int bytes;
            InputStream is = null;
            try {
                is = mSocket.getInputStream();
                while (true) {
                    if ((bytes = is.read(buffer)) > 0) {
                        byte[] buf_data = new byte[bytes];
                        for (int i = 0; i < bytes; i++) {
                            buf_data[i] = buffer[i];
                        }
                        String s = new String(buf_data);
                        Message msg = new Message();
                        msg.obj = s;
                        msg.what = 1;
                        mHandler.sendMessage(msg);
                    }
                }
            } catch (IOException e1) {
                e1.printStackTrace();
            } finally {
                try {
                    is.close();
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
            }

        }
    }

    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
    }

    @Override
    public void onClick(View view) {
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (BluetoothActivity.mType == Type.CILENT) {
            shutdownClient();
        } else if (BluetoothActivity.mType == Type.SERVICE) {
            shutdownServer();
        }
        BluetoothActivity.isOpen = false;
        BluetoothActivity.mType = Type.NONE;
    }

}

三、相关代码下载
链接:http://pan.baidu.com/s/1eSNRvzG 密码:awgv

Android 实现蓝牙客户端与服务器端通信

标签:

原文地址:http://blog.csdn.net/lovoo/article/details/51576246

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!