LoginSignup
16

More than 5 years have passed since last update.

Xamarin.iOS/Androidアプリで、バンドルリソース処理を完全共通化できそうな仕様

Last updated at Posted at 2014-05-17

もしかしたら私が知らなかっただけで常識だったのかもしれません。
だったらみんなもっと早く教えてくれればよかったのに!的なww

Xamarin.iOS/Androidアプリで画像やjson設定ファイル、内部html等のリソースを、iOSのBundleResourceやAndroidのAndroidAssetの形で持ってませんか。
私はそうしていたので、リソースアクセスのロジックを書く時もいつも場合分けしてました。
(もちろん普通は隠蔽化しますが)こんな感じで

リソースアクセスの場合分け
#if __IOS__
    var bundlePath = NSBundle.MainBundle.BundlePath;
    var filePath   = Path.Combine(bundlePath, "Assets/hoge.png");
    InputStream attachmentStream = File.OpenRead(filePath);
#else
    InputStream attachmentStream = Application.Context.Assets.Open ("hoge.png");
#endif

これ、ビルドアクションとしてBundleResourceやAndroidAssetではなく、EmbeddedResourceというのを使ってやると、共通化できるようです。
EmbeddedResourceを使うと、そのリソースが含まれたアセンブリのアセンブリ名(デフォルト名前空間かもしれない。前記事で問題になった、Xamarin.iOSでのアセンブリ名でドットが外れる問題が、こちらでは存在しないので)をベースにして、プロジェクト内でのフォルダ構成を加えたものをアクセス子としてアクセスできるようです。
例えば、デフォルト名前空間がHoge.Fuga.Fooのアセンブリ内で、プロジェクト内での配置がBar/Baz.pngだった場合、アクセス子は「Hoge.Fuga.Foo.Bar.Baz.png」になります。

このアクセス子を利用して、

GetManifestResourceStream
    using System.Reflection;

      ...

    //thisはとりあえずクラスだと何でもいい模様?
    //その後の文法からして、アクセスするリソースのアセンブリに属するクラスでないといけないかもしれません。
    //その辺は要追調査…
    Type type = this.GetType(); 
    Stream manifestResourceStream = type.Assembly.GetManifestResourceStream ("Hoge.Fuga.Foo.Bar.Baz.png");
    InputStream resourceInputStream = InputStream.Wrap (manifestResourceStream);

のような形でアクセスしてやると、リソースからのStreamが取れます!

AOTかJITかの違いで、実機とシミュレータの動作が異なる事で不安のあるXamarinですが、Android/iOS実機でも(Debugモードでの流し込みのみですが)確認したので、多分共通に使えるはずです。
公式の情報としては、この辺にサンプルがあるようです(今まで知らなかったので未見…)。

環境変数での処理分けなんか必要なかったんや…。
これで相当レベル、下位レイヤの処理もPCL化できる?
書き込み可能フォルダ(iOSだとDocument/Cacheフォルダ、Androidだとdataフォルダとか)も隠蔽化/共通化できる仕様ってあるんだろか?
Xamarin.Mobileあたりがなんかしてるんだっけ?

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
16