Apple の新しい iOS 5.0.1 ガイドラインでは、データ保管に関するガイドラインが変更されました。新しいガイドラインについてはこちらに説明があります。 (閲覧には開発者登録が必要です)
それに伴い、AIR の一部の機能の利用が制限されます。アドビのフォーラムに投稿されたポストによれば、この制限によりアプリが却下されると、以下のようなメッセージが届くそうです。
Rejection: 2.23 Apps must follow the iOS Data Storage Guidelines or they will be rejected
具体的には、以下の条件を満たす必要があるとのことです。 (正確な情報は、上のアップルサイトへのリンク先を参照してください)
- ユーザが生成した情報、またはアプリだけでは生成できない情報のみ /Documents ディレクトリ以下に保存し、自動的に iCloud にバックアップされる
- 再ダウンロード、あるいは再生可能なデータは /Library/Caches ディレクトリ以下に保管する
- 一時的な利用のためのデータは /tmp ディレクトリ以下に保存する。これらのファイルは iCloud にはバックアップされないが、余分な記憶領域を使用しないよう、不要になったら削除する
例えば、ユーザが新しいコンテンツをアプリを通じて作成した場合は、そのコンテンツを /Document に保存できるが、ユーザ設定情報やデータベースなどは /Library/Caches に保存しなければならない、という話のようです。
おそらく、/Documents 以下は iCloud が自動的にバックアップするため、不要なバックアップが発生しないようにという配慮から変更されたものと思われます。
iOS 向け AIR アプリへの影響
この変更により影響を受ける AIR の API は、File.applicationStorageDirectory() と、ローカルの SharedObject です。
applicationStorageDirectory() を使用している場合の変更は、単純作業でできそうです。
新しいガイドラインで、代わりに使うよう指示されている 2 つのディレクトリの File オブジェクトを作成して、あとは、保存するファイルの種類に応じて使い分ける、という変更になると思われます。
例えば、以下のような変数を宣言しておいて、
public var cacheDir:File; public var tempDir:File; var str:String = File.applicationDirectory.nativePath; cacheDir = new File(str + "/\.\./Library/Caches"); tempDir = new File(str + "/\.\./tmp");
以下のように利用する、という感じです。
var fs:FileStream = new FileStream(); fs.open(cacheDir.resolvePath("myCache.txt"), FileMode.WRITE); fs.writeUTFBytes("Hello World"); fs.close();
一方、SharedObject の場合は、保存先をアプリから指定する手段が無いため、単純に回避することができません。
AIR 3.2 辺りで対応してくれることを期待して待つか、ローカル保存用には SharedObject を使用しないか、MySharedObject のような実装を利用するか、という選択になりそうです。
追記 (2012 年 12 月)
AIR 3.3 から、新しいガイドラインに対応して、ファイル関連の仕様が変更されています。現在は以下の 4 つのオプションが利用できます。
- オフラインでも確実に利用できるべき重要なデータ: (データサイズ注意)
File.userDirectory.nativePath + ’/Library/PrivateDocuments’; // または File.applicationStorageDirectory.nativePath;
- デバイス外へのバックアップが必要な程度に重要データ: (iTunes からのアクセスや iClould へのバックアップの対象となる)
File.userDirectory.nativePath + ’/Documents’; // または File.documentsDirectory.nativePath;
- バックアップ不要な一時データ (iTunes からのアクセスや: iClould へのバックアップの対象外)
File.userDirectory.nativePath + ’/tmp’; // または File.createTempDirectory().nativePath + ’/tmp’;
- 一時的に書き出すだけのデータ: (ストレージ容量が少なくなると削除される場合があり、iTunes からのアクセスや iClould へのバックアップの対象外)
File.userDirectory.nativePath + ’/Library/Caches’; // または File.applicationStorageDirectory.nativePath + ’/Caches’;
SharedObject も AIR 3.3 以降は問題なく利用できるはずです。
追記 (2013 年 3 月)
AIR 3.6 から、キャッシュ用のフォルダ名が File クラスの属性に追加されました。そのため、上の例の 4 番目は、以下のように書き直すことができます。
File.cacheDirectory.nativePath;
また AIR 3.6 では、iOS 5.1 以降で有効な機能として、本来バックアップ対象となる場所にあるファイルに、バックアップの対象外とする属性を指定できるようになりました。
以下のように、File オブジェクトの preventBackup 属性の値を true にするとバックアップの対象では無くなります。フォルダに対してこの設定をした場合は、そのフォルダ以下の全てのファイルがバックアップ対象では無くなります。
var foo:File; foo = File.applicationStorageDirectory.resolvePath("foo.txt"); foo.preventBackup = true;
以上 2 つの新しい属性を利用するには、名前空間を 3.6 にして、コンパイル時に -swf-version=19 を指定します。
初めまして。
今FLASHでiPhoneゲームを作っていて、SharedObject が使えなくなったという情報を知って色々調べていてここにたどり着きました。
しかし、actionscriptを始めたばかりで、かろうじてSharedObject は使えていたんですが、ここで解説しているapplicationStorageDirectory()の仕組みがよくわかりません。
SharedObjectのように、変数を読み込んだり書き込んだりすることはできるんでしょうか?
例えばハイスコアを保存して、次回起動時に表示させる・・・といった感じです。
もしできたら簡単な例を教えて頂けたらと思っています。
shin さん、こんにちは。
記事内で紹介している MySharedObject のコードが、参考になると思います。
もしくは MySharedObject をそのまま (保存場所だけ変えて) 使ってもよいかもしれません。
MySharedObjectのコードを見てみたんですがやはりまだ自分には何をしているかが理解できませんでした。
実際にファイルを使ってプレビューしてみましたが起動できずに終わってしまいました。
手持ちの資料がFlashの物しかないのでAirの物をちょっと探してみようと思います。
それでは、お忙しい中返答ありがとうございました。
度々すいません、今気づきました。
これはカスタムクラスでスクリプトから呼び出すんですね。
まだまだ理解できてませんが、探り探りやってみます。
三度すいません、shinです。
あれから色々ヘルプを見たり本を読んだりして、ようやく何をしているのか理解できてきました。
実際にカスタムクラスとして登録してファイルの書き込みと読み込みに成功しました。
が、ディレクトリの指定で悩んでいます。
PC上ではapplicationDirectory(うちの環境の場合C:\Users\my pc\AppData\Roaming\test\Local Storeになりました)を指定してそれ以下に/Library/Cachesができてそこにデータが保存されていましたが、iPhone上でもこれで合っているんでしょうか?
shin さん、こんにちは。
とりあえず動いたようでよかったです。
わかりにくい説明で申し訳ありませんでした。
/Library/Caches の場所ですが、今持っている情報では、applicationDirectory.nativePath の直下ではなく、1 つ上の階層ということです。
お世話になります。
あれから色々試したんですが、MySharedObjectでapplicationDirectory.nativePathの上の階層にアクセスしてファイルを書き込むというのがどうしてもうまくいきません。
this.f = File.userDirectory.resolvePath("Library/Application Support/" + NativeApplication.nativeApplication.applicationID + "/" + key);
この部分を
this.f = File.applicationDirectory.resolvePath("/\.\./Library/Caches+"/" + key);
ではダメなんでしょうか?
ちなみに、
this.f = File.applicationDirectory.resolvePath("Library/Caches+"/" + key)
だと直下にですが保存はできました。
Shin さん、こんにちは。
nativePath 属性の後に追加する形は試したでしょうか?
記事内のコードを参考にしてみてください。
お世話になります。
返信ありがとうございます。
実はresolvePathをnativePathに変えてやったりもしたんですが、
F:\iphone\test\MySharedObject.as、行 13 1195: アクセスできないメソッド nativePath へのアクセスを、静的型 flash.filesystem:File の参照を使用して試行しました。
とエラーが出てしまい実行できませんでした。
そこで、記事のように一度変数に代入して後から組み合わせてみたら動きました!
なんでかわかりませんがとにかく保存と読み込みに成功しました。
ゲームも完成間近なのにここで詰まってしまっていたので本当に助かりました。
何度もアドバイスを頂いて本当にありがとうございました。
この間はありがとうございました。
無事問題が解決して開発を進めることができました。
しかし、今やってる物とは関係が無いんですが、ひとつ疑問があります。
MySharedObjectを、タイムライン上にスクリプトを書いて使うと普通に使えるんですが、プロジェクトのクラスのasファイルから使うと、FLASH CS5.5のプレビューでは普通に使えるんですが、書きだしたswfファイルをFlashPlayerで再生すると全体のスクリプトが停止して動きませんでした。
これはAir for iOSで書きだしてるから普通のFlashPlayerで再生できないと理解してよろしいのでしょうか?
ちなみに、FlashPlayer用にパブリッシュするとエラーが出てパブリッシュできませんでした。
ただ、タイムライン上にMySharedObjectを書くとOKなのになぜクラスに書くとダメなのかが理解できません。
もしできたら理由を教えて頂けませんでしょうか?
Shin さん、こんにちは。
返事が遅くなりました。
API によって、利用できる環境が異なります。最初は面倒かもしれませんが、ドキュメントを確認しながら使うことをお勧めします。
ちなみに File は AIR のみで利用できるクラスです。
http://help.adobe.com/ja_JP/FlashPlatform/reference/actionscript/3/index.html#!flash/filesystem/File.html
ですので、タイムラインに書いても、AIR の実行環境でなければ動作しないはずです。
(AIR がターゲットの FLA ファイルのプレビューは AIR 環境で行われます)
この記事で大変助かりました。
どうもありがとうございます。
キャッシュディレクトリですが下記でも良かったです。
実際に保存、読込みできました。
public var cacheDir:File;
var str:String = File.userDirectory.nativePath;
cacheDir = new File(str + "/Library/Caches");
ではでは
tsuka! さん、こんにちは。
ご指摘ありがとうございました。しばらく前に仕様が変更されていたのですが、
記事の修正をサボってました。
情報追加しましたので、よろしければご覧ください。