Multiple dialogs are created when chatting Quickblox - ios

While creating a chat dialog for a group.
For e.g User A is creating dialog and User B want to use that dialog.
But sometimes scenario is occurring that User A create one dialog and then User B create another dialog.
So they are not able to chat with each other because of two different dialogs.
Below is the code i am using to create dialog :-
-(void) moveToChatView:(QBChatDialog *)chatDialog ObjFriend:(Friend *)objFriend
{
[QBRequest createDialog:chatDialog successBlock:^(QBResponse *response, QBChatDialog *createdDialog)
{
// Success, do something
}
errorBlock:^(QBResponse *response)
{
}];
}
Edit :- Is there any method like createOrJoinRoomWithName??

To if you want to add user in groupchat then you need to update the group dialogue.
QBChatDialog *updateDialog = [[QBChatDialog alloc] initWithDialogID:#"53aac645535c12bd3b008a40" type:QBChatDialogTypeGroup];
updateDialog.pushOccupantsIDs = #[#"300", #"301", #"302"];
updateDialog.name = #"school friends";
[QBRequest updateDialog:updateDialog successBlock:^(QBResponse *responce, QBChatDialog *dialog) {
} errorBlock:^(QBResponse *response) {
}];
For more detail check this Update_group_dialog
And for chat in group dialogue check Chat_in_group_dialog
Don't forget to use delegate method.
pragma mark QBChatDelegate
- (void)chatRoomDidReceiveMessage:(QBChatMessage *)message fromDialogId:(NSString *)dialogId{
}
Edit 1:- you will get DialogId with retriving all dialog.
QBResponsePage *page = [QBResponsePage responsePageWithLimit:100 skip:0];
[QBRequest dialogsForPage:page extendedRequest:nil successBlock:^(QBResponse *response, NSArray *dialogObjects, NSSet *dialogsUsersIDs, QBResponsePage *page) {
} errorBlock:^(QBResponse *response) {
}];
Edit 2:- To know the dialogId when creating new Dialog use createChatNotificationForGroupChatCreation method.
- (QBChatMessage *)createChatNotificationForGroupChatCreation:(QBDialog *)dialog
{
// create message:
QBChatMessage *inviteMessage = [QBChatMessage message];
NSMutableDictionary *customParams = [NSMutableDictionary new];
customParams[#"xmpp_room_jid"] = dialog.roomJID;
customParams[#"name"] = dialog.name;
customParams[#"_id"] = dialog.ID;
customParams[#"type"] = #(dialog.type);
customParams[#"occupants_ids"] = [dialog.occupantIDs componentsJoinedByString:#","];
// Add notification_type=1 to extra params when you created a group chat
//
customParams[#"notification_type"] = #"1";
inviteMessage.customParameters = customParams;
return inviteMessage;
}

Related

QuickBlox - QBChatDialogTypePublicGroup : Dialog have to be in memory cache

Hello Friends i have create an application with QuickBlox. i am to create an 10 QBChatDialogTypePublicGroup from admin panel. it is static.
i want to create static public group from quickblox admin panel and chat any user in this group.
i am get this all group in viewController and display it. then user can choose any group to chat publicly.
i am using quickblox framework to chat with user. i am done QBChatDialogTypePrivate one to one user cheating.
Login :
- (void)loginWithQuickBlox{
NSString *emaiAddress = [[NSUserDefaults standardUserDefaults] objectForKey:#"UserLogin"];
NSString *password = [[NSUserDefaults standardUserDefaults] objectForKey:#"UserPassword"];
[QBRequest logInWithUserLogin:emaiAddress password:password successBlock:^(QBResponse *response, QBUUser *user)
{
[[NSUserDefaults standardUserDefaults]setObject:[NSString stringWithFormat:#"%ld",(unsigned long)user.ID] forKey:#"USerLoginID"];
[self loginWithQuickBloxChat:user];
} errorBlock:^(QBResponse *response)
{
// error handling
NSLog(#"errorsssss : %#", response.error);
}];
}
Login with QuickBloxChat
- (void)loginWithQuickBloxChat:(QBUUser *)selectedUser {
QBUUser *selectedUserx = [QBUUser user];
selectedUserx.login = [[NSUserDefaults standardUserDefaults] objectForKey:#"UserLogin"];
selectedUserx.password = [[NSUserDefaults standardUserDefaults] objectForKey:#"UserPassword"];
selectedUserx.ID = [[[NSUserDefaults standardUserDefaults] objectForKey:#"USerLoginID"] integerValue];
NSLog(#"Currunt User : %#", [QBSession currentSession].currentUser);
[ServicesManager.instance logInWithUser:selectedUserx completion:^(BOOL success, NSString *errorMessage)
{
[[QBChat instance] connectWithUser:selectedUserx completion:^(NSError * _Nullable error) {
}];
if (success)
{
NSLog(#"Login in Quickblox : %#",selectedUser);
[self getPublicGroup];
}
else
{
NSLog(#"Error in QuickBlox : %#",errorMessage);
}
}];
}
Get Public Group
- (void)getPublicGroup {
NSMutableDictionary *extendedRequest = #{#"type" : #(1)}.mutableCopy;
QBResponsePage *page = [QBResponsePage responsePageWithLimit:100 skip:0];
[QBRequest dialogsForPage:page extendedRequest:extendedRequest successBlock:^(QBResponse *response, NSArray *dialogObjects, NSSet *dialogsUsersIDs, QBResponsePage *page) {
publicGroupArray = dialogObjects.mutableCopy;
NSLog(#"Public Group : %#",publicGroupArray);
[self.groupCollectionview reloadData];
} errorBlock:^(QBResponse *response) {
}];
}
Select Any one Group and Chat With ChatViewcontroller
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
QBChatDialog *groupChatDialog = [publicGroupArray objectAtIndex:indexPath.row];
ChatViewController *chatViewController = [[ChatViewController alloc] init];
chatViewController.dialog = groupChatDialog;
chatViewController.hidesBottomBarWhenPushed = YES;
[self.navigationController pushViewController:chatViewController animated:YES];
}
This all procedure are working perfectly but when i send message from ChatViewController it will give me error
Assertion failure in -[QMChatService
sendMessage:toDialogID:saveToHistory:saveToStorage:completion:],
All/September/21/ChatApp/Pods/QMServices/QMChatService/QMChatService/QMChatService.m:1338
Terminating app due to uncaught exception
'NSInternalInconsistencyException', reason: 'Dialog have to be in
memory cache!'
*** First throw call stack:
You are trying to combine core SDK methods with QMServices' methods.
QBRequest is part of the Quickblox SDK, QMServices are high-level API for Chat features including:
Authentication service for logging to Quickblox REST and XMPP.
Inbox persistent and memory storage for messages, dialogs and users.
If you want to get dialog using QMServices try the method below:
- (void)loadDialogWithID:(NSString *)dialogID completion:(nullable void (^)(QBChatDialog * _Nullable loadedDialog))completion;
Example:
[ServicesManager.instance.chatService loadDialogWithID:dialogID
completion:^(QBChatDialog * _Nullable loadedDialog)
{
}];
This method will load dialog from the server, join it(if dialog's type is group) and store in memory and CoreDate.
If you want to fetch dialog using core method of the SDK you should implement all described actions by yourself.

Unable to see update value in Quick Blox Admin Panel

I am using QuickBlox SDK from follwing refrence
https://quickblox.com/developers/SimpleSample-chat_users-ios
In Sample chat I am also making Group video chat . but When I Update particular tag With the help of below code. Than I am unable to see the updated value in my quickblox admin panel. If some one update the tag name than Please suggest me. I am using below code
QBUUser *qbUser = [QBUUser user];
qbUser.ID = 23429378;
NSString *roomName = #"ios group";
qbUser.tags = #[roomName].mutableCopy;
NSArray *arry = [[NSArray alloc]initWithObjects:qbUser, nil];
[QMUsersCache.instance insertOrUpdateUsers:users];
- (BFTask *)insertOrUpdateUsers:(NSArray *)users
{
__weak __typeof(self)weakSelf = self;
return [BFTask taskFromExecutor:[BFExecutor executorWithDispatchQueue:self.queue] withBlock:^id{
__typeof(self) strongSelf = weakSelf;
NSManagedObjectContext* context = [strongSelf backgroundContext];
NSMutableArray *toInsert = [NSMutableArray array];
NSMutableArray *toUpdate = [NSMutableArray array];
//To Insert / Update
for (QBUUser *user in users)
{
CDUser *cachedUser = [CDUser QM_findFirstWithPredicate:IS(#"id", #(user.ID)) inContext:context];
if (cachedUser) {
QBUUser *qbCachedUser = [cachedUser toQBUUser];
if (![user.updatedAt isEqualToDate:qbCachedUser.updatedAt]) {
[toUpdate addObject:user];
}
}
else {
[toInsert addObject:user];
}
}
if (toUpdate.count > 0) {
[strongSelf updateUsers:toUpdate inContext:context];
}
if (toInsert.count > 0) {
[strongSelf insertUsers:toInsert inContext:context];
}
if (toInsert.count + toUpdate.count > 0) {
[context QM_saveToPersistentStoreAndWait];
}
QMSLog(#"[%#] Users to insert %tu, update %tu", NSStringFromClass([weakSelf class]), toInsert.count, toUpdate.count);
return nil;
}];
}
Your code is just updating users in CoreData store.
You can update only the current user from the application:
+ (QBRequest *)updateCurrentUser:(QBUpdateUserParameters *)parameters
successBlock:(nullable void (^)(QBResponse *response, QBUUser * _Nullable user))successBlock
errorBlock:(nullable QBRequestErrorBlock)errorBlock;
If you want to update other users you should do it via Admin Panel.
Sample chat related to this question.
API Documentation related to this question.

Send message to dialog iOS Quickblox

I have this in AppDelegate.m
[QBSettings setApplicationID:xxxxxx];
[QBSettings setAuthKey:#"dsad"];
[QBSettings setAuthSecret:#"asdd"];
[QBSettings setAccountKey:#"asdsda"];
[QBSettings setLogLevel:QBLogLevelNothing];
[QBRequest logInWithUserLogin:#"testuser" password:#"testuser" successBlock:^(QBResponse *response, QBUUser *user) {
if (user) {
user.login = #"testuser";
user.password = #"testuser";
// __typeof(self) strongSelf = weakSelf;
[[QBChat instance] connectWithUser:user completion:^(NSError * _Nullable error) {
}
];
}
} errorBlock:^(QBResponse * _Nonnull response) {
}];
and this trying to send a message in another ViewController.m
QBChatMessage *messagetosend = [QBChatMessage message];
messagetosend.senderID = 10516336;
messagetosend.senderNick = #"Andrey M.";
messagetosend.text = #"test test";
messagetosend.dateSent = [NSDate dateWithTimeInterval:-12.0f sinceDate:[NSDate date]];
QBChatDialog *chatDialog = [[QBChatDialog alloc] initWithDialogID:#"56d9e95ba28f9a7bf5000058" type:QBChatDialogTypePublicGroup];
[chatDialog joinWithCompletionBlock:^(NSError * _Nullable error) {
[chatDialog sendMessage:messagetosend completionBlock:^(NSError * _Nullable error) {
NSLog(#"%#",[error localizedDescription]);
}];
}];
but the message doesn't sent to the dialog I check in quickblox dashboard it doesn't work. I used PHP framework and it works but in the iOS i do not know where it the problem, must open a session or what ?
FYI: this dialog ID " 56d9e95ba28f9a7bf5000058 " from Quickblox dashboard it isn't randomly or fake
Thanks
In order to send message in group chat dialog you should create dialog on a server.
Dialog must contain occupantIDs
+ (QB_NONNULL QBRequest *)createDialog:(QB_NONNULL QBChatDialog *)dialog
successBlock:(QB_NULLABLE void(^)(QBResponse * QB_NONNULL_S response, QBChatDialog * QB_NULLABLE_S createdDialog))successBlock
errorBlock:(QB_NULLABLE QBRequestErrorBlock)errorBlock;
You must send custom parameters
messagetosend.senderID = 10516336;
messagetosend.senderNick = #"Andrey M.";
messagetosend.text = #"test test";
/** You will see the on dashboard after you set save_to_history to true **/
messagetosend.customParameters = ["application_id":kQBApplicationID, "save_to_history":true]
Let me know if this works for you.

SPTTrack trackWithURI issue

I had created the new project which fetches the track of songs, so I tried to pass an array of SPTTracks to the player, please find it below.
self.player = [[SPTAudioStreamingController alloc] initWithClientId:auth.clientID];
self.player.diskCache = [[SPTDiskCache alloc] initWithCapacity:1024 * 1024 * 64];
NSString *trackURI = #"spotify:track:1zHlj4dQ8ZAtrayhuDDmkY";
[SPTTrack trackWithURI:[NSURL URLWithString:trackURI] accessToken:auth.session.accessToken market:#"ES" callback:^(NSError *error, id object) {
if (!error) {
SPTTrack *trackInfo = object;
NSArray *tracks = #[trackInfo];
[self.player playURIs:tracks fromIndex:0 callback:^(NSError *error) {
if (!error) {
} else {
NSLog(#"*** Failed to play track : %#", error);
}
}];
} else {
NSLog(#"Error %#", error);
}
}];
But I get crashes, whenever I run it. Please find error below while it is getting crash :
Simple Track Playback[254:24669] -[__NSCFConstantString absoluteString]: unrecognized selector sent to instance 0x1000c0508
I had also looked it on spotify api spotify_ios_sdk but I had found that one developer had already posted the same issue link.
If anyone has solved these type of issue then please provide your guidance.
Thanks in advanced.
Unfortunately, this method is not "equivalent", because the SPTTrack object returned inside the callback of [SPTTrack trackWithURI.... has many less informations.
I've tried some workaround, and I found that for me the solution is
1) Create a request for an SPTTrack object.
2) Pass that request to SPRequest performRequest callback.
3) Wait for the response, and eventually create a track from data (please find the below complete code).
self.player = [[SPTAudioStreamingController alloc] initWithClientId:auth.clientID];
self.player.diskCache = [[SPTDiskCache alloc] initWithCapacity:1024 * 1024 * 64];
NSString *market = [[NSLocale currentLocale] objectForKey:NSLocaleCountryCode];
NSURLRequest *request = [SPTTrack createRequestForTrack:[NSURL URLWithString:#"spotify:track:1zHlj4dQ8ZAtrayhuDDmkY"]
withAccessToken:auth.session.accessToken
market:market
error:nil];
[[SPTRequest sharedHandler] performRequest:request
callback:^(NSError *error, NSURLResponse *response, NSData *data) {
if (!error) {
NSError *parsingError = nil;
SPTTrack *track = [SPTTrack trackFromData:data
withResponse:response
error:&parsingError];
self.arrURIs = #[track.playableUri];
[self.player playURIs:self.arrURIs fromIndex:0 callback:nil];
}
}];
Thanks "Kry256" for detail explaination.

iOS Authenticate Azure Active Directory & get calendar events from office 365 exchange

Trying to Authenticate with Azure Active Directory and fetch mail, calendar data, accessToken is returned successfully:
authority = #"https://login.windows.net/common/oauth2/authorize";
redirectUriString = #"http://xxxxxx.xxxxxxx.com/oauth";
resourceId = #"https://outlook.office365.com";
clientId = #"xxxxxxx-xxxxx-xxx";
-(void) getToken : (BOOL) clearCache completionHandler:(void (^) (NSString*))completionBlock;
{
ADAuthenticationError *error;
authContext = [ADAuthenticationContext authenticationContextWithAuthority:authority
error:&error];
[authContext setValidateAuthority:YES];
NSURL *redirectUri = [NSURL URLWithString:redirectUriString];
if(clearCache){
[authContext.tokenCacheStore removeAllWithError:&error];
if (error) {
NSLog(#"Error: %#", error);
}
}
[authContext acquireTokenWithResource:resourceId
clientId:clientId
redirectUri:redirectUri
completionBlock:^(ADAuthenticationResult *result) {
if (AD_SUCCEEDED != result.status){
// display error on the screen
[self showError:result.error.errorDetails];
}
else{
completionBlock(result.accessToken);
}
}];
}
-(NSArray*)getEventsList
{
__block NSMutableArray * todoList;
[self getToken:YES completionHandler:^(NSString* accessToken){
NSURL *todoRestApiURL = [[NSURL alloc]initWithString:#"https://outlook.office365.com/api/v1.0/me/folders/inbox/messages?$top=2"];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc]initWithURL:todoRestApiURL];
NSString *authHeader = [NSString stringWithFormat:#"Bearer %#", #""];
[request addValue:authHeader forHTTPHeaderField:#"Authorization"];
[request addValue:#"application/json; odata.metadata=none" forHTTPHeaderField:#"accept"];
[request addValue:#"fbbadfe-9211-1234-9654-fe435986a1d6" forHTTPHeaderField:#"client-request-id"];
[request addValue:#"Presence-Propelics/1.0" forHTTPHeaderField:#"User-Agent"];
//[request addValue:#"true" forHTTPHeaderField:#"return-client-request-id"];
NSOperationQueue *queue = [[NSOperationQueue alloc]init];
[NSURLConnection sendAsynchronousRequest:request queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
if (error == nil){
NSArray *scenarios = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
todoList = [[NSMutableArray alloc]initWithArray:scenarios];
//each object is a key value pair
NSDictionary *keyVauePairs;
for(int i =0; i < todoList.count; i++)
{
keyVauePairs = [todoList objectAtIndex:i];
NSLog(#"%#", keyVauePairs);
}
}
NSLog(#"Finished");
//[delegate updateTodoList:TodoList];
}];
}];
return nil; }
Error is returned in response object:
{
error = {
code = ErrorAccessDenied;
message = "Access is denied. Check credentials and try again.";
};
}
I know its late to answer this but it might be helpful for someone like me who was struggling to get the same thing done
I have done this using the office 365 SDK for iOS which has all the inbuilt classes to do your work.
If you download their sample code it will provide you all the details you require to do certain operations (mail, calendar, contacts, one drive).
Before using the SDK make sure you login to Azure AD and register your application and add permissions so that you do not get 403 error code or any access denied message.
I am using the below code to fetch my events details from outlook calendar
[self getClientEvents:^(MSOutlookClient *client) {
NSURLSessionDataTask *task = [[[client getMe] getEvents] read:^(NSArray<MSOutlookEvent> *events, MSODataException *error) {
if (error==nil) {
if (events.count!=0) {
dispatch_async(dispatch_get_main_queue(), ^{
for(MSOutlookEvent *calendarEvent in events){
NSLog(#"name = %#",calendarEvent.Subject);
}
});
}else{
NSLog(#"No events found for today");
}
}
}];
[task resume];
}];
getClientEvents is a method which gives call to the Office 365 SDK and fetches the event details of the user but it first fetches the token for the resource and then makes the call with the acquired token
-(void)getClientEvents : (void (^) (MSOutlookClient* ))callback{
[self getTokenWith : #"https://outlook.office365.com" :true completionHandler:^(NSString *token) {
MSODataDefaultDependencyResolver* resolver = [MSODataDefaultDependencyResolver alloc];
MSODataOAuthCredentials* credentials = [MSODataOAuthCredentials alloc];
[credentials addToken:token];
MSODataCredentialsImpl* credentialsImpl = [MSODataCredentialsImpl alloc];
[credentialsImpl setCredentials:credentials];
[resolver setCredentialsFactory:credentialsImpl];
[[resolver getLogger] log:#"Going to call client API" :(MSODataLogLevel *)INFO];
callback([[MSOutlookClient alloc] initWithUrl:#"https://outlook.office365.com/api/v1.0" dependencyResolver:resolver]);
}];
}
getTokenWith method fetches the token for a resource first and then with the acquired token makes the necessary calls to fetch the events, but before fetching the token it checks in the cache to see if there are any tokens available for the same resource.
// fetch tokens for resources
- (void) getTokenWith :(NSString *)resourceId : (BOOL) clearCache completionHandler:(void (^) (NSString *))completionBlock;
{
// first check if the token for the resource is present or not
if([self getCacheToken : resourceId completionHandler:completionBlock]) return;
ADAuthenticationError *error;
authContext = [ADAuthenticationContext authenticationContextWithAuthority:[[NSUserDefaults standardUserDefaults] objectForKey:#"authority"] error:&error];
NSURL *redirectUri = [NSURL URLWithString:#"YOUR_REDIRECT_URI"];
[authContext acquireTokenWithResource:resourceId
clientId:[[NSUserDefaults standardUserDefaults] objectForKey:#"clientID"]
redirectUri:redirectUri
completionBlock:^(ADAuthenticationResult *result) {
if (AD_SUCCEEDED != result.status){
[self showError:result.error.errorDetails];
}
else{
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
[userDefaults setObject:result.tokenCacheStoreItem.userInformation.userId forKey:#"LogInUser"];
[userDefaults synchronize];
completionBlock(result.accessToken);
}
}];
}
getCacheToken method: Checks if there are any reusable token for any resources.
-(BOOL)getCacheToken : (NSString *)resourceId completionHandler:(void (^) (NSString *))completionBlock {
ADAuthenticationError * error;
id<ADTokenCacheStoring> cache = [ADAuthenticationSettings sharedInstance].defaultTokenCacheStore;
NSArray *array = [cache allItemsWithError:&error];
if([array count] == 0) return false;
ADTokenCacheStoreItem *cacheItem;
for (ADTokenCacheStoreItem *item in array) {
if([item.resource isEqualToString:resourceId]){
cacheItem = item;
break;
}
}
ADUserInformation *user = cacheItem.userInformation;
if(user == nil) return false;
if([cacheItem isExpired]){
return [self refreshToken:resourceId completionHandler:completionBlock];
}
else
{
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
[userDefaults setObject:user.userId forKey:#"LogInUser"];
[userDefaults synchronize];
completionBlock(cacheItem.accessToken);
return true;
}
}
Using this code and Office 365 SDK in place you can get the outlook events for a particular user, before that make sure you have full permissions in the Azure AD else you may get 0 events as response.
Please note all the methods are from the SDK example apart from the first method to view how to fetch the events i would recommend to download the exchange example from the github.
You can also use MSGraph SDK to fetch calendars and events:
Check this link: Configuration process is same, only fetching events is different(see given code for fetching events):
How to Fetch/Create calender by O365-iOS-Connect?
Note: Above link is used to fetch calendars from outlook the process is same for this but you should use this code after authentication and completed get events action look like this:
- (IBAction)getCalendarsEvents:(id)sender {
[NXOAuth2AuthenticationProvider setClientId:clientId
scopes:#[#"https://graph.microsoft.com/Files.ReadWrite",
#"https://graph.microsoft.com/Calendars.ReadWrite"]];
[[NXOAuth2AuthenticationProvider sharedAuthProvider] loginWithViewController:nil completion:^(NSError *error) {
if (!error) {
[MSGraphClient setAuthenticationProvider:[NXOAuth2AuthenticationProvider sharedAuthProvider]];
self.client = [MSGraphClient client];
// Authentication done
[[[[_client me] events] request] getWithCompletion:^(MSCollection *response, MSGraphUserEventsCollectionRequest *nextRequest, NSError *error){
NSArray *arr = response.value;
MSGraphEvent *event = arr.firstObject;
// Here you will getting outlook events
}];
}
}];
}

Resources