巴法云 SDK for Java & Android 实战指南,让你轻松接入巴法云
巴法云 Java & Android SDK 实战指南,让你轻松接入巴法云
这是《巴法云 SDK》系列的第二篇。上一篇《高二学生写了 15273 行代码,就为把"接巴法云"的重复活儿包圆》聊了为什么写这个 SDK、把哪些"重复活"包了。这篇不绕弯,直接带你从加依赖跑到第一个请求,JVM 和 Android 都给完整示例,顺带把几个接入时容易忽略、或者我在设计上特意处理过的使用须知讲清楚。
看完这篇,你能搞定这几件事:
- 10 分钟内把 SDK 接进自己的 JVM / Android 项目;
- 用 Builder 链式构建任意一个巴法云 API 并发起请求;
- 绕开 SLF4J 冲突、混淆、线程模型这几个最常见的坑。
一、先一句话回顾项目
Bemfa SDK 是巴法云的 Java / Android 开发工具包。你用 Builder 链式调用把请求拼好,拿回来的是解析好的强类型业务对象——不用自己拼 URL,也不用手写 JSON 解析,更不用手动判断错误码。坐标已经发到 Maven Central:
io.github.nebulagate:bemfa-api:1.0.0
io.github.nebulagate:bemfa-jvm:1.0.0 // JVM 环境
io.github.nebulagate:bemfa-android:1.0.0 // Android 环境
它适合谁、能省什么,我用一张表带过(细节都在第一篇):
| 它能帮你 | 适合谁 |
|---|---|
| 不发 HTTP、不写 JSON 解析,直接拿业务对象 | 想快速接入巴法云、不想啃文档的同学 |
| 一套调用代码,JVM / Android 共用(SPI 自动适配平台) | 学生党(课设 / 毕设 / 电子竞赛) |
| Android 请求跟随 Activity 生命周期自动取消,防内存泄漏 | 自己写 APP 接入巴法云的 Android 开发者 |
| 错误码统一成枚举,一个姿势处理失败 | 个人开发者 & 创客做物联网小工具 |
📌 适用边界:这是 Java / Android 这一侧的方案——能在 JVM(含树莓派等能跑 Java 的环境)和 Android 上使用,适合做客户端。Arduino / ESP8266 / ESP32 这类单片机不是 Java 运行环境,暂时用不上。
二、先感受差距:不用 SDK vs 用了
看代码最直观。拿"获取主题列表"来说,不用 SDK 时你得自己揽一大堆活:
// 不用 SDK:自己拼 URL、自己建 OkHttp、自己 parse JSON、自己判 code
Request request = new Request.Builder()
.url("https://api.bemfa.com/api/...").build();
Response response = client.newCall(request).execute();
JSONObject obj = new JSONObject(response.body().string());
if (obj.getInt("code") != 0) {
/* 自己映射错误 */
}
JSONArray arr = obj.getJSONArray("data"); // 还得记清这回字段叫 data 还是 array
用了 SDK 之后:
// 用了 SDK:直接拿强类型业务对象
BemfaClient.init(config);
TopicInfos result = BemfaClient.getHttpClient().executeSync(
BemfaRequestApis.v1.Device.getAllTopicApiBuilder()
.topicType(TopicType.MQTT)
.build()
);
System.out.println(result.getTopics()); // 不用解析 JSON,字段已是对象
拼 URL、解析 JSON、判错误码这些脏活、累活,SDK 一次性全包了。
三、JVM 环境:5 步跑通
1. 加依赖(Gradle)
dependencies {
implementation('io.github.nebulagate:bemfa-api:1.0.0')
implementation('io.github.nebulagate:bemfa-jvm:1.0.0')
}
已发布到 Maven Central,不需要像 JitPack 那样额外配仓库。用 Maven 的话把
bemfa-api+bemfa-jvm两个依赖写进pom.xml即可。
2. 初始化
BemfaConfig config = new BemfaConfig();
config.setLogLevel(LogLevel.INFO); // 想看 SDK 日志就开
BemfaClient.init(config);
3. 登录
// 手机号登录(也支持邮箱登录)
BemfaClient.getHttpClient().executeSync(
BemfaRequestApis.v1.User.loginWithPhoneApiBuilder()
.phone("yourPhone")
.password("yourPassword")
.area("86")
.build()
);
// 也可以 UID 登录:
// BemfaClient.loginByUid("yourUid");
4. 建主题 + 推消息(完整一条龙)
HttpClient client = BemfaClient.getHttpClient();
// 创建设备主题
client.executeSync(
BemfaRequestApis.v1.Device.createTopicApiBuilder()
.topicId("yourTopic")
.topicType(TopicType.MQTT)
.nickname("客厅灯")
.build()
);
// 推送消息
client.executeSync(
BemfaRequestApis.v1.Device.pushMessageApiBuilder()
.topicId("yourTopic")
.topicType(TopicType.MQTT)
.message("开灯")
.build()
);
// 获取所有主题,直接拿强类型 TopicInfos
TopicInfos topics = client.executeSync(
BemfaRequestApis.v1.Device.getAllTopicApiBuilder()
.topicType(TopicType.MQTT)
.build()
);
System.out.println(topics.getTopics());
5. 关闭
BemfaClient.close();
到这 JVM 就跑通了。后台任务里同步调用不阻塞,直接 executeSync 最省事。
四、Android 环境:注意线程
1. 加依赖(Gradle)
dependencies {
implementation('io.github.nebulagate:bemfa-api:1.0.0')
implementation('io.github.nebulagate:bemfa-android:1.0.0')
}
📌 AndroidX 依赖:SDK 的 Android 模块用了 AndroidX 的 Lifecycle 特性,仅支持 AndroidX 项目。若还在用旧版 Support Library(
android.support.*),需先迁移到 AndroidX 才能接入。
2. 初始化(建议开启生命周期管理)
AndroidBemfaConfig config = new AndroidBemfaConfig();
config.setHttpLifecycleAutoManaged(true); // 开启后请求自动跟随 Activity 生命周期
BemfaClient.init(config);
开启后,把 Activity 作为 tag 传进请求,页面 onDestroy() 时 SDK 自动取消该页面名下的在途请求,你不用手写取消逻辑。
3. 后台线程登录(同步会阻塞,必须在后台线程)
new Thread(() -> {
BemfaClient.getHttpClient().executeSync(
BemfaRequestApis.v1.User.loginWithPhoneApiBuilder()
.phone("yourPhone")
.password("yourPassword")
.area("86")
.build()
);
}).start();
4. 带 Activity tag 请求(页面销毁自动取消)
new Thread(() -> {
try {
TopicInfo topic = BemfaClient.getHttpClient().executeSync(
BemfaRequestApis.v1.Device.getTopicApiBuilder()
.topicId("yourTopic")
.topicType(TopicType.MQTT)
.build(),
MainActivity.this // 传入 Activity 作为 tag,页面销毁时自动取消
);
runOnUiThread(() -> textView.setText("主题昵称:" + topic.getNickname()));
} catch (RequestCanceledException e) {
// 页面已销毁,请求被自动取消,无需处理
} catch (BemfaSdkException e) {
runOnUiThread(() -> showError(e));
}
}).start();
5. 异步请求(主线程发起,回调需切回 UI)
BemfaClient.getHttpClient().executeAsync(
BemfaRequestApis.v1.Device.getTopicApiBuilder()
.topicId("yourTopic")
.topicType(TopicType.MQTT)
.build(),
new RequestCallback<TopicInfo>() {
@Override
public void onSuccess(TopicInfo topic) {
runOnUiThread(() -> textView.setText("主题昵称:" + topic.getNickname()));
}
@Override
public void onError(BemfaSdkException e) {
runOnUiThread(() -> textView.setText("请求失败:" + e.getMessage()));
}
}
);
⚠️ Android 线程模型:同步
executeSync会阻塞当前线程,必须在后台线程执行;异步executeAsync调用本身可在主线程发起(网络在 SDK 内部线程池跑),但回调运行在后台线程,更新 UI 一定要runOnUiThread(...)包起来。
五、请求怎么构建(Builder 三种写法)
所有 API 都是 Builder 链式构造,编译期强校验,漏填参数直接编译不过。三种写法你可以挑顺手的:
// 一:用集中访问点(推荐,IDE 自动补全最友好)
BemfaRequestApi<Void> apiA = BemfaRequestApis.v1.User.loginWithPhoneApiBuilder()
.phone("yourPhone")
.password("yourPassword")
.area("86")
.build();
// 二:直接用对应的 API Builder
LoginWithPhoneApi apiB = LoginWithPhoneApi.builder()
.phone("yourPhone")
.password("yourPassword")
.area("86")
.build();
// 三:执行时现写(最简洁)
BemfaClient.getHttpClient().executeSync(
BemfaRequestApis.v1.User.loginWithPhoneApiBuilder()
.phone("yourPhone")
.password("yourPassword")
.area("86")
.build()
);
目前已封装 41 个 API,按功能分了类:Device(设备管理)、User(用户认证)、Timer(定时任务)、Image(图片)、WeChat(微信通知)、Share(设备分享)、Firmware(OTA)、Voice(语音)、Time(校时)。返回值都是强类型对象(TopicInfo、TimerInfos 等),不是 JSON 字符串。
六、同步还是异步
HttpClient client = BemfaClient.getHttpClient();
BemfaRequestApi<String> api = BemfaRequestApis.v1.Time
.getCurrentTimeApiBuilder()
.type(1)
.build();
// 同步:阻塞当前线程,直接返回结果,try-catch 捕获异常
String time = client.executeSync(api);
// 异步:不阻塞,结果在回调里返回,可按错误类型分别处理
client.executeAsync(api, new RequestCallback<String>() {
@Override
public void onSuccess(String result) {
System.out.println("成功:" + result);
}
@Override
public void onBusinessError(BemfaSdkErrorCode errorCode, ApiBusinessException e) {
System.err.println("业务错误:" + e.getMessage());
}
@Override
public void onNetworkError(NetworkException e) {
System.err.println("网络错误:" + e.getMessage());
}
@Override
public void onResponseParseError(String responseBody, ApiResponseException e){
System.err.println("响应解析错误:" + e.getMessage());
}
@Override
public void onError(BemfaSdkException e) {
System.err.println("其他错误:" + e.getMessage());
}
});
// 如果对请求产生的错误不关心,也可以只实现回调接口的成功方法
client.executeAsync(api, new RequestCallback<String>() {
@Override
public void onSuccess(String result) {
System.out.println("成功:" + result);
}
});
具体用同步还是异步,看你调用方在哪个线程、要不要当场等结果——前面两段代码已经写清楚了。
七、接入前你需要留意的几点(使用须知)
下面几个点,是接入时容易忽略、或者我在设计上特意帮你处理过、也有需要你配合一下的地方:
1. SLF4J 绑定:SDK 已经帮你选好默认实现
为了开箱即用,bemfa-jvm 默认绑定 slf4j-jdk14、bemfa-android 默认绑定 slf4j-android。如果你的项目已经接了 Logback / Log4j2 / Logback-Android,会出现「SLF4J 检测到多个绑定」的冲突警告——这时排除掉 SDK 的默认绑定、引你自己的即可:
implementation('io.github.nebulagate:bemfa-jvm:1.0.0') {
exclude group: 'org.slf4j', module: 'slf4j-jdk14'
}
// Android
implementation('io.github.nebulagate:bemfa-android:1.0.0') {
exclude group: 'org.slf4j', module: 'slf4j-android'
}
(slf4j-api 门面由 bemfa-api 自动传递,不用手动声明。)
2. 混淆(R8 / ProGuard):已内置规则
Android 模块通过 consumer-rules.pro 内置了混淆规则,开启混淆的 Release 构建会自动合并 SDK 的 -keep 规则,一般不用你额外配置。
3. 配置需按平台选择类(当前版本的设计取舍)
这块是我目前还没做干净的地方——初始化时 JVM 用 BemfaConfig、Android 必须用 AndroidBemfaConfig;取配置也得你自己传平台类。理想情况是这两步像选 HTTP 客户端那样由 SDK 内部自动判断,但受 Java 类型擦除 + 静态构造限制,暂时没找到干净的实现,这版只好先保留手动选择,接入时按平台选对类就行。大佬们要是有更顺的思路,欢迎去 Gitee Issue / GitHub Issue 聊。
4. 错误处理分层:异常类型已为你规划好
SDK 把失败归成了明确的异常类型,按需捕获即可,不用你自己去解析错误码:
| 错误类型 | 异常类 | 说明 |
|---|---|---|
| 参数校验错误 | InvalidArgumentException |
构建请求时参数不合法 |
| 网络连接错误 | NetworkException |
无网络、超时等 |
| HTTP 状态错误 | ApiHttpException |
服务器返回非 2xx |
| 响应解析错误 | ApiResponseException |
JSON 解析失败等 |
| 请求被取消 | RequestCanceledException |
生命周期销毁或手动取消 |
| 业务逻辑错误 | ApiBusinessException |
后端业务错误码(如主题不存在) |
| 客户端状态错误 | IllegalClientStateException |
未登录 |
| 未初始化错误 | UninitializedException |
未初始化 SDK |
| SPI 错误 | ServiceProviderException |
平台适配器加载失败 |
同步调用用 try-catch 捕获,异步调用在 onError / 各分类回调里统一处理。
5. Android 同步必须在后台线程
这是 Android 平台的线程约束(不是 SDK 的限制,但 SDK 会如实遵守):executeSync 会阻塞当前线程,务必包在 new Thread(...) / 协程 / Executors 里,别在主线程调。
八、结尾 & 相关阅读
这一篇就到这,"怎么接"应该讲清楚了。系列两篇是这样分工的:
- 第一篇:为什么写这个 SDK、把哪些重复活包了(初衷、设计思路、已知缺陷都在那);
- 这一篇:从依赖到跑通请求,JVM / Android 完整示例 + 避坑。
我是个高二学生,这个 SDK 是课余时间一点点堆出来的。要是它帮你省掉了手拼 HTTP / JSON 那堆活儿,欢迎来:
- 🌟 GitHub 点个 Star(对个人开发者是最大的鼓励)
- 🐛 Gitee Issues(国内访问快) / GitHub Issues 提 Bug、建议或 PR
完整用法、41 个 API 参考和更多示例,都在 GitHub README。后面真要写 TCP / MQTT 长连接那篇,我还会在这个系列更,感兴趣可以留意一下。
浙公网安备 33010602011771号