Client guide
iOS development guide
Integrate floo-ios, manage the complete account and chat lifecycle, send media, receive callbacks, configure APNs, and add one-to-one voice & video.
The iOS SDK exposes the shared native communication core through Objective-C APIs that can be called from Objective-C or Swift. BMXClient is the application entry point; feature work is delegated to user, chat, roster, group, push, and voice & video services.
Install and configure the target
- Create an application and obtain the App ID from the Lanying console.
- Install floo-ios with CocoaPods, or add the downloaded framework and required native libraries manually.
- For manual integration, include the SDK headers, libz, libresolv, libc++, libsqlite3, and libcrypto as required by the release package.
- Add -ObjC to Other Linker Flags and enable HTTPS access for the target.
- Enable APNs capabilities and prepare the development and production push credentials separately.
#import <floo-ios/floo_proxy.h>Initialise BMXClient once
Create persistent data and cache directories, build BMXSDKConfig with the App ID and correct push certificate name, then create the client once during the application lifecycle. Use DNS discovery for hosted deployments and explicit host configuration only when your deployment supplies it.
| Setting | Purpose |
|---|---|
| appID | Identifies the Lanying application. |
| dataDir / cacheDir | Persistent database and downloaded/cached content. |
| pushCertName | Selects the APNs credential configured for this build environment. |
| loadAllServerConversations | Loads server conversations for multi-device/offline synchronisation. |
| hostConfig / enableDNS | Selects private endpoints or hosted DNS discovery. |
| logLevel | Controls diagnostic logging; avoid verbose logs in release builds. |
Register, sign in, restore, and sign out
[[BMXClient sharedClient] signUpNewUserWithUsername:name password:password completion:^(BMXUserProfile *profile, BMXError *error) {
if (error.errorCode == BMXErrorCode_NoError){
[self registerLoginByName:name password:password];
} else if (error.errorCode == BMXErrorCode_UserAlreadyExist){
[self.config showErrorText:NSLocalizedString(@"This_username_already_exists", @"该用户名已存在")];
} else if (error.errorCode == BMXErrorCode_InvalidRequestParameter) {
[HQCustomToast showDialog:NSLocalizedString(@"username_constraint", @"用户名仅支持字母数字下划线中文组合,且不能是纯数字,不能以maxim、mta开头") time:5.0f];
} else {
[HQCustomToast showDialog:[error description]];
}
}];[[BMXClient sharedClient] signInByNameWithName:name password:password completion:^(BMXError *error) {
if (!error) {
NSLog(@"登录成功 username = %lld , password = %@",name, password);
} else {
NSLog(@"失败 errorCode = %lu ", error.errorCode);
}
}];
// 快速登录(跳过获取token环节)
[[BMXClient sharedClient] fastSignInByNameWithName:name password:password completion:^(BMXError *error) {
if (!error) {
NSLog(@"登录成功 username = %@ , password = %@", name, password);
} else {
NSLog(@"失败 errorCode = %ld ", error.errorCode);
}
}]; [[BMXClient sharedClient] signOutWithUid:(NSInteger)self.profile.userId ignoreUnbindDevice:NO completion:^(BMXError * _Nonnull error) {
if (!error) {
NSLog(@"Log out successfully");
} else {
NSLog(@"Log out failed");
}
}];Conversations and synchronisation
[[[BMXClient sharedClient] chatService] getAllConversationsWithCompletion:^(BMXConversationList *res) {
NSLog(@"%ld", res.size);
}];- Enable loadAllServerConversations before client creation when multi-device conversation discovery is required.
- Use conversation IDs as stable keys and refresh unread state from SDK callbacks.
- Load history through BMXChatService and page older messages rather than rendering the entire history at once.
- Reconcile outgoing UI state through message-status callbacks instead of assuming send completion means delivery.
Contacts, requests, and block lists
[[[BMXClient sharedClient] rosterService] applyWithRosterId:rosterId message:reason completion:^(BMXError *error) {
MAXLog(@"%lld", rosterId);
if (!error) {
MAXLog(@"申请成功");
} else {
MAXLog(@"申请失败");
}
}];
| Area | BMXRosterService responsibility |
|---|---|
| Relationships | Apply, accept, decline, remove, and read relationship state. |
| Profiles | Fetch roster details and aliases; refresh when callbacks indicate change. |
| Block list | Add, remove, and enumerate blocked users. |
| Events | Register a roster-service delegate and remove it when its owner is released. |
Groups and permissions
BMXGroupService covers creation and destruction, invitations and applications, membership, owner/admin roles, mute and block lists, announcements, shared files, history visibility, read acknowledgements, and per-member nicknames. Check group policy and the current member role before exposing administrative actions.
| UI area | Data to load |
|---|---|
| Group header | BMXGroup profile, avatar, description, owner, and current member count. |
| Member list | Paged members, roles, nicknames, mute state, and block state. |
| Requests | Pending invitations and applications plus the current user's permission to handle them. |
| Files and announcements | Shared-file list, announcements, and operation permissions. |
Build text and media messages
Single and group chat share the same message factory. Select BMXMessage_MessageType_Single or BMXMessage_MessageType_Group and use the peer or group ID as the conversation ID. Attachments carry their own upload and download state.
BMXMessage *message;
long long toId = 0;
NSInteger conversationId = self.conversationId;
if (self.messageType == BMXMessage_MessageType_Single) {
toId = self.currentRoster.rosterId;
}else {
toId = self.currentGroup.groupId;
}
BMXMessage *message = [BMXMessage createMessageWithFrom:[self.account.usedId longLongValue] to:toId type:self.messageType conversationId:conversationId content:content]; UIImage *image = contentImg;
NSData *imageData = UIImageJPEGRepresentation(image,1.0f);
NSData *thumImageData = UIImageJPEGRepresentation(image,1.0f);
IMAcount *account = [IMAcountInfoStorage loadObject];
BMXMessageAttachmentSize *sz = [[BMXMessageAttachmentSize alloc] initWithWidth:image.size.width height:image.size.height];
BMXImageAttachment *imageAttachment = [[BMXImageAttachment alloc] initWithData:imageData thumbnailData:thumImageData imageSize:sz displayName:@"" conversationId: roster.rosterId];
BMXMessage *msg;
msg = [BMXMessage createMessageWithFrom:[account.usedId longLongValue] to:roster.rosterId type: BMXMessage_MessageType_Single conversationId:roster.rosterId attachment:imageAttachment];
if (msg) {
[[[BMXClient sharedClient] chatService] sendMessageWithMsg: msg completion:nil];
[self.navigationController popViewControllerAnimated:YES];
}
| Content | Attachment type |
|---|---|
| Image | BMXImageAttachment with original and thumbnail data plus dimensions. |
| File | BMXFileAttachment with data/path and display name. |
| Location | BMXLocationAttachment with latitude, longitude, and address. |
| Voice | BMXVoiceAttachment with local path, duration, and display name. |
| Video | BMXVideoAttachment with media metadata and thumbnail. |
| Custom | A supported custom message representation with explicit push content. |
Send, forward, resend, recall, and download
/**
发送消息,消息状态变化会通过listener通知
**/
[[[BMXClient sharedClient] chatService] sendMessageWithMsg: messageObject completion:^(BMXError *aError) {
}];- Create a forward message before calling forwardMessageWithMsg.
- Use resend only for a message whose previous send failed.
- Recall within the configured server window and update the conversation from recall callbacks.
- Track attachment upload and download progress in the chat-service delegate.
- Do not remove local files until the SDK no longer needs them for retry or upload.
Register and remove chat callbacks
/**
* 添加聊天监听者
**/
[[[BMXClient sharedClient] chatService] addDelegate:self delegateQueue:dispatch_get_main_queue()];
/**
* 移除聊天监听者
**/
[[[BMXClient sharedClient] chatService] removeDelegate:self];Implement receive, status, recall, read-acknowledgement, delivery-acknowledgement, and attachment-progress callbacks. Dispatch UI changes to the main queue and keep persistence work off it.
APNs and notification behaviour
[[[BMXClient sharedClient] userService] bindDeviceWithToken:deviceToken completion:^(BMXError *error) {
NSLog(@"绑定成功");
}];- Enable Push Notifications, Communication Notifications, and Time Sensitive Notifications only when your product requires them.
- Upload the matching APNs development or production credential in the console.
- Bind refreshed tokens and unbind on account sign-out.
- Set push content for custom messages; the SDK can supply default content for built-in messages.
- After opening a notification, synchronise through chat and deduplicate by message ID.
Voice & video on iOS
floo-ios supplies call signalling and floo-rtc-ios supplies media behaviour. Add the media framework and GoogleWebRTC dependency, build local and remote render views, then register both BMXRTCEngineProtocol and BMXRTCServiceProtocol.
| Phase | Responsibility |
|---|---|
| Invite | Create call configuration, create a call message, and send it through rtcService. |
| Join | Obtain room authorization and join through RTCEngineManager. |
| Media | Publish local audio/video and render subscribed remote tracks. |
| Answer / hang up | Send the matching signalling message using the stable call ID. |
| Cleanup | Leave the room and remove engine plus signalling delegates on every exit path. |
Release checklist
- Test first install, restored session, expired token, password change, and multi-device sign-in.
- Test every message type over slow and interrupted networks, including upload retry.
- Verify delegate removal with repeated view entry and exit.
- Test APNs in development and distribution builds on physical devices.
- Test microphone, camera, Bluetooth, interruptions, backgrounding, and network handover.
- Disable verbose logging and confirm no credentials or message content appear in production logs.