基于 STM32 WB 蓝牙模块的开源 SDK 实现蓝牙对讲功能时,总是无法建立连接。 而使用官方 APP ST BLE Sensor 或者我自己不用 SDK 实现的 App 都可以正常建立连接。
最终发现是前台服务,及 Android 12 的兼容性问题引起的。做了下修改就可以正常运行了。
连接异常
我的状态异常:
Lost connection with the node BVL-WB1
而官方 APP 是在正常连接中显示:
连接到
对应的翻译文件:
<string name="progressDialogConnTitle">Connecting..</string>
<string name="progressDialogConnMsg">Connecting to: %s</string>
<string name="progressDialogConnMsgLostNodeError">Lost connection with the node %s</string>
显示代码在 ConnectionStatusView/ConnectionStatusView.java
@Override
public void showLostNodeError(String nodeName) {
final String error = String.format(getContext().getString(R.string.progressDialogConnMsgLostNodeError), nodeName);
mGuiThread.post(() -> showError(error));
}
ConnectionStatusView/ConnectionStatusController.java
private Node.NodeStateListener mNodeStateListener = new Node.NodeStateListener() {
@Override
public void onStateChange(@NonNull Node node, @NonNull Node.State newState, @NonNull Node.State prevState) {
switch (newState){
case Connecting:
mView.showConnecting(node.getName());
break;
case Connected:
mView.showConnected();
break;
case Disconnecting:
break;
case Lost:
mView.showLostNodeError(node.getName());
break;
case Unreachable:
mView.showUnreachableNodeError(node.getName());
break;
case Dead:
mView.showDeadNodeError(node.getName());
break;
case Init:
case Idle:
break;
}
}
为何状态会变成 Lost 呢
日志中显示:
BVL-WB1 Idle->Lost
蓝牙模块有哪些状态
com/st/BlueSTSDK/Node.java
/** State of the node */
public enum State {
/** dummy initial state */
Init,
/** the node is waiting for a connection, it is sending advertise message*/
Idle,
/** we open a connection with the node */
Connecting,
/** we are connected with the node, this status can be fired 2 times if we do a secure
* connection using bt pairing */
Connected,
/** we are closing the node connection */
Disconnecting,
/** we saw the advertise message for some time but now we do not receive anymore*/
Lost,
/** we were connected with the node but now it is disappear without
disconnecting */
Unreachable,
/** dummy final state */
Dead
}//State
建立连接的过程
DemosActivity.java onResume
if(!mNode.isConnected()){
mNode.addNodeStateListener(mBuildDemoAdapterOnConnection);
NodeConnectionService.connect(this,mNode, mConnectionOption);
NodeConnectionService.java
/**
* start the service asking to connect with the node
* @param c context used for start the service
* @param n node to connect
* @param option connection options, if no parameters present the default one will be used
*/
static public void connect(Context c, Node n,@Nullable ConnectionOption option ){
Intent i = new Intent(c,NodeConnectionService.class);
i.setAction(CONNECT_ACTION);
i.putExtra(NODE_TAG_ARG,n.getTag());
if(option==null)
option = ConnectionOption.builder().build();
i.putExtra(CONNECTION_PARAM_ARG,option);
ContextCompat.startForegroundService(c,i);
}
ContextCompat.startForegroundService(c,i);
调用之后,Service 对应的入口函数在哪里?
Inside the service, usually in onStartCommand(), you can request that your service run in the foreground. To do so, call startForeground(). This method takes two parameters: a positive integer that uniquely identifies the notification in the status bar and the Notification object itself.
在 onStartCommand 中打印日志,并没有显示。说明没有走这里。
加个 onCreate 试试,也没有显示日志。
感觉没有建立连接
但是我用自己写的 BLE 工具就可以正常的建立连接。
前台服务的 Manifest 配置
白天没定位到问题,下班的班车上搜了一下关于前台服务 (Foreground Service) 的资料。在微信公众号上找到不少有用的文章。
对照着,确实发现了几个问题:
Manifest 文件增加配置:
<!-- needed for the NodeConnectionService: Android 9 (API level 28) or higher -->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<!-- application -->
<service
android:name=".NodeConnectionService"
android:enabled="true"
android:exported="false" />
修改之后,就可以看到建立连接的状态显示了。
唯一难以理解的是,为何之前没有加配置任何提示都没有。
FLAG_IMMUTABLE or FLAG_MUTABLE be specified when creating a PendingIntent
java.lang.RuntimeException: Unable to start service com.sunzhongwei.bluevoice.NodeConnectionService@f2b942d with Intent { act=com.sunzhongwei.bluevoice.NodeConnectionService.CONNECT cmp=com.sunzhongwei.bluevoice/.NodeConnectionService (has extras) }: java.lang.IllegalArgumentException: com.sunzhongwei.bluevoice: Targeting S+ (version 31 and above) requires that one of FLAG_IMMUTABLE or FLAG_MUTABLE be specified when creating a PendingIntent.
修复:
private PendingIntent getDisconnectPendingIntent(Node n){
Intent stopServiceIntent = buildDisconnectIntent(this,n);
return PendingIntent.getService(this, STOP_SERVICE, stopServiceIntent,
- PendingIntent.FLAG_ONE_SHOT);
+ //PendingIntent.FLAG_ONE_SHOT);
+ PendingIntent.FLAG_IMMUTABLE
+ );
}
这里的 pending intent 用于点击通知条上的断开连接按钮时触发。
最后
至此,功能终于调通了,顺便学习了 Service 及 Foreground Service 的使用。
看来边动手写代码,边查,更适合我。
参考
- https://medium.com/androiddevelopers/all-about-pendingintents-748c8eb8619
微信关注我哦 👍
我是来自山东烟台的一名开发者,有感兴趣的话题,或者软件开发需求,欢迎加微信 zhongwei 聊聊, 查看更多联系方式