モノズキット

「やってみたい」を応援するスターターキット

Unity2018.2でAndroidのIl2cpビルドにスタティックリンクする方法

ここでは、Unity2018.2で強化された、Androidアプリ作成におけるIl2cppビルドで、自前のスタティックライブラリ(.a)を実装する方法を紹介します。
f:id:hisato-t05241123:20180915151242p:plain

2018年7月頃にUnity2018.2が公開されました。どんな機能が増えたのかとリリースノートを眺めていると興味深い文言が。

Android: C++ source files and static libraries now supported as plugins using IL2CPP scripting backend

 引用:Unity 2018.2

今までAndroidでは、自前のネイティブライブラリを実装する際は共有ライブラリ、つまりsoファイルだけが対応していました。
今回の強化によって、.aファイルや、それこそc/c++のようなソースコードも同時にビルドをしてくれるようです。 是非試してみたかったのですが、新しい機能なのでなかなか参考となる記事が少なかったので、四苦八苦しながら成功した事例を紹介します。

0. 前提条件

以下のことが前提となります

  • Unity2018.2以降がインストールされている
  • UnityのAndroidアプリ作成で、Il2cppビルドできる
  • ARMv7、ARMv8、x86用(いずれか或いは全て)の.aを持っている
  • 或いはAndroidNDKでAndroid用ネイティブライブラリを作ることができる。

Il2cppでビルドする方法や、AndroidNDKでビルドする方法などは、それだけでもはじめての人にはハードルだったりするのですが、そのあたりは別の記事などを参考にしていただければと思います。

1. 環境

以下、私の環境です。

  • Windows10
  • Unity 2018.2.7f1 (64-bit)
  • AndroidNDK r13b
    • ライブラリの作成には、Cygwingccで.aを作成しています。
    • 現在主流である、gradleでビルドしても問題ないとは思います。

2. アプリの仕様

以下のような、単純に値を加算して表示するアプリを作ります。

C#

引数を足し算(AddTest)関数に渡し、結果を表示する。

C++

渡ってきた引数を加算し、結果をC#側に返す。

3. 手順

今回の方法は、Unityのドキュメントを参考にしました。合わせて読むと、より理解が進むと思います。
参考:Native (C++) plug-ins for Android

3.1. ライブラリの作成

  • 作業フォルダ([任意のパス]/StaticTest/jni))を作り、そこで作業します。

  • C++(NativeAdd.cpp)で以下のような加算処理を書きます。

#include <stdio.h>

extern "C" int AddTest(int x, int  y)
{
    return x + y;
}
  • Android.mkは以下のように記述しました。
    ※個々の開発環境や目的によって異なるかもしれませんので、あくまで参考です。
LOCAL_PATH := $(call my-dir)

#----------------------------
include $(CLEAR_VARS)
LOCAL_MODULE    := NativeAdd
LOCAL_SRC_FILES := NativeAdd.cpp

include $(BUILD_STATIC_LIBRARY)
#-----------------------------
  • Application.mkは以下のように記述しました。今回はARMv7とx86CPU用のライブラリが欲しかったので、2つを記載しています。
APP_ABI:= armeabi-v7a x86

これらの条件でビルドします。以下はCygwinでの作成の様子です。
jniフォルダの一つ上(StaticTest)をカレントディレクトリとして、"ndk-build"コマンドを実行しています。

f:id:hisato-t05241123:20180915151240j:plain f:id:hisato-t05241123:20180915151237j:plain f:id:hisato-t05241123:20180915151235j:plain

objフォルダが作成され、各CPUごとのライブラリが作られているはずです。

3.2. Unityでの実装

  • Unityを立ち上げて、適当なプロジェクトを作成します。
  • [File] > [Build Settings]から、BuildSettingsウィンドウを表示して、対象プラットフォームをAndroidに変更します。
  • Projectパネルの[Assets]を右クリック > [Create] > [C#]と進み、新規C#ファイルを作成します。今回は”CallNativeLibrary”という名前をつけました。

f:id:hisato-t05241123:20180915151233j:plain

  • C#(CallNativeLibrary.cs)で、ライブラリを呼び出す処理を書きます。はじめにDllImport属性を利用します。
using System.Runtime.InteropServices;
  • 次に、MonoBehaviorに以下のように、宣言を加えます。
[DllImport("__Internal")]
    private static extern int AddTest(int x, int y);
  • 最後に、AddTest関数を呼び出し、計算結果を表示する処理を追加します。
    void OnGUI()
    {
        int x = 3;
        int y = 10;
        GUI.Label(new Rect(15, 125, 450, 200), "adding " + x + " and " + y + " in native code equals " + AddTest(x, y));
    }
  • 全体としてはこんな感じです。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Runtime.InteropServices;

public class CallNativeLibrary : MonoBehaviour {

    [DllImport("__Internal")]
    private static extern int AddTest(int x, int y);

    void OnGUI()
    {
        int x = 3;
        int y = 10;
        GUI.Label(new Rect(15, 125, 450, 200), "adding " + x + " and " + y + " in native code equals " + AddTest(x, y));
    }
}
  • 保存したら、このコードをMain Cameraにでもアタッチしておいてください。 f:id:hisato-t05241123:20180915151405j:plain

  • ライブラリの配置に移ります。

  • Projectパネルの[Assets]以下に、[Plugins] > [Android] > [libs] > [armeabi-v7a] ([x86])とフォルダを作成します。

    • もし追加するライブラリが一つであれば、作るフォルダは[Android]までで大丈夫でした。
  • [armeabi-v7a]と[x86]フォルダに、先程のlibNativeAdd.aを入れます(入れる対象を逆にしないように!!)。

    • Inspectorで、入れたファイルの形式を指定します。自動で選択してくれるようですが、間違えていたら自分で修正してください。
    • 追加するライブラリが一つだけであれば、[Android]フォルダに入れてください。
f:id:hisato-t05241123:20180915151415j:plainf:id:hisato-t05241123:20180915151413j:plain
  • 2枚目は入れるライブラリが一つの例

  • ここまでできたら、シーンを保存して、一旦再起動してください。

    • 必須ではないですが、ビルドの失敗確率が減ります(経験則。後述参照)。

3.3. ビルド設定

  • いよいよビルドをしていきます。
    • 当然ですが、Il2cppビルドするので、ExternToolsのNDKの項目に"Android NDK r13b"までのパスが設定されていることが前提です。まだであればしておいてください。
  • [File] > [BuildSettings]でBuildSettingウィンドウを開き、player Settingsボタンを押します。
  • Player Settingsの項目では、最低限以下の3つは修正してください。
    • CompanyName, ProductName
    • Scripting Backendを[mono] -> [IL2CPP]に変更
    • Target Architecturesを今回追加したライブラリ"のみ"をチェックする。

f:id:hisato-t05241123:20180915151411j:plain

  • 準備ができたら、ビルドを実行し、結果を待ちます。

4. 確認

端末に入れて実際に動かしてみましょう。きちんと足し算をした結果が表示されています。

f:id:hisato-t05241123:20180915151509p:plain

※↓今回のコードだと文字が小さすぎるので、少しコードを修正したものを貼っておきます。

f:id:hisato-t05241123:20180915151506p:plain

念の為apkを展開して中を除くと、新たに自前soが生成されておらず、libil2cpp.soに組み込まれていることがわかります。

f:id:hisato-t05241123:20180915151504j:plain

5. まとめ

今回は.aファイルを用いて、スタティックリンクする方法を紹介しました。私は未検証ですが、CやC++で書かれたソースコードをUnity上に入れておくだけでも全てビルドしてくれるようです。
以上、Unity2018.2で実装された、Androidのスタティックリンク方法でした。

6. 詰まったところ

1. 以下のような文言でビルドできなかったら、BuildSystemの部分を"Gradle"から"Internal"に変更してみてください。

Moving file failed

Moving Temp/StagingArea\assets\bin\Data\Managed to

Temp/StagingArea\Il2Cpp\Manages:アクセスが拒否されました。

f:id:hisato-t05241123:20180915151500j:plain

2. 以下のエラーのように、ライブラリが認識されてないようであれば次のことを試してみてください。

  • .aファイル追加後、InspectorパネルでAndroidのチェックを外し、再度チェックして"Apply"ボタンを押す。
  • 何度かUnityを再起動する。

f:id:hisato-t05241123:20180915151458j:plain

Eception:Unknown CPU architecture for library Assets/Plugins/Android/lib[ファイル名].so

3. Unityのネイティブプラグインのサンプル(このページの下の方)は罠なので超気をつけてください!!

  • libnative.soはダミーっぽい(?)
  • Cのソースコードはそのままでは使えない
  • Android.mkやApplication.mkもなんか適当
  • 正直このサンプルで何度も苦戦しました。。。