窓を作っては壊していた人のブログ

提督の窓や成績の窓を作ってました.今では適当に好き勝手に開発をしてます.

Xamarin SDKのPinningを行う ~MSBuildと仲良くなる~

本日Twitter

Xamarin SDK複数バージョン入れて、指定したバージョンビルドって可能なんだっけ?

みたいな書き込みがあり,そういえば前Currentを書き換えてiOSSDKの変更をしたことがあったなと思い,他にやり方がないか試してみました. 以下に挙げるテクニックなどを使用したSDKのPinningを行うことで出来ることとしては,

  • OSSになったXamarin SDKを自前ビルドして最新版を試してみること
  • あるバージョンから入ったバグ探しをすること
  • macのバージョンが低く,Xcodeのバージョンなどが上げられない時の対処(たぶん)

などが挙げられるかと思います. どんな仕組みでビルドが走っているのかの一端を見ることも出来るので,興味のある人は読んでみてください.

今回提案する方法は3つあります.

実験環境

  • macOS 10.12.6
  • mono 5.8.0.108
  • Visual Studio Community 2017 for Mac (Preview) Version 7.4 Preview (7.4 build 884)
  • Xamarin.Android Version: {8.1.0.25,8.2.0.1,8.2.0.6}
  • Xamarin.Mac Version: 4.2.0.8
  • Xamarin.iOS Version: 11.8.0.8

その1,Currentの書き換え

デフォルトではmacOSの場合 /Library/Frameworks/Xamarin.{Android,iOS,Mac}.framework/Versions/Current/のバージョンを使用します. あなたがもしsudoを使える立場なのであれば,シンボリックリンクを張り直すことでバージョンのPinningが行えます.

メリット:

  • 以降のビルドが基本的にはそのバージョンで行われ続ける

デメリット:

  • sudoを行う権限が必要
  • 新しいバージョンのSDKがインストールされるとCurrentが新しい方に移り,再度修正が必要
  • 全プロジェクトでそのバージョンが使われてしまい,使い勝手が悪かったりする

その2,csprojを書き換える

Android, iOS, macOSのプロジェクトのcsprojを見てみると,いくつか.targetファイルをImportしているのが確認できるかと思います. macOSだと

<Import Project="$(MSBuildExtensionsPath)\Xamarin\Mac\Xamarin.Mac.CSharp.targets" />

こんな感じのものです.

それをどんどん遡っていくと,

macの場合は /Library/Frameworks/Mono.framework/External/xbuild/Xamarin/Mac/Xamarin.Mac.ObjCBinding.CSharp.propsXamarinMacFrameworkRoot

Androidの場合は /Library/Frameworks/Mono.framework/External/xbuild/Xamarin/Android/Xamarin.Android.Common.propsXamarinAndroidVersion (未検証です...)

iOSの場合は /Library/Frameworks/Mono.framework/External/xbuild/Xamarin/iOS/Xamarin.iOS.ObjCBinding.CSharp.propsMonoTouchSdkRoot

というプロパティにたどり着きます. これらのプロパティが設定されていない場合,Currentを指すような仕組みになっているようです.

決して面倒だからと言って上記のpropsファイルを書き換えるようなことはしないでください

ということで,このプロパティを指定することでSDKのPinningが行えそうです. macOSのプロジェクトの場合,プロジェクトのcsprojを開いて

<PropertyGroup>
  <XamarinMacFrameworkRoot>/Library/Frameworks/Xamarin.Mac.framework/Versions/4.2.0.8/</XamarinMacFrameworkRoot>
</PropertyGroup>

こんな感じでパスを指定してあげます. こうすることでsudoなどを使わずとも良くなりました. PropertyGroupのConditionをいい感じに変えてあげればCurrentを使うときや,Pinningしたバージョンでビルドするといったことが切り替えることが出来るので,そちらも試してみてください.

その際のビルドログを載せておきます.(179行目ぐらいから指定したバージョンを使っていることが見える)

macOSでSDKを指定した場合とそうでない場合のビルドログ(VS4Mに出力されてるやつのコピペなので見づらい) · GitHub

メリット:

  • csprojを見ればどのバージョンでビルドしたいのかがはっきりわかる
  • 他のプロジェクトに影響を与えない

デメリット:

  • csprojファイルを自分で書き換えるのが面倒

その3,コマンドラインでビルドする

この条件は少し特殊です. 自前でCI環境などを作っていて,cscだったりmsbuildを自分で叩く人のみに関係してきます. この場合も その2 と変わらずプロパティを指定してあげるだけです.

csc /p:XamarinMacFrameworkRoot=/Library/Frameworks/Xamarin.Mac.framework/Versions/4.2.0.8/ ... some_project.csproj

みたいな感じでしょうか. これはcsprojに書いてなくてもプロパティを外部から与えてあげる際に使用されるような場合に用いられます.

詳しくはこちら

MSBuild コマンド ライン リファレンス | Microsoft Docs

まとめ

3つの方法でSDKのPinningが可能であることがわかりました. 一番オススメなのが私としてはcsprojを書き換え,SDKのPathを指定してあげることです.

今回はmacOSをターゲットとする場合でしたが,iOSでも同様の手順で可能のはずです.

また今回はAndroidの検証が行えていません. Android

<XamarinAndroidVersion>8.2.0-6</XamarinAndroidVersion>

の様に指定されているので,このプロパティに対象のバージョンを指定することで可能になりそうです. どなたか試していただければと...

またこれ以外に簡単な手段があればぜひともコメントやTwitterなどで教えていただければと思います(普通にシェルとかの環境変数で出来たら楽そう...)


追記(2018/02/07 13:40)

このようなリプをいただいたので

XamarinMacFrameworkRoot=/Library/Frameworks/Xamarin.Mac.framework/Versions/4.2.0.8/ /Applications/Visual\ Studio.app/Contents/MacOS/VisualStudio

みたいな方法でVS4Mを起動してみた所,SDKに関する変数を反映した状態でVS4Mが起動でき,またビルドを走らせることが出来ました. 情報ありがとうございました.

とすると,コマンドラインでビルドを走らせる場合はある程度プロファイルを作ってシェルを叩いてしまってもいいし,MSBuildにパラメータとして与えても問題ないって感じですね. CI環境では同時に環境変数を与えることが出来るものも多いので(Visual Studio App Centerとかもそうだし),そういう感じで条件変えながらビルドのテストが出来そうです.

最近(2018年2月)のXamarin関連で気になっていること

Xamarinの管理するリポジトリを眺めていて最近気になった点が2点

flex

github.com

CSSなどで使っている人も多いであろうFlexboxのCインプリのライブラリ. 趣味レベルで使うのかなぁと思っていたのですが,vNextのプロジェクトの欄を見ているとタスクに存在しています.

XAMLを書き慣れている人はpaddingなどでいい感じに位置調整をしたりするのかもしれませんが, Androidのアプリのデザインをxmlで行っていた方はこっちのほうが慣れた形式で出来たりするのかもしれませんね.

私は初めてのGUIアプリはQtから入って,コードでGUIをガリガリ生成していたので,見慣れた感じがしてそこそこ嬉しい感じはします.

3.0.0のpre

Release beta-3.0.0-pre1: [XamlC] TypedBindings to self for value types (#1617) · xamarin/Xamarin.Forms · GitHub

Releaseのページを見てみると,既に3.0.0のbetaのpre(betaのpreとは...という感じがすごい)がタグ付けされて公開されています.

そういえばXamarin.Forms 3.0ってどんなものを提供するんだっけ?と思い過去の記事を見てみると

blog.xamarin.com

macOSなどのプラットフォームのサポートや,Xamarin Forms embeddedなどの提供が主な変更点と見て取れます. 実際Embeddedは2.5.0ぐらいから出来た気はしますが.

リファレンス実装としては

github.com

github.com

このあたりが参考になるかと思います. 時間を作って試してみようかと思います.