安卓蓝牙BluetoothBLE开发JDY-10M

 

由于毕业设计用得到蓝牙,因此简单研究了一下蓝牙。由于本人学术知识有限,本文可能出现错误,请指正。

介绍一下

JDY-10M蓝牙模块:

手机系统为安卓9版本。

使用的工具为android studio3.5.(应该算是最新版本了),适配的安卓版本为安卓9(我手机的版本为安卓9)

买的JAY-10M附带的资料给了APP的源码,然后尝试了将这个源代码直接移植到我自己的项目中,出了问题。自带两个apk文件,一个闪退,另一个能够正常使用。源代码适配的是安卓5的。因此,这个源代码应该是没有问题的。查看报错,是权限的问题。但是已经再声明文件中给了蓝牙的权限,这是为什么呢?最后搞清楚了需要增加一个动态权限申请蓝牙权限后才能够正常使用。

这个硬件自带的直接控制硬件的删掉了,要自己焊,拆开比较麻烦(使用热缩套把贴片和底板锁在一起,就不拆了)

由于篇幅有限以及时间问题,功能上做了一些删减。

由于是使用旧版的示例代码,有些方法已经不推荐使用了,最新的方法也有,但是最官网上BLE的示例还是使用该方法实现的,后期有时间会写一下(别问为什么不用最新的,问就是不会,问就是英语不行,问就是懒)。

贴一下安卓蓝牙的手册(当然谷歌是纯英文的)

蓝牙概述

该APP有两个界面,第一个界面显示蓝牙扫描到的蓝牙设备名称、mac地址(有些蓝牙设备是没名字的,带mac地址保险点),第二个界面连接蓝牙设备进行控制。

扫描界面放一个listview。

假定名字为SCAN_VIEW.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity" >

    <ListView
        android:id="@+id/lv_bleList"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" />

</LinearLayout>

创建一个layout(显示单条蓝牙信息)

用于显示蓝牙设备的名称和mac地址

假定名字为ITEM_BLE_LIST.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="vertical"
              android:layout_width="match_parent"
              android:layout_height="wrap_content"
              >
    <TextView android:id="@+id/device_name"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:textSize="25dp"/>
    <TextView android:id="@+id/device_address"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:textSize="15dp"/>

</LinearLayout>

扫描界面右上角设置按钮,用来扫描设备和停止扫描。

新建一个menu

假定名字为SCAN_MAIN.xml.

三个按钮分别为刷新中,扫描,停止扫描


<menu xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:id="@+id/menu_refresh"
          android:checkable="false"
          android:orderInCategory="1"
          android:showAsAction="ifRoom"/>

    <item android:id="@+id/menu_scan"
          android:title="@string/menu_scan"
          android:orderInCategory="100"
          android:showAsAction="ifRoom|withText"/>

    <item android:id="@+id/menu_stop"
          android:title="@string/menu_stop"
          android:orderInCategory="101"
          android:showAsAction="ifRoom|withText"/>

</menu>

扫描界面代码:

import java.util.ArrayList;
import java.util.List;
import java.util.Timer;

import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothAdapter.LeScanCallback;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.Handler;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.ToggleButton;
 
/**
 * Activity for scanning and displaying available Bluetooth LE devices.
 */
public  class DeviceScanActivity extends Activity implements OnClickListener  {
    private BluetoothAdapter mBluetoothAdapter;
    private boolean mScanning;
    private Handler mHandler;
    
    private static final int REQUEST_ENABLE_BT = 1;
    // Stops scanning after 10 seconds.
    private static final long SCAN_PERIOD = 10000;
    
    private DeviceListAdapter mDevListAdapter;
	ToggleButton tb_on_off;
	TextView btn_searchDev;
	Button btn_aboutUs;
	ListView lv_bleList;
	
	Timer timer;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        //getActionBar().setTitle(R.string.title_devices);
        mHandler = new Handler();
        
        
        // Use this check to determine whether BLE is supported on the device.  Then you can
        // selectively disable BLE-related features.
        if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
            Toast.makeText(this, R.string.ble_not_supported, Toast.LENGTH_SHORT).show();
            finish();
        }

        // Initializes a Bluetooth adapter.  For API level 18 and above, get a reference to
        // BluetoothAdapter through BluetoothManager.
        final BluetoothManager bluetoothManager =
                (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
        mBluetoothAdapter = bluetoothManager.getAdapter();

        // Checks if Bluetooth is supported on the device.
        if (mBluetoothAdapter == null) {
            Toast.makeText(this, R.string.error_bluetooth_not_supported, Toast.LENGTH_SHORT).show();
            finish();
            return;
        }
        lv_bleList = (ListView) findViewById(R.id.lv_bleList);
		mDevListAdapter = new DeviceListAdapter();
		lv_bleList.setAdapter(mDevListAdapter);
		lv_bleList.setOnItemClickListener(new OnItemClickListener() {
			@Override
			public void onItemClick(AdapterView<?> parent, View view,
					int position, long id) {
				if (mDevListAdapter.getCount() > 0) {	
					 BluetoothDevice device1 = mDevListAdapter.getItem(position);
				        if (device1 == null) return;
				        Intent intent1 = new Intent(DeviceScanActivity.this,
								DeviceControlActivity.class);;
				        intent1.putExtra(DeviceControlActivity.EXTRAS_DEVICE_NAME, device1.getName());
				        intent1.putExtra(DeviceControlActivity.EXTRAS_DEVICE_ADDRESS, device1.getAddress());
				        if (mScanning) {
				            mBluetoothAdapter.stopLeScan(mLeScanCallback);
				            mScanning = false;
				        }
				        startActivity(intent1);
				}
			}
		});
    }
    
	public void onClick(View v) {
		switch (v.getId()) {
		case 0:
			break;
		}
	}
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.main, menu);
        if (!mScanning) {
            menu.findItem(R.id.menu_stop).setVisible(false);
            menu.findItem(R.id.menu_scan).setVisible(true);
            menu.findItem(R.id.menu_refresh).setActionView(null);
        } else {
            menu.findItem(R.id.menu_stop).setVisible(true);
            menu.findItem(R.id.menu_scan).setVisible(false);
            menu.findItem(R.id.menu_refresh).setActionView(
                    R.layout.actionbar_indeterminate_progress);
        }
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case R.id.menu_scan:
                //mLeDeviceListAdapter.clear();
                scanLeDevice(true);
                //mDevListAdapter.;
                mDevListAdapter.clear();
                mDevListAdapter.notifyDataSetChanged();
                break;
            case R.id.menu_stop:
                scanLeDevice(false);
                break;
        }
        return true;
    }
    private void scanLeDevice(final boolean enable) {
        if (enable) {
            // Stops scanning after a pre-defined scan period.
            mHandler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    mScanning = false;
                    mBluetoothAdapter.stopLeScan(mLeScanCallback);
                    invalidateOptionsMenu();
                }
            }, SCAN_PERIOD);

            mScanning = true;
            mBluetoothAdapter.startLeScan(mLeScanCallback);
        } else {
            mScanning = false;
            mBluetoothAdapter.stopLeScan(mLeScanCallback);
        }
        invalidateOptionsMenu();
    }

	private BluetoothAdapter.LeScanCallback mLeScanCallback = new LeScanCallback() {

		@Override
		public void onLeScan(final BluetoothDevice device, int rssi,
				byte[] scanRecord) {
			runOnUiThread(new Runnable() {
				@Override
				public void run() {
					mDevListAdapter.addDevice(device);
					mDevListAdapter.notifyDataSetChanged();
				}
			});
		}
	};

	@Override
	protected void onResume() {//打开APP时扫描设备
		super.onResume();
		scanLeDevice(true);
	}

	@Override
	protected void onPause() {//停止扫描
		super.onPause();
		scanLeDevice(false);
	}

    //自定义DeviceListAdapter类,用于显示数据,清除数据
	class DeviceListAdapter extends BaseAdapter {
		private List<BluetoothDevice> mBleArray;
		private ViewHolder viewHolder;

		public DeviceListAdapter() {
			mBleArray = new ArrayList<BluetoothDevice>();
		}

		public void addDevice(BluetoothDevice device) {
			if (!mBleArray.contains(device)) {
				mBleArray.add(device);
			}
		}
		public void clear(){
			mBleArray.clear();
		}

		@Override
		public int getCount() {
			return mBleArray.size();
		}

		@Override
		public BluetoothDevice getItem(int position) {
			return mBleArray.get(position);
		}

		@Override
		public long getItemId(int position) {
			return position;
		}

		@Override
		public View getView(int position, View convertView, ViewGroup parent) {
			if (convertView == null) {
				convertView = LayoutInflater.from(DeviceScanActivity.this).inflate(
						R.layout.listitem_device, null);
				viewHolder = new ViewHolder();
				viewHolder.tv_devName = (TextView) convertView
						.findViewById(R.id.device_name);
				viewHolder.tv_devAddress = (TextView) convertView
						.findViewById(R.id.device_address);
				convertView.setTag(viewHolder);
			} else {
				convertView.getTag();
			}

			// add-Parameters
            //设置蓝牙名称和mac地址如果没有名称就设置为“unknow-device”
			BluetoothDevice device = mBleArray.get(position);
			String devName = device.getName();
			if (devName != null && devName.length() > 0) {
				viewHolder.tv_devName.setText(devName);
			} else {
				viewHolder.tv_devName.setText("unknow-device");
			}
			viewHolder.tv_devAddress.setText(device.getAddress());

			return convertView;
		}

	}
//返回蓝牙名字,mac地址
	class ViewHolder {
		TextView tv_devName, tv_devAddress;
	}
    
}

查看SCAN_VIEW.xml的design界面,如果是显示空白的,代表导入ITEM_BLE_LIST.xml没成功,在检查ITEM_BLE_LIST.xml。可能是有引用的资源没有,导致无法显示。下图是正常,没有导入成功就是空白的。

在代码转移的时候遇到过这个问题,没有报错,能够运行,但是不显示。

创建第二个界面

如下图所示

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_margin="5dp"
    android:orientation="vertical" >

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="1dp"
        android:orientation="horizontal" >

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/label_device_address"
            android:textSize="14sp" />

        <TextView
            android:id="@+id/device_address"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:textSize="14sp" />
    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="1dp"
        android:orientation="horizontal" >

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/label_state"
            android:textSize="14sp" />

        <TextView
            android:id="@+id/connection_state"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/disconnected"
            android:textSize="14sp" />
    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="1dp"
        android:layout_marginLeft="10dp"
        android:layout_marginRight="10dp"
        android:background="#00f0e0"
        android:orientation="horizontal" >

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/label_data"
            android:textSize="12sp" />

        <TextView
            android:id="@+id/data_value"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/no_data"
            android:textSize="12sp" />

        <CheckBox
            android:id="@+id/checkBox5"
            android:layout_width="wrap_content"
            android:layout_height="20dp"
            android:layout_marginLeft="50dp"
            android:layout_marginTop="0dp"
            android:text="hex收" />
    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical" >

        <EditText
            android:id="@+id/rx_data_id_1"
            android:layout_width="fill_parent"
            android:layout_height="60dp"
            android:enabled="true"
            android:focusable="false"
            android:gravity="top"
            android:inputType="textMultiLine"
            android:maxLines="10"
            android:minLines="5"
            android:scrollbars="vertical"
            android:textSize="10dp" />
    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="25dp"
        android:layout_marginLeft="10dp"
        android:layout_marginRight="10dp"
        android:layout_marginTop="0dp"
        android:background="#00f0e0"
        android:orientation="horizontal" >

        <TextView
            android:id="@+id/tx"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/TXD"
            android:textSize="12sp" />

        <CheckBox
            android:id="@+id/checkBox1"
            android:layout_width="wrap_content"
            android:layout_height="20dp"
            android:layout_marginLeft="25dp"
            android:text="hex发" />

        <CheckBox
            android:id="@+id/checkBox1_tc_send"
            android:layout_width="wrap_content"
            android:layout_height="10dp"
            android:layout_marginLeft="40dp"
            android:text="连续发"
            android:visibility="invisible" />
    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal" >

        <EditText
            android:id="@+id/tx_text"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginLeft="2dp"
            android:textSize="11sp" >
        </EditText>
    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal" >

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="#00f0e0"
            android:text="以上部份为普通 APP透传功能,一般客户需要使用APP透传数据的话,请使用以上串口中功能"
            android:textSize="11dp" />
    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="1dp"
        android:orientation="horizontal" >

        <Button
            android:id="@+id/tx_button"
            android:layout_width="60dp"
            android:layout_height="30dp"
            android:layout_marginLeft="50dp"
            android:text="发送"
            android:textSize="10sp" />

        <Button
            android:id="@+id/clear_button"
            android:layout_width="60dp"
            android:layout_height="30dp"
            android:layout_marginLeft="50dp"
            android:text="清除"
            android:textSize="10sp" />
    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginLeft="1dp"
        android:layout_marginRight="1dp"
        android:layout_marginTop="10dp"
        android:background="#f00000"
        android:orientation="horizontal" >

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="以下为MESH(串口透传、IO、PWM、LED灯、支持一对多,多对一,多对多通信"
            android:textSize="12sp" />
    </LinearLayout>

    <LinearLayout
        andr
  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值