I would like to transfer (send and receive) the file using XMPP Framework in Objective C (from iPhone to iPhone).Is there any tutorial which explains the detail steps to do this.
File Transfer using XMPPFramework
This application is merely a brief demo of how to use the file transfer extension of the XMPPFramework.
A detailed blog post can be found here.
My changes have been merged into the master branch of the XMPPFramework, so you'll want to include the latest version in your project.
Both incoming file transfers and outgoing file transfers are functional within this demo, but I've left a significant amount of error-handling out, so you'll want to include that in your app.
Server Settings
In order for SOCKS5 to work properly, your server must be configured to handle proxy connections. I've only tested this using ejabberd, but these are the mod_proxy65 settings I used:
{mod_proxy65, [
{ip, {0,0,0,0}},
{hostname, "myhostnamehere"},
{port, 7777},
{access, all},
{shaper, c2s_shaper}
]},
If you're unable to get the proxy functioning, you always have the option to set disableSOCKS5 = YES, which will force an IBB transfer instead. This is slower, but it's very widely supported.
Usage
Incoming File Transfers
Instantiate a new XMPPIncomingFileTransfer, activate it, add a delegate, and wait for a file transfer request.
_xmppIncomingFileTransfer = [XMPPIncomingFileTransfer new];
[_xmppIncomingFileTransfer activate:_xmppStream];
[_xmppIncomingFileTransfer addDelegate:self delegateQueue:dispatch_get_main_queue()];
Responding to disco#info queries and the like are handled for you. You'll get a delegate call when an SI offer is received, at which point you can decide whether or not you wish to accept. You can also set autoAcceptFileTransfers = YES and you won't need to call acceptSIOffer: yourself.
- (void)xmppIncomingFileTransfer:(XMPPIncomingFileTransfer *)sender
didFailWithError:(NSError *)error
{
DDLogVerbose(#"%#: Incoming file transfer failed with error: %#", THIS_FILE, error);
}
- (void)xmppIncomingFileTransfer:(XMPPIncomingFileTransfer *)sender
didReceiveSIOffer:(XMPPIQ *)offer
{
DDLogVerbose(#"%#: Incoming file transfer did receive SI offer. Accepting...", THIS_FILE);
[sender acceptSIOffer:offer];
}
- (void)xmppIncomingFileTransfer:(XMPPIncomingFileTransfer *)sender
didSucceedWithData:(NSData *)data
named:(NSString *)name
{
DDLogVerbose(#"%#: Incoming file transfer did succeed.", THIS_FILE);
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask,
YES);
NSString *fullPath = [[paths lastObject] stringByAppendingPathComponent:name];
[data writeToFile:fullPath options:0 error:nil];
DDLogVerbose(#"%#: Data was written to the path: %#", THIS_FILE, fullPath);
}
Outgoing File Transfers
To start a new outgoing file transfer, simply create an instance of XMPPOutgoingFileTransfer, activate it, add a delegate, and send your data:
_fileTransfer = [[XMPPOutgoingFileTransfer alloc] initWithDispatchQueue:dispatch_get_main_queue()];
[_fileTransfer activate:[self appDelegate].xmppStream];
[_fileTransfer addDelegate:self delegateQueue:dispatch_get_main_queue()];
NSError *err;
if (![_fileTransfer sendData:data
named:filename
toRecipient:[XMPPJID jidWithString:recipient]
description:#"Baal's Soulstone, obviously."
error:&err]) {
DDLogInfo(#"You messed something up: %#", err);
}
The following delegate calls when get invoked when appropriate:
- (void)xmppOutgoingFileTransfer:(XMPPOutgoingFileTransfer *)sender
didFailWithError:(NSError *)error
{
DDLogInfo(#"Outgoing file transfer failed with error: %#", error);
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Error"
message:#"There was an error sending your file. See the logs."
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
}
- (void)xmppOutgoingFileTransferDidSucceed:(XMPPOutgoingFileTransfer *)sender
{
DDLogVerbose(#"File transfer successful.");
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Success!"
message:#"Your file was sent successfully."
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
}
Related
I'm building an app that is using the Instagram API to display photos but I'm running into some trouble. The app is crashing when there is no network connection and I have found the code that is causing the problem.
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
self.accessToken = [userDefaults objectForKey:#"accessToken"];
if (self.accessToken == nil) {
[SimpleAuth authorize:#"instagram" options:#{#"scope": #[#"likes"]} completion:^(NSDictionary *responseObject, NSError *error) {
self.accessToken = responseObject[#"credentials"][#"token"];
[userDefaults setObject:self.accessToken forKey:#"accessToken"];
[userDefaults synchronize];
[self refresh];
}];
} else {
[self refresh];
}
I have found that the [self refresh]; is causing the problem in the else block and I tried to replace it with a alert view like this
UIAlertView *networkError = [[UIAlertView alloc] initWithTitle:#"Network Error" message:#"Please connect your device to a network and restart application" delegate:nil cancelButtonTitle:nil otherButtonTitles:nil];
[networkError show];
However, with this problem I find that if I open the app with a network connection I still get the alert. Any help would be great because I'm still new to Objective C!
Thank you for the help!
I know this code from Treehouse :).
The thing is that the if (self.accessToken == nil) { /.../ } block will only get execute when the app is not authorized using your Instagram credentials.
Once you logged in successfully, it will always execute the code in the else { /.../ } block. If it has connection to Internet, it will do its work, download, display images etc. If you insert the code to display alert, it will always do that because you actually mean that by that code.
If you want to check if there is some connection, you need to do that before all that code, display an error and return instantly if connection is not available. However, the author tried to keep things simple, assuming there is always Internet connection.
Hope it makes you understand it.
This is the some code you can use for checking if there is connection:
// show some activity indicator
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
// Do something...
[[UIApplication sharedApplication] beginIgnoringInteractionEvents];
NSURL *url = [NSURL URLWithString:#"http://www.apple.com/"];
NSString *s = [NSString stringWithContentsOfURL:url
encoding:NSUTF8StringEncoding
error:nil];
dispatch_async(dispatch_get_main_queue(), ^{
// hide the activity indicator
self.connected = (s != nil);
[[UIApplication sharedApplication] endIgnoringInteractionEvents];
if (self.isConnected)
{
NSLog(#"self.connected == YES");
}
else
{
NSLog(#"self.connected == NO");
NSString *alertMessage = #"In order to load images, you need an active Internet connection. Please try again later!";
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Sorry!"
message:alertMessage
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
}
});
});
You obviously need to add a property to you class. You can insert this code:
#interface LDPhotosViewController ()
#property (nonatomic, copy, getter = isConnected) NSString *connected;
#end
at the top of LDPhotosViewController.m file, before the #implementation line.
Developing an app for iOS, I need to know how to have instanced and available an object created when user authenticates.
I am using OAuth2 method properly implementing gtm-oauth2 framework. The user entries, sees the login form displayed in a web view and correctly authenticates. In that moment, as detailed in the documentation, I go like this:
if (error != nil){
// Do whatever to control the error
}
else
{
// Authentication succeeded
// Assign the access token to the instance property for later use
self.accessToken = myAuth.accessToken;
[myAuth setShouldAuthorizeAllRequests:YES];
[self setAuth:myAuth];
// Display the access token to the user
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Authorization Succeeded"
message:[NSString stringWithFormat:#"Access Token: %#", myAuth.accessToken]
delegate:self
cancelButtonTitle:#"Dismiss"
otherButtonTitles:nil];
[alertView show];
}
Later, in the same controller, I use the self.auth object like this to access my API once the user has authenticated:
[request setURL:getCartsURL];
[request setValue:self.accessToken forHTTPHeaderField:#"Authorization"];
[self.auth authorizeRequest:request
completionHandler:^(NSError *error) {
NSString *output = nil;
if (error) {
output = [error description];
} else {
// Synchronous fetches like this are a really bad idea in Cocoa applications
//
// For a very easy async alternative, we could use GTMHTTPFetcher
NSURLResponse *response = nil;
NSData *data = [NSURLConnection sendSynchronousRequest:request
returningResponse:&response
error:&error];
if (data) {
// API fetch succeeded
output = [[NSString alloc] initWithData:data
encoding:NSUTF8StringEncoding];
SBJsonParser *jsonParser = [SBJsonParser new];
// Parse the JSON into an Object
id parsed = [jsonParser objectWithString:output];
NSArray *arrayResponse = [[NSArray alloc] initWithArray:parsed];
} else {
// fetch failed
output = [error description];
}
}
}];
So far, I have been using a local instance of self.auth object, what happens to be insufficient if I want to have that object globally accessed from any point of the whole app. Ok for the init view controller, but not for the whole app.
I think I can somehow access this first view controller to get the object anytime I want it. But I guess we have better methods to have it globally instanced and accessible from any point of the app.
Can you please help me with this?
Thanks a lot.
You should use a Singleton. Here is a nice article on how to set one up.
You could change the [self setAuth:myAuth]; of that ViewController to set an object on the AppDelegate. Create it there and set it, then you'll be able to access it from anywhere.
[[UIApplication sharedApplication] delegate] will give you a pointer to your app delegate, the one that was automatically created when you made the project.
I use NSURLConnection delegate methods to download either a video or audio file, the download is OK, now i need to play it right after it has finished downloading.
My relevant code is this:
-(IBAction)downloadAndPlay:(id)sender{
NSString *fileUrlPath=[host stringByAppendingString:rowContent];
// Create the request.
NSURLRequest *theRequest=[NSURLRequest requestWithURL:[NSURL URLWithString:fileUrlPath]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:60.0];
// create the connection with the request
// and start loading the data
NSURLConnection *theConnection=[[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
if (theConnection) {
// Create the NSMutableData to hold the received data.
receivedData = [NSMutableData data] ;
//NSLog(#"connection succeeded");
} else {
// Inform the user that the connection failed.
UIAlertView* alertView = [[UIAlertView alloc] initWithTitle:#"Music Album" message:#"Connection failed, please try again" delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alertView show];
}
}
//NSURLConnection delegate methods
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
// This method is called when the server has determined that it
// has enough information to create the NSURLResponse.
// It can be called multiple times, for example in the case of a
// redirect, so each time we reset the data.
// receivedData is an instance variable declared elsewhere.
[receivedData setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
// Append the new data to receivedData.
// receivedData is an instance variable declared elsewhere.
[receivedData appendData:data];
}
- (void)connection:(NSURLConnection *)connection
didFailWithError:(NSError *)error
{
// inform the user
NSLog(#"Connection failed! Error - %# %#",
[error localizedDescription],
[[error userInfo] objectForKey:NSURLErrorFailingURLStringErrorKey]);
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
// do something with the data
// receivedData is declared as a method instance elsewhere
NSLog(#"Succeeded! Received %d bytes of data",[receivedData length]);
}
How can i play the file (either audio or video) right after it is downloaded (auto play).
Thanx in advance.
You will need to save the data you've downloaded to a file, and then open the file using a MPMoviePlayerViewController or similar. Right now you just download your file as NSData, and leave it at that.
So save your NSData object to the file system with the appropriate name/extension (or just write your download to the file system itself, which makes more sense for larger files), get a file URL handle, and pass it to your media player.
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/
I have been trying to implement the GameKit Framework for bluetooth connection and want to use a Server/Client relationship to reduce lag and be able to distinguish between to connected devices. I found this thread and it is similar to what I am trying to do, but the code doesn't work for me. Here is what I have:
Connect Method:
-(IBAction) btnConnect:(id) sender {
if(sender == server){
[self.currentSession initWithSessionID:#"BT" displayName:nil sessionMode:GKSessionModeServer];
currentSession.available == YES;
NSLog(#"Setup Server");
}else{
[self.currentSession initWithSessionID:#"BT" displayName:nil sessionMode:GKSessionModeClient];
currentSession.available == YES;
NSLog(#"Setup Client");
}
currentSession.delegate = self;
currentSession.disconnectTimeout = 0;
[currentSession setDataReceiveHandler:self withContext:nil];
[client setHidden:YES];
[server setHidden:YES];
[disconnect setHidden:NO];
}
didChangeState:
- (void)session:(GKSession *)session peer:(NSString *)peerID didChangeState:(GKPeerConnectionState)state {
NSLog(#"didChangeState was called with status: %#.", state);
switch (state)
{
case GKPeerStateConnected:
NSLog(#"connected");
break;
case GKPeerStateDisconnected:
NSLog(#"disconnected");
[self.currentSession release];
currentSession = nil;
[connect setHidden:NO];
[disconnect setHidden:YES];
break;
case GKPeerStateAvailable:
NSLog(#"Server is Available, Presenting UIALert...");
NSLog(#"%#", peerID);
peerName = [session displayNameForPeer:peerID];
NSLog(#"%#", peerName);
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Server Available!" message:[NSString stringWithFormat:#"The Server %# is Available, Would you like to Connect?", peerName] delegate:self cancelButtonTitle:#"Decline" otherButtonTitles:#"Accept", nil];
[alert show];
[alert release];
if(selection == #"accept"){
[session connectToPeer:peerID withTimeout:15];
session.available = NO;
}else{
}
break;
}
}
didReceiveConnectionRequest:
- (void)session:(GKSession *)session didReceiveConnectionRequestFromPeer:(NSString *)peerID{
NSLog(#"Recieved Connection Request");
NSLog(#"%#", peerID);
peerName = [session displayNameForPeer:peerID];
NSLog(#"%#", peerName);
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Connection Request" message:[NSString stringWithFormat:#"The Client %# is trying to connect.", peerName] delegate:self cancelButtonTitle:#"Decline" otherButtonTitles:#"Accept", nil];
[alert show];
[alert release];
if(selection == #"accept"){
[session acceptConnectionFromPeer:peerID error:nil];
}else{
[session denyConnectionFromPeer:peerID];
}
}
I think I have this all setup right, but the didChangeState isn't getting called to inform the user that another device is available. Am I missing something or should I try to use a different method. Thanks for any help
currentSession.disconnectTimeout = 0;
The disconnect timeout is a time in seconds that peers should wait before disconnecting unresponsive peers. You don't want this to be 0. The default is 20 seconds, you should leave it there or say like 10 seconds. I actually don't set this in my GameKit code and it works well.
Also, it might help to post your entire implementation class somewhere. We'll need to make sure you are implementing GKSessionDelegate, e.g.:
#interface SomeObject : NSObject <GKSessionDelegate>
Also, you're setting up a Peer-2-Peer above. You said you were trying to do client/server. If so you should start the client session with a mode of GKSessionModeClient and server as GKSessionModePeer.
Lastly...are you testing this on actual devices or with a device and simulator? Don't forget that simulator and first gen iPhones and touches do not support bluetooth. So you'll have to have everyone involved connected to the same wireless network for anything to happen.
What are you seeing in the console when you start up your debug session?