引言 Cocos2d-x 作为经典的跨平台游戏引擎,其 Android 平台的构建配置一直是开发者关注的重点。随着 Android Studio 成为官方推荐的开发环境,掌握 Cocos2d-x 在 Android Studio 中的项目配置变得至关重要。本文将从零开始,详细介绍 Cocos2d-x 3.x 项目在 Android Studio 中的完整配置流程,包括 Gradle 构建、NDK 编译、Android.mk 自动遍历、闪屏实现等核心环节。
项目结构概览 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 ┌─────────────────────────────────────────────────────────────────────┐ │ Cocos2d-x Android Studio 项目结构 │ ├─────────────────────────────────────────────────────────────────────┤ │ │ │ MyGame/ │ │ ├── cocos2d/ # Cocos2d-x 引擎源码 │ │ │ ├── cocos/ │ │ │ ├── external/ │ │ │ └── ... │ │ ├── Classes/ # 游戏 C++ 源码 │ │ │ ├── AppDelegate.cpp │ │ │ ├── HelloWorldScene.cpp │ │ │ └── ... │ │ ├── Resources/ # 游戏资源文件 │ │ └── proj.android-studio/ # Android Studio 项目目录 │ │ ├── app/ # 游戏主模块 │ │ │ ├── build.gradle │ │ │ ├── src/ │ │ │ ├── jni/ │ │ │ │ ├── Android.mk │ │ │ │ └── Application.mk │ │ │ └── AndroidManifest.xml │ │ ├── settings.gradle │ │ ├── build.gradle │ │ └── gradle.properties │ │ │ └─────────────────────────────────────────────────────────────────────┘
基础配置文件 local.properties(本地环境配置) local.properties 用于指定本地 Android SDK 和 NDK 路径,该文件不应加入版本控制。
1 2 3 4 5 6 ndk.dir =C:\\android-ndk-r16b sdk.dir =C:\\Users\\Administrator\\AppData\\Local\\Android\\Sdk
属性
说明
示例
ndk.dir
NDK 安装路径
C:\android-ndk-r16b
sdk.dir
Android SDK 路径
C:\Users\...\Android\Sdk
settings.gradle(模块配置) settings.gradle 定义了项目包含的模块及其路径。注意 libcocos2dx 的相对路径必须正确。
1 2 3 4 5 include ':libcocos2dx' project (':libcocos2dx' ).projectDir = new File (settingsDir, '../cocos2d/cocos/platform/android/libcocos2dx' )include ':xxxGame' project (':xxxGame' ).projectDir = new File (settingsDir, 'app' )
注意事项 :
libcocos2dx 版本不能太低,否则可能出现 No implementation found for void org.cocos2dx.lib.Cocos2dxHelper.nativeSetAudioDeviceInfo 错误
xxxGame 替换为实际的游戏项目名称
gradle.properties(项目属性) 1 2 3 4 5 PROP_TARGET_SDK_VERSION =14 PROP_APP_ABI =armeabi-v7a
属性
说明
常用值
PROP_TARGET_SDK_VERSION
Android 平台版本
14, 21, 28
PROP_APP_ABI
目标 CPU 架构
armeabi-v7a, arm64-v8a, x86
Gradle 构建配置 顶层 build.gradle 项目级的 build.gradle 配置构建工具和仓库地址:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 buildscript { repositories { jcenter() google() } dependencies { classpath 'com.android.tools.build:gradle:2.3.3' } } allprojects { repositories { jcenter() google() } }
libcocos2dx 模块 build.gradle 引擎库模块的配置:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 apply plugin: 'com.android.library' android { compileSdkVersion 24 buildToolsVersion "26.0.2" defaultConfig { minSdkVersion 10 targetSdkVersion 24 versionCode 1 versionName "1.0" } sourceSets .main { aidl.srcDir "../java/src" java.srcDir "../java/src" manifest.srcFile "AndroidManifest.xml" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt' ), 'proguard-rules.pro' } } } dependencies { compile fileTree (dir: 'libs' , include : ['*.jar' ]) }
游戏主模块 build.gradle 游戏模块的配置最为复杂,需要配置 NDK 编译、签名和资源路径:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 import org.apache.tools.ant .taskdefs.condition.Osapply plugin: 'com.android.application' android { compileSdkVersion 24 buildToolsVersion "26.0.2" compileOptions.encoding = "UTF-8" defaultConfig { applicationId "com.xxxx.xxxGame" minSdkVersion 10 targetSdkVersion 23 versionCode 1 versionName "1.0" externalNativeBuild { ndkBuild { if (!project .hasProperty("PROP_NDK_MODE" ) || PROP_NDK_MODE.compareTo ('none' ) != 0 ) { targets 'cocos2dcpp' arguments 'NDK_TOOLCHAIN_VERSION=4.9' arguments 'APP_PLATFORM=android-' + PROP_TARGET_SDK_VERSION def module_paths = [ project .file ("../../cocos2d" ).absolutePath, project .file ("../../cocos2d/cocos" ).absolutePath, project .file ("../../cocos2d/external" ).absolutePath ] if (Os.isFamily(Os.FAMILY_WINDOWS)) { module_paths = module_paths.collect { it.replaceAll('\\\\' , '/' ) } arguments 'NDK_MODULE_PATH=' + module_paths.join (";" ) } else { arguments 'NDK_MODULE_PATH=' + module_paths.join (':' ) } arguments '-j' + Runtime .runtime .availableProcessors() abiFilters.addAll(PROP_APP_ABI.split(':' ).collect { it as String }) } } } } sourceSets .main { java.srcDir "src" res.srcDir "res" jniLibs.srcDir "libs" manifest.srcFile "AndroidManifest.xml" assets.srcDir "../../Resources" } externalNativeBuild { ndkBuild { path "jni/Android.mk" } } signingConfigs { release { keyAlias 'xxx' keyPassword 'xxxx' storeFile file ('E:/xxxx.keystore' ) storePassword 'xxx' } } buildTypes { release { minifyEnabled false externalNativeBuild { ndkBuild { arguments 'NDK_DEBUG=0' } } signingConfig signingConfigs.release } debug { externalNativeBuild { ndkBuild { arguments 'NDK_DEBUG=1' } } } } } dependencies { compile fileTree (include : ['*.jar' ], dir: 'libs' ) compile project (':libcocos2dx' ) }
配置项
说明
externalNativeBuild
NDK 构建配置
ndkBuild.targets
编译目标名称
arguments '-j'
并行编译线程数
abiFilters
过滤支持的 CPU 架构
assets.srcDir
游戏资源目录路径
NDK 编译配置 Android.mk(自动遍历 C++ 源文件) Android.mk 是 NDK 构建的核心文件。以下配置实现了自动遍历 Classes 目录下的所有 .cpp 文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 LOCAL_PATH := $(call my-dir ) include $(CLEAR_VARS) $(call import-add-path,$(LOCAL_PATH) /../../../cocos2d) $(call import-add-path,$(LOCAL_PATH) /../../../cocos2d/external) $(call import-add-path,$(LOCAL_PATH) /../../../cocos2d/cocos) $(call import-add-path,$(LOCAL_PATH) /../../../cocos2d/cocos/audio/include) LOCAL_MODULE := cocos2dcpp_shared LOCAL_MODULE_FILENAME := libcocos2dcpp define walk $(wildcard $(1) ) $(foreach e, $(wildcard $(1) /*), $(call walk, $(e) ) ) endef define uniq $(eval seen :=) $(foreach _,$(1) ,$(if $(filter ${_},${seen}) ,,$(eval seen += ${_}) )) ${seen} endef ALLFILES = $(call walk, $(LOCAL_PATH) /../../../Classes) FILE_LIST := $(filter %.cpp, $(ALLFILES) ) LOCAL_SRC_FILES := $(FILE_LIST:$(LOCAL_PATH) /%=%) LOCAL_SRC_FILES += ../../../Classes/Libs/SQLite/sqlite3secure.c FILES_PATH := $(LOCAL_PATH) /../../../Classes FILE_INCLUDES := $(dir $(foreach src_path,$(FILES_PATH) , $(call walk,$(src_path) ,*/) )) FILE_INCLUDES := $(call uniq,$(FILE_INCLUDES) ) LOCAL_C_INCLUDES := $(FILE_INCLUDES) LOCAL_STATIC_LIBRARIES := cocos2dx_static include $(BUILD_SHARED_LIBRARY) $(call import-module,.)
核心技巧说明 :
技巧
作用
walk 宏
递归遍历目录,自动发现所有源文件
uniq 宏
去除重复的头文件包含路径
filter %.cpp
从遍历结果中筛选 C++ 源文件
$(FILE_LIST:$(LOCAL_PATH)/%=%)
将绝对路径转换为相对路径
Application.mk(编译选项配置) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 APP_STL := gnustl_static APP_CPPFLAGS := -frtti -DCC_ENABLE_CHIPMUNK_INTEGRATION=1 -std=c++11 -fsigned-char APP_LDFLAGS := -latomic APP_SHORT_COMMANDS := true APP_CPPFLAGS += -Wno-error=format-security ifeq ($(NDK_DEBUG) ,1) APP_CPPFLAGS += -DCOCOS2D_DEBUG=1 APP_OPTIM := debug else APP_CPPFLAGS += -DNDEBUG APP_OPTIM := release endif
参数
说明
APP_STL
C++ 标准库实现,gnustl_static 或 c++_static
APP_CPPFLAGS
传递给 C++ 编译器的额外参数
APP_SHORT_COMMANDS
解决 Windows 命令行长度限制
NDK_DEBUG
Debug 模式开关,由 Gradle 传入
AndroidManifest.xml 配置 游戏主模块 AndroidManifest.xml 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 <?xml version="1.0" encoding="utf-8" ?> <manifest xmlns:android ="http://schemas.android.com/apk/res/android" package ="com.xxxx.xxxGame" android:installLocation ="auto" > <uses-feature android:glEsVersion ="0x00020000" /> <application android:label ="@string/app_name" android:icon ="@drawable/icon" > <meta-data android:name ="android.app.lib_name" android:value ="cocos2dcpp" /> <activity android:name ="com.xxxx.xxxGame.AppActivity" android:label ="@string/app_name" android:launchMode ="singleTop" android:screenOrientation ="sensorPortrait" android:configChanges ="orientation|keyboardHidden" android:theme ="@android:style/Theme.NoTitleBar.Fullscreen" > <intent-filter > <action android:name ="android.intent.action.MAIN" /> <category android:name ="android.intent.category.LAUNCHER" /> </intent-filter > </activity > </application > <supports-screens android:anyDensity ="true" android:smallScreens ="true" android:normalScreens ="true" android:largeScreens ="true" android:xlargeScreens ="true" /> <uses-permission android:name ="android.permission.INTERNET" /> </manifest >
属性
说明
android.app.lib_name
对应 Android.mk 中的 LOCAL_MODULE_FILENAME
android:screenOrientation
屏幕方向,sensorPortrait 为竖屏
android:configChanges
防止配置变化时 Activity 重建
AppActivity 闪屏实现 自定义 AppActivity 在 Cocos2d-x 资源加载期间,Android 会显示黑屏。通过自定义 AppActivity 添加闪屏图片,可以显著提升用户体验:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 package com.gamedo.clonehero.pass;import android.content.Context;import android.os.Bundle;import android.os.Handler;import android.view.View;import android.view.WindowManager;import android.widget.ImageView;import org.cocos2dx.lib.Cocos2dxActivity;public class AppActivity extends Cocos2dxActivity { protected static Handler mUIHandler; private Context mContext; private static ImageView mWelcome = null ; protected ImageView createLaunchImage () { mWelcome = new ImageView (mContext); mWelcome.setImageResource(R.drawable.splash); mWelcome.setScaleType(ImageView.ScaleType.CENTER_CROP); return mWelcome; } public static void removeLaunchImage () { mUIHandler.post(new Runnable () { @Override public void run () { if (mWelcome != null ) { mWelcome.setVisibility(View.GONE); } } }); } @Override protected void onCreate (Bundle savedInstanceState) { super .onCreate(savedInstanceState); mContext = this ; mUIHandler = new Handler (); addContentView( createLaunchImage(), new WindowManager .LayoutParams( WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN ) ); JniService.initWithActivity(this ); new Thread () { @Override public void run () { try { Thread.sleep(5000 ); } catch (Exception e) { e.printStackTrace(); } removeLaunchImage(); } }.start(); } static { System.loadLibrary("cocos2dcpp" ); } }
C++ 层调用移除闪屏 在 AppDelegate.cpp 的资源加载完成后,调用 Java 方法移除闪屏:
1 2 3 4 5 6 7 8 9 10 11 #include "platform/android/jni/JniHelper.h" void AppDelegate::applicationDidFinishLaunching () { cocos2d::JniHelper::callStaticVoidMethod ( "com/gamedo/clonehero/pass/AppActivity" , "removeLaunchImage" ); }
常见问题与解决方案 问题一:No implementation found for nativeSetAudioDeviceInfo 原因 :libcocos2dx 模块版本过低,缺少对应的 native 方法实现。
解决方案 :升级 libcocos2dx 模块到与引擎版本匹配的最新版本。
问题二:Windows 路径过长导致编译失败 原因 :Windows 命令行有最大长度限制。
解决方案 :在 Application.mk 中开启短命令模式:
1 APP_SHORT_COMMANDS := true
原因 :NDK 默认将 format 警告视为错误。
解决方案 :修改 NDK 的 default-build-commands.mk 文件:
1 2 3 4 5 TARGET_FORMAT_STRING_CFLAGS := -Wformat -Werror=format-security TARGET_FORMAT_STRING_CFLAGS := -Wformat
或在 Application.mk 中添加:
1 APP_CPPFLAGS += -Wno-error=format-security
问题四:gradle sync 失败 原因 :Gradle 版本与 Android Gradle Plugin 不兼容。
解决方案 :在 gradle-wrapper.properties 中指定兼容的 Gradle 版本:
1 distributionUrl =https\://services.gradle.org/distributions/gradle-4.1-all.zip
配置对照速查表
文件
作用
关键配置
local.properties
本地 SDK/NDK 路径
ndk.dir, sdk.dir
settings.gradle
模块定义
include, projectDir
gradle.properties
构建属性
PROP_TARGET_SDK_VERSION, PROP_APP_ABI
build.gradle (顶层)
项目级构建
classpath, repositories
build.gradle (app)
应用级构建
externalNativeBuild, signingConfigs
Android.mk
NDK 源文件配置
LOCAL_SRC_FILES, LOCAL_C_INCLUDES
Application.mk
NDK 编译选项
APP_STL, APP_CPPFLAGS
AndroidManifest.xml
应用清单
activity, uses-permission
总结 Cocos2d-x Android Studio 项目配置的核心要点:
路径配置 :正确设置 local.properties 中的 SDK/NDK 路径,以及 settings.gradle 中的模块路径
Gradle 配置 :主模块 build.gradle 需配置 NDK 编译参数、模块路径和签名信息
自动遍历 :利用 Android.mk 中的 walk 宏自动收集 Classes 目录下的源文件,避免手动维护文件列表
闪屏处理 :通过自定义 AppActivity 添加闪屏视图,在 C++ 层资源加载完成后移除
平台适配 :Windows 平台注意路径分隔符转换和命令行长度限制
通过合理的配置,可以在 Android Studio 中高效地开发和调试 Cocos2d-x 游戏项目。