首页 > Unity3D频道 > 【Unity3D研究院之游戏开发】 > Unity3D研究院之Android NDK编译C/C++结合Unity实现本地数据共享(二十八)
2012
06-02

Unity3D研究院之Android NDK编译C/C++结合Unity实现本地数据共享(二十八)

          开始本篇文章之前我先为大家简单的介绍一下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++的代码做为一个中转站,实现两边的数据引用与共享。

 

Unity3D研究院之Android NDK编译C/C++结合Unity实现本地数据共享(二十八) - 雨松MOMO程序研究院 - 1

 

首先在官网中下载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

 

在看看C++文件,它和C文件的调用原理差不多,不过值得注意的是C++中一定要把需要调用的方法写在extern “C”{ } 中,否则无法调用。

cplus.cpp

         再看看第三个配置文件,文件中比较重要的两个变量 LOCAL_MODULE表示生成出的.so的名称 LOCAL_SRC_FILES 表示需要编译的文件,如果是多个C/C++文件中间需要使用  \ 隔开。

Android.mk

 OK ,此时C/C++代码的准备工作就做完了,下面我们学习如何把c.c 与 cplus.cpp 一个C文件与一个C++文件一同打包进.so文件中。首先打开终端,cd到刚刚创建的jni目录下,然后执行一开始下载的DNK开发包中的ndk-build命令,你可以直接在android-ndk-r8中找到ndk-build然后拖拽到终端中即可,如果代码没有错误如图所示表示.so文件编译成功。

Unity3D研究院之Android NDK编译C/C++结合Unity实现本地数据共享(二十八) - 雨松MOMO程序研究院 - 2

 

         再看看当前Android工程的目录结构,libs -> armeabi -> libxuanyusong.so 就是刚刚编译生成的.so文件,xuanyusong.so前面的lib是系统默认添加的,大家不必惊慌。

 

Unity3D研究院之Android NDK编译C/C++结合Unity实现本地数据共享(二十八) - 雨松MOMO程序研究院 - 3

 

       下面我们编写Java代码,学习如何在java代码中调用C/C++,代码比较简单在OnCreat()方法中分别调用C与C++的方法,并且弹出一个Toast显示在界面中。

UnityTestActivity.java

 

     好的,我们终于把Android的工程建立完毕。接着我们需要把工程拷贝至Unity的Android插件中, 插件的制作还有谁不会?? 不会的朋友请看之前的文章,这里就不赘述。如下图所示,Android插件已经制作完毕放在Unity中。目录结构如下所示。

 

Unity3D研究院之Android NDK编译C/C++结合Unity实现本地数据共享(二十八) - 雨松MOMO程序研究院 - 4

 

         编写test.cs脚本,实现通过C#脚本直接访问libxuanyusong.so文件,直接把test.cs挂在摄像机上。使用[DllImport (“xuanyusong”)]来引入.so 的方法, 这里注意的是 一定要把.so文件名的lib 与后缀.so去掉, 最后将数据通过GUI显示在屏幕中。

test.cs

 

所有的工作已经做完,我们打包编译上真机,首先是在Android中调用.so时 弹出结果的Toast 。

 

Unity3D研究院之Android NDK编译C/C++结合Unity实现本地数据共享(二十八) - 雨松MOMO程序研究院 - 5

 

然后是在Unity中调用.so后通过GUI绘制在屏幕中的结果,蛤蛤。Unity给力吧。。

 

Unity3D研究院之Android NDK编译C/C++结合Unity实现本地数据共享(二十八) - 雨松MOMO程序研究院 - 6

 

最后雨松MOMO希望和大家一起进步,哇咔咔,啦啦啦,~~~本文下载内容包括 Android工程 与 Unity工程,欢迎大家下载学习。,不早了MOMO祝大家学习愉快并且Good night !

下载地址: http://vdisk.weibo.com/s/ab_Ll

 

雨松MOMO提醒您:亲,如果您觉得本文不错,快快将这篇文章分享出去吧 。另外请点击网站顶部彩色广告或者捐赠支持本站发展,谢谢!

--

最后编辑:
作者:雨松MOMO
专注移动互联网,Unity3D游戏开发
捐 赠如果您愿意花10块钱请我喝一杯咖啡的话,请用手机扫描二维码即可通过支付宝直接向我捐款哦。

  1. 大家可能会漏掉一个地方,就是把打包好的so文件放到plugins文件夹之后,在Unity里单击,看到Import Settings了吗,要把平台改成Android,然后把CPU改成ARMv7,不然在打包的时候是不会把这个dll打包进去的

  2. 你好,请问下,怎么做unity安卓插件,我现在的做法是在unity的assert文件夹下创建一个Plugins/Andriod 将我制作好的.so动态库放在下面,然后用你上面的方法调用,报错dllnotfoundexception,我想请问下是什么原因还是因为我的安卓插件做的不对,请momo知道下,急急急~~~~

  3. 我在unity里面dllimport一个第三方的so文件,按照规则去掉了lib和.so
    libtest.so [DllImport (“test”)]
    unity里放入了这个so文件
    放在了 plugins/Android/libs/armeabi/里
    导出了安卓工程到eclipse里
    我的这个so在工程目录下的libs/armeab-v7a/里可以找到
    然后运行该项目
    在真机上测试时load这个so报错,DllNotFoundException:test

    ide上的信息是
    tag Unity
    unable to load library ‘/data/data/com.test.testso/lib/libtest.so’
    native render plugin support disable:java.lang.UnsatisfiedLinkError:Cannot load library:find_library[1201]:139 ‘libtest.so’ failed to load previously

    tag dalvikvm
    Tring to load lib /data/data/com.test.testso/lib/test.so

    tag Unity
    Unable to find test

    tag Unity
    DllNotFoundException:test

    请问是我哪一步有问题吗?

    ps:1 我用的第三方的so文件 并非自己生成的
    2 在UnityPlayerActivity类里
    static
    {
    //加载.so文件
    System.loadLibrary(“xuanyusong”);
    }
    这一句我并没有写··不知道有没有关系··因为没带项目回家··暂时没法实验这点···

    希望大神帮忙看下问题所在 ,多谢

  4. 我想知道能不能注册带有函数参数的函数,比如 [DllImport (“xuanyusong”)] private static extern int addInt(int a,int b,callback func);

  5. 请问C/C++这一层能否向Java层或者Unity发送消息,打算用C++捕获系统的信号量再回传给Java或者Unity是否可行。

  6. 雨松,您好,DllNotFoundException: xuanyusong 是什么原因,我自己写的例子,也报这个错误。DllNotFoundException: xuanyusongtest.Start () (at Assets/test.cs:19)

    • 好吧,我知道为什么了!也给后面的人统一回复一下吧。1、在Unity中的Windows平台上根本无法使用so库,所以直接在Windwos用会报上面的错误。(开始一直以为unity在win下能够直接用so,还以为里面有做什么操作)。2、在Android中(linux)本身是支持so的,所以可以直接调用到。感觉这是个及其低端的错误,误以为unity可以用导致的。后面如果发现同样的问题,估计大部分是和我一样的原因了。所以在此特殊说明下

      • 一般安卓手机cpu是arm的,pc端cpu类似 x86之类。。安卓编译出的so也是手机硬件arm上才能运行的指令。windows的dll是电脑硬件x86才能运行的指令,两个动态库不能互用。不同硬件平台需要交叉编译

  7. 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.有谁做过这方面的实验,相烦说下相关经验!

  8. Pingback: make money from photos

  9. 这个例子做出来 是 Unity3d与C++交互 。 java与C++交互。 可是要怎么才能实现Unity和Android交互。。。 除了用作者写的文章(十八)(十九)的方法 还有什么方法捏

  10. 请问雨松,unity3d调用c/c++的库,只能打包成so吗?打包成dll行吗?我在模拟器上OK,跑到android真机上不行,解包apk后发现,没有把我的dll放到assets目录下,我手动放进去也提示找不到dll,那么,android真机上读取dll的路径应该是哪里呢?多谢啊

  11. 雨松,你好 ,我想问一下在安卓平台上用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 ..你知道这种情况怎么处理么。。求教