cocos2dx使用汇总备查

2023/04/01 cocos 共 20424 字,约 59 分钟

版本说明

3.x的最新版本是 cocos2d-x 3.17.2 ,4.x的最新版本是 cocos2d-x4.0

3.x的架构图:

4.x的架构图:

可以明显地看出:从4.0开始,不再只是JavaScript引擎,也不再支持网页端,支持网页端的JavaScript部分被单独剥离出来,统一使用Cocos Creator来完成。因此定位就比较清晰了,Cocos Creator主打小游戏的开发,当然也支持网页端,cocos2dx4.0开始只支持原生端的Lua和C++。因为网页端的小游戏本身就可以在原生端运行,因此以后主推的开发平台就是Cocos Creator,并配合TypeScript语言进行开发。cocos2dx基本上已经成为了过去式,但是也不代表无法使用,如果需要,仍然可以使用该引擎进行开发,相信很多团队都有很多适合自己的版本。

环境配置

官方的安装编译环境要求:Build Requirements - cocos2d-x

  • 下载解压 cocos2d-x 3.17.2 ,并把X:\cocos2d-x-3.17.2\tools\cocos2d-console\bin 设置到环境变量Path中,使得可以直接使用cocos命令。如果未设置到环境变量中,使用绝对路径也可以。

  • Python 2.7.5+, Python 2,7.10 reccomended, NOT Python 3+

    • 安装Python2,并设置Python安装路径到环境变量Path中,使得直接使用python命令能够调用到该Python2。
  • NDK r91c+ is required to build Android games (tested with r19c) May be called 19.2.xx from within Android Studio

  • Android Studio 3.4+ to build Android games (tested with 3.0)。 也可以不安装,不影响使用命令行打包。

  • Java8 Downloads - Oracle download java from oracle without login

  • 安装。执行:python setup.py,主要是按照提示设置两个路径:NDK路径和AndroidSDK路径,设置好后重新打开控制台终端。

  • 新建项目:cocos new HelloWorld -p com.xx.yy -l lua -d F:\CocosProjects ,提示是否同意发送数据时,可以选择N(不同意。)

  • 修改64位支持:修改gradle.propertiesPROP_APP_ABI=arm64-v8a

  • 运行项目

    • Windows版本:VisualStudio打开\frameworks\runtime-src\proj.win32 目录下的sln文件即可。

    • Android版本:进入frameworks\runtime-src\proj.android文件夹,运行如下命令:

      cocos run -p android
      

      gradle相关配置更新或下载完成,运行至真机/模拟器查看效果。或者直接用AndroidStudio打开frameworks\runtime-src\proj.android

编译

AndroidStudio老版本

使用官方推荐的AndroidStudio版本,以及老的gradle版本:

// 配置java8
classpath 'com.android.tools.build:gradle:3.1.0'
distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip

如果不想安装老版本的AndroidStudio,则可以直接用gradle进行命令行编译。如果官方的gradle比较慢的话,可以使用国内镜像,例如:

https://mirrors.cloud.tencent.com/gradle/gradle-4.4-all.zip

编译完成后,在app\build\outputs\apk目录下生成相应的debugrelease(未签名)的APK,其中debug版本的lua脚本是明文的,release版本的lua脚本被编译为luajit,文件扩展名为.luac。Lua编译工具使用的是tools\cocos2d-console\plugins\plugin_luacompilecocos2d-x-3.17.2使用的 LuaJIT 版本信息为:LuaJIT 2.1.0-beta2 ,GitHub镜像:https://github.com/LuaJIT/LuaJIT

错误及解决方法。

Invalid revision: 3.18.1-g262b901-dirty

解决:这个是因为使用了较高版本CMake导致,手动修改使用较低版本即可,步骤如下:

  1. 打开AndroidStudio菜单的Tools - SDK Manager,选择 SDK Tools , 勾选「Show Package Details」,向下滑动一直找到CMake,把CMake高版本的都去掉,只保留一个3.6版本的。
  2. 这个时候可能还不行,还需要删除安卓SDK目录(例如:D:\Android\Sdk)下的临时文件夹(.temp),清除缓存后才能生效。
gradle  Task :Demo:lint FAILED

解决:这个是因为编译的时候把lint警告也当做错误,从而终止了编译。解决办法就是不把警告当错误即可,在app/build.gradle 文件中添加配置:

android {
    //...
    lintOptions {
        abortOnError false
    }
}

参考: Gradle build: Execution failed for task :app:lint

AndroidStudio新版本(推荐)

笔者使用的AndroidStudio版本信息如下:

Android Studio Iguana | 2023.2.1 Patch 2
Build #AI-232.10300.40.2321.11668458, built on April 4, 2024
Runtime version: 17.0.9+0--11185874 amd64
VM: OpenJDK 64-Bit Server VM by JetBrains s.r.o.
Windows 10.0
GC: G1 Young Generation, G1 Old Generation
Memory: 512M
Cores: 16
Registry:
    ide.instant.shutdown=false

配置gradle使用一个稍高的版本,但也不能太高,例如:

// 配置java8
classpath 'com.android.tools.build:gradle:4.2.2'
distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-all.zip
    
// 国内镜像:https://mirrors.cloud.tencent.com/gradle/

    
// 如果要使用更高版本的gradle,可能需要配置较高的Java版本,例如:Java 11
distributionUrl = https\://services.gradle.org/distributions/gradle-7.3.3-all.zip
classpath 'com.android.tools.build:gradle:7.2.2'

Android Gradle 插件 8.3 版本说明 Android Developers

Android Studio Gradle插件版本与Gradle 版本对应关系_gradle版本对应关系

配置NDK版本:

// 如果后面so文件通过外部工具进行编译,则该可以不用该配置
// 使用该配置后,可以无须再设置 ndk.dir 配置,使用AndroidStudio的SDKManager下载的NDK版本
android {
    ndkVersion = "19.2.5345600" //"major.minor.build"
}

配置lib的cpu架构:

// 这样配置后,也无须设置 PROP_APP_ABI
android {
    defaultConfig {
        ndk {
            abiFilters = ["arm64-v8a"]
            //abiFilters.addAll(PROP_APP_ABI.split(':').collect { it as String })
        }
    }
}

配置sourceSets

android {
    sourceSets.main {
        java.srcDir "src"
        res.srcDir "res"
        // libs 目录设置到和 CMakeLists.txt 同级目录
        //jniLibs.srcDir "libs"
        jniLibs.srcDir "../../../../libs"	
        manifest.srcFile "AndroidManifest.xml"
    }
}

文件目录结构如下:

WinAppRun.bat 	 # 运行Win版可执行程序
libs			# 存放lib文件的
	arm64-v8a
		libcocos2dlua.so
frameworks
res				# 游戏资源目录
src				# 游戏脚本目录
runtime
simulator
.cocos-project.json
.project
CMakeLists.txt
config.json
README.md
UserDefault.xml

移除jni工程,因为AndroidStudio加载cpp太卡了,修改调试c++代码还是用VisualStudio比较丝滑。直接注释下面的代码即可:

// 临时注释:工程不再包含cpp项目,否则太卡了
//    externalNativeBuild {
//        if (project.hasProperty('PROP_REBUILD_NDK') && PROP_REBUILD_NDK=='true') {
//            if (PROP_BUILD_TYPE == 'ndk-build') {
//                ndkBuild {
//                    path "jni/Android.mk"
//                }
//            } else if (PROP_BUILD_TYPE == 'cmake') {
//                cmake {
//                    path "../../../../CMakeLists.txt"
//                }
//            }
//        }
//    }

为了灵活期间,可以增加一个配置开关来控制:

// 通过修改 gradle.properties 中的 PROP_BUILD_NDK 开关(true/false),来决定是否导入cocos的jni工程
externalNativeBuild {
    if (project.hasProperty('PROP_BUILD_NDK') && PROP_BUILD_NDK=='true') {
        if (PROP_BUILD_TYPE == 'ndk-build') {
            ndkBuild {
                path "jni/Android.mk"
            }
        } else if (PROP_BUILD_TYPE == 'cmake') {
            cmake {
                path "../../../../CMakeLists.txt"
            }
        }
    }
}

gradle.properties 文件中增加一个 PROP_BUILD_NDK 默认设置为false即可。

修改variant.mergeAssetsProvider.get().doLast 任务,使得可以根据gradle版本不同进行不同的处理:

// 打印当前Gradle版本
println "Current Gradle version: ${gradle.gradleVersion}"

// 判断Gradle版本并执行不同逻辑
if (gradle.gradleVersion.startsWith("4.")) {
    tempDir = "${buildDir}/intermediates/assets/${variant.dirName}"
} else {
    tempDir = "${buildDir}/intermediates/merged_assets/${variant.dirName}/out"
}

println "intermediates path: ${tempDir}"
def tempSrc = "${tempDir}/src"
def resSrc = "${tempDir}/res"

完整的gradle文件内容见后文。

常见错误

错误:cvc-complex-type.2.4.a: 发现了以元素 'base-extension' 开头的无效内容。应以 '{layoutlib}' 之一开头。
解决:升级Gradle。


Unable to start the daemon process.

The project uses Gradle 4.6 which is incompatible with Java 11 or newer.

Possible solution:
 - Upgrade Gradle wrapper to 7.2 version and re-import the project


// 解决办法:settings搜索gradle,修改gradle sdk版本为1.8
No version of NDK matched the requested version 20.0.5594570. Versions available locally: 23.1.7779620, 25.1.8937393, 25.2.9519653, 26.1.10909125

// 解决办法:local.properties添加:
ndk.dir=D\:\\NDK\\android-ndk-r19c


// 新版本在gradle里配置:
android {
    ndkVersion = "19.2.5345600" //"major.minor.build"
}
ld: error: lib/libluacocos2d.a(CCLuaEngine.cpp.o): unable to find library from dependent library specifier: lua51.lib

// 解决办法: 
#if (CC_TARGET_PLATFORM == CC_PLATFORM_WIN32)
#pragma comment(lib,"lua51.lib")
#endif

Cocos 4.0新建lua项目安卓打包报错,CCLuaEngine,lua51.lib

API 'variant.getMergeAssets()' is obsolete and has been replaced with 'variant.getMergeAssetsProvider()'.

// 解决办法:修改build.gradle,将:

variant.mergeAssets.doLast {
}
    
// 修改为:
    
variant.mergeAssetsProvider.get().doLast {
}
This app only has 32-bit [armeabi-v7a] native libraries. Beginning August 1, 2019 Google Play store requires that all apps that include native libraries must provide 64-bit versions. For more information, visit https://g.co/64-bit-requirement
Affected Modules: Bricks

// 解决办法:修改gradle.properties
// PROP_APP_ABI=armeabi-v7a
PROP_APP_ABI=arm64-v8a

缺失的类

LocalStorage

https://github.com/yangc999/jfclient/tree/master/frameworks/cocos2d-x/cocos/scripting/lua-bindings/manual/localstorage

打开VisualStudio工程,为libluacocos2d项目添加头文件和源文件,然后在 frameworks/cocos2d-x/cocos/scripting/lua-bindings/manual/lua_module_register.cpp 中添加:

#include "scripting/lua-bindings/manual/localstorage/lua_cocos2dx_localstorage_manual.h"

register_localstorage_module(L);

还缺少对Init函数的注册,需要添加:

int lua_cocos2dx_localstorage_Init(lua_State* L) {
	int argc = 0;
#if COCOS2D_DEBUG >= 1
	tolua_Error tolua_err;
	if (!tolua_isusertable(L, 1, "cc.LocalStorage", 0, &tolua_err)) goto tolua_lerror;
#endif

	argc = lua_gettop(L) - 1;
	if (argc == 1) {
#if COCOS2D_DEBUG >= 1
		if (!tolua_isstring(L, 2, 0, &tolua_err))
			goto tolua_lerror;
#endif
		std::string fullpath = tolua_tostring(L, 2, "");
		localStorageInit(fullpath);
		return 0;
	}
	return 0;

#if COCOS2D_DEBUG >= 1
	tolua_lerror:
	tolua_error(L, "#ferror in function 'lua_cocos2dx_localstorage_removeItem'.", &tolua_err);
	return 0;
#endif    
}

// 在 lua_register_cocos2dx_localstorage 函数中添加注册:
tolua_function(L, "init", lua_cocos2dx_localstorage_Init);

并修复lua_cocos2dx_localstorage_getItem一个BUG:

if (localStorageGetItem(key, &value)) {
	lua_pushlstring(L, value.c_str(), value.length());
	return 1;
}

完整代码如下。

//lua_cocos2dx_localstorage_manual.h

#ifndef COCOS_SCRIPTING_LUA_BINDINGS_LUA_COCOS2DX_LOCALSTORAGE_MANUAL_H
#define COCOS_SCRIPTING_LUA_BINDINGS_LUA_COCOS2DX_LOCALSTORAGE_MANUAL_H

#ifdef __cplusplus
extern "C" {
#endif
#include "tolua++.h"
#ifdef __cplusplus
}
#endif

TOLUA_API int register_localstorage_module(lua_State* L);

#endif // #ifndef COCOS_SCRIPTING_LUA_BINDINGS_LUA_COCOS2DX_CONTROLLER_MANUAL_H
//lua_cocos2dx_localstorage_manual.cpp

#include "scripting/lua-bindings/manual/localstorage/lua_cocos2dx_localstorage_manual.h"
#include "scripting/lua-bindings/manual/tolua_fix.h"
#include "scripting/lua-bindings/manual/LuaBasicConversions.h"
#include "storage/local-storage/LocalStorage.h"

int lua_cocos2dx_localstorage_setItem(lua_State* L)
{
	int argc = 0;
#if COCOS2D_DEBUG >= 1
    tolua_Error tolua_err;
    if (!tolua_isusertable(L,1,"cc.LocalStorage",0,&tolua_err)) goto tolua_lerror;
#endif

	argc = lua_gettop(L) - 1;
	if (argc == 2)
	{
#if COCOS2D_DEBUG >= 1
		if (!tolua_isstring(L, 2, 0, &tolua_err) ||
			!tolua_isstring(L, 3, 0, &tolua_err))
			goto tolua_lerror;
#endif
		std::string key = tolua_tostring(L, 2, "");
		//std::string value = tolua_tostring(L, 3, "");
		size_t size = 0;
		const char* data = (const char*)lua_tolstring(L, 3, &size);
		std::string value(data, size);
		localStorageSetItem(key, value);
		return 0;
	}
    return 0;

#if COCOS2D_DEBUG >= 1
tolua_lerror:
    tolua_error(L,"#ferror in function 'lua_cocos2dx_localstorage_setItem'.",&tolua_err);
    return 0;
#endif  
}

int lua_cocos2dx_localstorage_getItem(lua_State* L)
{
	int argc = 0;
#if COCOS2D_DEBUG >= 1
    tolua_Error tolua_err;
    if (!tolua_isusertable(L,1,"cc.LocalStorage",0,&tolua_err)) goto tolua_lerror;
#endif

	argc = lua_gettop(L) - 1;
	if (argc == 1)
	{
#if COCOS2D_DEBUG >= 1
		if (!tolua_isstring(L, 2, 0, &tolua_err))
			goto tolua_lerror;
#endif
		std::string key = tolua_tostring(L, 2, "");
		std::string value;
		if (localStorageGetItem(key, &value)) {
			lua_pushlstring(L, value.c_str(), value.length());
			return 1;
		}
	}
	return 0;

#if COCOS2D_DEBUG >= 1
tolua_lerror:
    tolua_error(L,"#ferror in function 'lua_cocos2dx_localstorage_getItem'.",&tolua_err);
    return 0;
#endif   
}

int lua_cocos2dx_localstorage_removeItem(lua_State* L)
{
	int argc = 0;
#if COCOS2D_DEBUG >= 1
    tolua_Error tolua_err;
    if (!tolua_isusertable(L,1,"cc.LocalStorage",0,&tolua_err)) goto tolua_lerror;
#endif

	argc = lua_gettop(L) - 1;
	if (argc == 1)
	{
#if COCOS2D_DEBUG >= 1
		if (!tolua_isstring(L, 2, 0, &tolua_err))
			goto tolua_lerror;
#endif
		std::string key = tolua_tostring(L, 2, "");
		localStorageRemoveItem(key);
		return 0;
	}
	return 0;

#if COCOS2D_DEBUG >= 1
tolua_lerror:
    tolua_error(L,"#ferror in function 'lua_cocos2dx_localstorage_removeItem'.",&tolua_err);
    return 0;
#endif    
}

int lua_cocos2dx_localstorage_clear(lua_State* L)
{
	int argc = 0;
#if COCOS2D_DEBUG >= 1
	tolua_Error tolua_err;
	if (!tolua_isusertable(L, 1, "cc.LocalStorage", 0, &tolua_err)) goto tolua_lerror;
#endif
	
	argc = lua_gettop(L) - 1;
	if (argc == 0)
	{
		localStorageClear();
		return 0;
	}
	return 0;

#if COCOS2D_DEBUG >= 1
tolua_lerror:
	tolua_error(L, "#ferror in function 'lua_cocos2dx_localstorage_removeItem'.", &tolua_err);
	return 0;
#endif    
}

int lua_cocos2dx_localstorage_Init(lua_State* L) {
	int argc = 0;
#if COCOS2D_DEBUG >= 1
	tolua_Error tolua_err;
	if (!tolua_isusertable(L, 1, "cc.LocalStorage", 0, &tolua_err)) goto tolua_lerror;
#endif

	argc = lua_gettop(L) - 1;
	if (argc == 1) {
#if COCOS2D_DEBUG >= 1
		if (!tolua_isstring(L, 2, 0, &tolua_err))
			goto tolua_lerror;
#endif
		std::string fullpath = tolua_tostring(L, 2, "");
		localStorageInit(fullpath);
		return 0;
	}
	return 0;

#if COCOS2D_DEBUG >= 1
	tolua_lerror:
	tolua_error(L, "#ferror in function 'lua_cocos2dx_localstorage_removeItem'.", &tolua_err);
	return 0;
#endif    
}

int lua_register_cocos2dx_localstorage(lua_State* L)
{
    tolua_usertype(L,"cc.LocalStorage");
    tolua_cclass(L,"LocalStorage","cc.LocalStorage","",nullptr);

    tolua_beginmodule(L,"LocalStorage");
		tolua_function(L, "init", lua_cocos2dx_localstorage_Init);
		tolua_function(L, "setItem", lua_cocos2dx_localstorage_setItem);
        tolua_function(L, "getItem", lua_cocos2dx_localstorage_getItem);
        tolua_function(L, "removeItem", lua_cocos2dx_localstorage_removeItem);
		tolua_function(L, "clear", lua_cocos2dx_localstorage_clear);
    tolua_endmodule(L);
    std::string typeName = "localStorage";
    g_luaType[typeName] = "cc.LocalStorage";
    g_typeCast["LocalStorage"] = "cc.LocalStorage";
    return 1;
}

int register_all_cocos2dx_localstorage(lua_State* L)
{
    tolua_open(L);
    
    tolua_module(L,"cc",0);
    tolua_beginmodule(L,"cc");

    lua_register_cocos2dx_localstorage(L);

    tolua_endmodule(L);
    return 1;
}

int register_localstorage_module(lua_State* L)
{
    lua_getglobal(L, "_G");
    if (lua_istable(L,-1))//stack:...,_G,
    {
        register_all_cocos2dx_localstorage(L);
    }
    lua_pop(L, 1);
    return 1;
}

还要为Android工程添加这俩文件,步骤如下:

找到文件 /frameworks/cocos2d-x/cocos/scripting/lua-bindings/CMakeLists.txt 添加上述的头文件和源文件:

set(
	...
    manual/localstorage/lua_cocos2dx_localstorage_manual.h
    )

set(
	...
    manual/localstorage/lua_cocos2dx_localstorage_manual.cpp
    )

Gradle优化

模板创建的build.gradle太复杂了,简单优化了下:

import org.gradle.internal.os.OperatingSystem

apply plugin: 'com.android.application'

android {
    compileSdkVersion PROP_COMPILE_SDK_VERSION.toInteger()

    lintOptions {
        abortOnError false
    }

    ndkVersion = "19.2.5345600" //"major.minor.build"

    defaultConfig {
        applicationId "com.sing.demo"
        minSdkVersion PROP_MIN_SDK_VERSION
        targetSdkVersion PROP_TARGET_SDK_VERSION
        versionCode 1
        versionName "1.0"


        ndk {
            abiFilters = ["arm64-v8a"]
            //abiFilters.addAll(PROP_APP_ABI.split(':').collect { it as String })
        }

        externalNativeBuild {
            if (PROP_BUILD_TYPE == 'ndk-build') {
                ndkBuild {
                    targets 'cocos2dlua'
                    arguments 'NDK_TOOLCHAIN_VERSION=clang'
                    arguments '-j' + Runtime.runtime.availableProcessors()

                    def module_paths = [project.file("../../../cocos2d-x").absolutePath,
                                        project.file("../../../cocos2d-x/cocos").absolutePath,
                                        project.file("../../../cocos2d-x/external").absolutePath]
                    if (OperatingSystem.current().isWindows()) {
                        module_paths = module_paths.collect { it.replaceAll('\\\\', '/') }
                        arguments 'NDK_MODULE_PATH=' + module_paths.join(";")
                    } else {
                        arguments 'NDK_MODULE_PATH=' + module_paths.join(':')
                    }
                }
            } else if (PROP_BUILD_TYPE == 'cmake') {
                cmake {
                    arguments "-DCMAKE_FIND_ROOT_PATH=", "-DANDROID_STL=c++_static", "-DANDROID_TOOLCHAIN=clang", "-DANDROID_ARM_NEON=TRUE"
                    cppFlags "-frtti -fexceptions -fsigned-char"
                }
            }
        }

    }

    sourceSets.main {
        java.srcDir "src"
        res.srcDir "res"
        //jniLibs.srcDir "libs"
        jniLibs.srcDir "../../../../libs"
        manifest.srcFile "AndroidManifest.xml"
    }

    // 通过修改 gradle.properties 中的 PROP_BUILD_NDK 开关(true/false),来决定是否导入cocos的jni工程
    externalNativeBuild {
        if (project.hasProperty('PROP_BUILD_NDK') && PROP_BUILD_NDK == 'true') {
            if (PROP_BUILD_TYPE == 'ndk-build') {
                ndkBuild {
                    path "jni/Android.mk"
                }
            } else if (PROP_BUILD_TYPE == 'cmake') {
                cmake {
                    path "../../../../CMakeLists.txt"
                }
            }
        }
    }

    signingConfigs {
        release {
            if (project.hasProperty("RELEASE_STORE_FILE")) {
                storeFile file(RELEASE_STORE_FILE)
                storePassword RELEASE_STORE_PASSWORD
                keyAlias RELEASE_KEY_ALIAS
                keyPassword RELEASE_KEY_PASSWORD
            }
        }
    }

    buildTypes {
        release {
            debuggable false
            jniDebuggable false
            renderscriptDebuggable false
            minifyEnabled true
            shrinkResources true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            if (project.hasProperty("RELEASE_STORE_FILE")) {
                signingConfig signingConfigs.release
            }

            externalNativeBuild {
                ndkBuild {
                    arguments 'NDK_DEBUG=0'
                }
            }
        }

        debug {
            debuggable true
            jniDebuggable true
            renderscriptDebuggable true
            externalNativeBuild {
                ndkBuild {
                    arguments 'NDK_DEBUG=1'
                }
            }
        }
    }
}

def getCocosCommandPath() {
    if (OperatingSystem.current().isWindows()) {
        return 'cocos.bat'
    } else {
        // on unix like system, can not get environments variables easily
        // so run a shell script to get environment variable sets by cocos2d-x setup.py
        new ByteArrayOutputStream().withStream { os ->
            def result = exec {
                executable = project.file('get_environment.sh')
                standardOutput = os
            }
            ext.console_path = os.toString().trim()
        }
        return new File(console_path + '/cocos').absolutePath
    }
}

// a method used to invoke the cocos luacompile command
def compileLua(srcDir, dstDir, doCompile, is64bit, doEncrypt) {
    def compileArgs = ['luacompile', '-s', srcDir, '-d', dstDir]
    if (!doCompile) {
        compileArgs << '--disable-compile'
    } else if (is64bit) {
        compileArgs << '--bytecode-64bit'
    }

    if (doEncrypt) {
        compileArgs << '-e'
        compileArgs << '-k'
        compileArgs << project.property('PROP_LUA_ENCRYPT_KEY')
        compileArgs << '-b'
        compileArgs << project.property('PROP_LUA_ENCRYPT_SIGN')
    }

    // commandLine compileArgs
    println 'running command : ' + 'cocos ' + compileArgs.join(' ')
    exec {
        // if you meet problem, just replace `getCocosCommandPath()` to the path of cocos command
        executable getCocosCommandPath()
        args compileArgs
    }

    // remove the lua files in dstDir
    delete fileTree(dstDir) {
        include '**/*.lua'
    }
}

android.applicationVariants.all { variant ->
    // delete previous files first
    delete "${buildDir}/intermediates/assets/${variant.dirName}"

    variant.mergeAssetsProvider.get().doLast {
        def tempDir = ""

        // 打印当前Gradle版本
        println "Current Gradle version: ${gradle.gradleVersion}"

        // 判断Gradle版本并执行不同逻辑
        if (gradle.gradleVersion.startsWith("4.")) {
            tempDir = "${buildDir}/intermediates/assets/${variant.dirName}"
        } else {
            tempDir = "${buildDir}/intermediates/merged_assets/${variant.dirName}/out"
        }

        println "intermediates path: ${tempDir}"
        def tempSrc = "${tempDir}/src"
        def resSrc = "${tempDir}/res"

        copy {
            from "${buildDir}/../../../../../res"
            into "${resSrc}"
        }

        copy {
            from "${buildDir}/../../../../../src"
            into "${tempSrc}"
        }

        // compile & encrypt the scripts if necessary
        def compileScript = (variant.name.compareTo('release') == 0)
        if (project.hasProperty('PROP_COMPILE_SCRIPT')) {
            compileScript = (PROP_COMPILE_SCRIPT.compareTo('1') == 0)
        }

        def encryptLua = project.hasProperty('PROP_LUA_ENCRYPT') && (PROP_LUA_ENCRYPT.compareTo('1') == 0)
        if (compileScript || encryptLua) {
            // -1 means not build bytecode
            // 0 means build 32bit only
            // 1 means build 64bit only
            // 2 means build both 32bit & 64bit
            def buildType = -1
            if (compileScript) {
                def need64 = false
                def need32 = false
                android.defaultConfig.ndk.getAbiFilters().each { abi ->
                    if (abi == 'arm64-v8a') {
                        need64 = true
                    } else {
                        need32 = true
                    }
                }

                if (need64 && need32) {
                    buildType = 2
                } else if (need64) {
                    buildType = 1
                } else {
                    buildType = 0
                }
            }

            println "buildType is  ${buildType} "
            // invoke cocos command to compile & encrypt the lua files
            switch (buildType) {
                case -1:
                    compileLua("${tempSrc}", "${tempSrc}", false, false, encryptLua)
                    break
                case 0:
                    compileLua("${tempSrc}", "${tempSrc}", true, false, encryptLua)
                    break
                case 1:
                    compileLua("${tempSrc}", "${tempSrc}", true, true, encryptLua)
                    break
                case 2:
                    compileLua("${tempSrc}", "${tempSrc}/64bit", true, true, encryptLua)
                    compileLua("${tempSrc}", "${tempSrc}", true, true, encryptLua)
                    break
            }
        }
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation project(':libcocos2dx')
}

可以在gradle.properties中添加一个配置:

PROP_REBUILD_NDK=true

# uncomment it and fill in sign information for release mode
RELEASE_STORE_FILE=../sign.keystore
RELEASE_STORE_PASSWORD=xxxxx
RELEASE_KEY_ALIAS=xxx
RELEASE_KEY_PASSWORD=xxxxx

编译SO的脚本

BuilSO.bat

@REM set abi=armeabi-v7a
set abi=arm64-v8a
set ANDROID_SDK_HOME=D:/Android/Sdk
set ANDROID_NDK_HOME=D:/Android/Sdk/ndk/19.2.5345600
set CMAKE_VERSION=3.10.2.4988404
set CMAKE=%ANDROID_SDK_HOME%/cmake/%CMAKE_VERSION%/bin/cmake
set NINJA=%ANDROID_SDK_HOME%/cmake/%CMAKE_VERSION%/bin/ninja

if not exist %abi% md %abi%
cd %abi%

%CMAKE% ^
  -DANDROID_ABI=%abi% ^
  -DANDROID_NDK=%ANDROID_NDK_HOME% ^
@REM  -DCMAKE_BUILD_TYPE=Debug ^
  -DCMAKE_BUILD_TYPE=Release^
  -DCMAKE_TOOLCHAIN_FILE=%ANDROID_NDK_HOME%/build/cmake/android.toolchain.cmake ^
  -DANDROID_NATIVE_API_LEVEL=16 ^
  -DANDROID_STL=c++_static ^
  -DANDROID_TOOLCHAIN=clang -DCMAKE_GENERATOR="Ninja" ^
  -DCMAKE_MAKE_PROGRAM=%NINJA% ^
  ..

%NINJA%

cd ..

把该批处理文件放置在和CMakeLists.txt 同级目录下,运行后会创建一个临时目录,目录下会有生成的so文件,复制出来使用即可。为了优化so的编译体积,可以在CMakeLists.txt 中增加如下设置:

# 优化编译的so体积
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -Os -Wall -s")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -Os -Wall -s")

日常开发

  • 维持cocos2dx的命令行创建的项目工程目录不变,需要做的主要是修改目录ressrc下的文件。

  • 使用CocosStudio设计的UI素材发布后直接复制到res目录下即可。

  • src下就是编辑脚本代码。

  • 在Windows上使用VisualStudio编译的可执行程序运行,方便直接查看运行效果,效率会高很多,一旦将要发布的时候再进行编译打包。

  • 运行测试:在项目的根目录下(res所在目录)创建一个WinAppRun.bat,日常测试就运行它就可以了,非常方便。

    call .\simulator\win32\AppName.exe
    
  • 如果有少量的代码需要编写Java代码时,可以用AndroidStudio打开项目进行Java代码的编写。如果是C++代码,仍然建议使用VisualStudio进行编写,效率会高很多。

  • AndroidStudio可以用新版,但是gradle版本仍旧用默认的老版本,无论AndroidStudio怎么提示都不要升级,能保证在IDE里正常编写Java代码即可,最后用命令行的方式编译打包。

打包发布

Windows

VisualStudio直接编译,也可以使用VisualStudio的命令行编译。

Android

使用老版本gradle(4.4版本)直接命令行打包,不建议使用AndroidStudio打开,太卡了。

下载地址:

https://mirrors.cloud.tencent.com/gradle/gradle-4.4-all.zip

下载好之后解压,老版本gradle只能使用Java8,因此环境变量JAVA_HOME要修改为指向Java8的安装目录。其实不修改系统的环境变量也可以,直接修改gradle.bat文件中JAVA_HOME指向Java8路径即可,这样最绿色环保。

然后进入到项目目录下,直接使用gradle build命令进行编译:

 F:\CocosProjects\Demo\frameworks\runtime-src\proj.android> F:\gradle\gradle-4.4\bin\gradle.bat build

也可以只生成release版本,节省时间:

gradle assemblerelease 

三方SDK

SDK功能作用简介官方链接
Google Play Services提供了广泛的 Google API 功能,包括广告服务、地图、身份验证等。Google Play Services SDK
Facebook提供了 Facebook 社交平台集成,包括登录、分享、分析等功能。Facebook SDK for Android
Facebook Audience Network将 Audience Network SDK 添加到您的 Android 应用 
AppLovin提供了移动广告解决方案,包括广告展示、收益最大化等功能。others-AppLovin广告接入_applovin 拉取applovin官方广告AppLovin SDK
Unity Ads提供了 Unity 游戏开发平台的广告服务,用于在游戏中展示广告并获取收益。Unity Ads SDK
Firebase提供了一系列的移动应用开发工具,包括分析、远程配置、消息推送等功能,全面支持应用开发和增长。将 Firebase 添加到您的 Android 项目 Firebase for AndroidFirebase SDK
appsflyer  
 使用入门:在 Android 项目中使用 AdMob Firebase with Google AdMob 

参考资料

文档信息

Search

    Table of Contents