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

  1. Create an application and obtain the App ID from the Lanying console.
  2. Install floo-ios with CocoaPods, or add the downloaded framework and required native libraries manually.
  3. For manual integration, include the SDK headers, libz, libresolv, libc++, libsqlite3, and libcrypto as required by the release package.
  4. Add -ObjC to Other Linker Flags and enable HTTPS access for the target.
  5. Enable APNs capabilities and prepare the development and production push credentials separately.
Import the SDKobjective-c
#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.

SettingPurpose
appIDIdentifies the Lanying application.
dataDir / cacheDirPersistent database and downloaded/cached content.
pushCertNameSelects the APNs credential configured for this build environment.
loadAllServerConversationsLoads server conversations for multi-device/offline synchronisation.
hostConfig / enableDNSSelects private endpoints or hosted DNS discovery.
logLevelControls diagnostic logging; avoid verbose logs in release builds.

Register, sign in, restore, and sign out

Registerobjective-c
    [[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]];
        }
    }];
Password sign-in and fast sign-inobjective-c
[[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);
 }
}];
Never put the server access token in an iOS application. For token-based client sign-in, request a user-scoped token from your backend.
Sign out and unbind the deviceobjective-c
    [[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

Read conversationsobjective-c
 [[[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

Send a contact requestobjective-c
    [[[BMXClient sharedClient] rosterService] applyWithRosterId:rosterId message:reason completion:^(BMXError *error) {
        MAXLog(@"%lld", rosterId);
        if (!error) {
            MAXLog(@"申请成功");
        } else {
            MAXLog(@"申请失败");
        }
    }];
AreaBMXRosterService responsibility
RelationshipsApply, accept, decline, remove, and read relationship state.
ProfilesFetch roster details and aliases; refresh when callbacks indicate change.
Block listAdd, remove, and enumerate blocked users.
EventsRegister 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 areaData to load
Group headerBMXGroup profile, avatar, description, owner, and current member count.
Member listPaged members, roles, nicknames, mute state, and block state.
RequestsPending invitations and applications plus the current user's permission to handle them.
Files and announcementsShared-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.

Text messageobjective-c
    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];
Image attachmentobjective-c
    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];
    }
ContentAttachment type
ImageBMXImageAttachment with original and thumbnail data plus dimensions.
FileBMXFileAttachment with data/path and display name.
LocationBMXLocationAttachment with latitude, longitude, and address.
VoiceBMXVoiceAttachment with local path, duration, and display name.
VideoBMXVideoAttachment with media metadata and thumbnail.
CustomA supported custom message representation with explicit push content.

Send, forward, resend, recall, and download

Send and observe statusobjective-c
     /**
      发送消息,消息状态变化会通过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

Delegate lifecycleobjective-c
    /**
     * 添加聊天监听者
     **/
    [[[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

Bind the APNs device tokenobjective-c
[[[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.

PhaseResponsibility
InviteCreate call configuration, create a call message, and send it through rtcService.
JoinObtain room authorization and join through RTCEngineManager.
MediaPublish local audio/video and render subscribed remote tracks.
Answer / hang upSend the matching signalling message using the stable call ID.
CleanupLeave 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.