Skip to content

Instantly share code, notes, and snippets.

@ykst
Created January 28, 2015 14:12
Show Gist options
  • Save ykst/4a37222a44ec57a58059 to your computer and use it in GitHub Desktop.
Save ykst/4a37222a44ec57a58059 to your computer and use it in GitHub Desktop.
Bundle IDからアプリのアイコンを取得する

Bundle IDからアプリのアイコンを取得する

例えばインストールされているアプリをリストアップする機能を作りたいとします。

インストールされているアプリのアイコンそのものを取得するにはmobile.installation.plistからディレクトリを掘って直接ファイルを拾ってくれば良いのですが、サンドボックス環境を破る必要があるので若干面倒です。

もし仮に知りたいアプリのBundle IDが判明していれば、そこでiTunes Search APIを使うとBundle IDから一意にアプリを検索出来るので、これを使ってAppStoreに公開されているアイコンを取得する事が出来ます。

サンプルコード

@interface BundleHelper : NSObject
+ (void)retrieveIconURLForBundleID:(NSString *)bundle_id withHandler:(void (^)(NSURL *url))handler;
@end

@implementation BundleHelper
+ (void)retrieveIconURLForBundleID:(NSString *)bundle_id withHandler:(void (^)(NSURL *))handler
{
    // カレントロケールからストアの国を推定
    static NSString *country = nil;
    if (!country) {
        NSLocale *currentLocale = [NSLocale currentLocale];
        country = [currentLocale objectForKey:NSLocaleCountryCode];
    }
    // Search APIを叩く => http://itunes.apple.com/<country code>/lookup?bundleID=<bundle id>
    NSMutableString *requestUrlString = [[NSMutableString alloc] init];
    [requestUrlString appendFormat:@"http://itunes.apple.com/%@/lookup", country];
    [requestUrlString appendFormat:@"?bundleId=%@", bundle_id];
    
    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
    [request setURL:[NSURL URLWithString:requestUrlString]];
    [request setTimeoutInterval:20.0f];
    [request setCachePolicy:NSURLRequestReturnCacheDataElseLoad];

    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    // 非同期リクエスト (キューはいいかげん)
    [NSURLConnection sendAsynchronousRequest:request queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
        if (!connectionError) {
            // APIレスポンスのJSONデコード
            NSError *jsonError = nil;
            NSDictionary *jsonDictionary = [NSJSONSerialization JSONObjectWithData:data
                                                                           options:NSJSONReadingMutableLeaves
                                                                             error:&jsonError];
            if (!jsonError) {
                NSArray *results = [jsonDictionary objectForKey:@"results"];
                if (results.count > 0) {
                    // 検索結果の一つ目を取得
                    NSDictionary *dic = results[0];
                    // 60x60のアイコンのURL
                    handler([NSURL URLWithString:[dic objectForKey:@"artworkUrl60"]]);
                    });
                } else {
                    handler(nil);
                }
            } else {
                handler(nil);
            }
        } else {
            handler(nil);
        }
    }];
}
@end

ここで取った適当なURLをSDWebImageなど使って読み込めば楽ですね。その他のAppStore掲載情報もここで取得出来ているので、それを利用する事も考えられます。

##AppStore-safeな方法 アイコンを調べるという目的に対して、このやり方自体はAppStore-safeですが、そもそもBundle IDを取得するためには(実行中またはインストール済みどちらの場合も)Private Frameworkを使うかJailbreakするかしないとダメっぽいです。 既知のBundle IDならうまくいくとはいっても、そもそもこういうことをしたい時に興味があるのは未知のアプリのアイコンなので、このままではイマイチです。

実行中のプロセス名は正当に取得出来るので、Search APIを使ってhttp://itunes.apple.com/search?country=JP&term=<Process Name>&entity=softwareみたいに検索してヒューリスティックに探すという手も考えましたが、似たようなアプリがヒットしたりそもそもプロセス名から辿れなかったりして当然確実性のある方法ではありません。

もう一つはiHasAppのようなやり方でカスタムURLスキームを叩きまくり持ってるアプリを調べた上で検索するという方法があります。これもAppStore-safeですが、データベースをアップデートしないと最新のアプリには対応出来ないのと、そもそもカスタムURLスキームに対応してないアプリには何も出来ないという弱点があります。

既存のシステム監視系アプリを見ても全てのアイコンのリストアップをしているものは見当たらなかったので、安全かつ確実な方法というのは今のところ難しそうです。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment