开始本篇文章之前我先为大家简单的介绍一下Android NDK编程的原理, 我们知道Android开发使用JAVA语言来编程它的运行效率要比C/C++低很多,为了让JAVA语言可以调用 C/C++ 这时候NDK就出现了,使用DNK可以很方便的实现 JAVA 与 C/C++之间的互相调用。NDK的工作原理是使用谷歌提供的NDK工具将C/C++的代码编译成 .so文件,最后使用JAVA代码与.so文件之间相互调用。下面我先说一下在Unity中结合Android NDK实现本地数据的共享的原理,如下图所示 ,Unity工程加入NDK后工程大致可分为三个部分 Android(JAVA) 、 C/C++(.so)、Unity(C#)它们之间是可以相互调用的,在之前的文章中我向大家介绍了 Android与Unity之间相互调用的原理,Unity3D研究院之打开Activity与调用JAVA代码传递参数(十八)。这种方式只能相互传递String字符串,少量数据传递时可以使用这种方式。如果是大量数据这样就有点限制了,其实我们可以把C/C++的代码做为一个中转站,实现两边的数据引用与共享。
首先在官网中下载NDK最新的安装包,安装包分为三个版本这里我下载使用的是MAC OS版本,最新版本已经到了R8。
下载地址:http://developer.android.com/sdk/ndk/index.html
OK,我们在Eclipse中创建一个Android工程,在res与src平级文件夹目录下创建一个jni的文件夹。接着在文件夹中创建两个代码文件,分别是C与C++还有一个配置文件Android.mk。
c.c代码一共分为两个方法,先说说方法Java_com_xys_UnityTestActivity_TestAddInt 这个方法是漏给Java代码调用的,jint表示此方法的返回值为整形,数据类型还可以是jlong 、jfloat、jdouble、 jobject、jboolean、jbyte、jchar、jshort,搞程序的一看就应该明白了吧?我就不一一解释了。 方法名中java开头是标准用法,com_xys表示当前程序的包名,UnityTestActivity表示当前类,TestAddInt表示方法名,在Android中就是调用这个方法的,这个方法实现了一个简单的整形相加的操作。在说说第二个方法int addInt(),这个方法是留给Unity中C#语言调用的,它的结构与上面不一样不能在Java代码中调用,同样它也就是实现整形相加的操作。
先是C的文件 c.c
#include <string.h>
#include <jni.h>
//Android中java代码调用此方法
jint
Java_com_xys_UnityTestActivity_TestAddInt( JNIEnv* env, jobject thiz ,jint a,jint b)
{
return addInt(a,b);
}
//Unity中C#代码调用此方法
int addInt(int a, int b)
{
return a + b;
}
在看看C++文件,它和C文件的调用原理差不多,不过值得注意的是C++中一定要把需要调用的方法写在extern “C”{ } 中,否则无法调用。
cplus.cpp
#include <string.h>
#include <jni.h>
//声明一个类
class MyClass
{
public:
static float add(float a, float b)
{
return a + b;
}
};
//外部调用的方法需要写在这里
extern "C"
{
jfloat
Java_com_xys_UnityTestActivity_TestAddFloat( JNIEnv* env, jobject thiz ,jfloat a,jfloat b)
{
return MyClass::add(a,b);
}
float addFloat(float a,float b)
{
return MyClass::add(a,b);
}
}
再看看第三个配置文件,文件中比较重要的两个变量 LOCAL_MODULE表示生成出的.so的名称 LOCAL_SRC_FILES 表示需要编译的文件,如果是多个C/C++文件中间需要使用 隔开。
Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := xuanyusong
LOCAL_SRC_FILES :=
c.c
cplus.cpp
include $(BUILD_SHARED_LIBRARY)
OK ,此时C/C++代码的准备工作就做完了,下面我们学习如何把c.c 与 cplus.cpp 一个C文件与一个C++文件一同打包进.so文件中。首先打开终端,cd到刚刚创建的jni目录下,然后执行一开始下载的DNK开发包中的ndk-build命令,你可以直接在android-ndk-r8中找到ndk-build然后拖拽到终端中即可,如果代码没有错误如图所示表示.so文件编译成功。
再看看当前Android工程的目录结构,libs -> armeabi -> libxuanyusong.so 就是刚刚编译生成的.so文件,xuanyusong.so前面的lib是系统默认添加的,大家不必惊慌。
下面我们编写Java代码,学习如何在java代码中调用C/C++,代码比较简单在OnCreat()方法中分别调用C与C++的方法,并且弹出一个Toast显示在界面中。
UnityTestActivity.java
package com.xys;
import android.os.Bundle;
import android.widget.Toast;
import com.unity3d.player.UnityPlayerActivity;
public class UnityTestActivity extends UnityPlayerActivity
{
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
//在这里调用.so中的两个方法,并且显示在屏幕中
Toast.makeText(getApplicationContext(), "整形 = " + TestAddInt(1,2)+" 浮点型 = " + TestAddFloat(1.5f, 1.1f),
Toast.LENGTH_LONG).show();
}
//声明c.c中的TestAddInt方法
public native int TestAddInt(int a, int b);
//声明cplus.cpp中的TestAddFloat方法
public native float TestAddFloat(float a, float b);
static
{
//加载.so文件
System.loadLibrary("xuanyusong");
}
}
好的,我们终于把Android的工程建立完毕。接着我们需要把工程拷贝至Unity的Android插件中, 插件的制作还有谁不会?? 不会的朋友请看之前的文章,这里就不赘述。如下图所示,Android插件已经制作完毕放在Unity中。目录结构如下所示。
编写test.cs脚本,实现通过C#脚本直接访问libxuanyusong.so文件,直接把test.cs挂在摄像机上。使用[DllImport (“xuanyusong”)]来引入.so 的方法, 这里注意的是 一定要把.so文件名的lib 与后缀.so去掉, 最后将数据通过GUI显示在屏幕中。
test.cs
using UnityEngine;
using System.Collections;
using System.Runtime.InteropServices;
public class test : MonoBehaviour {
int i = 0 ;
float f = 0.0f;
//引用C 、C++中的方法
[DllImport ("xuanyusong")]
private static extern int addInt(int a,int b);
[DllImport ("xuanyusong")]
private static extern float addFloat(float a,float b);
void Start ()
{
//调用方法中相加函数
i = addInt (1,2);
f = addFloat (1.0f,2.2f);
}
void OnGUI()
{
//将相加后的信息显示在屏幕中
if(i !=0)
GUILayout.Label(" use c =" + i );
if(f !=0.0f)
GUILayout.Label(" use cplus =" + f );
}
}
所有的工作已经做完,我们打包编译上真机,首先是在Android中调用.so时 弹出结果的Toast 。
然后是在Unity中调用.so后通过GUI绘制在屏幕中的结果,蛤蛤。Unity给力吧。。
最后雨松MOMO希望和大家一起进步,哇咔咔,啦啦啦,~~~本文下载内容包括 Android工程 与 Unity工程,欢迎大家下载学习。,不早了MOMO祝大家学习愉快并且Good night !
下载地址: http://vdisk.weibo.com/s/ab_Ll
- 本文固定链接: https://www.xuanyusong.com/archives/1129
- 转载请注明: 雨松MOMO于 雨松MOMO程序研究院 发表







IOS要使用C++的插件,可以编译成dll吗?我看官方手册上说:For cross platform plugins you must include the .bundle (for Mac), .dll (for Windows), and .so (for Linux) files in the Plugins folder. No further work is then required on your side – Unity automatically picks the right plugin for the target platform and includes it with the player.有谁做过这方面的实验,相烦说下相关经验!
雨松,您好,DllNotFoundException: xuanyusong 是什么原因,我自己写的例子,也报这个错误。
请问,这个问题你解决了吗?我也遇到了,不知道怎么解决,系统是mac
请问您最后是怎么解决的吗?我现在也遇到这个问题了
make money from photos…
[…]that could be the finish of this report. Here you?ll come across some web pages that we think you?ll value, just click the hyperlinks over[…]…
您好,下载例子后运行提示 DllNotFoundException: xuanyusong 请问这是为什么?
我自己编出来的.so文件在unity3d中调用也提示未找到。
我也遇到这种情况,请问你解决了吗?
这个例子做出来 是 Unity3d与C 交互 。 java与C 交互。 可是要怎么才能实现Unity和Android交互。。。 除了用作者写的文章(十八)(十九)的方法 还有什么方法捏
这个例子做出来 是 Unity3d与C++交互 。 java与C++交互。 可是要怎么才能实现Unity和Android交互。。。 除了用作者写的文章(十八)(十九)的方法 还有什么方法捏
我打包好在手机上怎么是强退啊 求帮助,还有你是怎么在unity3d上测试的啊?unity3d掉.so捏
报错问题解决了。 是多了一句这个this.setContentView(xxxxxx);希望大家引以为戒。 我找了好久。。。。
在ndk中也可以用UnitySendMessage来和u3d传数据吗
c# 是虚拟机运行的,可以跨平台,而c/c 编译的是native代码,无法跨平台
c# 是虚拟机运行的,可以跨平台,而c/c++编译的是native代码,无法跨平台
这个我还真不知道。 我们使用的是.so文件
请问雨松,unity3d调用c/c 的库,只能打包成so吗?打包成dll行吗?我在模拟器上OK,跑到android真机上不行,解包apk后发现,没有把我的dll放到assets目录下,我手动放进去也提示找不到dll,那么,android真机上读取dll的路径应该是哪里呢?多谢啊
请问雨松,unity3d调用c/c++的库,只能打包成so吗?打包成dll行吗?我在模拟器上OK,跑到android真机上不行,解包apk后发现,没有把我的dll放到assets目录下,我手动放进去也提示找不到dll,那么,android真机上读取dll的路径应该是哪里呢?多谢啊
Android下不能用dll在别的平台下可以, 因为android不支持DLL 所以必需使用.so
谢谢雨松,可是用c#写的dll却可以在android内使用,解包apk后发现存放在assets目录下。是不是因为mono会解析c#而不会解析c/c++的原因呢?
谢谢雨松,可是用c#写的dll却可以在android内使用,解包apk后发现存放在assets目录下。是不是因为mono会解析c#而不会解析c/c 的原因呢?
雨松,你好 ,我想问一下在安卓平台上用sqlite.db 这种数据库可行?我在U3D的Plugins里面放了 sqlite.dll,libsqlite.so,mono.data.sqlite.dll, mono.data.sqliteclient.dll.然后 如果是在 U3D 的编辑器里选择安卓平台,然后可以正常访问数据。但是如果是放到真机上就会提示
DllNotFoundException: sqlite3
07-15 13:27:33.550: INFO/Unity(31157): at (wrapper managed-to-native) Mono.Data.Sqlite.UnsafeNativeMethods:sqlite3_open_ v2 (byte[],intptr&,int,intptr)
07-15 13:27:33.550: INFO/Unity(31157): at Mono.Data.Sqlite.SQLite3.Open (System.String strFilename, SQLiteOpenFlagsEnum flags, Int32 maxPoolSize, Boolean usePool) [0x00000] in :0
07-15 13:27:33.550: INFO/Unity(31157): at Mono.Data.Sqlite.SqliteConnection.Open () [0x00000] in :0 ..你知道这种情况怎么处理么。。求教
115 网盘不给力啊 ,居然把我以前上传的文件删了 郁闷。 不过还好我重新上传了, 希望常来看我~
你说的语音控制 是调节声音大小 还是 录制音频 ?
不是。比如我说了一句 换模型,,U3D 里面可以对当前的建筑换模型。类似这种
支持,大好人啊,不过只是初学者,暂时用不到
不客气, 留着以后肯定能用到的。
呵呵,,,产量真快
蛤蛤!! 学习ing!!
自己沙发, 加油哇咔咔!
问下MOMO,游戏中C++ C# Android Unity都会用到么?是用在渲染上还是哪呀..
问下MOMO,游戏中C C# Android Unity都会用到么?是用在渲染上还是哪呀..
雨凇大大,必须使用Android插件吗??? 插件怎么制作??新手新手新手!!