はつねの日記

Kinect, Windows 10 UWP, Windows Azure, IoT, 電子工作

Humans of IT Blogに寄稿しました

techcommunity.microsoft.com

Microsoftが最近取り組んでいるHumans of ITのブログにブログ記事を寄稿しました。

他のゲストブログの方が、困っている当事者である開発者がITで問題解決する内容なのでちょっとだけ異色かもしれませんが、音声認識アクセシビリティをブーストするよという取り組みの紹介となります。

お時間のある時にご一読いただけると幸いです。

Unityで作成したアプリをMicrosoftストアで配布するには

事前準備

Unityでビルドされるexe名は、あらかじめMicrosoft Storeで名前の予約をしておきます。

例)HoloLabStoreCheck2D 

Unityアプリ側での設定

Build Settingsを開いて、
Platformで「PC, Mac & Linux Standalone」を選択して、Target Platformに「Windows」を指定、Architectureは「x86_64」を選択します。
これで、配布ターゲットは、Windows 10 x64のみとなります。
必要なのはExeや実行に必要なDLLそしてデータですので、Create Visual Studio Solutionは不要です。

Player SettingでProduct Nameにストアで予約した名前にします。
「↓」タブの中のIconなど必要な設定をします。

BuildボタンとクリックしてExeの生成先をUnityのプロジェクトフォルダ配下(例:Buildフォルダ)に指定します。
以降の説明では、Unityプロジェクトフォルダ直下にBuildフォルダがあることを前提とします、

作成先のフォルダの内容を確認します。
例)
HoloLabStoreCheck2D.exe
UnityCrashHandler64.exe
UnityPlayer.dll
WinPoxEventRuntime.dll
HoloLabStoreCheck2D_Dataフォルダ
MonoBleedingEdgeフォルダ

Visual StudioWindowsアプリケーションパッケージプロジェクトを作成

Visusl Studioを立ち上げて、Windowsアプリケーションパッケージプロジェクトを新規作成します。
プロジェクト名は、UnityのExe名+AppPackageを推奨します(例:HoloLabStoreCheck2DAppPackage)
場所は、Unityプロジェクトフォルダを指定します(以降の説明は、この位置を指定している前提となります)。
「ソリューションとプロジェクトを同じディレクトリに配置する」チェックは外したままです。

ターゲットプラットフォームを指定します。UWPアプリケーションがサポートするとありますが気にしないで大丈夫です。
ターゲットバージョンは、できれば最新のバージョンを指定するのがいいでしょう。
最小バージョンはビルド14393(バージョン1607)以降を指定する必要があります。2020/04/30現在のWindows 10サポートは1803以降なので、1809以降を指定するのも1案です。
※LTSC/LTSBを考慮するならば、ビルド14393(バージョン1607)のLTSCの延長サポート終了日が2026/10/13なのでそれを最小バージョンとするという戦略もあります。

Unityで作成したexeを直接指定できないので中間プロジェクトを作成

次に、.NET Frameworkのコンソールアプリプロジェクトを追加します。
このあたりから正攻法から外れた邪法に突入しますので、本当はWindowsアプリケーションパッケージプロジェクトのテンプレートあたりでUnityアプリの配布もサポートしてくれるといいんじゃないかと思います。
プロジェクト名はUnityのExe名と必ず同じ(例:HoloLabStoreCheck2D)にします。

プロジェクトが追加されたらばVisual Studioの[ビルド]-[構成マネージャー]で

  • アクティブソリューション構成:Release
  • アクティブソリューションプラットフォーム:x64

を選択します。
そうするとコンソールアプリのプラットフォームが「Any CPU」のままなので、x64を追加して選択しておきます。

パッケージ対象のプロジェクトとして参照

 次にソリューションエキスポローラーで、Windowsアプリケーションパッケージプロジェクトの「アプリケーション」を右クリックして[参照の追加]で、追加したコンソールアプリケーションプロジェクトを参照します。

上記が完了したら、このあたりで、[ファイル]-[すべて保存]で、一度保存しておきましょう。

中間プロジェクトにUnityアプリの実行ファイルをコピー

コンソールアプリケーションプロジェクト名を右クリックして、[エクスプローラーでフォルダを開く]をします。
エキスプローラ―での表示例:

f:id:hatsune_a:20200430144100p:plain

このフォルダにUnityでビルドした中身を丸ごとコピーします。

f:id:hatsune_a:20200430144156p:plain

中間プロジェクトビルド時にUnityアプリの実行ファイルが使われるように調整

ソリューションエキスプローラ―でコンソールアプリケーションプロジェクト名を指定して[すべてのファイルを表示]します。
さらに
HoloLabStoreCheck2D_Dataフォルダ
MonoBleedingEdgeフォルダ
HoloLabStoreCheck2D.exe
UnityCrashHandler64.exe
UnityPlayer.dll
WinPixEventRuntime.dll
を選択して右クリックメニューで[プロジェクトに含める]をクリックします。

f:id:hatsune_a:20200430143941p:plain

これでUnityアプリが必要としているファイルやフォルダ構造がプロジェクトに取り込まれました。

更にプロジェクトに含めたexeやdll、フォルダ内のファイル全てのプロパティを次のように指定します。

  • ビルドアクション:なし
  • 出力ディレクトリにコピー:常にコピーする 

コンソールアプリをビルドします。

bin\x64\ReleaseフォルダにUnityのビルド先と同じファイル+若干のコンソール用ファイルが出力されているのが確認できると思います。

もし、bin\x64\Releaseフォルダではなくbin\Releaseフォルダに出力されていたらプラットフォームがAny CPUのままなので再確認をしてください。

この状態でexeファイルをダブルクリックして実行してもコンソールアプリが実行されます。
つまり、Unityで作成した実行ファイルとコンソールアプリケーションプロジェクトでビルドされるExe名が同じなので出力フォルダでは上書きされてしまうのです。

これを次に解決します。

中間プロジェクトビルド時で作成されたexeファイルをUnityアプリのexeファイルに変更

そこで、ソリューションエキスプローラーからコンソールアプリケーションプロジェクトのプロパティを開いて、[ビルドイベント]-「ビルド後イベントのコマンドライン」に以下をいれて、上書きされた本来のExeを更に本来のものに上書きし直します。

xcopy /Y "$(ProjectDir)$(TargetFileName)" "$(TargetDir)"
del /Q "$(TargetDir)$(TargetName).pdb"

再度、bin\x64\Releaseフォルダ上のexeを起動してみましょう。
作成したUnityアプリが起動するはずです。
無事に起動出来たらば、Windowsアプリケーションパッケージプロジェクトに情報を伝えるためのダミープロジェクトの構成がまずは完了しました。

Microsoft Storeに登録

ここから先は、WPFアプリなどをAppPackage化してMicrosoft Storeに登録するのと同じ流れになります。
身近に、Windows Phoneアプリ、Windows Storeアプリ、UWPアプリのストア配布経験者がいらっしゃるようであれば、ぜひ、その方に以降の手順を一読いただいて以降の説明をショートカットするチートルートを進んでいただければと思います。

Package.appxmanifestの編集(AppPackage化特有事項)

WindowsアプリケーションパッケージプロジェクトにあるPackage.appxmanifestをテキストエディタVisual Studio Codeで開くと下記の部分があります。
<Dependencies>
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.0.0" MaxVersionTested="10.0.0.0" />
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.14393.0" MaxVersionTested="10.0.14393.0" />
</Dependencies>
こちらからWindows.Universalの行を削除して保存しましょう。
<Dependencies>
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.14393.0" MaxVersionTested="10.0.14393.0" />
</Dependencies>

Package.appxmanifestの内容設定(UWPアプリと同等項目)

次にソリューションエキスプローラーでPackage.appxmanifestをダブルクリックして内容を編集します。
表示名は、元々とのExe名にAppPackageが付いた形になっているので適切な名前にします。

例:HoloLabStoreCheck2DAppPackage→HoloLabStoreCheck2D for Desktop

説明もきちんと記載しましょう。
パッケージ化のところにもパッケージ表示名があるのでそちらも同様(例:HoloLabStoreCheck2DAppPackage→HoloLabStoreCheck2D)に編集します。
[ビジュアル資産]のところにアプリのアイコン画像など必要な解像度のアイコンを作成します。
大きめのアイコンファイルを作成して、[生成]ボタンで一気に必要な解像度の画像を自動生成するのも良いでしょう。
アイコンは背景を透過pngにしておき、タイルの背景やスプラッシュスクリーンの背景に色を指定してください。
もしくは、アイコンのイメージ部分を白で作成し、背景指定色をtransparentを指定してシステムカラーを使うようにするのも、それっぽい感じの仕上げになります。

試しにローカルインストールを確認

コンソールアプリケーションプロジェクトを右クリックして[リビルド]します。
Windowsアプリケーションパッケージプロジェクトを右クリックして[配置]を実行します。
うまく配置がいけば、Windowsのスタートの中にアプリが出現します(例:HoloLabStoreCheck2D)。
配置したアプリを実行してUnityアプリが起動すれば、ストア登録前の確認は終了です。
忘れずにアンインストールして置きましょう。

Microsoft Storeに登録

Windowsアプリケーションパッケージプロジェクトを右クリック[公開]-[アプリパッケージの作成]をクリックします。
配布方法は、アプリ名は予約済ですが[新しいアプリ名でMicrosoft Storeに]を選択します。
ストアに登録するアカウントを追加して、[既存のアプリケーション名]リストから、事前に予約した名前を選択します。
バージョンは[自動的に増加]チェックは外して、アーキテクチャはx64のみチェックします。ソリューション構成も「Release (x64)」になっていることを確認して、[作成]をクリックします。
成功すれば次のような出力となります。

1>パッケージが正常に作成されました。
========== 公開: 1 正常終了、0 失敗、0 スキップ ==========
パッケージが Release (x64) 向けに正常にビルドされました。
========== パッケージ: 1 正常終了、0 失敗 ===========
アプリケーション バンドルが Release (x64) 向けに正常にビルドされました。
========== アプリケーション バンドル: 1 正常終了、 0 失敗 ===========  

出力先フォルダはプロジェクトフォルダ内のAppPackagesフォルダになります。この中にあるmsixuploadフォルダをストアに登録します。

例)HoloLabStoreCheck2DAppPackage_1.0.0.0_x64_bundle.msixupload  

ストア登録時の注意表示について(AppPackage化特有事項) 

Windowsアプリケーションパッケージプロジェクトは自動的にrunFullTrustがついているので下記の注意書き(次の制限された機能は、アプリで使用する前に承認が必要です)が表示されますが、気にしないで大丈夫です。

The following restricted capabilities require approval before you can use them in your app: runFullTrust. 

f:id:hatsune_a:20200430144332p:plain

 ストア登録自体は一般的なものと同じですが、申請オプションの項目にある制限付き機能については、下記のようなコメントを記載します。

デスクトップアプリのブリッジを使ったAppPackage化によるストア登録なのでrunFullTrustが必要です。
Because it is a store registration by AppPackage using the bridge of the desktop application, runFullTrust is necessary.

 あとは申請に提出してストアに公開されるのを待つだけです。

以前とは異なり数時間くらいで審査通過してストア公開フェーズになります。

ストア公開フェーズになってから実際に公開されるまで数時間待たされるので翌朝には公開されているかなくらいの感覚でいるとイライラしないでしょう。

もちろんストア公開なので有料アプリもサクッと指定ができてアプリ費用もMSさんが回収してくれる(マージンは取られるけれど)ので、これはっ!というUnityアプリを登録してみるのもいいでしょう!

Xamarin.Androidで、Could not determine the installation pathというエラーがでたときの対処方法

XamarinでAndroidアプリを実機デプロイして試していたら、何かのタイミング(多分、実機で直接アプリをアンインストール)でビルドは成功するけれど

Could not determine the installation path com.companyname.programname

のようなエラーがでて実機デプロイができなくなりました。

AndroidManifest.xmlのなかのTYPOみたいな情報もあったのですが、今回のケースでは下記が原因でした。

個人用からはアプリをアンインストールしたけれど、仕事用の方からアンインストールしていなかった 

仕事用からもアンインストールすることで無事に実機デプロイが可能になりました。

 

 

MessagePack for C#始めました

以前から使おう使おうと思って(実際は使ってみようとして上手くいかなくてを何回か繰り返して、最近の状況で在宅でがっつり集中できるようになったので)いたneueccさんの素敵ライブラリMessagePack-CSharpを既存アプリに組み込むことができました。

github.com

いくつか、DataContractJsonSerializerから書き換えるうえで迷った点がありましたので、まとめておきたいと思います。

MessagePack-CSharpは、非常に高速なC#用シリアライザーです。例えば構造体⇔Byte配列、構造体⇔Byte配列⇔JSON文字列あたりの変換が多数あるような例えば多端末間メッセージ送受信のデータシリアライズなどに適用するとシステム全体の快適さが増すかもしれません。

GitHubで公開されている測定結果を見ると、まさに桁が違う処理速度です。

https://cloud.githubusercontent.com/assets/46207/23835716/89c8ab08-07af-11e7-9183-9e9415bdc87f.png

 

PublicクラスじゃなくてInternalやPrivateなクラスを使う場合

MessagePack-CSharpでは、デフォルトでは指定する構造体はPublicクラスじゃないと実行時エラーが発生します。ネットで検索してみると「Publicクラスでなければならない」という解説もありましたが、本家のneueccさんの説明ではそのような説明がありませんでした。ということはきっとできる方法が用意されているのだろうと考えてドキュメントをもう一度よんでみるた次のような方法の記載をみつけました。やっぱり原典をみないとですね。

InternalやPrivateなクラスを指定したいときは次のようにします。

gist.github.com

 MessagePackSerializerOptions.Standard.WithResolverの引数にStandardResolverAllowPrivate.Instanceを指定してオプション指定をつくり、それをSerialize<プライベートクラス>メソッドの第二引数に指定してあげれば、Privateクラスでも実行時エラーなくシリアライズできます。

便利ですね。

クラスのプロパティ名をJSON文字列の項目名に使う場合

これは簡単で、クラスに[MessagePack.MessagePackObject(true)]属性をつけてあげればOKです。

JSON文字列上の項目名を、クラスのプロパティ名とは別の名前にしたい場合

JSONに指定する項目名が"message-id"などが必要でプロパティ名に指定が難しいような場合には、Key属性で項目名を指定することができます。

まずはダメな例

gist.github.com

クラスに[MessagePack.MessagePackObject(true)]属性をつけて、変更したいプロパティにだけ[MessagePack.Key("message-id")]属性でJSON項目名を指定してみましたが、これでは変更されませんでした。

OKな例。きちんとすべてにKey属性をつけてクラスの属性ではkeyAsPropertyNameをfalseつまり指定しないようにします。

gist.github.com

これでいままで悩んでいた点が解決できたので、リリース版に反映&テストフェーズに入りたいと思います。

OBS Studio + OBS-WebSocketで字幕表示するときの2020/04/09現在の注意点

映像録画&ライブストリーミング用のオープンソースプロジェクトOBSのOBS Studioにはプラグイン拡張でWeb Socketのインターフェースを追加することができます。

OBS Studio (現時点での最新は、25.0.4)

obsproject.com

OBS-WebSocket (現時点での最新は、2.7)

github.com

OBS-WebSocketのC# .NET Library

github.com

 

OBS Studioが24→25に変わったときに文字を表示する領域(OBS Studioではソースと言います)のIDが変わってしまっているようで、OBS-WebSocketで、SetTextGDIPlusPropertiesやGetTextGDIPlusPropertiesを使うときに正しいソース名を指定しても「not a text gdi plus source」というエラーになってしまい、OBS Studioに字幕が表示できません。

Unable to control of GDI_Text version 2 · Issue #443 · Palakis/obs-websocket · GitHub

すでにこのissuesはソース的には修正が入っております。

具体的には、ソース名でヒットしたソースの属性チェックのところで、従来の「text_gdiplus」というIDに加えて、「text_gdiplus_v2」というIDもエラーにしないように修正されています。

http:// https://github.com/Palakis/obs-websocket/pull/448/commits/846d52ebe58d5f9f819680afa9d8a3e7516ab380

この変更は、「added this to the 4.8 milestone」とのことですので、OBS-WebSocketのVersion 4.8には入ってくるようです。

 

そのため、2020/04/09時点での解決方法は次のようになります。

  • OBS-WebSokcetの最新ソースから version 4.8 相当のバイナリをビルドして使用する
  • OBS Studioを24系にダウングレードする

 

[en]

OBS Studio from OBS, an open source project for video recording and live streaming, has a plug-in extension that adds a Web Socket interface.

OBS Studio (currently the latest is 25.0.4)

https://obsproject.com/ja/

OBS-WebSocket (current version is 2.7)

https://github.com/Palakis/obs-websocket/releases

OBS-WebSocket's C# .NET Library

https://github.com/Palakis/obs-websocket-dotnet.

 

When OBS Studio changed from 24 to 25, the ID of the area to display text (called source in OBS Studio) seems to have changed, and even if I specify the correct source name when using SetTextGDIPlusProperties or GetTextGDIPlusProperties in OBS-WebSocket, I get the error "not a text gdi plus source", and I can't display subtitles in OBS Studio.

https://github.com/Palakis/obs-websocket/issues/443

This issues has already been modified in terms of source.

Specifically, the ID of "text_gdiplus_v2" in addition to the ID of "text_gdiplus" in the attribute check of the source hit by the source name has been modified so that it is not an error.

https://github.com/Palakis/obs-websocket/pull/448/commits/846d52ebe58d5f9f819680afa9d8a3e7516ab380.

This change is "added this to the 4.8 milestone", so it seems to be coming in Version 4.8 of OBS-WebSocket.

 

Therefore, as of 04/09/2020, the solution is as follows.
-Build and use a binary equivalent to version 4.8 from the latest source of OBS-WebSokcet.
-Downgrade the OBS Studio to the 24

リモートワークには雑談チーム配信が効果的

様々な事情から、今月から在宅勤務でリモートワークという人たちも多いと思います。

そんな時にお勧めなのがTeamsのチーム機能を使ってチーム全体で映像配信を行う雑談チーム配信です。

f:id:hatsune_a:20200302152356p:plain

※上記は雑談チーム配信の活躍想像図です。実在の人物とは関係がありません。

 

特に何かミーティングをしていなくても繋がっている感がでますし、いわゆる突発的雑談にシームレスにはいれますし、(なぜか)だらだらと雑談せずにQA終わったら追われますね。

そして効果的なのは「わかりました」「ありがとう」なんていうもしかしたら普段ならスルーしてしまうような重要単語が自然に交わされるのがいいですね。

もしかしたら、私たちジャパニーズ会社員はリモートワークなTeams雑談配信で、海外企業の個室事務スペースとお互いに挨拶を交わすというフレンドリーな文化というのを進められるんじゃないかと思いました。

ピンチはチャンス。みなで次のステップに進んじゃいましょう!