NETSDK1032対策|.NET 9/MAUIをMacのiOSシミュレーターで動かす正しいアーキテクチャ設定と恒久対策

Mac 上で .NET 9/.NET MAUI アプリを iOS シミュレーターにデプロイした途端、NETSDK1032 が出て実行できない——この現象は「ビルドしたバイナリのアーキテクチャ」と「シミュレーター(=ホスト Mac)のアーキテクチャ」が不一致なときに必ず起きます。本記事では仕組みから原因、即効性のある修正、恒久対策、CI・複数構成での運用までを余すことなく解説します。

目次

症状とエラーメッセージ

Mac 単体で iOS シミュレーター起動を試みると、次のようなエラーが表示されます。

error NETSDK1032: The RuntimeIdentifier platform 'iossimulator-x64' and the PlatformTarget 'arm64' must be compatible.

Windows PC からのリモートビルドでは動くのに、同じソースでも Mac では失敗するケースが典型です。これは、プロジェクトかユーザー設定のどこかに「x64 と arm64 が混在する指定」が残っており、.NET SDK が正しく組み合わせられないために発生します。

結論(先に要点)

シミュレーターはホスト Mac と同じ CPU アーキテクチャのバイナリしか動きません。したがって RuntimeIdentifier(RID)と PlatformTarget を必ずそろえます。

ホスト MaciOS シミュレーターで動くバイナリ指定すべき RID指定すべき PlatformTarget
Intel Mac(x86_64)x64(x86_64)iossimulator-x64x64
Apple Silicon(arm64)arm64iossimulator-arm64arm64

これだけで多くのケースは解決しますが、しばしば .csproj では直したのに .csproj.user(ユーザー設定ファイル)に古い値が残っており、ビルド時に後から上書きされて失敗します。次節以降で根本から整えます。

仕組み:なぜ不一致が起きるのか

iOS シミュレーターは iPhone 実機ではなく、Mac の CPU で iOS ランタイムを模擬する仕組みです。ゆえに、シミュレーター用アプリは 実機用とは別アーキテクチャでビルドされます。Apple Silicon Mac なら arm64、Intel Mac なら x64 です。

.NET の観点では次の二つの値が鍵です。

  • RuntimeIdentifier(RID):発行・実行先プラットフォームの「OS+CPU」を示す識別子(例:ios-arm64、iossimulator-arm64、iossimulator-x64)。
  • PlatformTarget:生成するアセンブリの CPU ターゲット(x64/arm64 など)。

この二つが矛盾していると .NET SDK は「同じ世界線にいない組み合わせ」と判断し、NETSDK1032 を投げます。たとえば Apple Silicon なのに iossimulator-x64 と arm64 を混在させると、エラーメッセージの通り「x64 と arm64 が非互換」になります。

最短解決レシピ

ホスト CPU を確認する

まず Mac のアーキテクチャを把握します。

uname -m  # arm64 または x86_64 が返る

.csproj に明示的な既定値を設定する

Apple Silicon の例:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net9.0-ios</TargetFramework>
    <RuntimeIdentifier>iossimulator-arm64</RuntimeIdentifier>
    <PlatformTarget>arm64</PlatformTarget>
  </PropertyGroup>
</Project>

Intel Mac の例:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net9.0-ios</TargetFramework>
    <RuntimeIdentifier>iossimulator-x64</RuntimeIdentifier>
    <PlatformTarget>x64</PlatformTarget>
  </PropertyGroup>
</Project>

.csproj.user を点検・整理する

Visual Studio や Rider はユーザー固有の設定を <プロジェクト名>.csproj.user に保存します。ここに古い PlatformTarget や RuntimeIdentifier が残っていると、ビルド時に .csproj の値が上書きされます。次のいずれかで対処します。

  • 安全策:当該プロパティ行(PlatformTarget/RuntimeIdentifier)を削除。
  • リセット:.csproj.user 自体を削除し、IDE に再生成させる。

クリーンビルドする

キャッシュに残った混在バイナリを排除します。

dotnet clean
rm -rf bin obj
dotnet build -f net9.0-ios -c Debug -r iossimulator-arm64   # Apple Silicon 例
# または
dotnet build -f net9.0-ios -c Debug -r iossimulator-x64      # Intel Mac 例

実行して確認する

CLI からシミュレーター起動まで含めて検証するには次で十分です。

dotnet build -t:Run -f net9.0-ios -c Debug -r iossimulator-arm64

Intel Mac は iossimulator-x64 に読み替えてください。

構成を分けて運用する(Debug=シミュレーター/Release=実機)

日常開発はシミュレーター(=ホストと同一アーキテクチャ)、配布は実機(= arm64 固定)という切替を自動化します。次のように Condition を使えば、構成ごとにプロパティを分岐できます。

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net9.0-ios</TargetFramework>
  </PropertyGroup>



iossimulator-arm64
arm64



iossimulator-x64
x64




ios-arm64
arm64

このようにしておけば、手動で切替える手間がなく、NETSDK1032 の再発も抑止できます。

確認方法:ビルド成果物のアーキテクチャを実測する

「正しく設定したはず」を「正しくビルドされた」に落とし込むには、成果物の実体確認が最短です。

# 例: アプリ本体バイナリのパスは環境により異なる
# Apple Silicon / Debug / Simulator(arm64)例
APP=bin/Debug/net9.0-ios/iossimulator-arm64/<YourApp>.app/<YourApp>
lipo -archs "$APP"
# → arm64 が表示されればOK(Intel Macなら x86_64)

lipo -archs で検出されたアーキテクチャが arm64(Apple Silicon)または x86_64(Intel)になっているか必ず確認しましょう。

よくある落とし穴と対処

.csproj を直したのに直らない

  • .csproj.user の上書きが最有力。まず削除してから再ビルド。
  • IDE の構成(Debug/Release 切替)や「アーキテクチャ選択」の UI が PlatformTarget を設定していることがあるので、プロジェクト設定を見直す。
  • 複数の PropertyGroup が競合している場合、後勝ちで上書きされます。迷ったら dotnet build -bl でビルドログを採取し、プロパティの最終値を確認します。

Windows からのリモートビルドは動くのに Mac 直だと失敗する

リモートビルド時は Mac 側のエージェントが RID/アーキテクチャを適切に選びます。一方、Mac 直ビルドではローカルの .csproj.user や IDE 設定がそのまま効くため、古い値の混入が顕在化します。ローカルのユーザー設定をクリアしてから、上記の既定値を .csproj に固定しましょう。

マルチターゲットの MAUI で iOS だけ失敗する

<TargetFrameworks>net9.0-ios;net9.0-android;net9.0-maccatalyst</TargetFrameworks> のように複数指定していると、ターゲットごとの条件付き指定が必要です。iOS だけに適用したい値は Condition="'$(TargetFramework)'=='net9.0-ios'" を付けてください。

<PropertyGroup Condition="'$(TargetFramework)'=='net9.0-ios' and '$(Configuration)'=='Debug'">
  <RuntimeIdentifier>iossimulator-arm64</RuntimeIdentifier>
  <PlatformTarget>arm64</PlatformTarget>
</PropertyGroup>

古いキャッシュで誤検出される

一度でも x64 でビルドした成果物が残っていると、IDE がそれを拾って起動しようとして失敗します。bin/ と obj/ を削除してからビルドしましょう。Git 管理なら git clean -xdf も有効です。

CLI/IDE で .NET のパスが違う

ターミナルと IDE で別の .NET を参照していると、Workload の有無や既定の挙動が変わります。次で確認・統一を。

which dotnet
dotnet --info
dotnet workload list

Apple Silicon で Rosetta を使っている

一部のツールを Rosetta(x64)で起動していると、ツールは x64、実際のビルド対象は arm64 といった捻れが生じます。IDE とターミナルをネイティブ arm64 で起動し、プロジェクトの指定値と矛盾しないようにしましょう。

実機とシミュレーターの違い(混同しないための表)

用途RIDPlatformTarget備考
iOS 実機ios-arm64arm64配布・ストア提出はこれ一択。実機の CPU は常に arm64。
iOS シミュレーター(Apple Silicon)iossimulator-arm64arm64ホストが Apple Silicon の場合。
iOS シミュレーター(Intel)iossimulator-x64x64ホストが Intel の場合。

「Release だから ios-arm64 固定」「Debug はホストに合わせて iossimulator-* 」という運用が実務で一番安定します。

恒久対策:チーム・CI で再発を防ぐ

ユーザー設定の排除

  • Git で *.csproj.user をコミットしない(通常は .gitignore に入っています)。
  • もし既に入っているなら一度リポジトリから削除し、各自のローカルで再生成させる。

Directory.Build.props で既定を集中管理

ソリューション直下に Directory.Build.props を置くと、すべての子プロジェクトに既定値を配布できます。

<Project>
  <PropertyGroup Condition="'$(TargetFramework)'=='net9.0-ios' and '$(Configuration)'=='Debug'">
    <RuntimeIdentifier>iossimulator-arm64</RuntimeIdentifier>
    <PlatformTarget>arm64</PlatformTarget>
  </PropertyGroup>
  <PropertyGroup Condition="'$(TargetFramework)'=='net9.0-ios' and '$(Configuration)'=='Release'">
    <RuntimeIdentifier>ios-arm64</RuntimeIdentifier>
    <PlatformTarget>arm64</PlatformTarget>
  </PropertyGroup>
</Project>

Apple Silicon と Intel を混在運用する場合は、Debug 側を条件分岐(Arm64/X64)させてください。

CI のビルドマトリクス例(GitHub Actions 風)

strategy:
  matrix:
    config: [Debug, Release]
steps:
  - run: dotnet nuget locals all --clear
  - run: dotnet restore
  - run: dotnet build -f net9.0-ios -c ${{ matrix.config }} -r ${{ matrix.config == 'Release' && 'ios-arm64' || 'iossimulator-arm64' }}

Intel ランナーを使う場合は Debug の RID を iossimulator-x64 に切替えます。

MAUI プロジェクト例:最小構成の雛形

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFrameworks>net9.0-ios;net9.0-android</TargetFrameworks>
    <UseMaui>true</UseMaui>
    <Nullable>enable</Nullable>
  </PropertyGroup>



iossimulator-arm64
arm64



iossimulator-x64
x64



ios-arm64
arm64

この雛形をベースにすれば、開発者のマシン差異に影響されにくいプロジェクトになります。

デバッグのヒント:最終値を「見える化」する

「どこで上書きされているのか?」を調べるには MSBuild のビルドログが確実です。

dotnet build -f net9.0-ios -c Debug -bl
# カレントに msbuild.binlog が生成される(Binary Log Viewer で可視化)

ログ中で RuntimeIdentifier と PlatformTarget の最終決定値を辿れば、.csproj.user や条件分岐の影響が一目瞭然です。

チェックリスト(これだけ見れば直る)

  • Mac の CPU を確認:uname -m が arm64 か x86_64 か。
  • .csproj の二項目を統一:RuntimeIdentifier と PlatformTarget をホストに合わせる。
  • .csproj.user を削除:矛盾プロパティが潜んでいないか必ず点検。
  • クリーンビルド:dotnet clean → bin/obj 削除 → 再ビルド。
  • 成果物の実測:lipo -archs で生成バイナリのアーキテクチャを確認。
  • 構成の分離:Debug は iossimulator-*、Release は ios-arm64。

原因別の具体例と修正パターン

原因:IDE のアーキテクチャ選択 UI を誤設定

IDE の「アーキテクチャ」ドロップダウンで x64 を選んだまま Apple Silicon で実行すると、PlatformTarget=x64 が注入されます。arm64 に変更し、.csproj.user の残骸を削除します。

原因:過去の実機配布設定を Debug にも継承

実機向けに ios-arm64/arm64 を設定したあと、それを Debug にも流用するとシミュレーターで起動できません。Release のみに実機設定を残し、Debug はホストに合わせた iossimulator-* に分岐します。

原因:複数の PropertyGroup が衝突

似た条件の PropertyGroup が複数あると、読み込み順の後勝ちで意図せず上書きされます。「ターゲットフレームワーク」「構成」「OS アーキテクチャ」の 3 軸で条件を絞り、唯一のグループで決まるように整理します。

原因:Rosetta を介したビルド

Apple Silicon の IDE を Rosetta で起動していると、内部的には x64 の PlatformTarget が選ばれることがあります。IDE をいったん終了し、アプリケーション情報で「Rosetta を使用して開く」のチェックを外してから再起動してください。

補足:MAUI の典型的な .csproj 読み方

MAUI の iOS プロジェクトでは、おおむね次の項目だけで NETSDK1032 は避けられます。

  • <TargetFramework>net9.0-ios</TargetFramework>(または TargetFrameworks)。
  • Debug 時の RuntimeIdentifier と PlatformTarget をホストに合わせる。
  • Release 時は ios-arm64/arm64 を固定。

他のプロパティ(CodesignKey や Entitlements 等)は署名や配布に関わるもので、本件の不一致エラーとは切り離して考えるのがコツです。

トラブル再現から復旧までの実演(コマンド一式)

Apple Silicon 環境で誤って x64 の RID を指定してしまった場合の再現・復旧フローです。

# 誤設定(わざとエラーを出す)
dotnet build -f net9.0-ios -c Debug -r iossimulator-x64
# → NETSDK1032

# 修正(arm64 にそろえる)

dotnet clean
rm -rf bin obj
dotnet build -f net9.0-ios -c Debug -r iossimulator-arm64

# 実行確認

dotnet build -t:Run -f net9.0-ios -c Debug -r iossimulator-arm64

開発マシンの移行と将来の互換性

Apple Silicon 環境ではシミュレーターの動作・ビルド速度ともに有利です。Intel Mac を併用しているチームは、上記の条件分岐をプロジェクトに組み込んでおくと、開発者のマシン差を意識せずに作業できます。長期的には Apple Silicon への移行を視野に、Debug は iossimulator-arm64 を既定とし、Intel 専用の分岐は当面の互換レイヤーと捉えると運用が楽になります。

FAQ

Q. PlatformTarget を省略したらどうなる?

A. 省略時はツールや環境の既定に任され、IDE/プラットフォームによって変わる余地が残ります。NETSDK1032 を避ける観点では明示指定が安全です。

Q. RuntimeIdentifiers に複数列挙してもよい?

A. 発行(publish)シナリオでは有効ですが、実行対象は 1 つに決まります。開発中の Debug 実行は RuntimeIdentifier を単一に固定するのが確実です。

Q. 実機とシミュレーターでコードを分けたい

A. ビルド時定数(例:DefineConstants)を構成ごとに切り替え、#if で分岐するのが定石です。NETSDK1032 の解消とは独立の話なので、まずはアーキテクチャ不一致を解決してから検討しましょう。

まとめ

NETSDK1032 は「RID と PlatformTarget の不一致」が原因です。iOS シミュレーターはホスト Mac と同一アーキテクチャのみを受け付けるため、Apple Silicon では iossimulator-arm64/arm64、Intel では iossimulator-x64/x64 にそろえます。加えて .csproj.user の上書きを排除し、クリーンビルド&成果物の実測で検証すれば、Mac 単体でも確実に起動できます。Debug=シミュレーター/Release=実機という構成分離を取り入れ、プロジェクト既定として固定しておくことが、再発防止の最短ルートです。

この記事を書いた人

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

コメント

コメントする

目次