Bmob provides a native Java/Kotlin SDK for Android, published in the Maven repository io.github.bmob:android-sdk. The model layer uses the extend BmobObject approach (one JavaBean subclass = one table), and CRUD is returned via the Listener callbacks provided by the SDK.
Core Principles
1. SDK integration: app/build.gradle add:
dependencies {
implementation 'io.github.bmob:android-sdk:4.2.1'
implementation 'io.reactivex.rxjava3:rxjava:3.1.9'
implementation 'io.reactivex.rxjava3:rxandroid:3.0.2'
implementation 'com.squareup.okhttp3:okhttp:4.8.1'
implementation 'com.squareup.okio:okio:2.2.2'
implementation 'com.google.code.gson:gson:2.8.5'
}
2. Application subclass initialization: in one-time, and must be before any Bmob call.
public class BmobApp extends Application {
@Override public void onCreate() {
super.onCreate();
Bmob.initialize(this, "你的Application ID");
}
}
AndroidManifest.xml specify android:name=".BmobApp"。
3. Required permissions and ContentProvider: see references/manifest-and-deps.md(INTERNET / ACCESS_NETWORK_STATE / READ_PHONE_STATE / <provider> , etc.).
4. JavaBean extends BmobObject: table name = class name, field name = member variable name.Do notmanually write objectId / createdAt / updatedAt / ACL, BmobObject already provides getters.
5. Number fields must use wrapper classes(Integer / Long / Double , etc.), do not use primitive int / long / double, otherwise default values cannot be distinguished when saving.
6. Android 6.0+ network compatibility: see references/manifest-and-deps.md in useLibrary 'org.apache.http.legacy' and network_security_config.xml。
Security Checklist
- Do not leak the Master Key in the APK. The client only uses the Application ID (configure the Secret Key + encrypted authorization when necessary).
- Disable debug mode in release builds:
Bmob.setIsDebug(true)only enable it in debug builds. - Obfuscation configuration must keep SDK classes: see
references/manifest-and-deps.mdin the ProGuard section. - Tables with write operations must be configured with ACL: otherwise any user can modify any row.
- Replace with the registered domain before release:
Bmob.resetDomain("http://你的SDK域名/8/")must be beforeBmob.initializebefore。 - Use wrapper classes for Number types: avoid
0being indistinguishable from "not set".
FAQ
Cross-platform Q&A:shared/faq.md。
Anti-patterns
see shared/anti-patterns.md. Key points for this platform:success uncaught exception inside the callback → false 9015; do not use primitive int to store Number.
Custom JavaBean
public class Category extends BmobObject {
private String name;
private String desc;
private Integer sequence; // 必须是 Integer,不是 int
public String getName() { return name; }
public Category setName(String name) { this.name = name; return this; }
public String getDesc() { return desc; }
public Category setDesc(String desc) { this.desc = desc; return this; }
public Integer getSequence() { return sequence; }
public Category setSequence(Integer sequence) { this.sequence = sequence; return this; }
}
| Console type | Java type |
|---|---|
| String | String |
| Boolean | Boolean |
| Number | Integer / Long / Double / Float / Short / Byte / Character |
| Array | List |
| File | BmobFile |
| GeoPoint | BmobGeoPoint |
| Date | BmobDate |
| Pointer | Any subclass of BmobObject subclass |
| Relation | BmobRelation |
Single-record CRUD
Add
Category c = new Category();
c.setName("football");
c.setDesc("足球");
c.setSequence(1);
c.save(new SaveListener<String>() {
@Override public void done(String objectId, BmobException e) {
if (e == null) Log.i("BMOB", "new id=" + objectId);
else Log.e("BMOB", e.toString());
}
});
Update (by objectId)
Category c = new Category();
c.setSequence(2); // 只设要改的字段
c.update("6b6c11c537", new UpdateListener() {
@Override public void done(BmobException e) {
if (e == null) Log.i("BMOB", "updated");
}
});
Delete (by objectId)
Category c = new Category();
c.delete("6b6c11c537", new UpdateListener() {
@Override public void done(BmobException e) {
if (e == null) Log.i("BMOB", "deleted");
}
});
Query one (by objectId)
BmobQuery<Category> q = new BmobQuery<>();
q.getObject("6b6c11c537", new QueryListener<Category>() {
@Override public void done(Category obj, BmobException e) {
if (e == null) Log.i("BMOB", obj.getName());
}
});
Conditional query
BmobQuery provides chained calls (v3.5.2+):
BmobQuery<Book> q = new BmobQuery<>();
q.setLimit(20).setSkip(0).order("-createdAt")
.addWhereEqualTo("status", "published")
.findObjects(new FindListener<Book>() {
@Override public void done(List<Book> list, BmobException e) {
if (e == null) /* ... */;
}
});
| Method | Meaning |
|---|---|
addWhereEqualTo(field, value) |
= |
addWhereNotEqualTo |
!= |
addWhereGreaterThan / addWhereGreaterThanOrEqualTo |
> / >= |
addWhereLessThan / addWhereLessThanOrEqualTo |
< / <= |
addWhereContainedIn(field, List) |
IN |
addWhereNotContainedIn |
NOT IN |
addWhereExists(field) / addWhereDoesNotExists |
Field exists / does not exist |
addWhereContains(field, substr) |
LIKE (paid) |
order("-field") / order("field") |
Sort |
setLimit(n) / setSkip(n) |
Pagination (default 10, max 1000) |
include("pointerField") |
Also fetch Pointer |
For more, see references/query.md。
Batch operations (≤ 50)
List<BmobObject> list = new ArrayList<>();
for (int i = 0; i < 50; i++) {
Category c = new Category();
c.setName("name" + i);
list.add(c);
}
new BmobBatch().insertBatch(list).doBatch(new QueryListListener<BatchResult>() {
@Override public void done(List<BatchResult> results, BmobException e) { /* ... */ }
});
See references/batch.md。
Integration with MCP
If already configured Bmob MCP,first get_project_tables get the real schema, then generate the corresponding BmobObject subclass skeleton. This avoids:
- JavaBean field names / types do not match the table (wrong fields do not report errors, and cannot be queried after writing)
- The className pointed to by the Pointer is misspelled
Troubleshooting Quick Reference
For cross-platform symptoms, first check shared/faq.md。
| Symptom | Troubleshooting |
|---|---|
9001 AppKey is Null |
Did not call Bmob.initialize or the call timing is later than other SDK APIs |
9013 ObjectName format incorrect |
Table name / field name contains illegal characters (must start with a letter) |
9015 |
Catch-all error code—be sure to read the response description, it may be success Business exceptions are swallowed in the callback, see bmob-error-codes for the 9015 topic |
9016 |
Client has no network |
9021 |
Missing WAKE_LOCK permission |
| Crash after ProGuard release | Did not add -keep class cn.bmob.v3.** { *; } and other rules, see references for details |
| HTTP cleartext request rejected by Android P | Add network_security_config.xml, see references |
release package request rejected / 403 |
The console has not configured a registered domain for the SDK type;Bmob.resetDomain was not called or was called at the wrong time (must be before initialize ) |
Advanced capabilities (read references/ as needed)
| Topic | Path |
|---|---|
| End-to-end scenarios (blog, Todo ACL, migration, etc.) | shared/recipes/ |
| BmobDocs sync code snippets | references/snippets/ |
| Manifest + dependencies + ProGuard + Android P/6.0 compatibility | references/manifest-and-deps.md |
| Batch operations (insert/update/delete 50 per batch) | references/batch.md |
| Full query set (or / regex / pointer subquery) | references/query.md |
| Pointer and Relation usage | references/pointer-and-relation.md |
| User system, email, phone number SMS, third-party login | (P1: bmob-auth-android, not covered in detail by this skill) |
| File upload / download (BmobFile) | (P1: bmob-storage-android) |
| Data monitoring (real-time data) | (P1: bmob-realtime-android) |
| Geolocation (BmobGeoPoint) | references/query.md last segment |
Reference
- Full API:BmobDocs/mds/data/android/develop_doc.md
- Quick start:BmobDocs/mds/data/android/index.md
- Official quickstart project:https://github.com/bmob/bmob-android-quickstart
- Examples: image-text community Wonderful / SMS login bmob_android_demo_sms / Campus Xiaocai Shop
- Error codes:
bmob-error-codes - MCP integration:
bmob-mcp