Mac App Storeで配信するアプリがアクセス可能なディレクトリ

App StoreにサブミットしたMacアプリがリジェクトされてしまいました。リジェクト理由をみてみると、~/Library/Application Support/AppNameにアクセスしようとしているのが原因の様子。
参考資料として案内されていたFile System Usage Requirements for the App Storeによれば、アプリケーションがアクセスを許可されているディレクトリは下記の場所に限られています。

  1. Temporaryディレクトリ
  2. Libraryディレクトリの下記の場所
    1. ~/Library/Application Support/<app-identifier>
    2. ~/Library/<app-identifier>
    3. ~/Library/Caches/<app-identifier>
  3. ~/Musicや~/Picturesなど (音楽や画像などを扱うアプリケーションの場合)
  4. OpenPanel, SavePanelなどでユーザが指定したファイル

アプリケーション固有の設定で、NSUserDefaultsに入らないバイナリデータなど(ゲームデータや編集中のファイルの情報など)はこのうち2.のLibraryディレクトリにおく形になります。2のLibraryディレクトリの<app-identifer>については下記のような記述があり、アプリのBundle Identifierかアプリ名、会社名のいずれかに厳格にマッチしなければいけないようです。

<app-identifier> is your application’s bundle identifier, its name, or your company’s name. This must exactly match what is in iTunes Connect for the application.

今回のアプリケーションの場合、今まで配信していた有料アプリケーションの無料版を新たに追加リリースした形だったのですが、ここでapp-identifierが有料版と無料版で変更しなかったためにリジェクトされてしまった模様。というわけで、ここでは固定文字列でデータ保存先を決めるよりBundle Identifierを使う形でコーディングしておいたほうが良いですね。
ちょうどアップルのFile System Programming Guideにもこんなサンプルコードが乗っているので、これを使うのがよさそうですね。

- (NSURL*)applicationDataDirectory {
    NSFileManager* sharedFM = [NSFileManager defaultManager];
    NSArray* possibleURLs = [sharedFM URLsForDirectory:NSApplicationSupportDirectory
                                 inDomains:NSUserDomainMask];
    NSURL* appSupportDir = nil;
    NSURL* appDirectory = nil;
    if ([possibleURLs count] >= 1) {
        // Use the first directory (if multiple are returned)
        appSupportDir = [possibleURLs objectAtIndex:0];
    }
    // If a valid app support directory exists, add the
    // app's bundle ID to it to specify the final directory.
    if (appSupportDir) {
        NSString* appBundleID = [[NSBundle mainBundle] bundleIdentifier];
        appDirectory = [appSupportDir URLByAppendingPathComponent:appBundleID];
    }
    return appDirectory;
}

参考

  1. File System Usage Requirements for the App Store
  2. File System Programming Guide

SKPaymentQueueのaddPaymentとTransaction

StoreKit APIを使う上で不便な点の一つに、生成したTransactionを追跡するのが難しい、という問題があります。PaymentをQueueに積むとTransactionが生成されますが、その生成されたTransactionの情報を取得する方法について調べていきましょう。
“SKPaymentQueueのaddPaymentとTransaction” の続きを読む

MacでopenFrameworksを使う(サンプルの構造を見てみる)

まず、サンプルとして配布されているwindowExampleの中身を読んでいきましょう。windowExampleはapps/examples/windowExampleにあります。windowExample.xcodeprojを開いて中を見てみましょう。 “MacでopenFrameworksを使う(サンプルの構造を見てみる)” の続きを読む

openFrameworksの基本

どうもOS XあるいはiOS用のプログラムをC++で書く、というのは邪道な感じがするので個人的にはopenFrameworksはそんなに好きではないのですが、作る内容によっては手間を最小化できるのは事実なので、前回のMakeから一年たった現在最新のopenFrameworksをもう一回勉強しておこうと思います。 “openFrameworksの基本” の続きを読む

StoreKit(組み込みプロダクトモデル編) まとめ

というわけで、StoreKitの挙動について細かく検証してきましたが、少なくとも組み込みプロダクトモデル編については、ここから先はかなり細かい話になってきてしまうので一旦ここでまとめておきます。
なお、この情報は2011年11月現在のiOS 5.0におけるもので、将来的に仕様が変わっている可能性があります。また、公式ドキュメント等には記載されていない独自の検証に基づく見解が含まれます。参考程度に読んでください。そして気づいた点を躊躇せず指摘してください。 “StoreKit(組み込みプロダクトモデル編) まとめ” の続きを読む

StoreKit トランザクションの重複を防ぐ

トランザクションが複数できると面倒なことになると前回のポストで書きました。特に購入手続きの途中でアプリケーションが終了してしまったような場合は、アプリケーション側で少し面倒ですが対策をいれないと問題を回避できません。 “StoreKit トランザクションの重複を防ぐ” の続きを読む

StoreKit Consumableプロダクトの二重購入

トランザクションの中断と再開について、さらにケースを見ていきます。未完状態のトランザクションが既にある状態で、新しいペイメントをリクエストした場合の挙動について。厄介です。 “StoreKit Consumableプロダクトの二重購入” の続きを読む