| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Name | Name | Last commit date | ||
|---|---|---|---|---|
巴法云(Bemfa)的 Java / Android SDK —— 轻松接入,开箱即用!
👋 你好,我是一名高中生,这个 SDK 是我在课余时间从零开始写的。如果它对你有帮助,希望能点个⭐Star 支持一下 —— 你的鼓励是我继续学习和维护的动力!
📡 国内用户请注意:
- 提 Bug、建议或 PR → GitHub 与 Gitee 两个仓库都开放 Issues,国内访问慢可走 Gitee 仓库,习惯 GitHub 的也可走 GitHub 仓库;
- 点 Star 支持我 → 请到 GitHub 仓库。
简单说:Issue / PR 双平台都欢迎,Star 走 GitHub。感谢你的支持!
Bemfa SDK 是 巴法科技&巴法云 物联网平台的 Java / Android 开发工具包。它把巴法云的 REST API 封装成类型安全的 Java 接口,你用 Builder 链式调用构建请求,拿到的就是解析好的业务对象,不用自己拼 URL、不用手写 JSON 解析。
树莓派上跑 Java 也行,Android 手机上写 IoT 控制器也行,API 调用方式不变,业务模型不变,SDK 自己适配当前平台。后续有时间会更新 TCP 长连接和 MQTT 协议。
Bemfa SDK 的设计目标是「轻量、好上手」,所以在下面几类场景里最能发挥作用:
💡 本项目由个人开发者利用课余时间维护,更适合学习、原型验证与个人项目。如果你打算用于正式生产环境,建议先充分测试、并结合自身需求评估。
正常调 REST API,你得自己接 HTTP 响应、解 JSON、判错误码、抠业务字段。然而 Bemfa SDK 把这些全包了:
// ...
// 请求成功 = 拿到业务数据,就这么简单
TopicInfo topic = client.executeSync(
BemfaRequestApis.v1.Device.getTopicApiBuilder()
.topicId("yourTopic")
.topicType(TopicType.MQTT)
.build()
);
// topic 已经是强类型对象,可以直接使用
System.out.println(topic.getNickname());SDK 内部有 6 种 ResponseHandler 覆盖巴法云所有响应格式,像 JSON 解析、错误码判断、类型转换等等,这些全都由 SDK 自动完成。你拿到的不是解析好的业务对象,就是带明确原因的异常。
SDK 用 SPI(Service Provider Interface)机制做了平台无关的架构:
bemfa-api 公开 API 层(接口、模型、注解),所有平台共享 ├── bemfa-core 核心实现层(HTTP 引擎、响应处理器) ├── bemfa-jvm JVM 平台适配(SPI 注册:JvmBemfaServiceProvider) └── bemfa-android Android 平台适配(SPI 注册:AndroidBemfaServiceProvider)
启动时,BemfaServiceLoader 自动检测当前运行环境(JVM 还是 Android),加载对应的 BemfaServiceProvider。你不用指定平台,也不用写 if (isAndroid()) 之类的判断,引入对应平台的依赖就行,SDK 自己找。
以后要加新平台(比如鸿蒙),只需加一个 Provider 实现就够了,上层 API 不用动。
⚠️ 已知设计缺陷:配置的构建与获取尚未实现平台无感知使用 SPI 架构的初衷是让接入者完全不需要关心当前跑在什么平台——HTTP 客户端的选择、服务发现都已经做到了自动适配。但配置这块还有一个没跨过去的坎:
问题一:构建配置时需要自己选平台类
// JVM 环境
BemfaConfig config = new BemfaConfig();
// Android 环境 — 必须用 AndroidBemfaConfig,否则拿不到平台专属功能
AndroidBemfaConfig config = new AndroidBemfaConfig();问题二:获取配置时也需要传入平台类
// JVM 环境
BemfaConfig config = BemfaClient.getConfig(BemfaConfig.class);
// Android 环境 — 必须传 AndroidBemfaConfig.class
AndroidBemfaConfig config = BemfaClient.getConfig(AndroidBemfaConfig.class);理想情况下,这两步都应该由 SDK 内部自动判断平台、返回正确的配置类型,接入者完全不需要感知——就像引入依赖后 SDK 自动选择 HTTP 客户端一样。但由于 Java 类型擦除和静态构造的限制,我确实还没有找到合适的实现方式,暂时只能麻烦接入者自行判断平台。
如果你有解决思路或建议,非常欢迎在 Gitee Issue 或 GitHub Issue 中指教,不胜感激!
Activity 销毁了但网络请求还在跑,这事在 Android 开发里挺常见,往往需要手动取消相应的请求,然而手动取消又麻烦又容易漏。对此,Bemfa SDK 提供了一个可选项:
// 初始化时开启
AndroidBemfaConfig config = new AndroidBemfaConfig();
config.setHttpLifecycleAutoManaged(true);
BemfaClient.init(config);
// 也可以动态调整
BemfaClient.getConfig(AndroidBemfaConfig.class).setHttpLifecycleAutoManaged(true);
// 请求时把 Activity 作为 tag 传入
String time = http.executeSync(api, MainActivity.this);
// Activity 销毁时,SDK 将自动取消该 Activity 名下的所有在途请求开启后,LifecycleRequestManager 监听 LifecycleOwner 的 ON_DESTROY 事件,自动取消以该 Activity 为 tag 的所有在途请求。接入者的 onDestroy() 里不用写取消逻辑了。
💡 注意:默认为关闭状态。JVM 环境不受影响。
bemfa-sdk ├── bemfa-api 公开 API 层:BemfaClient、BemfaConfig、BemfaRequestApis、业务数据模型、异常、错误码等 ├── bemfa-core 核心实现层 ├── bemfa-jvm JVM 平台适配:引入此模块即可在 JVM 环境使用 ├── bemfa-android Android 平台适配:引入此模块即可在 Android 环境使用 ├── bemfa-test-jvm JVM 测试程序,主要测试各 HTTP 请求 API 的可用性 └── bemfa-test-android Android 测试程序,主要测试 HTTP 请求的生命周期自动管理
| 你的环境 | 需要引入的模块 |
|---|---|
| JVM(服务端、树莓派等) | bemfa-api + bemfa-jvm |
| Android | bemfa-api + bemfa-android |
bemfa-core 会被平台模块自动引入,无需单独依赖。
1. 添加依赖
dependencies {
implementation('io.github.nebulagate:bemfa-api:1.0.0')
implementation('io.github.nebulagate:bemfa-jvm:1.0.0')
}坐标已发布至 Maven Central,无需像 JitPack 那样额外配置仓库。如果你使用 Maven 构建,等效配置如下(pom.xml):
<dependency>
<groupId>io.github.nebulagate</groupId>
<artifactId>bemfa-api</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>io.github.nebulagate</groupId>
<artifactId>bemfa-jvm</artifactId>
<version>1.0.0</version>
</dependency>bemfa-jvm 默认已绑定 slf4j-jdk14(JDK 自带日志框架),引入依赖后无需额外配置即可输出 SDK 日志。
如果你已在项目中接入了其他基于 SLF4J 的日志框架(如 Logback、Log4j2),需要排除 SDK 默认的绑定、再引入你自己的绑定,否则会出现「SLF4J 检测到多个绑定」的冲突警告:
implementation('io.github.nebulagate:bemfa-jvm:1.0.0') {
exclude group: 'org.slf4j', module: 'slf4j-jdk14'
}slf4j-api 门面由 bemfa-api 自动传递引入,你无需手动声明;需要管理的只是「绑定」这一层。
2. 初始化 SDK
BemfaConfig config = new BemfaConfig();
config.setLogLevel(LogLevel.INFO);
BemfaClient.init(config);3. 登录并发起请求
HttpClient client = BemfaClient.getHttpClient();
// 使用手机号登录(还支持邮箱登录)
client.executeSync(
BemfaRequestApis.v1.User.loginWithPhoneApiBuilder()
.phone("yourPhone")
.password("yourPassword")
.area("86")
.build()
);
// 也可以使用 UID 登录
// BemfaClient.loginByUid("yourUid");
// 创建设备主题
client.executeSync(
BemfaRequestApis.v1.Device.createTopicApiBuilder()
.topicId("yourTopic")
.topicType(TopicType.MQTT)
.nickname("客厅灯")
.build()
);
// 获取所有主题,直接拿到 TopicInfos 对象,不用解析 JSON
TopicInfos topics = client.executeSync(
BemfaRequestApis.v1.Device.getAllTopicApiBuilder()
.topicType(TopicType.MQTT)
.build()
);
// 推送消息
client.executeSync(
BemfaRequestApis.v1.Device.pushMessageApiBuilder()
.topicId("yourTopic")
.topicType(TopicType.MQTT)
.message("开灯")
.build()
);
// ...4. 关闭 SDK
BemfaClient.close();1. 添加依赖
dependencies {
implementation('io.github.nebulagate:bemfa-api:1.0.0')
implementation('io.github.nebulagate:bemfa-android:1.0.0')
}坐标已发布至 Maven Central,无需像 JitPack 那样额外配置仓库。Android 项目通常用 Gradle,如果你使用 Maven 构建,等效配置如下(pom.xml):
<dependency>
<groupId>io.github.nebulagate</groupId>
<artifactId>bemfa-api</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>io.github.nebulagate</groupId>
<artifactId>bemfa-android</artifactId>
<version>1.0.0</version>
</dependency>💡 关于 SLF4J 日志绑定(Android)📌 AndroidX 依赖:由于 SDK 的 Android 模块使用了 AndroidX 的 Lifecycle 特性,目前仅支持 AndroidX 项目集成。若你的项目仍在使用旧版 Support Library(android.support.*),需先迁移到 AndroidX 才能接入 bemfa-android。
bemfa-android 默认已绑定 slf4j-android(输出到 Android Logcat),引入依赖后无需额外配置即可输出 SDK 日志。
如果你已在项目中接入了其他基于 SLF4J 的日志框架(如 Logback-Android),需要排除 SDK 默认的绑定、再引入你自己的绑定,否则会出现「SLF4J 检测到多个绑定」的冲突警告:
implementation('io.github.nebulagate:bemfa-android:1.0.0') {
exclude group: 'org.slf4j', module: 'slf4j-android'
}slf4j-api 门面由 bemfa-api 自动传递引入,你无需手动声明;需要管理的只是「绑定」这一层。
📌 混淆(R8 / ProGuard):SDK 已通过 consumer-rules.pro 内置混淆规则,开启混淆的 Release 构建会自动合并 SDK 内置的 -keep 规则。
2. 初始化(可开启生命周期管理)
AndroidBemfaConfig config = new AndroidBemfaConfig();
config.setHttpLifecycleAutoManaged(true); // 开启后请求自动跟随 Activity 生命周期
BemfaClient.init(config);3. 登录
// 防止线程阻塞,需在后台线程执行 HTTP 请求
new Thread(() -> {
// 手机号登录(还支持邮箱登录)
BemfaClient.getHttpClient().executeSync(
BemfaRequestApis.v1.User.loginWithPhoneApiBuilder()
.phone("yourPhone")
.password("yourPassword")
.area("86")
.build()
);
}).start();
// 也可以使用 UID 登录:
// BemfaClient.loginByUid("yourUid");4. 在后台线程发起请求(自动跟随生命周期)
new Thread(() -> {
try {
HttpClient http = BemfaClient.getHttpClient();
// 获取主题信息,直接拿到强类型 TopicInfo 对象,不用解析 JSON
TopicInfo topic = http.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) {
// 其他 SDK 异常(网络 / 业务 / HTTP 等)统一兜底
runOnUiThread(() -> showError(e));
}
}).start();5. 异步请求(回调在后台线程,UI 需切回主线程)
// 异步调用本身可在主线程发起;回调运行在后台线程,更新 UI 需 runOnUiThread 包起来
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()));
}
}
);6. 关闭 SDK
BemfaClient.close();SDK 对巴法云 API 按功能重新进行了分类,提供集中访问点(BemfaRequestApis 类),全部使用 Builder 模式链式构建:
| 分类 | 模块入口 | 代表性 API |
|---|---|---|
| 设备管理 | BemfaRequestApis.v1.Device | 创建/删除主题、获取主题列表、推送消息、修改分组/房间、修改主题昵称、获取主题昵称 |
| 用户认证 | BemfaRequestApis.v1.User | 手机/邮箱注册、手机/邮箱登录、创建/查询/删除 AppId |
| 定时任务 | BemfaRequestApis.v1.Timer | 添加/查询/启用/禁用/删除定时器 |
| 图片管理 | BemfaRequestApis.v1.Image | 上传图片、获取图片列表、删除图片 |
| 微信通知 | BemfaRequestApis.v1.WeChat | 发送微信提醒/告警 |
| 设备分享 | BemfaRequestApis.v1.Share | 分享主题、查询分享记录、取消分享 |
| 固件 OTA | BemfaRequestApis.v1.Firmware | 获取/上传固件 |
| 语音上传 | BemfaRequestApis.v1.Voice | 上传语音文件 |
| 网络校时 | BemfaRequestApis.v1.Time | 获取服务端时间 |
返回值都是强类型 Java 对象(TopicInfo、TimerInfos、ImageInfo、FirmwareInfo 等),不是 JSON 字符串。
📌 API 版本说明
当前 SDK 基于 2026 年 1 月 10 日巴法云官方 API 文档实现,暂未同步最新版本。完整 API 文档请参考 巴法云 HTTP 请求 API 文档 — 2026.1.10(PDF)。
作者学业繁忙,后续会尽量抽时间更新,感谢理解与耐心。
// 一:使用集中访问点(推荐)
BemfaRequestApi<Void> apiA = BemfaRequestApis.v1.User.loginWithPhoneApiBuilder()
.phone("yourPhone")
.password("yourPassword")
.area("86")
.build();
// 或者
LoginWithPhoneApi apiB = BemfaRequestApis.v1.User.loginWithPhoneApiBuilder()
.phone("yourPhone")
.password("yourPassword")
.area("86")
.build();
// 二:直接使用相应的 API Builder
LoginWithPhoneApi apiC = LoginWithPhoneApi.builder()
.phone("yourPhone")
.password("yourPassword")
.area("86")
.build();
// 或者
LoginWithPhoneApi apiD = LoginWithPhoneApi.loginWithPhoneApiBuilder()
.phone("yourPhone")
.password("yourPassword")
.area("86")
.build()
// 三:当然你也可以直接在执行请求方法中构建 API
BemfaClient.getHttpClient().executeSync(BemfaRequestApis.v1.User.loginWithPhoneApiBuilder()
.phone("yourPhone")
.password("yourPassword")
.area("86")
.build());同步和异步都能用:
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);
}
});⚠️ 注意(Android 线程模型):
- 同步 executeSync:会阻塞当前线程,在 Android 上必须在后台线程执行。
- 异步 executeAsync:调用本身可在主线程发起(网络由 SDK 内部线程池执行,不阻塞);但回调 RequestCallback 运行在后台线程,回调内更新 UI 必须用 runOnUiThread(...) 包起来。
错误分了几层,最终都落到 BemfaSdkErrorCode 枚举或对应的异常类型:
| 错误类型 | 异常类 | 说明 |
|---|---|---|
| 参数校验错误 | InvalidArgumentException | 构建请求时参数不合法(错误码 -100) |
| 网络连接错误 | NetworkException | 无网络、连接超时等(错误码 -300) |
| HTTP 状态错误 | ApiHttpException | 服务器返回非 2xx 状态码 |
| 响应解析错误 | ApiResponseException | 响应体格式异常、JSON 解析失败(错误码 -200);non-void API 返回空响应体也会抛此异常 |
| 请求被取消 | RequestCanceledException | 请求在返回前被取消(生命周期销毁或手动 cancelByTag 等方式取消);同步直接抛出,异步经 onError 回调 |
| 业务逻辑错误 | ApiBusinessException | 后端返回的业务错误码(正数,如 40004 主题不存在) |
| 客户端状态错误 | IllegalClientStateException | 未登录 |
| 未初始化错误 | UninitializedException | 未初始化 SDK |
| SPI 错误 | ServiceProviderException | 平台适配器加载失败(错误码 -400) |
异步回调里,RequestCallback 有几个分类的错误处理方法(onBusinessError、onNetworkError、onResponseParseError 等),onError 兜底所有情况。被取消的请求在异步中也会走 onError(携带 RequestCanceledException),在同步中则直接抛出 RequestCanceledException —— 因此同步调用需用 try-catch 捕获,异步调用在 onError 中即可统一处理。
你好,我是这个项目的作者,目前就读高二,即将步入高三。
写这个 SDK 的原因挺简单的:我自己用巴法云的时候,觉得每次都要手动拼 URL、解析 JSON、处理各种格式不一样的响应体,既麻烦,又容易出错,让人烦躁。然后就想做一套简单易用的 SDK,让接入巴法云的人更省心,请求成功直接拿到业务数据,开箱即用。于是就从高一寒假开始,断断续续写到了现在。
坦白说,这是我在课余时间独立完成的项目,代码和架构上难免有不成熟的地方:
如果你在使用中遇到了问题,或者有好的想法,可随时前往 Gitee 仓库(国内访问快)或 GitHub 仓库 提 Issue / PR;如果这个 SDK 能对你有所帮助,那就是我最开心的事了 —— 也希望你抽空到 GitHub 点个 ⭐ Star,这对一个高中生开发者来说是莫大的鼓励。
如果你在使用中遇到问题,或想交流想法,欢迎通过以下方式联系我。
| 渠道 | 地址 |
|---|---|
| Gitee Issues(国内推荐) | Gitee Issues |
| GitHub Issues | GitHub Issues |
| 3446936953 | |
| QQ 交流群 | 246394085 |
| 邮箱 | nebulagate@foxmail.com |
| CSDN 博客 | 云阙(NebulaGate) |
QQ 二维码 QQ 交流群二维码
本项目的部分设计思路参考了社区优秀的开源实践,特此致谢:
作为一个初学者,能站在这些优秀开源作品的肩膀上学习和实践,是我的荣幸。真诚感谢作者们的无私分享。
| Back | FazBrowse Home | New Git URL |