The first one is not possible; all applications are installed in their own sandbox, meaning that they cannot do anything outside their own application. This is true for all scenarios, but certain things are allowed by Apple, such as retrieving the users image folder etc. But I'm not sure if it works when it comes to music. I do not think Apple are keen to have compeditors when it comes to their iPod.
However, I'm not 100% sure about the first one, although it would surprise me a great deal if it was possible.
The first one is not possible; all applications are installed in their own sandbox, meaning that they cannot do anything outside their own application. This is true for all scenarios, but certain things are allowed by Apple, such as retrieving the users image folder etc. But I'm not sure if it works when it comes to music. I do not think Apple are keen to have compeditors when it comes to their iPod.
However, I'm not 100% sure about the first one, although it would surprise me a great deal if it was possible.
That's wrong, their is a way to check if an application is installed or not. Sometimes you may want to check if a specific app is installed on the device, in case you use custom URL schemes that require some other app to be installed (you could just gray out/disable some buttons then). Unfortunately, Apple apparently does not have any function that checks this for you, so I whipped one up. It does not enumerate every single app, instead it uses the MobileInstallation cache which is always up-to-date with SpringBoard and holds the Info dictionaries of all apps installed. Although you're not "supposed" to access the cache, it's readable my App Store apps. Here is my code which at least works perfectly fine with the Simulator:
Code:
// Declaration
BOOL APCheckIfAppInstalled(NSString *bundleIdentifier); // Bundle identifier (eg. com.apple.mobilesafari) used to track apps
// Implementation
BOOL APCheckIfAppInstalled(NSString *bundleIdentifier)
{
static NSString *const cacheFileName = @"com.apple.mobile.installation.plist";
NSString *relativeCachePath = [[@"Library" stringByAppendingPathComponent: @"Caches"] stringByAppendingPathComponent: cacheFileName];
NSDictionary *cacheDict = nil;
NSString *path = nil;
// Loop through all possible paths the cache could be in
for (short i = 0; 1; i++)
{
switch (i) {
case 0: // Jailbroken apps will find the cache here; their home directory is /var/mobile
path = [NSHomeDirectory() stringByAppendingPathComponent: relativeCachePath];
break;
case 1: // App Store apps and Simulator will find the cache here; home (/var/mobile/) is 2 directories above sandbox folder
path = [[NSHomeDirectory() stringByAppendingPathComponent: @"../.."] stringByAppendingPathComponent: relativeCachePath];
break;
case 2: // If the app is anywhere else, default to hardcoded /var/mobile/
path = [@"/var/mobile" stringByAppendingPathComponent: relativeCachePath];
break;
default: // Cache not found (loop not broken)
return NO;
break; }
BOOL isDir = NO;
if ([[NSFileManager defaultManager] fileExistsAtPath: path isDirectory: &isDir] && !isDir) // Ensure that file exists
cacheDict = [NSDictionary dictionaryWithContentsOfFile: path];
if (cacheDict) // If cache is loaded, then break the loop. If the loop is not "broken," it will return NO later (default: case)
break;
}
NSDictionary *system = [cacheDict objectForKey: @"System"]; // First check all system (jailbroken) apps
if ([system objectForKey: bundleIdentifier]) return YES;
NSDictionary *user = [cacheDict objectForKey: @"User"]; // Then all the user (App Store /var/mobile/Applications) apps
if ([user objectForKey: bundleIdentifier]) return YES;
// If nothing returned YES already, we'll return NO now
return NO;
}
Here is an example of this, assuming that your app is named "yourselfmadeapp" and is an app in the app store.
Code:
NSArray *bundles2Check = [NSArray arrayWithObjects: @"com.apple.mobilesafari", @"com.yourcompany.yourselfmadeapp", @"com.blahblah.nonexistent", nil];
for (NSString *identifier in bundles2Check)
if (APCheckIfAppInstalled(identifier))
NSLog(@"App installed: %@", identifier);
else
NSLog(@"App not installed: %@", identifier);
I'd be surprised if this works on non-jailbroken phones. I think SandboxTemplate.sb prevents you from reading "/private/var/mobile/Applications/" except for your own folder.
I'd be surprised if this works on non-jailbroken phones. I think SandboxTemplate.sb prevents you from reading "/private/var/mobile/Applications/" except for your own folder.
I'd test this on a device before relying on it.
Thanks for the concern, but yes it does, their are several apps that already utilize this. One of the most popular being Skype. It uses this to detect if it is running on a jailbroken device. The sandboxtemplate does not prevent it from reading a local file outside of the sandbox, only writing to it, unless it's on a jailbroken phone.
Thanks for the concern, but yes it does, their are several apps that already utilize this. One of the most popular being Skype. It uses this to detect if it is running on a jailbroken device. The sandboxtemplate does not prevent it from reading a local file outside of the sandbox, only writing to it, unless it's on a jailbroken phone.
Thanks Shmoopi, this is a surprise as I thought that the iPhone SDK would disallow access. But your code works only if I know the bundle identifier. But if I do not know it, there is no way I can find out the bundle identifier of any app that is already installed in the device?
and it mentions For example, you could create a trivia game that uses the metadata of the user’s songs. Improve on an arcade game by using a playlist as its soundtrack, or add the ability to listen to podcast lectures in a note taking app. You can make almost any app more enjoyable by bringing a user’s personal music and audio choices into your app.
__________________
Try out my latest game Piecehunters Lite for free
Else get the paid version for $1.99 cents and you can bring your progress from the lite version over to the premium version
@gibtang; Sure you can. If you check the code you can see that you load a dictionary from the plist named "com.apple.mobile.installation.plist". This code is intended to check if any given application you require is installed and therefore included in that dictionary, but you could just as easily extract the entire plist from what I can see and, say, display it in a UITableView. Why not print it out with NSLog() so that you can see the contents of it?
@gibtang; Sure you can. If you check the code you can see that you load a dictionary from the plist named "com.apple.mobile.installation.plist". This code is intended to check if any given application you require is installed and therefore included in that dictionary, but you could just as easily extract the entire plist from what I can see and, say, display it in a UITableView. Why not print it out with NSLog() so that you can see the contents of it?
@gibtang; Sure you can. If you check the code you can see that you load a dictionary from the plist named "com.apple.mobile.installation.plist". This code is intended to check if any given application you require is installed and therefore included in that dictionary, but you could just as easily extract the entire plist from what I can see and, say, display it in a UITableView. Why not print it out with NSLog() so that you can see the contents of it?
Hmm, ok. How about the app name itself? The one that appears below the icon?
__________________
Try out my latest game Piecehunters Lite for free
Else get the paid version for $1.99 cents and you can bring your progress from the lite version over to the premium version
I didn't try this snippet myself, but I did yesterday when trying to create a simple method to demonstrate what I mentioned earlier about retrieving the entire application list. Yet the code didn't work for me at all using the Simulator 3.0. There was no error, but I didn't get a dictionary at all.
Does this really work for you guys?
But, basically what I meant earlier was that in the code a dictionary is created with the contents of the file that -- according to the developer who wrote it -- contains all the info.plist data of each and every one of the applications installed. So instead of looping through an array of application bundle indicators as you do in the example, you could just manipulate the dictionary directly and show it in a UITableView.
But I can't give you any code example since I couldn't make it work myself. Even without changing the code.
Yes, the code only seems to work on pre-3.0 (it does at least on 2.2.1). It seems Apple does enforce the sandbox rules a bit stricter than previously. Although you can still access /var/mobile/Applications and get a listing of all the application directories - but those are in "08A9EF7A-8E49-4098-90F9-675CFC59208F" form. So unless somebodies knows how to get an appID out of this it's pretty useless.