how to get version of default browser on my mac os x - objective-c

I want to get system information in mac using objective C.
I am searching a lot but did not got single line of code for
my use.They provided solutions via javascript but i want them in
objective C.
Provide me some help to go ahead.

You can use launch services to get the path to the default browser as below
LSGetApplicationForURL((CFURLRef)[NSURL URLWithString: #"http:"],
kLSRolesAll, NULL, (CFURLRef *)&appURL);
NSString *infoPlistPath = [[appURL path] stringByAppendingPathComponent:#"Contents/info.plist"];
Now read the CFBundleShortVersionString from the info.plist.

Here you go :
NSString *userName=NSUserName();
NSLog(#"UserName: %#",userName);
NSArray *ipAddress=[[NSHost currentHost] addresses];
NSLog(#"IP Address=%#",ipAddress[0]);
Updating my answer

This is tested and works well
NSWorkspace *nsSharedWorkspace = [NSWorkspace sharedWorkspace];
NSString *nsAppPath = [nsSharedWorkspace fullPathForApplication:appName];
NSBundle *nsAppBundle = [NSBundle bundleWithPath: nsAppPath];
NSDictionary *nsAppInfo = [nsAppBundle infoDictionary];
//Now you can print all dictionary to view all its contents and pick which you want
NSLog(#"%#",nsAppInfo);
//or you can get directly using following methods
NSLog(#"%#",[nsAppInfo objectForKey:#"CFBundleShortVersionString"]);
NSLog(#"%#",[nsAppInfo objectForKey:#"CFBundleVersion"]);
Dont forget to add AppKit framework

Related

iTunes Mp3 Add Returning Nil Via Scripting Bridge In ObjC and Swift And Doesn't Import

I'm trying to import a downloaded MP3 into iTunes. My app is for OSX using Swift, and I've tried doing this both in Swift code and in ObjC using interoperability. I've generated the iTunes.h using sdef and sdp. I'm importing it in my Bridging Header for the Swift attempt and in my .m file for the ObjC attempt. I've added Scripting Bridge to my build.
This is my first program in Swift or ObjC (my experience is in C#) so this may be something simple I don't have the experience to realize.
Here is my ObjC code:
NSString *filepath = "~/Music/test.mp3";
iTunesApplication *iTunes = [SBApplication applicationWithBundleIdentifier:#"com.apple.iTunes"];
iTunesPlaylist *pl;
for (iTunesSource *source in sources) {
if([source kind] == iTunesESrcLibrary) {
SBElementArray *libraries = [source libraryPlaylists];
pl = [libraries objectAtIndex:1];
break;
}
}
iTunesTrack *track = [iTunes add:[NSArray arrayWithObject:[NSURL fileURLWithPath:filepath]] to: pl];
Everything compiles and runs, but the iTunes add returns nil (and more importantly, doesn't add to iTunes). I've tried using different Playlists from the Library, and difference Sources as well. I've tried using a different MP3 file. And as I said, I've written it in Swift as well. All give me the same result.
So apparently I was fetching the path for MyMusic incorrectly. You can't just use the tilde, you have to resolve it:
NSString *musicDirectory = [NSSearchPathForDirectoriesInDomains(NSMusicDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *filepath = [musicDirectory stringByAppendingPathComponent:#"test.mp3"];
Or with Swift:
let fileManager = NSFileManager.defaultManager()
let urls = fileManager.URLsForDirectory(.MusicDirectory, inDomains: .UserDomainMask)
let musicDirectory: NSURL = urls.first as? NSURL
let filepath = musicDirectory.URLByAppendingPathComponent("test.mp3")
At this point, I no longer needed to mess with any of the source searching either, I could just pass nil as the playlist:
iTunesTrack *track = [iTunes add:[NSArray arrayWithObject:[NSURL fileURLWithPath:filepath], nil] to: nil];
I still need an Objective C wrapper around the actual add method, however, which is connected to the Swift programming via the Bridging Header. If I try to use the add method in Swift directly, I get linker errors which seem unrelated to the original issue, so I won't address.

Drag Files come across Sandbox(__CFPasteboardIssueSandboxExtensionForPath)

I processed drag operation from browser view to custom view.It work well in snow lepoard,but not in Mountain Lion with sandbox.
in browser view:
NSMutableArray* urls = [[[NSMutableArray alloc] init] autorelease];
..............put some NSUrl to urls array....................
[pasteboard writeObjects:[NSArray arrayWithArray:urls]];
in my receive custom view:
NSArray* pasteboardItems = [pasteboard readObjectsForClasses:[NSArray arrayWithObject:[NSString class]] options:nil];
NSArray* pasteboardItems2 = [pasteboard readObjectsForClasses:[NSArray arrayWithObject:[NSURL class]] options:nil];
NSArray* pasteboardItems3 = [pasteboard readObjectsForClasses:[NSArray arrayWithObject:[NSImage class]] options:nil];
NSLog(#"%#",pasteboardItems);
NSLog(#"%#",pasteboardItems2);
NSLog(#"%#",pasteboardItems3);
my log is:
2012-08-09 18:33:43.886 iCollage[6885:303] __CFPasteboardIssueSandboxExtensionForPath: error for [/Users/xxxx/Library/Containers/xxxxxxxxxxxx/Data/Downloads/1343902069.jpg]
2012-08-09 18:33:44.546 iCollage[6885:303] ( "file://localhost/Users/xxx/Library/Containers/xxxxxxxx/Data/Downloads/1343902069.jpg")
2012-08-09 18:33:44.547 iCollage[6885:303] ( "file://localhost/Users/xxxxx/Library/Containers/xxxxxx/Data/Downloads/1343902069.jpg")
2012-08-09 18:33:44.547 iCollage[6885:303] ()
my question is:
1.how to fix this error __CFPasteboardIssueSandboxExtensionForPath;I refer the docs and found nothing about that.I am ensuer that i have the permission to access the file!google says, may be "startAccessingSecurityScopedResource" will help me, then i try and failed
2.why pasteboardItems2 have value?i write to pasteboard only url but not string.It disgusted me that I can get the url both from NSString type and NSUrl type! (I try drag a file from iFinder, the url will only exist in pasteboardItems but not pasteboardItems2).Anybody know why? I think the first problem will auto fixed when some one help me fix this problem.
I believe Apple answer question 1:
Important: Although you can support dragging file paths, in general,
you should avoid doing so unless you are certain that the destination
app will never be run in an app sandbox. If you use an NSString, OS X
has no way to know whether that string should be interpreted as a
path; thus, OS X does not expand the destination app’s sandbox to
allow access to the file or directory at that location. Instead, use
an NSURL, a bookmark, or a filename pasteboard type.
WRT to question 2, it looks like you have pasted URLs so reading NSURL objects would seem to be correct. However I think you should implement the dragging using the following code (also from the link above):
- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
{
NSPasteboard *pboard = [sender draggingPasteboard];
if ( [[pboard types] containsObject:NSFilenamesPboardType] ) {
NSArray *files = [pboard propertyListForType:NSFilenamesPboardType];
int numberOfFiles = [files count];
// Perform operation using the list of files
}
return YES;
}
You need to generate security-scoped URL bookmark data on the sender side, and turn that data back into a URL on the receiver side. There's some other stuff you have to do after that when you want to actually access the URL; the documentation elaborates.
The receiving application, when running in a sandbox, will not be able to handle bare paths. This is a core part of being sandboxed; you are not allowed to use bare paths or their corresponding URLs to access files that aren't in your sandbox container and haven't been explicitly handed to you by the user.
Your pasteboardItems read object of NSString type, but you dragged a file(with jpg extension), you should register for NSString type in your init method:
[self registerForDraggedTypes:[NSArray arrayWithObject:NSPasteboardTypeString]];
You need to have Document Types defined in your application so that the sandboxing mechanism knows your application should be opening files with those extensions. You can do this by clicking the project on the left in Xcode, and in the Info tab, under Document Types add a new document type for each extension.
You just need to fill in the name and extensions field.
Also if you want to persist your permission to access the files dragged onto your application, you can use this class to wrap up all that logic. https://github.com/leighmcculloch/AppSandboxFileAccess

Access iTunes user preferences in OSX Lion

I want to access iTunes user preferences such as playlists programmatically.
I use to do it with the following code, however since OSX Lion, I get a nil in response.
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
NSDictionary *userPreferences = [userDefaults persistentDomainForName:#"com.apple.iApps"];
NSArray *databasePaths = [userPreferences objectForKey:#"iTunesRecentDatabasePaths"];
I've also made sure my app has all of its entitlements enabled.
Any suggestions on how I can fix this?
Long story made short: You just can not do it using a Sandboxed app. Turn off Sandboxing and you will see that it works. Why? Well, that's because of containers. A sandbox lives in its own container and so when you call [NSUserDefaults standardUserDefaults] Cocoa uses the path of your container rather than the POSIX path of ~/Library/Preferences which is where com.apple.iApps.plist resides. That sums up why you get nil. Also, there is a blurb on this here in NSUserDefaults: link
How to fix this?
It's really not to bad. First you have to do a little bit of work to get the POSIX path of your home directory. I setup a bunch of NSURL category methods. However the root path is POSIX based. Here is the code snippet to get you started.
1.
+ (NSURL *) homePOSIXURL {
struct passwd *pwUser = getpwuid(getuid());
const char *homeDir = pwUser->pw_dir;
return [NSURL fileURLWithPath:[NSString stringWithUTF8String:homeDir] isDirectory:YES]; }
When all is said and done, construct a full path to the plist. It hasn't changed for years so you can consider it sticky.
So you might get something that looks like this now:
2.
NSURL * prefURL = [[NSURL libraryPOSIXURL] URLByAppendingPathComponent:#"Preferences" isDirectory:YES];
prefURL = [prefURL URLByAppendingPathComponent:#"com.apple.iApps.plist"];
Now let's turn this plist, which is fairly small into something we can play with. Perhaps NSData? That sounds good, right?
3.
NSData * prefData = [NSData dataWithContentsOfURL:prefURL];
Ok, finally we can use this now to get an NSDictionary. Here is how I do it.
4.
NSDictionary * prefDict = [NSDictionary collectionFromPropertyList:prefData];
Yeah, yeah another Category on NSDictionary. I must have a million of them.
Because I'm in a sharing mood, here ya go:
+ (id) collectionFromPropertyList:(NSData *)pList {
if ( [pList length] > 0 )
return [NSPropertyListSerialization propertyListWithData:pList
options:NSPropertyListImmutable
format:nil error:nil];
return nil;
}
So, you think we are done? Well, almost. If you get this far, you will get a deny like so:
deny file-read-data
/Users/UserName/Library/Preferences/com.apple.iApps.plist
Are we loving our Sandboxed app?! Basically add your temporary entitlement and you should be off to the races again. Best of luck to ya!

How to make QTMovie play file from URL with forced (MP3) type?

I'm using QTKit to progressively download and play an MP3 from a URL. According to this documentation, this is the code I should use to accomplish that:
NSURL *mp3URL = [NSURL URLWithString:#"http://foo.com/bar.mp3"];
NSError *error = nil;
QTMovie *sound = [[QTMovie alloc] initWithURL:mp3URL error:&error];
[sound play];
This works, and does exactly what I want — the MP3 URL is lazily downloaded and starts playing immediately. However, if the URL does not have the ".mp3" path extension, it fails:
NSURL *mp3URL = [NSURL URLWithString:#"http://foo.com/bar"];
NSError *error = nil;
QTMovie *sound = [[QTMovie alloc] initWithURL:mp3URL error:&error];
[sound play];
No error is given, no exception is raised; the duration of the sound is just set to zero, and nothing plays.
The only way I have found to work around this is to force a type by loading the data manually and using a QTDataReference:
NSURL *mp3URL = [NSURL URLWithString:#"http://foo.com/bar"];
NSData *mp3Data = [NSData dataWithContentsOfURL:mp3URL];
QTDataReference *dataReference =
[QTDataReference dataReferenceWithReferenceToData:mp3Data
name:#"bar.mp3"
MIMEType:nil];
NSError *error = nil;
QTMovie *sound = [[QTMovie alloc] initWithDataReference:dataReference error:&error];
[sound play];
However, this forces me to completely download ALL of the MP3 synchronously before I can start playing it, which is obviously undesirable. Is there any way around this?
Thanks.
Edit
Actually, it seems that the path extension has nothing to do with it; the Content-Type is simply not being set in the HTTP header. Even so, the latter code works and the former does not. Anyone know of a way to fix this, without having access to the server?
Edit 2
Anyone? I can't find information about this anywhere, and Google frustratingly now shows this page as the top result for most of my queries...
Two ideas. (The first one being a bit hacky):
To work around the missing content type, you could embed a small Cocoa webserver that supplements the missing header field and route your NSURL over that "proxy".
Some Cocoa http server implementations:
http://code.google.com/p/cocoahttpserver/
http://cocoawithlove.com/2009/07/simple-extensible-http-server-in-cocoa.html
http://culturedcode.com/cocoa/
The second one would be, to switch to a lower level framework (From QTKit to AudioToolbox).
You'd need more code, but there are some very good resources out there on how to stream mp3 using AudioToolbox.
e.g.:
http://cocoawithlove.com/2008/09/streaming-and-playing-live-mp3-stream.html
Personally I'd go with the second option. AudioToolbox isn't as straightforward as QTKit but it offers a clean solution to your problem. It's also available on both - iOS and Mac OS - so you will find plenty of information.
Update:
Did you try to use another initializer? e.g.
+ (id)movieWithAttributes:(NSDictionary *)attributes error:(NSError **)errorPtr
You can insert your URL for the key QTMovieURLAttribute and maybe you can compensate the missing content type by providing other attributes in that dictionary.
This open source project has a QTMovie category that contains methods to accomplish similar things:
http://vidnik.googlecode.com/svn-history/r63/trunk/Source/Categories/QTMovie+Async.m
If you thought weichsel's first solution was hacky, you're going to love this one:
The culprit is the Content-Type header, as you have determined. Had QTKit.framework used Objective-C internally, this would be a trivial matter of overriding -[NSHTTPURLResponse allHeaderFields] with a category of your choosing. However, QTKit.framework (for better or worse) uses Core Foundation (and Core Services) internally. These are both C-based frameworks and there is no elegant way of overriding functions in C.
That said, there is a method, just not a pretty one. Function interposition is even documented by Apple, but seems to be a bit behind the times, compared to the remainder of their documentation.
In essence, you want something along the following lines:
typedef struct interpose_s {
void *new_func;
void *orig_func;
} interpose_t;
CFStringRef myCFHTTPMessageCopyHeaderFieldValue (
CFHTTPMessageRef message,
CFStringRef headerField
);
static const interpose_t interposers[] __attribute__ ((section("__DATA, __interpose"))) = {
{ (void *)myCFHTTPMessageCopyHeaderFieldValue, (void *)CFHTTPMessageCopyHeaderFieldValue }
};
CFStringRef myCFHTTPMessageCopyHeaderFieldValue (
CFHTTPMessageRef message,
CFStringRef headerField
) {
if (CFStringCompare(headerField, CFSTR("Content-Type"), 0) == kCFCompareEqualTo) {
return CFSTR("audio/x-mpeg");
} else {
return CFHTTPMessageCopyHeaderFieldValue(message, headerField);
}
}
You might want to add logic specific to your application in terms of handling the Content-Type field lest your application break in weird and wonderful ways when every HTTP request is determined to be an audio file.
Try replacing http:// with icy://.
Just create an instance like this...
QTMovie *aPlayer = [QTMovie movieWithAttributes:[NSDictionary dictionaryWithObjectsAndKeys:
fileUrl, QTMovieURLAttribute,
[NSNumber numberWithBool:YES], QTMovieOpenForPlaybackAttribute,
/*[NSNumber numberWithBool:YES], QTMovieOpenAsyncOKAttribute,*/
nil] error:error];

ScriptingBridge Finder POSIX path

is it possible to get the POSIX path or target to the frontmost window using the Scripting Bridge framework?
I'm using
FinderApplication *theFinder = [SBApplication aplicationWithBundleIdentifier:#"com.apple.Finder";
but I can't find anything in "Finder.h" that could work.
This might be what you are after using ScriptingBridge and NSURL
FinderApplication *finder = [SBApplication applicationWithBundleIdentifier:#"com.apple.finder"];
SBElementArray *windows = [finder windows ]; // array of finder windows
NSArray *targetArray = [windows arrayByApplyingSelector:#selector(target)];// array of targets of the windows
//gets the first object from the targetArray,gets its URL, and converts it to a posix path
NSString * newURLString = [[NSURL URLWithString: (id) [[targetArray objectAtIndex:0]URL]] path];
NSLog(#"newURLString %# ", newURLString);
Running drawnonward's code through appscript's ASTranslate tool gives me this:
#import "FNGlue/FNGlue.h"
FNApplication *finder = [FNApplication applicationWithName: #"Finder"];
FNReference *ref = [[[finder windows] at: 1] target];
FNGetCommand *cmd = [[ref get] requestedType: [ASConstant alias]];
id result = [cmd send];
The result will be an ASAlias instance; use -[ASAlias path] to get the POSIX path.
You can't do it in SB short of resorting to raw Apple event codes as that's one of the features the Apple engineers forgot/didn't bother to put into SB's less than stellar API.
I have not used ScriptingBridge. As part of an NSAppleScript it would be:
get POSIX path of (target of window 1 as alias)
Hopefully that helps. I think the POSIX part is from the StandardAdditions ScriptingAddition, not the Finder itself.