Advertise here




Advertise here

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Sign In with Google Sign In with OpenID

Finding out what Apps are installed

fiftysixtyfiftysixty Posts: 310Registered Users
edited January 2010 in iPhone SDK Development
Hi,

I did a quick search on this but it pretty much came up empty. Is there a way to know which Apps are installed on a given device? I suspect this is impossible using the iPhone SDK, but how about in a Mac or Windows machine? It seems that the iTunes Music Library.xml file does not contain information about the Apps, or at least I couldn't find my installed Apps in the file. Obviously there is the Mobile Applications -folder, but it contains all the apps I've purchased, with seemingly no information about which are actually installed on my iPhone. Looks like AppsFire is able to pull out that information from somewhere, anybody know how they do it?
Post edited by fiftysixty on
<a href="http://www.fiftysixtysoftware.com" target="_blank">Fifty Sixty Software</a><br />
<a href="http://www.fiftysixtysoftware.com/blog" target="_blank">iPhone development tips and tutorials</a><br />
<br />
<b>Apps in store:</b><br />
<a href="htt

Replies

  • kdp8791kdp8791 Posts: 57Registered Users
    edited January 2010
    fiftysixty wrote: »
    Hi,

    I did a quick search on this but it pretty much came up empty. Is there a way to know which Apps are installed on a given device? I suspect this is impossible using the iPhone SDK, but how about in a Mac or Windows machine? It seems that the iTunes Music Library.xml file does not contain information about the Apps, or at least I couldn't find my installed Apps in the file. Obviously there is the Mobile Applications -folder, but it contains all the apps I've purchased, with seemingly no information about which are actually installed on my iPhone. Looks like AppsFire is able to pull out that information from somewhere, anybody know how they do it?

    I highly doubt you will be able to do something like this and if you were to find a way to do so, the application you create to do that will more than likely be rejected by Apple.
    <a href="http://www.buzzgadgets.com" target="_blank">logo.png</a>
  • fiftysixtyfiftysixty Posts: 310Registered Users
    edited January 2010
    kdp8791 wrote: »
    I highly doubt you will be able to do something like this and if you were to find a way to do so, the application you create to do that will more than likely be rejected by Apple.

    I'm not looking for ways to do it by violating the SDK agreement, but I suspect it might be possible on the desktop side of things, at least AppsFire seems to do it. I just don't know how they do it. Obviously you can scan the Mobile Applications directory to get a rough list of all Apps one has downloaded but then you need a way to parse the filenames to correct App names, and you still don't know which Apps are actually installed. Knowing which Apps are installed would be cruicial in utilizing custom URL schemes for App interoperation. Right now, without a way to know if an App is present it is quite pointless to have Apps communicating together.
    <a href="http://www.fiftysixtysoftware.com" target="_blank">Fifty Sixty Software</a><br />
    <a href="http://www.fiftysixtysoftware.com/blog" target="_blank">iPhone development tips and tutorials</a><br />
    <br />
    <b>Apps in store:</b><br />
    <a href="htt
  • thewittthewitt Posts: 180iPhone Dev SDK Supporter, Registered Users
    edited January 2010
    Though it won't help you to "browse" the App directory and see what's installed on the iPhone, canOpenURL will let you test to see whether or not you can use a specific App URL scheme before actually trying it out in your code.

    -t
  • ShmoopiShmoopi Posts: 213Tutorial Authors, Registered Users
    edited January 2010
    kdp8791 wrote: »
    I highly doubt you will be able to do something like this and if you were to find a way to do so, the application you create to do that will more than likely be rejected by Apple.

    That's wrong, their is a way to check if an application is installed or not, however, it does violate the Sandbox rules and Apple *may reject your app for using this. But it has been done before by other Apps that are available in the App Store, so feel free to try it :)

    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 by App Store apps. Here is my code which at least works perfectly fine with the Simulator 2.2.1:
    // 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);
    
    Log Output:
    2009-01-30 12:19:20.250 SomeApp[266:20b] App installed: com.apple.mobilesafari
    2009-01-30 12:19:20.254 SomeApp[266:20b] App installed: com.yourcompany.yourselfmadeapp
    2009-01-30 12:19:20.260 SomeApp[266:20b] App not installed: com.blahblah.nonexistent
    
    Try this out before using it, I think Apple changed where the MobileInstallation.plist is located and if you do change it, try it out on an actual device not the simulator. Good Luck!

    Trackback for this code goes to:
    iDevKitCode Sample: Check if an app is installed -
    iPhoneDevSDK: Is it possible to retrieve these information?
    [SIGPIC][/SIGPIC]<br />
    <a href="http://www.shmoopi.net/" target="_blank">Check Out The Official Shmoopi LLC Website</a><br />
    <a href="http://itunes.apple.com/us/app/iprivatebrowser/id314281847?mt=8" target="_blank">iPrivateBrowser</a> | <a href="http:
  • fiftysixtyfiftysixty Posts: 310Registered Users
    edited January 2010
    Thank you very much for the suggestions, I think I have enough to get moving now. I'm a bit reluctant to go ahead with a method that could at some point cause rejection, and since canOpenURL will be sufficient for my needs, I think I'll end up using it. I don't want to be forced to change my App later on if an update gets caught in the review process.
    <a href="http://www.fiftysixtysoftware.com" target="_blank">Fifty Sixty Software</a><br />
    <a href="http://www.fiftysixtysoftware.com/blog" target="_blank">iPhone development tips and tutorials</a><br />
    <br />
    <b>Apps in store:</b><br />
    <a href="htt
  • metronomadicmetronomadic Posts: 1New Users
    edited January 2010
    Shmoopi wrote: »
    That's wrong, their is a way to check if an application is installed or not, however, it does violate the Sandbox rules and Apple *may reject your app for using this. But it has been done before by other Apps that are available in the App Store, so feel free to try it :)

    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 by App Store apps. Here is my code which at least works perfectly fine with the Simulator 2.2.1:
    // 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);
    
    Log Output:
    2009-01-30 12:19:20.250 SomeApp[266:20b] App installed: com.apple.mobilesafari
    2009-01-30 12:19:20.254 SomeApp[266:20b] App installed: com.yourcompany.yourselfmadeapp
    2009-01-30 12:19:20.260 SomeApp[266:20b] App not installed: com.blahblah.nonexistent
    
    Try this out before using it, I think Apple changed where the MobileInstallation.plist is located and if you do change it, try it out on an actual device not the simulator. Good Luck!

    Trackback for this code goes to:
    iDevKitCode Sample: Check if an app is installed -
    iPhoneDevSDK: Is it possible to retrieve these information?

    I don't mean to be a pain, but I'm a newbie trying to work my way through an introductory iPhone programming book, and I'd really like to be able to enumerate apps if possible. Can you tell me how I'd achieve that using this com.apple.mobile.installation.plist technique, or at least point me in the right direction? I was considering a desktop app that could look at all of the apps that are being synced, but it looks to me like the best I could manage with that would be all of the downloaded apps (i.e., I can't find any info on which ones are synced).

    Thanks in advance for any help you can provide.!

    Cheers,
    -m
Sign In or Register to comment.