1. 程式人生 > >unity 呼叫C++庫(android+jni+window dll平臺實現)

unity 呼叫C++庫(android+jni+window dll平臺實現)

方便不知道如何再unity呼叫各平臺動態庫的同學參考,實測可用:

window案例

動態庫名

tracker_model.dll

位置

unity工程 Assets\Plugins目錄下

c# 關鍵呼叫

程式碼 

using UnityEngine;
using System.Collections;
using System.Runtime.InteropServices;
using System.Collections.Generic;

//[StructLayout(LayoutKind.Sequential)]
public struct Point3F {
 public float x;
 public float y;
 public float z;
}

public class Control : MonoBehaviour {

System.IntPtr center_data_prt;

System.IntPtr fingertips_data_prt;

[DllImport("tracker_model")]
 public static extern long points_init (string iin);

........

void Start () {
  handle = points_init(fileName);

...................

center_data_prt = Marshal. AllocHGlobal(Marshal.SizeOf(typeof(Point3F)));

fingertips_data_prt = Marshal. AllocHGlobal(Marshal.SizeOf(typeof(Point3F))*maxFingerTips);

tri_cnt = points_get_fingertips(handle, center_data_prt, fingertips_data_prt

}

 void Update () {

Point3F center = (Point3F)Marshal.PtrToStructure(
    (System.IntPtr)(center_data_prt.ToInt64()),typeof(Point3F));

for (int i = 0; i < tri_cnt; i++) {
    Point3F point = (Point3F)Marshal.PtrToStructure(
     (System.IntPtr)(fingertips_data_prt.ToInt64()+i*Marshal.SizeOf(typeof(Point3F))),typeof(Point3F));

}

}

void OnDestroy(){

Marshal.FreeHGlobal(center_data_prt);

Marshal.FreeHGlobal(fingertips_data_prt);

}

對應tracker_model.dll c++標頭檔案介面

#ifndef _model_api_H_
#define _model_api_H_

#ifdef WIN32
#ifdef HTM_DLL_EXPORT
#define HTM_API extern "C" _declspec(dllexport)
#else
#define HTM_API extern "C"  _declspec(dllimport)
#endif
#else
#define HTM_API
#endif

struct Point3F
{
 float x;
 float y;
 float z;
};

HTM_API long points_init(const char *config_file);

HTM_API int  points_get_tri(long handle, Point3F* triangle_vertex_list, int list_len);

~~~~~~~

具體動態庫編譯過程不敘述

Android jni

(android ndk 編譯c++庫過程 具體不敘述  jni工程製作也不敘述,網上有  ) jni方法: 進入專案資料夾, 生成JNI的標頭檔案, 使用命令: javah -classpath bin/classes -d jni com.example.hellomyjni.JniClient 命令解析: javah 生成標頭檔案; -classpath 使用類的位置(bin/classes), 都是.class檔案; -d jni 需要生成JNI的類(com.example.hellomyjni.JniClient), 包括[package].[classname]. 按F5重新整理專案, 專案會自動生成jni資料夾, 幷包含一個頭檔案com_example_hellomyjni_JniClient.h. 右鍵點選專案在Android Tools裡面點選Add NativeSupport, 就會自動生成: HelloMyJni.cpp和Android.mk.
*/ 1 unity使用c#呼叫android函式案例  製作unity的android外掛(具體流程百度)  建立完外掛和目錄後 unity工程下有Assets\Plugins\Android\libs目錄 2  eclipse下利用jni製作c++庫如下 h檔案=========================== #include <jni.h>
/* Header for class com_example_pluginar_arlib_JniAr */ #ifndef _Included_com_example_pluginar_arlib_JniAr
#define _Included_com_example_pluginar_arlib_JniAr
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_example_pluginar_arlib_JniAr
 * Method:    getVersion
 * Signature: ()Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_com_example_pluginar_arlib_JniAr_getVersion
  (JNIEnv *, jclass); #ifdef __cplusplus
}
#endif
#endif cpp檔案:================ #include <jni.h>
#include "com_example_pluginar_arlib_JniAr.h" JNIEXPORT jstring JNICALL Java_com_example_pluginar_arlib_JniAr_getVersion
  (JNIEnv *env, jclass jc){  return env->NewStringUTF("22");
} //下面這個和jni介面無關,是後面測試c#直接呼叫c++介面準備的測試介面 extern "C" {
 int getInt(){
  return 5;
 }
} eclipse自動生成的編譯配置檔案Application.mk
APP_MODULES  := Plugin
APP_OPTIM  := release
#APP_OPTIM  := debug
#APP_ABI   := all
APP_ABI   := armeabi armeabi-v7a x86 mips
#APP_ABI   := armeabi armeabi-v7a x86 mips arm64-v8a x86_64 mips64
APP_PLATFORM    := android-8
#NDK_TOOLCHAIN_VERSION := clang 總之最後生成我們需要的各平臺libPlugin.so庫(這些c++庫將被拷貝到unity工程Assets\Plugins\Android\libs目錄下)
對應的在eclipse jni工程中呼叫c++介面的java關鍵程式碼如下 public class Jni {
 
  // Load the native libraries.
    static {
    // System.loadLibrary("c++_shared");
  
  System.loadLibrary("Plugin");        //載入libPlugin.so
    }
   
 static public native String getVersion();
} public class ActivityMain extends UnityPlayerActivity {  //unity外掛具體百度
 Context mContext;
 private LinearLayout u3dLayout;
 UnityPlayer mUnityPlayer;
 Button bt1;
 Button bt2;
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  mContext = this;
  u3dLayout = (LinearLayout) findViewById(R.id.u3d_layout);
  mUnityPlayer = new UnityPlayer(this);
  View playerView = mUnityPlayer.getView();
  u3dLayout.addView(playerView);
  
  bt1 = (Button)findViewById(R.id.u3d_button1);
  bt2 = (Button)findViewById(R.id.button2);
  
  bt1.setOnClickListener(new OnClickListener() {
   
   @Override
   public void onClick(View v) {
    startActivity(new Intent(mContext,ActivityArManage.class));
   }
  });
  bt2.setOnClickListener(new OnClickListener() {
   
   @Override
   public void onClick(View v) {
    Toast.makeText(mContext, Jni.getVersion(), Toast.LENGTH_LONG).show();
   }
  });
 }  // only for test, C# in unity will call it 
 public int GetInt(){ 
  runOnUiThread(new Runnable() {
   
   @Override
   public void run() {
    // TODO Auto-generated method stub
    Toast.makeText(mContext, "Unity Button test", Toast.LENGTH_LONG).show();
   }
  });
  //send message to Unity object named ArManager
  UnityPlayer.UnitySendMessage("ArManager", "ZoomIn", "");
   return 1000; 
 }
 
 @Override
  public boolean onKeyDown(int keyCode, KeyEvent event) {
   if (keyCode == KeyEvent.KEYCODE_BACK) {
    onDestroy();
   }
   return true;
  }
} 基本的android測試程式碼就搭建完成,如果不放心可以不先做unity外掛不要extends UnityPlayerActivity,只用普通的android工程測試jni是否正確然後再製作unity外掛 unity下程式碼簡單,就是製作android外掛部分麻煩,具體不敘述: using UnityEngine;
using System.Collections;
using System.Runtime.InteropServices;
using System.Collections.Generic;

publicclassTestAndroidScript:MonoBehaviour{
intn=0;

[DllImport("Plugin")] // 注意工程下lib
c++庫名是libPlugin.so
publicstaticexternintgetInt();
//Usethisfor initialization
voidStart(){

}

//Updateiscalledonceper frame
voidUpdate(){

}

voidOnGUI(){
if(GUI.Button(newRect(20,20,250,100),"c#androidtest"+n)){
AndroidJavaClassjc=newAndroidJavaClass("com.unity3d.player.UnityPlayer");
AndroidJavaObjectjo=jc.GetStatic<AndroidJavaObject>("currentActivity");
n+=jo.Call<int>("GetInt");
}

if(GUI.Button(newRect(20,220,250,100),"c#c++test"+getInt())){

}
}
}