Help us understand the problem. What is going on with this article?

Xamarin.AndroidでNDKを利用する

More than 3 years have passed since last update.

JXUG Conference 大阪で発表したXamarin.Android+NDKの、デモ部分の解説記事です。

スライドはこちら。
「Xamarin.Androidでネイティブコードと仲良しになる方法」
http://www.slideshare.net/hIDDENxv/xamarinandroidndk

Xamarin.AndroidでC/C++記述したネイティブコードをプロジェクトに含めて利用するための、シンプルな手順を解説します。
前提は、Xamarin、Android SDK、Android NDK環境が整っていること。
Mac+Xamarin Studioで解説しているので、他の環境の場合は適宜読み替えていただければと。

アジェンダはこちら。
1.NDKビルド環境を整える
2.ビルドしてできたlibsフォルダ以下を、プロジェクトに追加する
3.C#からコールする
4.ビルドターゲットを追加する

1.NDKビルド環境を整える

まずはAndroidアプリプロジェクトを作成します。
そして、ndk-buildからみて通常のAndroidアプリプロジェクトにみえるように、プロジェクトフォルダ以下の構成を整えます。

ひとつめ。プロジェクトにproject.propertiesファイルを追加。

project.properties
target=android-19

ふたつめ、プロジェクトにjniフォルダを作成し、mkファイルとソースを追加。

Android.mk
LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)
LOCAL_MODULE    := NativeTest
LOCAL_SRC_FILES := Native.cpp

include $(BUILD_SHARED_LIBRARY)
Application.mk
APP_ABI := all
Native.cpp
extern "C"
{
    int add( int a, int b );
}

int add( int a, int b )
{
    return a + b;
}

ここまでできたら、ターミナルを開いてビルドしてみます。
プロジェクトフォルダまで移動して、ndk-buildを実行。下記のようなメッセージが表示されれば成功です。

Compile++ thumb  : NativeTest <= Native.cpp
SharedLibrary  : libNativeTest.so
Install        : libNativeTest.so => libs/armeabi/libNativeTest.so
Compile++ thumb  : NativeTest <= Native.cpp
SharedLibrary  : libNativeTest.so
Install        : libNativeTest.so => libs/armeabi-v7a/libNativeTest.so
Compile++ mips   : NativeTest <= Native.cpp
SharedLibrary  : libNativeTest.so
Install        : libNativeTest.so => libs/mips/libNativeTest.so
Compile++ x86    : NativeTest <= Native.cpp
SharedLibrary  : libNativeTest.so
Install        : libNativeTest.so => libs/x86/libNativeTest.so

2.ビルドしてできたlibsフォルダ以下を、プロジェクトに追加する

NDKビルドに成功すると、プロジェクトフォルダ下にlibsフォルダが作成されているはず。
libsフォルダには、各プラットフォーム向けのライブラリファイルができているので、必要なぶんだけプロジェクトに追加し、ビルドアクションを「AndroidNativeLibrary」に設定します。
スクリーンショット 2015-07-17 12.13.39.png

3.C#からコールする

このネイティブバイナリをC#コードからコールするには、C#でWindowsアプリを書いていたことのある人にはおなじみの、DllImport属性を使います。

今回はテンプレートで生成されたMainActivityに追記してみます。

MainActivity.cs
[DllImport("NativeTest")]
public static extern int add(int a, int b);

そのままボタンタッチ時の処理を書き換えて、ネイティブコード実行の確認ができるようにします。

MainActivity.cs
button.Click += delegate
{
    var rand = new Random();
    var a = rand.Next(100);
    var b = rand.Next(100);
    button.Text = String.Format("{0} + {1} = {2}", a, b, add(a, b));
};

実行するとこのように。無事コールされているのが確認できます。
run.png

4.ビルドターゲットを追加する

ここまでネイティブコードのビルドにはターミナルからndk-buildを実行していましたが、これでは不便。
そこでプロジェクトファイル(csproj)に下記のような<Target>タグを追加します。

*.csproj
<Project>
  <Target Name="BeforeBuild">
    <Exec Command="$(AndroidNdkDirectory)/ndk-build" />
  </Target>
</Project>

(いただいたコメントにより、追記修正しました)
ここまでネイティブコードのビルドにはターミナルからndk-buildを実行していましたが、これでは不便。
というわけで、プロジェクト設定のカスタムコマンドという機能を使って、プロジェクトビルド時にNDKビルドも実行できるよう設定します。

ここで1点問題。。。
この例では、カスタムコマンドにndk-buildのフルパスを記載しているんですが、チーム開発などには不便ですね。環境設定から値を読み出す方法とかご存知のかたいたらコメントなどいただければありがたいです。

まとめ

これで、Xamarin.AndroidプロジェクトでNDKネイティブコード含めてビルド・実行する環境が整いました。
プロジェクト内に一元管理することで、ビルド・デバッグのテンポがよくなる、リポジトリを分散させなくてすむなどのメリットが生まれるかと。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした