LoginSignup
20
16

More than 3 years have passed since last update.

UnityでC++連携をする(2020年度版)

Last updated at Posted at 2020-05-10

概要

サーバー連携をする際に送る認証用データを作ったりしたくて、そういった箇所はリコンパイルが(比較的)難しいC++側で作り込みたいなと思ったのでそのやり方をまとめます。
まずはC++の簡単なファイルを作ってのUnity連携までを記載します。

なお、連携部分は以下を大いに参考にさせていただきました。

Unity iOS/Android共用プラグイン C++ライブラリ作成
https://qiita.com/satotin/items/05fad323de3101f775d5

動作環境

  • Mac OSX (10.15.4)
  • Xcode 11.4.1
  • Android Studio 3.5
  • Android NDK r17b
  • Crypto++ 8.2.0
  • Unity 2019.3.13f1

Unityプロジェクトの作成

とりあえず、サクっとUnityプロジェクトを作成します。こちらは割愛。

Assetsフォルダ直下に必要なフォルダを作成

以下になるように、Assetsフォルダ内にフォルダを作成していきます。

■ Assets
├ ■ Plugins: ネイティブ側の連携ソースを入れる
| ├ ■ iOS: iOSのビルド済のFrameworkを格納
| └ ■ Android: Androidのビルド済のsoファイルを格納
└ ■ Scripts: C#のスクリプトを格納
■ src: C++のビルドする環境などを格納
└ ■ CppBridge: C++のソースファイルを格納 (名前は何でもいいですが以下はこの前提で記載しています)

srcファイルは、Assetsの外側に配置します(そうしないと中のC++ファイルもビルド時に取り込まれちゃう)。

image.png

src 直下に Static Library を作成

とりあえずC++をいじるのにXcodeの環境を使っていきます。ということでStatic Libraryを作成します。

image.png

LanguageはSwiftだとC++連携も面倒なのでObjective-cにします。
とはいってもObjective-c は特には使わないから何でもいいんですが。

iOS側のビルド設定

Deployment Targetを 8.0 にします。

image.png

その後、Build Settingsより、以下を変更します。

  • Supported Platforms: iphoneos
  • Build Active Architecture Only : Debug / Releaseともに YES
  • Valid Architectures: arm64 armv7 armv7s

Android側のビルド設定

src直下に以下をそれぞれ作成します。

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

include $(CLEAR_VARS)

LOCAL_MODULE    := CppBridge_shared
LOCAL_MODULE_FILENAME := libcppbridge
LOCAL_CFLAGS    := -Werror
CPP_FILES := $(shell find $(LOCAL_PATH)/CppBridge -name *.cpp)
CPP_FILES += $(shell find $(LOCAL_PATH)/CppBridge -name *.c)
LOCAL_SRC_FILES += $(CPP_FILES:$(LOCAL_PATH)/%=%)
LOCAL_C_INCLUDES := $(LOCAL_PATH)/CppBridge
LOCAL_LDLIBS    := -llog

include $(BUILD_SHARED_LIBRARY)
Application.mk
APP_STL := c++_static
APP_CPPFLAGS := -frtti -DCC_ENABLE_CHIPMUNK_INTEGRATION=1 -std=c++11 -fsigned-char -Wno-extern-c-compat
APP_LDFLAGS := -latomic

APP_OPTIM        := debug
APP_ABI          := armeabi-v7a arm64-v8a x86
APP_PLATFORM     := android-14
APP_BUILD_SCRIPT := Android.mk

ビルドスクリプトの作成

Xcodeビルド時にiOS / Androidの両方ともビルドされるようにBuild Phases -> Run Scriptに処理を追加します。

image.png

スクリプトの内容
# iOSの成果物を移動
mv -f $TARGET_BUILD_DIR/libCppBridge.a $SRCROOT/../Assets/Plugins/iOS

# Androidの実行プログラム作成&移動
ANDROID_NDK_ROOT=<Android_NDKのパス>

$ANDROID_NDK_ROOT/ndk-build NDK_PROJECT_PATH=. NDK_APPLICATION_MK=$SRCROOT/Application.mk $*
rm -rf $SRCROOT/../Assets/Plugins/Android/**
mkdir $SRCROOT/../Assets/Plugins/Android/libs
mv -f $SRCROOT/libs/** $SRCROOT/../Assets/Plugins/Android/libs/

rm -rf $SRCROOT/libs
rm -rf $SRCROOT/obj

ビルド時の動作確認

ひとまず、簡単なC++のファイルを作ってビルドをしてみます。
https://qiita.com/satotin/items/05fad323de3101f775d5 に記載の内容をそのまま使わせていただきました。

NativeBridge.hpp
#ifndef NativeBridge_hpp
#define NativeBridge_hpp

extern "C" {
    int test();
}

#endif /* NativeBridge_hpp */
NativeBridge.cpp
#include "NativeBridge.hpp"
#include <stdio.h>

#ifdef __ANDROID__
#include <android/log.h>
#endif

int test(){
#ifdef __ANDROID__
    __android_log_write(ANDROID_LOG_DEBUG, "hello.cpp", "Hello,World!");
#else
    printf("Hello,World!\n");
#endif
    return 0;
}

XcodeでRunして、以下のように表示されてたら(多分)成功です。

image.png

その際、Unityへの配置は以下のようになります。

image.png

ちなみに、実行時にこんなのが出る場合、セキュリティでXcodeを許可するようにしましよう。

image.png

image.png

Unity側での動作確認

そんなわけで、いよいよUnityでの動作確認を行います。

その前に、配置された実行ファイルのプラットフォームが正しく設定されているかどうかを確認します。

Android側

image.png

いずれの実行ファイルも Android にだけチェックがついてたらOKです。

iOS側

image.png

iOS にだけチェックがついてたらOKです。

C#のソース作成

こちらも、 以下を大いに参考にさせてもらいました(というかほぼコピペさせてもらいました)
https://qiita.com/satotin/items/05fad323de3101f775d5

Scripts/PluginCall.cs
using UnityEngine;

public class PluginCall : MonoBehaviour {
    // Start is called before the first frame update
    void Start() {

    }

    // Update is called once per frame
    void Update() {

    }

    public void OnClickedButton() {
        Debug.Log("OnClickedButton");
        Plugins.NativeBridge.HelloTest();
    }
}

上記は、適当なボタンにアタッチしてOnClickedButtonが呼ばれるようにしておきます。

Plugins/NativeBridge.cs
using UnityEngine;
using System.Runtime.InteropServices;

namespace Plugins {
public class NativeBridge {
#if UNITY_IOS || UNITY_ANDROID
    #if UNITY_IOS 
        [DllImport ("__Internal")]
    #elif UNITY_ANDROID
        [DllImport ("CppBridge")]
    #endif
    private static extern int test();
#endif
    public static int HelloTest() {
#if UNITY_EDITOR
        Debug.Log("Call Native");
        return 1;
#else
            return test();
#endif
    }
}
}

一応はUnity Editorでも動かせるように適当な値を返すようにしてます。

実機ビルド

あとは、実機でビルドします。

image.png

iOS側は以下のように表示されました。

(Filename: ./Runtime/Export/Debug/Debug.bindings.h Line: 35)

Hello,World!

Android側のLogCatもこんな感じで表示されます。

05-10 20:46:00.171 20232 20261 D hello.cpp: Hello,World!
20
16
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
20
16