.NET MAUI(.NET 8)でAndroidのResource.Layout/Resource.Rawが参照できない原因と解決策(using Droid = Androidの罠)

.NET MAUI(.NET 8)でAndroid固有画面を作るとき、Platforms/Android/Resources に置いた layout や raw が Resource.Layout / Resource.Raw から参照できず詰まることがあります。原因は意外にも「using Droid = Android;」の持ち込み。ARCore+OpenGL でハマった実例で解決までを整理します。

目次

起きていること:Resource.Layout / Resource.Raw が見つからない

今回の症状は、Android 用のリソースを正しい場所に置いているはずなのに、C# から参照しようとした瞬間にコンパイルエラーになるパターンです。

  • Platforms/Android/Resources/layout に ar_layout.xml(ビルドアクション: AndroidResource)を置いた
  • Android 側コードで Resource.Layout.ar_layout を書くと「Resource.Layout に ar_layout の定義がない」
  • Platforms/Android/Resources/raw に object_vertex.shader を置いた
  • Resource.Raw.object_vertex でも同様に定義が見つからない

クリーン/リビルド、VS 再起動、ビルドアクションの確認までやっても直らないと、「MAUI が Android リソースを拾えていないのでは?」と疑いがちです。ですが、このケースではリソースの配置ではなく、名前空間の解決(using)で詰まっているのがポイントです。

結論:using Droid = Android; を消して、Resource をそのまま使う

最短で直す手順は次の2つです。

  1. using Droid = Android; のエイリアス指定を削除する
  2. Android 固有コードでは Resource.Layout / Resource.Raw をそのまま参照する

たったこれだけで、Resource.Layout.ar_layout や Resource.Raw.object_vertex が解決され、ビルドが通るようになります。

修正前(問題を起こしやすい書き方)

// 削除対象:MAUI では混乱の元になりやすい
using Droid = Android;

public class MainActivity : MauiAppCompatActivity
{
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);


    // ここで ar_layout が見つからない等のエラーになりやすい
    SetContentView(Droid.Resource.Layout.ar_layout);
}


}

修正後(MAUI で素直に動く書き方)

// エイリアスは使わない(削除する)

public class MainActivity : MauiAppCompatActivity
{
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);


    // アプリ側の Android リソースを参照
    SetContentView(Resource.Layout.ar_layout);

    // raw リソースも同様
    int vertexShaderResId = Resource.Raw.object_vertex;
}


}

この状態でリビルドすると、Visual Studio の補完にも ar_layout / object_vertex が出てくるはずです。

なぜ “以前のやり方” が MAUI で通用しなくなったのか

ここが一番モヤっとしやすい部分なので、現場目線で整理します。

Xamarin.Forms 時代:プロジェクト分割が前提

Xamarin.Forms の典型的な構成は、

  • 共通コード(PCL / .NET Standard)
  • Android プロジェクト(Droid)
  • iOS プロジェクト

のようにプラットフォームごとに別プロジェクトでした。そのため「共通コードから Android 側のクラス(Resource など)に触りたい」という動機で、エイリアスや参照の工夫が必要になる場面がありました。

.NET MAUI:単一プロジェクト+マルチターゲット

一方で MAUI は、

  • 1つのプロジェクトに全プラットフォームのコードが入る
  • Android 固有コードは Platforms/Android 配下に置く
  • Android 用の Resource クラスも同じプロジェクト内で生成される

という設計です。つまり、MAUI ではわざわざ “Droid という別プロジェクト” を想定した書き方を持ち込む必要がありません。

using Droid = Android; が招く “Resource の取り違え”

さらにやっかいなのは、Android という名前そのものが .NET(Xamarin.Android / MAUI)で既に特別な意味を持つことです。

名前中身例用途
Resource(アプリ側)あなたのアプリの Resources から生成されたリソース IDResource.Layout.ar_layout
Resource.Raw.object_vertex
自作レイアウト、shader、画像、values など
Android.Resource(OS 側)Android OS が提供する標準リソース IDAndroid.Resource.Layout.SimpleListItem1 などOS 標準のレイアウトやアイコンを使うとき

using Droid = Android; と書いた時点で、Droid は Android(= OS 側の名前空間)を指すエイリアスになります。結果として Droid.Resource はほぼ Android.Resource の意味になり、あなたのアプリで追加した ar_layout や object_vertex は当然そこには存在しません。

エラーが「リソースが生成されていない」ように見えて、実際には参照先を間違えている。このズレが、クリーンや VS 再起動をしても直らない原因です。

MAUI の Android リソースは “どこで生成される” のか

「本当に MAUI が拾っている?」を確認したいときは、生成物を見るのが一番早いです。MAUI の Android ビルドでは、Android の aapt2(リソースコンパイル)相当の処理が走り、最終的に C# から参照できる Resource クラスが生成されます。

手元で確認するときの目安は次の通りです(プロジェクト名や構成で多少変わります)。

  • obj/Debug/net8.0-android/ 配下に生成物が出る
  • その中に Resource.designer.cs(またはそれに相当する生成ファイル)があり、Layout/Raw の定義が並ぶ
  • そのファイル内検索で ar_layout や object_vertex を探す

ここに定義があるのにコードから参照できない場合は、ほぼ確実に名前空間・using・参照先の問題です(今回のケースがまさにそれです)。逆に、生成物にも定義がないなら、配置やビルドアクション、命名規則の問題を疑います。

配置と参照の基本ルール(表で確認)

MAUI の Android 固有リソースは、Android のルールに従って配置し、AndroidResource としてビルドに含めるのが基本です。混乱しやすいポイントを、用途別にまとめます。

種類配置場所ビルドアクションC# からの参照補足
Android レイアウト XMLPlatforms/Android/Resources/layout/AndroidResourceResource.Layout.<ファイル名>例:ar_layout.xml → Resource.Layout.ar_layout
raw(shader / bin / txt など)Platforms/Android/Resources/raw/AndroidResourceResource.Raw.<ベース名>例:object_vertex.shader → Resource.Raw.object_vertex
drawable(PNG 等)Platforms/Android/Resources/drawable/AndroidResourceResource.Drawable.<名前>密度別(drawable-hdpi 等)も同様
values(strings / styles 等)Platforms/Android/Resources/values/AndroidResourceResource.String / Resource.Style などvalues の中身(name 属性)で参照名が決まる

ここで一つ注意点があります。MAUI にはプロジェクト直下に Resources/Raw というフォルダもありますが、こちらは「MAUI のアセット(MauiAsset)」として扱われることが多く、Resource.Raw.◯◯ の “Android リソース ID” としては参照できません。

今回のように SetContentView や OpenRawResource で扱う「Android のリソース ID」が欲しい場合は、必ず Platforms/Android/Resources/raw 側に置くのが安全です。

それでも直らないときの追加チェックリスト

エイリアス削除で直るケースが多い一方、チーム開発や試行錯誤の途中で複数の要因が重なっていることもあります。ここからは実務で遭遇しやすい “第二原因” を潰すためのチェック項目です。

症状よくある原因具体的な対処
Resource.Layout にファイル名が出てこないファイル名が Android の命名規則違反(大文字、ハイフン、日本語など)小文字+数字+アンダースコアのみで命名する(例:ar_layout.xml)
raw に置いたのに Resource.Raw に出てこないBuild Action が AndroidResource になっていない/誤って MauiAsset になっているファイルのプロパティで Build Action を AndroidResource に変更する
Android では通るが、別ターゲットのビルドで落ちる共通コード(全ターゲットでコンパイルされる場所)から Resource を参照しているPlatforms/Android 配下に移す、または #if ANDROID で囲む
SetContentView は通るが FindViewById で NullReferenceレイアウトに対象 View の id がない/レイアウトが別のものになっているar_layout.xml の id を確認し、SetContentView の引数が正しいか確認
ビルドは通るが実機で raw が読めない拡張子の扱い勘違い(参照名は拡張子なし)/エンコード問題Resource.Raw は拡張子を除いたベース名。shader は UTF-8(BOM なし推奨)で保存する

Android リソースの命名規則(ここが一番壊れやすい)

Android のリソース名は、基本的に次の制約があります。

  • 英小文字(a-z)、数字(0-9)、アンダースコア(_)のみ
  • 先頭は英小文字(数字開始は避ける)
  • ハイフン(-)やドット(.)は “ベース名” に入れない(raw は拡張子としてのドットはOK)
  • 日本語やスペースは不可

たとえば raw で object_vertex.shader は “ベース名が object_vertex” なので問題になりにくいですが、ObjectVertex.shader(大文字)や object-vertex.shader(ハイフン)は失敗の原因になります。

Android OS の Resource と混同しないためのコーディング指針

今回のトラブルをきっかけに、Resource の参照はチームでルール化しておくと再発が減ります。

  • アプリ側は Resource(またはアプリの名前空間を含めた完全修飾)で参照する
  • OS 側は global::Android.Resource のように “必ず明示” する
  • Android という名前のエイリアスや、Android と紛らわしいプロジェクト名/名前空間は避ける

どうしても OS 側 Resource をよく使うなら、次のように “意図が伝わる別名” を付ける方が安全です。

// OS 側の Resource を使いたいときだけ、明確な別名にする例
using SysRes = global::Android.Resource;

// 例:標準レイアウトを使う
var id = SysRes.Layout.SimpleListItem1;

この形なら、アプリ側の Resource と混ざりません。「Droid」という曖昧な別名より、意図が読みやすくレビューでも事故が減ります。

ARCore + OpenGL で raw shader を読む実装例

shader を raw に置く目的は、OpenGL の初期化時に GLSL を読み込むことが多いはずです。MAUI の Android 側では、次のようにして raw をストリームとして開けます。

using System.IO;
using Android.OS;

public class MainActivity : MauiAppCompatActivity
{
    protected override void OnCreate(Bundle savedInstanceState)
    {
        base.OnCreate(savedInstanceState);

        // 例:レイアウト適用
        SetContentView(Resource.Layout.ar_layout);

        // 例:raw から shader 文字列を読む(vertex)
        string vertexShaderCode = ReadRawText(Resource.Raw.object_vertex);

        // fragment shader も raw に置いている場合だけ有効化
        // string fragmentShaderCode = ReadRawText(Resource.Raw.object_fragment);

        // ここで OpenGL の Shader コンパイル処理へ渡す
        // CompileShader(GLES20.GlVertexShader, vertexShaderCode);
    }

    private string ReadRawText(int resId)
    {
        using var stream = Resources.OpenRawResource(resId);
        using var reader = new StreamReader(stream);
        return reader.ReadToEnd();
    }
}

「raw の参照ができない」ところで詰まっていると、OpenGL の初期化や ARCore のセッション作成まで辿り着けません。まずは Resource.Raw が解決する状態を作り、その上で shader 読み込みまで動作確認するのが近道です。

shader ファイル運用のコツ

  • 改行コードは LF/CRLF どちらでも動くことが多いが、チームで統一する
  • 文字コードは UTF-8(BOM なし)を推奨。BOM が先頭に入ると GLSL の解釈でハマることがある
  • shader の include 的なことをしたいなら、ファイル分割より “1ファイルに埋め込む” 方がまずは安全(読み込み回数が減る)

Android レイアウトを SetContentView する場合の注意点

MAUI は本来 XAML を中心に UI を組みますが、ARCore や GLSurfaceView の都合で Activity 直下に Android レイアウトを貼ることがあります。その場合、次の点を押さえると “レイアウトは出たが後で詰まる” を避けられます。

  • MAUI の MainActivity は通常 MauiAppCompatActivity 継承。既存の MAUI 初期化を壊さないように、必要な処理は残す
  • レイアウト内に GLSurfaceView を置くなら、id を付けて取り出せるようにしておく
  • ARCore のカメラプレビューと OpenGL の描画順(透過、Z順)で詰まりやすい。まずは真っ黒でも “描画ループが回っている” を確認する

レイアウト自体の例(最小イメージ)は次のようになります(実際の構成は用途に合わせて調整してください)。

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.opengl.GLSurfaceView
        android:id="@+id/gl_surface"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <!-- デバッグ用のオーバーレイ UI などを重ねたい場合はここに配置 -->

</FrameLayout>

ここまで動けば、あとは ARCore のセッション開始やレンダラ実装など “本題の部分” に集中できます。

ビルドアクションを確実にする(csproj で固定する方法)

チーム開発では「誰かの環境では Build Action が変わっていた」「フォルダ移動で別扱いになった」などが起きがちです。対策として、csproj で AndroidResource を明示する方法もあります。

<ItemGroup>
  <AndroidResource Include="Platforms\Android\Resources\layout\ar_layout.xml" />
  <AndroidResource Include="Platforms\Android\Resources\raw\object_vertex.shader" />
</ItemGroup>

この指定があると、IDE の操作ミスでビルドアクションが変わっても気づきやすくなります(既定で拾われる場合でも “保険” として有効です)。

まとめ:MAUI では “Resource を素直に使う” が最短ルート

  • MAUI の Android リソースは、基本的に Platforms/Android/Resources 配下に置き、Resource.Layout / Resource.Raw で参照する
  • using Droid = Android; は OS 側の Android 名前空間を指しやすく、アプリのリソース参照を壊す原因になる
  • 生成物(obj 配下)に定義があるかを見ると、配置問題か参照問題かを素早く切り分けできる
  • 命名規則(小文字+_)と Build Action(AndroidResource)を固めると再発が減る

ARCore + OpenGL のように Android 固有の資産(layout や shader)を多用するプロジェクトほど、Resource 参照での小さな混乱が大きな手戻りになります。今回のように “原因が using だった” というケースは意外と多いので、まずはエイリアスを疑い、アプリ側 Resource を正しく参照できる状態から進めるのがおすすめです。

この記事を書いた人

実務の現場で詰まりがちなポイントを地図にするITブログ「IT trip」を運営。Windows/Office(Teams・Excel)からSQL、サーバ運用、ガジェットまで、再現性のある手順と“なぜそうなるか”を丁寧に解説します。読んだらすぐ試せること、そして迷った人の次の一歩が見えることを大切にしています。

コメント

コメントする

目次