見出し画像

Unityで自作ライブラリをDLLにするには

HIKKY開発チーム・VketCloudSDKリードエンジニアのyunodaです。開発ブログの担当が回ってきたので、最近の業務でちょっと学びがあったUnity向けのDLL生成方法について解説しようと思います。

本記事のレベル感については、asmdefやUPMといったところが絡んでくるため、一応Unity上級者向けです。

DLL化とは・なぜ必要?

そもそもDLL化ってなんですか、という話をさらっとしておきます。非常に簡単に説明すると、「だれでも読み書きできてしまうソースコードを中間言語に変換して難読化によるプロテクトをかける処理」です。ライブラリを配布したいけど中身は読まれたくない、といったケースでDLLにしてしまえば、割と安全にコードを配布することができます。

わたしのケースだと、

①VketCloudSDKのとある機能にロックをかけたい

②ソースコードの書き換えでロックの回避が容易にできてしまう

③DLLで難読化

という感じでした。

DLLへのパッケージング手順

DLL化の手順を検索してみると、いくつかネット記事がヒットします。それらの方法を使ってもぜんぜん構いません。

ただし、紹介されている多くの記事が、規模の小さいライブラリでしか試していない感じで、わたしが業務で作っている大規模なコード群では、VisualStudioを使った手動コンパイルが通りませんでした。

なので、わたしが取った方法としては、「Unityがコンパイルしたものを取り出す」という作戦です。

ご存じかとは思いますが、Unityからコードを開くとVisual Studioが立ち上がります。そして、変更を保存してUnityに戻ると、すこし読み込み時間が挟まりますよね? あれは、UnityがC#ファイルをコンパイルしている作業時間で、実はプロジェクト内にアセンブリが逐一生成されています。

では、実際にどこに生成されているのかというと、「プロジェクト > Library> ScriptAssemblies」になります。

画像1

注意点は、Unityが使用するすべてのアセンブリが格納されているので、必要のないコードまで含まれているという点です。たとえば、ここにはUnity.timeline.dllやUnityEingine.dllといったオフィシャルなアセンブリもあります。

CSharp.Assemblyから目的のコードを切り離す

さて、アセンブリが格納されるディレクトリがわかったところで、いざ目的のアセンブリを取り出してみましょう。.....あれ、見つかりませんか?

そうなんです、じつは単純にスクリプトを作っただけでは、先ほどのディレクトリには一切アセンブリは作られません。というのも、なにもしていないスクリプトはCSharp.Assemblyという大きなアセンブリに吸収されてしまうためです。

これを回避するには、目的のスクリプトにasmdefを設定していく必要があります。asmdefの簡単な説明をすると、アセンブリを切り分ける機能です。asmdefはUnityPackageManagerでコードを配布する場合にも必要な機能です。詳しくはこちらのスライドで解説しているので、ぜひ参考にしてください。

asmdefを適切に設定すると、先ほどのディレクトリに、切り分けたアセンブリがちゃんと生成されていることを確認できるでしょう。

アセンブリをまとめる

適切にアセンブリが切り分けられたら、目的のアセンブリだけを抽出します。手作業でやるには少々めんどくさいので、以下のようなコードを書いて、手順を自動化してしまいましょう。

private static string destinationFolder; //出力先のパスを入れてください

private static void PackagingProcess()
{
   var targetFolderPath = destinationFolder + "/com.hikky.vketcloudsdk";
   Directory.CreateDirectory(targetFolderPath);

   ///HIKKY.VketCloudSDK系のdllを検索&コピー
   var DLLs = System.IO.Directory.GetFiles(scriptAssembliesPath)
       .Where(x => x.Contains("HIKKY.VketCloudSDK") && x.Contains(".dll"))

   foreach (var v in DLLs)
   {
       System.IO.File.Copy(v, targetFolderPath + "/" + System.IO.Path.GetFileName(v), true);
   }
   ///
}

DLLにするデメリット

ここまでDLL化するメリットを解説してきましたが、DLL化はいいことばかりではありません。少々の副作用があることに注意してください。DLL化のデメリットとしてあげられるものは以下のとおりです。

・配布のたびにDLL化作業が必要
・サンプルシーンなどで参照が切れる(missing scriptになる)
・元となるソースコードがあるプロジェクトに成果物を同居させられない
・内部者しかメンテナンスできない

わたしが実際にDLL化してみて感じたデメリットはざっとこんな感じです。それぞれ詳しく説明していきます。

デメリット1:配布のたびにDLL化作業が必要

ちょっとした修正だけでも、DLL化作業が毎回発生します。どうしてもDLLにしないといけないものかどうかは慎重に判断したほうがいいです。もしくは、よりコアな部分を切り分けて、DLLにする範囲を狭くするという手もあります。

デメリット2:サンプルシーンなどで参照が切れる

UPMやアセットストアで配布する場合は、おそらくサンプルシーンを含めることになるかと思います。しかし、ソースコードのGUIDとDLLにした後のGUIDは別ものです。なので、サンプルシーンをソースコードで作っていた場合、それらのコンポーネントはmissing scriptになってしまいます。

画像2

これを回避するには、DLLにした後にサンプルシーンを作る、というちょっとめんどくさいプロセスを踏む必要があります。これを無視してサンプルシーンを先に作ってしまうと、重たい手戻りが発生するため注意が必要です。

デメリット3:ソースコードと成果物を同居させられない

前述したサンプルシーン作成に関係することですが、ソースコードとDLL化したコードを同じプロジェクト内に同居させられません。サンプルシーンを作成する場合だったり、DLL後の動作検証をする場合は、必然的にプロジェクトを二つ管理する必要があるということになります。

画像3

デメリット4:内部者しかメンテナンスできない

難読化しているため、外部コントリビューターが参加しづらくなります。難読化している以上、仕方のないことですが、ソースコードを公開する方がいろいろなissueやプルリクが取り込めるので、わたし個人としては積極的に公開するほうがいいと考えています。こればっかりは、一概に言えることではないので、よく吟味してDLL化する範囲を絞るなどの対策を取ってみるといいでしょう。

まとめ

DLL化する方法について、ちょっと雑ではありますが、まとめてみました。ぶっちゃけたところ難読化して配布したいっていうケースがそんなに多いとは思いませんが、認証とかお金周りが絡むライブラリだったら必要になるかもしれません。

あらかじめ注意しておきますが、DLLで難読化したからといって、コードを完全にプロテクトできているわけではないので、含めてはいけないコードなんかの管理はきっちりやりましょう。いくら規約でリバースエンジニアリングを禁止していたとしても、悪さをする人はお構いなしです。場合によっては、サーバー通信を挟むなど、DLL化以外の対策を検討したほうがいい場合もあります。Unityだとあんまりなさそうですけどね.....(笑) 

というわけで、Unityを使ったDLL化についての解説記事でした!

最後に

HIKKYではエンジニアを募集しています!開発チームは完全フルリモートで、世界中のどこにいてもメタバース開発にジョインできます!お仕事の内容はこんな感じです。

・VketCloudSDK開発(Unity、C#、python、web系もろもろ)
・自社エンジン開発(C++)
・VirtualMarketギミック実装(VRChat)

などなど。とくにUnityエンジニアは活躍の場所が広いです。お仕事に慣れてきたら、ガンガンにリードポジションを与えられるエンジニア主導のチームなので、ぜひHIKKYでお持ちのエンジニアリングスキルを発揮してませんか!? みなさんのご応募、お待ちしております!