如何宣传Android作为Bluetooth LE外围设备

尽管是一种相对较新的技术,但低功耗蓝牙(LE)已证明自己是一种通用且有用的通信介质。 尽管它可以用于无线连接设备,但它也使设备能够充当信标和广播数据。

在本教程中,您将学习BluetoothLeAdvertiser类,该类使开发人员无需额外的硬件即可将受支持的电话变成Bluetooth LE信标。 您还将学习如何扫描Bluetooth LE广告数据,以便可以在自己的应用程序中做出适当的反应。 您可以在GitHub上下载本教程的源文件。

1.项目设置

对于本教程,您可以从在Android Studio中创建一个基本的空项目开始。 您需要在build.gradle文件中将最低SDK版本设置为21 ,因为直到Lollipop发行版才在Android上引入了蓝牙LE广告。 尽管有一些方法可以包装在SDK 21之前不支持的API,但本教程将不介绍它们。 我们只专注于手头的新技术。

defaultConfig {
    applicationId "com.tutsplus.bleadvertising"
    minSdkVersion 21
    targetSdkVersion 23
    versionCode 1
    versionName "1.0"
}

接下来,您需要向项目的AndroidManifest.xml添加三个权限。 前两个允许蓝牙通信,第三个许可ACCESS_COARSE_LOCATION是在Android 6.0及更高版本的设备上使用蓝牙的新要求。

<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

如果您在运行Android 6.0或更高版本的设备上进行开发,则您的应用需要用户授予的位置权限。 可以在我今年早些时候写的《 了解Android M中的权限》中找到有关执行此操作的说明。 为了简单起见,本教程将仅在Android App Info屏幕上授予权限。

Android应用程序权限屏幕显示已授予的位置权限

既然您已经有权访问应用程序所需的所有内容,那么现在该创建布局文件了。 打开activity_main.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="match_parent"
    android:orientation="vertical">

    <Button
        android:id="@+id/advertise_btn"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Advertise"/>

    <Button
        android:id="@+id/discover_btn"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Discover" />

    <TextView
        android:id="@+id/text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="test"/>
</LinearLayout>

这两个Button对象用于启动广告或发现。 TextView用于显示发现时发现的数据。 完成填写布局文件后,可以将其关闭并打开MainActivity.java 。 在此文件中要做的第一件事是添加按钮所使用的View.OnClickListener的实现。

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
    
    @Override
    public void onClick(View v) {
        if( v.getId() == R.id.discover_btn ) {
            discover();
        } else if( v.getId() == R.id.advertise_btn ) {
            advertise();
        }
    }
}

在上面的onClick(View v)方法中,本教程后面将定义advertise()discover() 。 您现在可以为这些方法添加存根,以便您的应用进行编译。 接下来,您需要在类的顶部创建成员变量,以跟踪按钮和文本视图。

private TextView mText;
private Button mAdvertiseButton;
private Button mDiscoverButton;

定义视图后,需要在onCreate(Bundle savedInstanceState)对其进行初始化,并将每个Button连接到OnClickListener定义的OnClickListener

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    mText = (TextView) findViewById( R.id.text );
    mDiscoverButton = (Button) findViewById( R.id.discover_btn );
    mAdvertiseButton = (Button) findViewById( R.id.advertise_btn );
    
    mDiscoverButton.setOnClickListener( this );
    mAdvertiseButton.setOnClickListener( this );
}

最后,请确保您或您的用户使用的设备支持多个广告。 虽然Lollipop可以提供外围设备广告所需的软件功能,但制造商还必须使用支持广告的蓝牙芯片组。

如果不支持Bluetooth LE广告,则应禁用应用程序中的两个按钮。 虽然已知此功能可在Nexus 6、5X,6P和9上使用,但其他手机也支持Bluetooth LE广告,随着制造商生产更新的手机和平板电脑,将继续制造其他设备。

if( !BluetoothAdapter.getDefaultAdapter().isMultipleAdvertisementSupported() ) {
    Toast.makeText( this, "Multiple advertisement not supported", Toast.LENGTH_SHORT ).show();
    mAdvertiseButton.setEnabled( false );
    mDiscoverButton.setEnabled( false );
}

2.通过蓝牙LE投放广告

要启动广告通过蓝牙LE,你需要检索BluetoothLeAdvertiser从Android BluetoothAdapter 。 您可以在点击广告按钮时调用的advertise()方法中执行此操作。

BluetoothLeAdvertiser advertiser = BluetoothAdapter.getDefaultAdapter().getBluetoothLeAdvertiser();

有了BluetoothLeAdvertiser ,您就可以定义在广告中使用的设置,例如广播时天线应使用的电量以及设备应多久进行一次广告宣传。 AdvertiseSettings.Builder类还允许您定义移动设备是否应可连接,从而可以跨设备流式传输更多数据。

AdvertiseSettings settings = new AdvertiseSettings.Builder()
        .setAdvertiseMode( AdvertiseSettings.ADVERTISE_MODE_LOW_LATENCY )
        .setTxPowerLevel( AdvertiseSettings.ADVERTISE_TX_POWER_HIGH )
        .setConnectable( false )
        .build();

您会注意到,此示例在广告中具有较高的信号强度(发射功率)和较低的延迟。 虽然这可以使您的设备快速被发现,但它也可能会占用大量电池,这在移动空间中发展时是宝贵的商品。

广告模式还有其他选项。 ADVERTISE_MODE_LOW_POWER选项是广告的默认设置,并以最少的频率传输以节省最大电量。 ADVERTISE_MODE_BALANCED选项尝试节省功率,而不必在广告之间等待太久。

可以将TX功率设置为超低,低,中或高。 每个级别对应于蓝牙LE广告包可见的程度,尽管确切范围取决于设备硬件。

接下来,定义一个UUID,用于在发布数据包时标识它们。 您可以从命令行使用uuidgen实用程序来创建新的UUID。

➜  ~  uuidgen
CDB7950D-73F1-4D4D-8E47-C090502DBD63

虽然此实用程序创建了128位的UUID,但Android系统仅使用16位的UUID进行广告宣传,并将自动调整128位的UUID以使其符合要求。 在上面的示例中,16位UUID为950D。 接下来,将128位UUID另存为strings.xml中的字符串

<string name="ble_uuid">CDB7950D-73F1-4D4D-8E47-C090502DBD63</string>

一旦创建了UUID,就该创建ParcelUuidAdvertiseData对象,并广播一些附加数据作为附加服务了。 在此示例中,您仅广播了设备的名称和字符串"Data" (必须将其转换为字节数组),因为您的广告数据包的大小相当有限。

ParcelUuid pUuid = new ParcelUuid( UUID.fromString( getString( R.string.ble_uuid ) ) );

AdvertiseData data = new AdvertiseData.Builder()
        .setIncludeDeviceName( true )
        .addServiceUuid( pUuid )
        .addServiceData( pUuid, "Data".getBytes( Charset.forName( "UTF-8" ) ) )
        .build();

使用设备通过Bluetooth LE进行广告的最后一件事是创建一个回调,侦听广告时是否成功,然后再通过BluetoothLeAdvertiser广告。

AdvertiseCallback advertisingCallback = new AdvertiseCallback() {
    @Override
    public void onStartSuccess(AdvertiseSettings settingsInEffect) {
        super.onStartSuccess(settingsInEffect);
    }

    @Override
    public void onStartFailure(int errorCode) {
        Log.e( "BLE", "Advertising onStartFailure: " + errorCode );
        super.onStartFailure(errorCode);
    }
};

advertiser.startAdvertising( settings, data, advertisingCallback );

此时,您应该能够运行您的应用并开始通过Bluetooth LE进行广告。 但是,本教程的下一步将涉及发现广告,以便您可以显示该信息。

3.发现蓝牙LE广告

在开始发现Bluetooth LE服务之前,您需要在课程顶部添加一些其他成员变量。

private BluetoothLeScanner mBluetoothLeScanner;
private Handler mHandler = new Handler();

mBluetoothLeScanner用于扫描蓝牙LE数据包,并且mHandler控制一个小的计时器,该计时器在设置的时间段后停止发现。

除了这些成员变量之外,您还需要在类的顶部创建一个新的ScanCallback ,以便稍后内部类可以在应用程序中对其进行访问。 此回调接收发现的可接受广告的结果,并在文本视图中显示广告设备名称和关联的数据。

private ScanCallback mScanCallback = new ScanCallback() {
    @Override
    public void onScanResult(int callbackType, ScanResult result) {
        super.onScanResult(callbackType, result);
        if( result == null
                || result.getDevice() == null
                || TextUtils.isEmpty(result.getDevice().getName()) )
            return;

        StringBuilder builder = new StringBuilder( result.getDevice().getName() );

        builder.append("\n").append(new String(result.getScanRecord().getServiceData(result.getScanRecord().getServiceUuids().get(0)), Charset.forName("UTF-8")));

        mText.setText(builder.toString());
    }

    @Override
    public void onBatchScanResults(List<ScanResult> results) {
        super.onBatchScanResults(results);
    }

    @Override
    public void onScanFailed(int errorCode) {
        Log.e( "BLE", "Discovery onScanFailed: " + errorCode );
        super.onScanFailed(errorCode);
    }
};

接下来,如下所示在onCreate(Bundle savedInstanceState)初始化mBluetoothLeScanner

mBluetoothLeScanner = BluetoothAdapter.getDefaultAdapter().getBluetoothLeScanner();

初始化蓝牙扫描器后,您可以开始充实discover()方法。 对于此示例应用程序,您将创建一个ScanFilter对象并将其放入List以便您的应用程序仅响应您感兴趣的广告包。

ScanFilter filter = new ScanFilter.Builder()
        .setServiceUuid( new ParcelUuid(UUID.fromString( getString(R.string.ble_uuid ) ) ) )
        .build();
filters.add( filter );

您还需要创建一个ScanSettings对象,该对象的工作原理与您在本教程前面创建的AdvertiseSettings对象相似。

ScanSettings settings = new ScanSettings.Builder()
        .setScanMode( ScanSettings.SCAN_MODE_LOW_LATENCY )
        .build();

设置好过滤器,设置和回调后,即可开始发现Bluetooth LE广告。

mBluetoothLeScanner.startScan(filters, settings, mScanCallback);

如果现在在两个都支持Bluetooth LE广告的设备上运行您的应用程序,并且将其中一个设置为做广告,而另一个设置为进行发现,则发现设备应找到广告商并显示广告的数据。 以下屏幕截图显示了Nexus 5X发现了广告Nexus 6。

Nexus 5X从Nexus 6发现蓝牙LE广告数据包

您需要做的最后一件事是创建一个新的Runnable对象,并将其与mHandler关联。 处理程序等待十秒钟,然后启动可停止发现的Runnable 。 原因是发现会很快耗尽设备的电池。 您只想尝试在短时间内或期望找到广告设备时发现广告包。

mHandler.postDelayed(new Runnable() {
    @Override
    public void run() {
        mBluetoothLeScanner.stopScan(mScanCallback);
    }
}, 10000);

结论

尽管该示例可能看起来不多,但您刚刚创建了一个可以正常工作的应用程序,该应用程序通过Bluetooth LE进行广告发布,以便其他设备可以发现它并传输数据。 尽管本教程介绍了如何通过Android进行广告和发现,但是您也可以轻松地为iOS创建类似的应用,以便在两个平台之间共享数据或构建自己的支持蓝牙LE的设备,从而可以与手机和平板电脑进行交互。

随着这项技术的不断发展并将其集成到每个人的口袋中,开发人员将有无穷的可能性制作出真正有趣的东西。 有关在Android上使用其他蓝牙技术的更多信息,请查看Matthew Kim的 使用Android的蓝牙API创建蓝牙扫描仪

翻译自: https://code.tutsplus.com/tutorials/how-to-advertise-android-as-a-bluetooth-le-peripheral--cms-25426

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值