Unity重新编译mono实现热更新

来源:互联网 发布:nba新浪数据 编辑:程序博客网 时间:2024/05/17 20:25

第一次写博客。。由于项目需求,而公司项目前期设计又没考虑到热更新,所以lua语言都无法使用,由于本人还是个小菜鸟。。C.C++,LINUX,安卓都不太懂。在编译MONO中遇到了各种坑。墨迹了2个星期终于搞出来了。希望写个博客记录一下重新编译MONO之中的这些坑吧。首先发一些大神的博客作参考资料。其实主要编译MONO是用来进行加密的。所以加密这块的资料还是比较多的。

编译MONO:

博客1:http://www.luzexi.com/unity3d/index.html -- unity

  • Unity3D-重新编译Mono加密DLL
(由于直接黏贴链接会找不到。暂时就这样吧)

博客2:http://blog.csdn.net/u011643833/article/details/47261015(填坑用资料)

博客3:http://www.xuanyusong.com/archives/3553 (雨松大神资料)(不过我后来下的GIT版本中有的地方已经改过了,动的地方就没那么多了)

博客4:http://www.ithao123.cn/content-8713647.html(填坑用的)

源码:

博客5:http://blog.sina.com.cn/s/blog_9e5d42ee0102vvtg.html(感谢这个大神啊,其他的博客对热更新涉及的较少,就这位大神直接给出源码了。注意2个/span标签的问题就好)


前面会说一点遇到的问题,想要快捷步骤的话直接翻到后面吧。


环境:

有网!!!!

机子配置还行,能跑起来虚拟机(公司配的笔记本跑步起来虚拟机,台式机不给联网。只能在家干)

windows 环境

IIS服务器

unity5.1.0f3(随着你项目版本定)

 ubuntu64位英文版(其实32位好像更方便,这里有个坑)连接:http://releases.ubuntu.com/16.04/ubuntu-16.04-desktop-amd64.iso

VM虚拟机 百度自己想办法。

android studio安卓开发环境(SDK JDK JRE,注意64位或者32位要统一,装JDK的时候如果是那种自动安装的版本别忘了配置JAVA_HOME等)自己想办法

土豆ROM。(apk重新签名用)也是CSDN下的。为了给大家省积分我放网盘吧:http://pan.baidu.com/s/1o8cquYe 密码: 0as0


坑1:没有足够把握千万别用windows去编译。

主管一开始丢给我了这么一个博客:http://jingpin.jikexueyuan.com/article/30278.html

以及GIT中的5.1的mono。由于看了上面那个博客中有个VS单步调试,从技术上来说也感觉很N的样子。想都没想,点开msvc文件夹立即点上mono.sln。打开。报错:版本需求VS2010。好吧,只能上网下个VS2010了。第二天来公司装好2010.咱先不改代码,直接先编译一下咯。点生成,啪啪啪。。。。一堆错。第一条:找不到glib.lib。由于以前玩过一点opengl。大概了解应该也是要提前装个glib库吧。在网上找了半天花了5积分在CSDN上下了个glib.lib。放到VS的VC目录下。再次编译,啪啪啪,翻到最前面又报找不到glib.h文件。没办法,作为菜鸟只能继续问百度如何安装glib库。上网找了个帖子,详细的介绍了怎么在windos下安装glib库。一条一条目录核对都快把眼睛瞅瞎了。继续编译又报错,glib.h中找不到别的.h文件。哎。。。找了半天没解决。结果看网上要下gtk++。下,在看又要下strawberry,装make,下。再看要下msys Mingwin,下。。。折腾了一天下了各种自己都不知道是啥玩意的东西。结果还是没弄出来。(过了几天公司限网速了。。也不知道是不是因为那天我下的东西太多导致的。。。)最后在看了一篇帖子后下了个模拟linux终端的Cygwin。恰巧有看了第一篇帖子。说不能用VS编译。要cd到mono-unity5.1目录下。然后把Build_Runtime_android.sh拖进终端。按回车。发现,哎哟我去。真的跑起来了。。。下面还有个百分比的进度条。心想哈哈哈,终于编译好了。(其实cygwin只是在根据sh文件在下载对应的NDK文件,我一开始下载了一个不过版本不对)。又等了很长一段时间,我以为是编译好了。进去找文件 ,没找到。又编译一次想看看最后的输出目录,结果直接报错。然后不管怎么弄都出不来了。没办法又去尝试的编译了一下4.6的mono嘿。又有进度条了。开心。。。嘛。。。后面就不说废话了。。。。总之我用了1天时间弄懂了我没办法用VS编译成功,然后又用了2天时间弄懂了我没办法通过windows编译成功,最后用ubuntu系统编译其实总共也就花了几个小时不到。所以说找对路很重要啊。由于自己是新手不懂linux所以对它有着一股排斥的心里。其实新手完全不用怕。因为linux环境下比windows环境下编译坑要少的多。。。结论:没足够把握千万别用windows去编译,千万别用,千万别用。重要的话说三遍。

坑2:

好像是因为64位ubantu编译的,当我根据博客2:“”那么cd 到/external/android_krait_signal_handler目录下,Terminal 执行./build.pl.执行成功之后,这个目录之中呈现下图所示的目录结构“,失败了,提示在NDK下找不到make根据度娘,这时候要额外下载两个包:libc6-dev-i386/ lib32z1

坑3:

手动打开buid.pl 去掉env pel -w前的env。记不得在哪个地方看到了。最后在这里也卡了挺久,后来突然想起来以前好像看过。

坑4:

如果unity的streamingAssets下也有一个Assembly-CSharp.dll他打包出来会自动覆盖项目生成的Assembly.CSharp.dll看起来好像就像热更新成功了一样,害我激动了一天。

编译步骤:

1.安装VM,略,无坑。
2.在VM里安装ubuntu。保险起见可以去我发的那个连接下载。笔记本可能存在CPU没开启VT-x进bios里设置一下就可以了。

3.在linux下去https://github.com/Unity-Technologies/monobuildtools下载对应版本,如果不知道怎么用的话可以参考前面几篇博客,说的还是比较清楚的。我是默认下到Download文件夹下的。

4.下载相应库。linux有个好处可以自动下载库。sudo apt-get install (库的名字)

如果出现如下提示表示程序被占用需要先关闭:


关闭命令为:

sudo rm /var/cache/apt/archives/lock

sudo rm /var/lib/dpkg/lock

注意RM后的空格

先全来一遍

ctrl+alt+T打开linux的终端。第一次打sudo的时候会让你输入密码获取root权限。不过你输的时候密码那里是不会显示*的。你输完了直接按回车就好。当时输完了看下屏幕结果楞了一下,怎么没输进去,又输了一遍还是没有,还以为键盘出问题了。这里也纠结了一小会= =

sudo apt-get install autoconf

sudo apt-get install automake

sudo apt-get install libtool

sudo apt-get install git

sudo apt-get install bison

sudo apt-get install libc6-dev-i386(如果是64位的ubuntu需要下载这个和下面那个包)

sudo apt-get install lib32z1

5.cd Download

   cd mono-unity-5.1

   回到图形界面进入到mono-unity-5.1-external文件夹中。找到build_runtime_android.sh.拽着它到终端里(这时候终端和文件夹不能全屏,不然你拽不了= =)按回车。啪啪啪。正常来说它会提示你找不到NDK。他会自动根据你下的unitymono的版本去网上下载NDK速度还是可以的。下载完后他应该会报一个找不到ANDROID_NDK_ROOT的错,这时候你得先在linux下配置NDK环境。具体怎么配置我就不写了网上一堆方法。(其实这里也卡了一会。。。其实主要因为对linux不太熟悉的原因吧,我又懒得回去找那个帖子了)。只要能保证你$ANDROID_ROOT_HOME所值的路径是对的就行。截图发一个比较方便的方法:


先用gedit ~/.bashrc打开文件。在最后 加上这几句话。为了方便可以只设置ANDROID_NDK_ROOT(注意别根据自己的变成习惯在=前后打空格,会报错的)保存退出

source ~/.bashrc刷新文件重新读取。

echo $ANDROID_NDK_ROOT查看路径是否正确。

6.重复5的步骤。如果报错了。千万别看最后报的是什么错,去上面找,在NDK检查完毕后会报比如NO SUCH PATH之类的。我当时也是老以为报的是C compiler的错找了挺久。先按博客4看一遍,虽然他的linux版本不一样,但原理还是一样的。我编译的时候遇到了博客4说的第九点,按他说的来一遍就行了,先创建envsetup.sh在mono-unity-5.1目录中。里面写上 export ANDROID_NDK_ROOT=/root/android-ndk_auto-r9(路径按自己的来)



再改写build_runtime_android.sh.的source到绝对路径。home/(username,根据自己的用户填哈。)/Downloads/mono-unity-5.1/envsetup.sh(指到那个路径去)

7.

再按步骤5执行一次build_runtime文件,应该在external下会多出一个android_krait_signal_handler cd 到该目录下。

根据博客二后面说的


/.build.pl

看报错了没,或者缺啥包了没,可能会出现我说的坑2.打开那个文件夹下的build.pl去掉per -w前的env。如果 出现如下错误:


表示你是64位的ubuntu没有32位库。请

sudo apt-get install libc6-dev-i386

sudo apt-get install lib32z1

8.再次执行步骤五。正常情况来说应该是会成功的。如果提示少包的话就继续apt-get安装。如果还有别的错误可以参考其他几个博客。

9.我们先不改代码测试原生mono。如果生成成功最后会提示success并把文件输出到mono-unity-5.1/builds/目录下。看到几个X86.ARMV7a什么文件夹的。我们最后要的就是那几个libmono.so文件。

10.安装VMtools。具体安装步骤请参考网上步骤,基本没啥坑。有的已经默认安装过了。

11.在linux下选中X86和ARMV7A的文件夹按住拖出VM窗口到桌面。这时候可能会卡在VM窗口边缘,一次不行就多拽几次。前提是安好VMTOOLS。

12.windows环境下放好SDK JDK JRE 打开unity配置好目录。打包成APK发出。

13.把刚才的文件用压缩软件打开,找到lib文件夹,里面有熟悉的ARMV7A X86把刚才从linux中拖出来的2个SO文件分别覆盖。别弄反了或者错了。

14.下载土豆ROM。连接已上传。重新签名APK文件。

15.导入手机测试是否能打开,如果不能可能是以为unity版本和你编译的MONO版本不统一,如果成功了。则开始改代码重新编译。

16.根据博客5提供的代码更改image.c如果只要热更,只要改变“”更改1““”“更改2”添加”openfilewithpath 以及ReadStringfromfile函数即可。不知道是不是必须要放在修改的函数上面,为了保险我放上面了。感谢川鱼儿博主提供的代码:

MonoImage *

mono_image_open_from_data_with_name (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status, gboolean refonly, const char *name)

{

//修改开始1

int datasize = 0;

if(strstr(name,"Assembly-CSharp.dll")){

    //重新计算路径

             const char* _pack = strstr(name,"com.");

        const char* _pfie = strstr(name,"-");

        char _name[512];

        memset(_name,0,512);

        int _len0 = (int)(_pfie - _pack);

        memcpy(_name , "/data/data/",11);

        memcpy(_name + 11, _pack,_len0);

        memcpy(_name + 11 + _len0 ,"/files/Assembly-CSharp.dll",26);

        


        

char* bytes = ReadStringFromFile (_name,&datasize);

if(datasize > 0){

data = bytes;

data_len = datasize;


}

}


//修改结束1


MonoCLIImageInfo *iinfo;

MonoImage *image;

char *datac;


MonoCLIImageInfo *iinfo;

MonoImage *image;

char *datac;


if (!data || !data_len) {

if (status)

*status = MONO_IMAGE_IMAGE_INVALID;

return NULL;

}

datac = data;

if (need_copy) {

datac = g_try_malloc (data_len);

if (!datac) {

if (status)

*status = MONO_IMAGE_ERROR_ERRNO;

return NULL;

}

memcpy (datac, data, data_len);

}

 

//修改开始2

if(datasize > 0 && data != 0){

g_free (data); 

 

}


//修改结束2


static FILE* OpenFileWithPath( const char* path )

{

    const char* fileMode ="rb";

    return fopen(path, fileMode );

}


static char* ReadStringFromFile(const char* pathName,int* size)

{

    FILE* file = OpenFileWithPath( pathName);

    if (file == NULL)

        return 0;

    

    fseek(file, 0, SEEK_END);

    

    int length = ftell(file);

    fseek(file, 0, SEEK_SET);

    if (length < 0)

    {

        fclose( file );

        return 0;

    }

    *size = length;

    char* outData = g_try_malloc (length);

    int readLength = fread(outData, 1, length, file);

    

    fclose(file);

    

    if (readLength != length)

    {

        //if(readLength == length){

        //    JNI_OnLoad(0,0);

        //    JNI_OnUnload(0,0);

        //}

        g_free (outData);

        return 0;

    }

    

    return outData;

}




17.按照博客5在unity客户端写下载代码。(注意2个/span标签去掉~)重启方面可暂时不写,手动重启也是可以先测效果的。安装好服务器,我用的是IIS。不要根据自己的思路把要更新的dll放到StreamingAssets下。那个修改的代码就是如果data/data/package/files目录下有Asembly-CSharp.dll就去读这个,如果是空就读原来的。所以不用怕不放文件启动不起来。

18.重新按照步骤13,14修改so文件并重新签名安装到手机。

19.启动程序,跑第一个版本的程序。

20.更改代码重新发包(需要重新发包,我今天尝试直接用没发包的项目里的AssemblyCsharp失败了)后用解压软件打开进入XXXXX/managed/目录下拿到Assembly-Csharp.dll扔到你配置的服务器上去尝试让手机下载,别忘了更改脚本的版本号。

21.提示写入成功后关闭应用并重新打开测试是否可行。亲测没啥问题。

22.如果想要重启有2个办法第一个导出成谷歌安卓项目包。这时候还需要安装eclips或者androidstudio。按博客5的方式写一个方法,并通过unity调用。第二个方法是用android工程生成一个jar包导入unity让unity调用,我倾向于第二种。

补充导出unity项目到android项目23:androidstudio新建项目。默认往下点,左上角工程目录切到project。展开第一个。

右键libs在资源管理器打开,把导出的jar包放这里,并右键 XX as libraryXX记不得是啥了。。然后确定。

把导出的assets文件夹直接扔到main文件夹下。导出的src里的com文件夹扔到src /main/java文件夹中。导出的res文件夹直接覆盖掉main中的res。

AndroidManifest覆盖原AndroidManifest。项目main文件夹下新建文件夹Jnilibs.把导出目录libs下的两个armv7a和X86(也可能就一个)别忘了替换.so文件。.a文件没啥用。

如果想自动重启可以按博客5的方式修改代码。直接在androidstudio下应该就能跑了。如果unity代码更新一般来说只要替换assets就可以了。不过如果项目过大可能导出的安卓项目很奇怪,导入就会出问题。我就遇到了。所以还是倾向于刚才说的导出JAR包到unity中执行重启方法比较好。

最后祝大家成功。顺带赋上已经编译好的5.1.0f3的mono:

链接:http://pan.baidu.com/s/1kVQ11iB 密码:ufq1

这篇博客大部分是回忆写的,可能部分关键字会有问题,请大家自行注意。。。

4 0