QuickBlox :How to share image/video in peer to peer chat module? - quickblox

I am trying to share image/video in chat module. I've referred Sample code for this but couldn't find any help.
Alos I've referred http://quickblox.com/modules/chat/ it says Add live chat functions to your app by plugging in our full featured chat module. Fast, Firewall friendly, Robust & Secure. Does it means I have to purchase full featured chat module ?
Please suggest me the right way.
Thanks

Yes, QuickBlox Chat allows to share files, video/audio between 2 users.
Right now iOS SDK doesn't provide methods for send file, live chat. This feature is under Beta testing right now. We are developing easy interface for end users, and we need more time for this. I hope, we will finish it at the end of December.
However, we allow developers develop this feature themself.
What you need for this?
Just create simple TCP/UDP socket between 2 users and send files, audio/video stream through it
For 1 you need to know each other ip address & port - there is STUN protocol that allow to know own address(IP & port) - here is my iOS implementation of STUN protocol https://github.com/soulfly/STUN-iOS
If you already know your address (IP & port) - just send it to your opponent through simple Chat messages - then do 1 item.
Thats all what you need

UPD:
QuickBlox has released VideoChat and Unlimited API Calls for Developers http://quickblox.com/blog/2013/02/quickblox-updates-videochat-and-unlimited-api-calls-for-developers
So, if you want to play with the code and integrate it with your apps, check the Simple Code Sample for iOS http://quickblox.com/developers/SimpleSample-videochat-ios

You have a uploadMethod like this,
-(IBAction)uploadFile:(id)sender
{
self.imagePicker = [[UIImagePickerController alloc] init];
self.imagePicker.allowsEditing = NO;
self.imagePicker.delegate = self;
self.imagePicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
[self presentViewController:self.imagePicker animated:YES completion:nil];
}
and in the QBChatDelegate, you have this method
- (void)completedWithResult:(Result*)result{
// Upload file result
if(result.success && [result isKindOfClass:[QBCFileUploadTaskResult class]])
{
QBCFileUploadTaskResult *res = (QBCFileUploadTaskResult *)result;
NSUInteger uploadedFileID = res.uploadedBlob.ID;
QBChatMessage *message = [[QBChatMessage alloc] init];
message.recipientID = self.opponent.ID;
NSMutableDictionary *msgDict = [[NSMutableDictionary alloc]init];
[msgDict setValue:[NSNumber numberWithInt:uploadedFileID] forKey:#"fileID"];
message.customParameters = msgDict;
[[QBChat instance] sendMessage:message];
}
else
{
NSLog(#"errors=%#", result.errors);
}
}
Here you are getting the uploaded file id, and you are sending this as a message..
In your chatDidReceiveNotification
- (void)chatDidReceiveMessageNotification:(NSNotification *)notification{
QBChatMessage *message = notification.userInfo[kMessage];
if(message.customParameters != nil)
{
NSUInteger fileID = [message.customParameters[#"fileID"] integerValue];
// download file by ID
[QBContent TDownloadFileWithBlobID:fileID delegate:self];
}
}
This method again calls completedWithResult method, add this code there...
if(result.success && [result isKindOfClass:[QBCFileDownloadTaskResult class]]){
QBCFileDownloadTaskResult *res = (QBCFileDownloadTaskResult *)result;
if ([res file]) {
UIImageView* imageView = [[UIImageView alloc] initWithImage:[UIImage imageWithData:[res file]]];
[self.messages addObject:imageView];
[self.messagesTableView reloadData];
}
}else{
NSLog(#"errors=%#", result.errors);
}
If you want to display the image in your tableView, change your cellForRow like this..
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
if([[self.messages objectAtIndex:indexPath.row]isKindOfClass:[QBChatMessage class]])
{
static NSString *ChatMessageCellIdentifier = #"ChatMessageCellIdentifier";
ChatMessageTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ChatMessageCellIdentifier];
if(cell == nil){
cell = [[ChatMessageTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:ChatMessageCellIdentifier];
}
QBChatMessage *message = (QBChatMessage *)self.messages[indexPath.row];
//
[cell configureCellWithMessage:message is1To1Chat:self.opponent != nil];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
return cell;
}
else if ([[self.messages objectAtIndex:indexPath.row]isKindOfClass:[UIImageView class]])
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"CellIdentifier"];
if (nil == cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:#"CellIdentifier"];
}
UIImageView *receivedImage = [self.messages objectAtIndex:indexPath.row];
[cell.contentView addSubview:receivedImage];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
return cell;
}
}
I have tried this and this piece of code works.
Cheers.

If your requirement is only for 1-1 chat, then please check this link
http://quickblox.com/developers/SimpleSample-chat_users-ios#Send_files
This will work for 1-1 chat.
But, in case of room I am unable to find any solution as of now. I am trying to figure out. If anybody knows a way, please post here.

Related

Objective-C MPMediaItem with null URL

I have a project that makes use of a MPMediaPickerController to select audio files from the Media Player. However, when trying to store it's URL, I am getting nothing but null returned. My code can be seen below:
- (void)showMediaPicker:(NSString *)title {
MPMediaPickerController *picker = [[MPMediaPickerController alloc] initWithMediaTypes:MPMediaTypeAny];
picker.delegate = self;
picker.prompt = title;
picker.allowsPickingMultipleItems = NO;
picker.showsCloudItems = NO;
[self.viewController presentViewController:picker animated:YES completion:NULL];
}
- (void)mediaPicker: (MPMediaPickerController *)mediaPicker didPickMediaItems:(MPMediaItemCollection *)mediaItemCollection {
MPMediaItem *item = [mediaItemCollection.items firstObject];
NSURL *assetURL = [item valueForProperty:MPMediaItemPropertyAssetURL];//returning null
NSString *type = [self contentTypeForFile:assetURL.lastPathComponent];
NSString *title = [item valueForProperty:MPMediaItemPropertyTitle];
[self callbackWithName:title type:type url:assetURL];
}
For whatever reason, my *assetURL is nil upon selecting a single audio item from the device's library. The only answers i could find with respect to this problem often relate to the url being null when a cloud item is selected from the MediaPicker. However, as seen above, I have set showCloudItems = NO.
I would greatly appreciate any help; let me know if you need any additional information!
Turns out, music from the "iCloud Music Library" is DRM protected and therefore, the assetURL is left null when selected in the MPMediaPickerController. The simple fix was to turn off the "iCloud Music Library" setting from within the settings for the "Music" app. I would expect picker.showsCloudItems = NO; to prevent this, but apparently I was mistaken.

Connect to peripheral in didSelectRowAtIndexPath

I am developing an app using CoreBluetooth. I am able to discover devices from the app and show their names in the table view. I am facing a problem with requirements below:
When used for the first time, the user selects a peripheral from the list. Connection should be established with the peripheral using the Bluetooth Serial Port Profile (SPP). Discovery and connection is simple and accomplished with a single click, minimizing user interaction.
Once a connection has been established between the peripheral device and the app, the app remembers the device and always seeks and connects to it for all subsequent uses.
I have written the following code for this as below for scanning and discovering
- (void)scan
{
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:NO], CBCentralManagerScanOptionAllowDuplicatesKey, nil];
NSLog(#"options are %#",options);
[self.centralManager scanForPeripheralsWithServices:nil
options:nil];
_txtLogMessage.text = [NSString stringWithFormat:#"%# \n %#",_txtLogMessage.text,#"Scanning started"];
NSLog(#"Scanning started");
}
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral
*)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI
{
[central connectPeripheral:peripheral options:nil];
self.discoveredPeripheral = peripheral;
_logData = [NSString stringWithFormat:#"Did discover peripheral. peripheral: %# rssi: %#, UUID: %# advertisementData: %# ", peripheral, RSSI, peripheral.UUID, advertisementData];
NSLog(#"%#",_logData);
[_periferalDevices addObject:peripheral.name];
[_tableView reloadData];
}
for connecting the device
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral
{
peripheral.delegate = self;
[self.discoveredPeripheral discoverServices:nil];
NSLog(#"Peripheral Connected");
NSLog(#" started time is %#",_timestring);
//[self.centralManager stopScan];
NSLog(#"Scanning stopped");
[self.data setLength:0];
[peripheral discoverServices:nil];
[peripheral discoverServices:#[[CBUUID UUIDWithString:TRANSFER_SERVICE_UUID]]];
}
in table view cell for row at index path aim able to get the data to view but aim facing problem in connecting to a peripheral while particular row is selected in the table view
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifier];
}
cell.textLabel.text = [_periferalDevices objectAtIndex:indexPath.row];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
_discoveredPeripheral.delegate = self;
[self.centralManager connectPeripheral:[_periferalDevices objectAtIndex:indexPath.row]
options:nil];
NSLog(#"discovered peripheral is %#",[_periferalDevices objectAtIndex:indexPath.row]);
NSString *datstr=[_discoveredPeripheral valueForKey:#"identifier"];
NSLog(#"value for key is ........%#",datstr);
}
The errors that you get when you try to use the peripheral object stems from the fact that you added the name of the peripheral to your array rather than the peripheral, itself. Thus, replace
[_periferalDevices addObject:peripheral.name];
With
[_periferalDevices addObject:peripheral];
And, obviously, you'll have to fix wherever you took advantage of just inserting the name. For example, your cellForRowAtIndexPath bears a line that says:
cell.textLabel.text = [_periferalDevices objectAtIndex:indexPath.row];
You'd probably want to replace that with something like:
CBPeripheral *peripheral = _periferalDevices[indexPath.row];
cell.textLabel.text = peripheral.name;
Your didDiscover... is connecting immediately. It probably shouldn't. You should probably only try connecting to the device the user selected. This could cause problems if you try to connect again (I don't know what it does if you try to connect twice). Your didSelectRow... connects on the ones the user chooses, so you should probably leave it at that.
You say "am facing problem connecting". So, what precisely did didFailToConnectPeripheral report?
As an aside, I'm unclear why you're calling discoverServices twice, too. Either discover all services (slow) or discover just the particular service, but you probably don't have to do both.
My original answer (based upon original code sample) is below.
You have code that says:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
NSString *cellText = cell.textLabel.text;
if([cellText isEqualToString:#""])
{
}
else
{
UIAlertView *alert=[[UIAlertView alloc] initWithTitle:#"Connected to "
message:cellText delegate:self cancelButtonTitle:#"ok"
otherButtonTitles: nil];
[alert show];
}
_discoveredPeripheral.delegate = self;
[self.centralManager connectPeripheral:_discoveredPeripheral options:nil];
NSLog(#"discovered peripheral is %#", _discoveredPeripheral);
NSString *datstr = [_discoveredPeripheral valueForKey:#"identifier"];
NSLog(#"value for key is ........%#", datstr);
}
You are retrieving the information on the selected cell (though Hot Licks is correct, you should be going to your model, not to the view for that information), retrieving the cellText, but you proceed to use _discoveredPeripheral, which is some variable that bears no obvious relation to the cell the user just selected.
You want to maintain your model of the array of peripherals, and when a user taps on the cell, use the indexPath.row to look up the peripheral in your model array, and use that CBPeripheral in your connection code.

How do to use the tel:// scheme with stringWithFormat

I am trying to create a simple phone book app that allows me to call people from the list. The app lists the names of the contacts and their phone numbers in different sections alphabetically based on the last name. Everything is displaying properly, my issue is when I select a contact and get prompted to "Cancel" or "Call", the "Call" button in the alertView doesn't do anything.
Here is the code I am using (urlString is a global variable):
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog("#didSelectRowAtIndexPath");
NSString *alphabet = [nameIndex objectAtIndex:[indexPath section]];
if([alphabet isEqual:#"A"])
{
UIAlertView *messageAlert = [[UIAlertView alloc] initWithTitle:#"Do you want to call.." message:[SectionA objectAtIndex:indexPath.row] delegate:self cancelButtonTitle:#"Cancel" otherButtonTitles:#"Call", nil];
NSString *urlString = [NSString stringWithFormat:#"tel://%#",[SectionA objectAtIndex:indexPath.row]];
[messageAlert show];
}
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
There are more if statements with the same code for the different sections of name/numbers, for the sake of space and time I just added the one section.
Here is where I attempt to make the "Call" button actually call the number:
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if(buttonIndex != [alertView cancelButtonIndex])
{
NSLog(#"Calling phone number");
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:urlString]];
}
}
The alert displays the proper phone number selected, and when I select "Call" nothing happens. But "Calling phone number" does show up in the output log. Stuck at the moment I'm assuming what I store in urlString isn't correct; or how I'm using urlString isn't correct. Any help would be appreciated, thanks!
Change this line
NSString *urlString = [NSString stringWithFormat:#"tel://%#",[SectionA objectAtIndex:indexPath.row]];
to this
urlString = [NSString stringWithFormat:#"tel://%#",[SectionA objectAtIndex:indexPath.row]];
You shadowed a local variable over a global / instance variable, hence the assigned value never reaches the point you expected. In other words, there are two urlString's existing at that point. A local one and one that is scoped globally / instance wide. Your assignment changed the local one, your attempt to use the value uses the global / instance one.

UITableView: How to load an image only once then use it in all cells

I'm creating an app using the Twitter API and parsing with JSON and every time I load the image into the cells it's taking multiple images and everything runs slowly. How would I go on by getting the image once then put the same image into all cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"TweetCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
NSDictionary *tweet = [tweets objectAtIndex:indexPath.row];
NSString *text = [tweet objectForKey:#"text"];
NSString *time = [tweet objectForKey:#"created_at"];
time = [time stringByReplacingOccurrencesOfString:#" +0000 "withString:#"/"];
NSString *twitterImage = [[tweet objectForKey:#"user"] objectForKey:#"profile_image_url_https"];
NSString *completeImage = [NSString stringWithFormat:#"%#", twitterImage];
NSData * imageData = [[NSData alloc] initWithContentsOfURL: [NSURL URLWithString: completeImage]];
imageLabel.image = [UIImage imageWithData: imageData];
cell.imageView.image = [UIImage imageWithData: imageData];
cell.textLabel.text = text;
cell.textLabel.numberOfLines = 3;
cell.detailTextLabel.text = [NSString stringWithFormat:#"%#", time];
}
return cell;
}
Looks like this right now but really laggy when I scroll.
http://gyazo.com/8ab8325f3921fdb7e4f0ea0107d389ac.png
Looks to me like the problem is in these lines:
NSDictionary *tweet = [tweets objectAtIndex:indexPath.row];
NSString *twitterImage = [[tweet objectForKey:#"user"] objectForKey:#"profile_image_url_https"];
I believe that is getting a new copy of the image for each cell. Each indexPath.row is a new tweet, thus you are getting multiple twitterImage
You should use cache for images. I hope this link helps you:
http://khanlou.com/2012/08/asynchronous-downloaded-images-with-caching/
If it's always the same picture, load it before the table's loading in a class parameter (for example in the viewDidLoad) and always use this parameter.
If it's dynamic, load the image in the background using performSelectorInBackground.
The problem that you are facing is because you are downloading all the images on the main thread.
To solve this either :
Download images using a separate thread using NSOperationQueue.
A good tutorial on the same : http://www.raywenderlich.com/19788/how-to-use-nsoperations-and-nsoperationqueues
Use this class 'AsyncImageView'. I have used this and it works fine. So, instead of UIImageView you will need to use the class AsyncImageView and this library will manage the downloading for you asynchronously.
https://github.com/nicklockwood/AsyncImageView

how to implement google chat in iphone app

i have searched a lot on the web but can not find the actual sample source code that can help me to get started for google chat implementation , the sample code provided with the xmpp framework also does not tell clearly about it, as it have a sample project of Mac desktop application.
I have been able to show all my friends who are online/ofline/away with the help of sample project(iphoneXmpp) which is provided in the xmppframework, but it also doest tell anything about how to initiate a chat.
Please provide me any sample source code so that i can initialize the google chat in my app.
i am really stuck.
thanks in advance
okey i didnt give up and had some solution after looking into the desktop application of xmpp framework and tried to include it in my iphone app..
here is the code to send message to our chat friend on gmail..
-(void)sendMessage
{
messageStr = [NSString stringWithFormat:#"%#",[msgField text] ];
//messageStr = [NSString stringWithString:#"hello ji....."];
BOOL isEmpty = [ self validateIsEmpty:msgField.text];
if([messageStr length] > 0 && isEmpty == NO )
{
NSXMLElementK *body = [NSXMLElementK elementWithName:#"body"];
[body setStringValue:messageStr];
NSXMLElementK *message = [NSXMLElementK elementWithName:#"message"];
[message addAttributeWithName:#"type" stringValue:#"chat"];
[message addAttributeWithName:#"to" stringValue:[[user jid] full]];
[message addChild:body];
[[self xmppStream ] sendElement:message];
}
and in didReceiveMessage , i have following code...
- (void)xmppStream:(XMPPStream *)sender didReceiveMessage:(XMPPMessage *)message
{
NSLog(#"---------- xmppStream:didReceiveMessage: ----------");
NSLog(#"--jid---%#", [[user jid] full]);
NSLog(#"--from----%#", [message from]);
//if(![[[user jid] full] isEqual:[message from]]) return;// important when chatting with 2 or more .. and receiving 2 or more messages...
if([message isChatMessageWithBody])
{
NSString *msg = [[message elementForName:#"body"] stringValue];
NSLog(#"mmmmmmmmmmssssssgggg-%#",msg);
[str appendString:[NSString stringWithFormat:#"%#:%#\n\n", [message from], msg]];
[chatBox setText:str];
}
}
i'm able to send/recieve the chat using these two methods but problem is that some times the person's id which i selected from the table view of available online contacts(to whom we can chat with) does'nt receive the message but any other person receives the message..
Cheers!!
- (void)xmppStream:(XMPPStream *)sender didReceiveMessage:(XMPPMessage *)message {
NSString *msg = [[message elementForName:#"body"] stringValue];
NSString *from = [[message attributeForName:#"from"] stringValue];
if (msg.length==0) {
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Receiving Message"
message:[NSString stringWithFormat:#"From %#",from]
delegate:nil
cancelButtonTitle:#"Ok"
otherButtonTitles:nil];
[alertView show];
}
if (msg.length!=0) {
NSMutableDictionary *m = [[NSMutableDictionary alloc] init];
[m setObject:msg forKey:#"msg"];
[m setObject:from forKey:#"sender"];
NSLog(#"message received : %#", m);
[_messageDelegate newMessageReceived:m];
}
}
This works great for you, and it will also give you the alert who is sending the message and who wants to chat with you, However I'm just stuck from where should I implement the Logout for the user through which I logged in to iOS SDK.
This tutorial should do the trick : http://mobile.tutsplus.com/tutorials/iphone/building-a-jabber-client-for-ios-server-setup/