【Cocos2dx】如何将CocosCreator构建发布的Android平台工程整合到已有的Android项目中

文章目录

  • 一,前言
  • 二,教程
    • 1. CocosCreator构建发布
    • 2. 导入libcocos2dx
    • 3.修改gradle配置
    • 3.复制jni文件夹
    • 4. 复制Activity
    • 5.编译运行
    • 6.出现的bug
    • 7.闪退(重点)
  • 三、整合后的编译运行
  • 四、数据交互

一,前言

CocosCreator可以将开发的游戏发布到Android平台,使用Android Studio可以构建和运行编译目录下(frameworks\runtime-src\proj.android-studio)的工程。但其生成的工程比较复杂,当我们需要从一个已有的Android项目启动我们开发出的游戏时,整合的过程极其繁琐。笔者整理了整合过程,供有需要的同志参考,

二,教程

1. CocosCreator构建发布

发布平台选择Android,模板选择default,方便后续整合。APP ABI笔者选择的是arm64-v8a。依次点击下方的“构建”、“编译“,编译过程会比较慢。

【Cocos2dx】如何将CocosCreator构建发布的Android平台工程整合到已有的Android项目中_第1张图片

编译成功后会在发布路径生成jsb-default文件夹。
【Cocos2dx】如何将CocosCreator构建发布的Android平台工程整合到已有的Android项目中_第2张图片

2. 导入libcocos2dx

将编译路径下的:frameworks\cocos2d-x 整个文件夹整个拷贝到我们自己的安卓项目根目录,然后在自己的安卓项目根目录下的setting.gradle中添加如下代码:

include ':libcocos2dx'
project(':libcocos2dx').projectDir = new File('cocos2d-x\\cocos\\platform\\android\\libcocos2dx')

3.修改gradle配置

将proj.android-studio\gradle.properties里的内容复制到我们自己的安卓项目对应的gradle.properties里:


# Android SDK version that will be used as the compile project
PROP_COMPILE_SDK_VERSION=29

# Android SDK version that will be used as the earliest version of android this application can run on
PROP_MIN_SDK_VERSION=16

# Android SDK version that will be used as the latest version of android this application has been tested on
PROP_TARGET_SDK_VERSION=29

# Android Build Tools version that will be used as the compile project
PROP_BUILD_TOOLS_VERSION=28.0.3

# List of CPU Archtexture to build that application with
# Available architextures (armeabi-v7a | arm64-v8a | x86)
# To build for multiple architexture, use the `:` between them
# Example - PROP_APP_ABI=arm64-v8a
PROP_APP_ABI=arm64-v8a

#这部分的内容注释掉不用,有需要的可以自行探索
# fill in sign information for release mode
#RELEASE_STORE_FILE=D:/software/cocosDashboard/resources/.editors/Creator/2.4.2/resources/static/build-templates/native/debug.keystore
#RELEASE_STORE_PASSWORD=123456
#RELEASE_KEY_ALIAS=debug_keystore
#RELEASE_KEY_PASSWORD=123456

android.injected.testOnly=false

然后sync

将proj.android-studio\app\build.gradle里的内容复制到我们安卓目录下的app\build.gradle

  • Os
    【Cocos2dx】如何将CocosCreator构建发布的Android平台工程整合到已有的Android项目中_第3张图片

  • externalNativeBuild
    【Cocos2dx】如何将CocosCreator构建发布的Android平台工程整合到已有的Android项目中_第4张图片

    externalNativeBuild这里要修改路径

  • 下面的externalNativeBuildbuildTypes照常复制过去
    【Cocos2dx】如何将CocosCreator构建发布的Android平台工程整合到已有的Android项目中_第5张图片

  • android.applicationVariants.all 需要修改一下,并且修改sourceDir的路径:

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

    variant.mergeAssets.doLast {
        def sourceDir = "D:/build/jsb-default"//这里改成你的编译路径

// 以下几行是旧的代码,在新版Gradle下有问题
//        copy {
//            from "${sourceDir}/res"
//            into "${outputDir}/res"
//        }
//
//        copy {
//            from "${sourceDir}/src"
//            into "${outputDir}/src"
//        }
//
//        copy {
//            from "${sourceDir}/jsb-adapter"
//            into "${outputDir}/jsb-adapter"
//        }

// 新的拷贝文件的方法,在新版Gradle可用
        copy{
            from "${sourceDir}"
            include "assets/**"
            include "res/**"
            include "src/**"
            include "jsb-adapter/**"

            into outputDir
        }

        copy {
            from "${sourceDir}/main.js"
            from "${sourceDir}/project.json"
            into outputDir
        }
    }
}

android.applicationVariants.all是将我们的游戏资源,包括代码和图片资源都复制到编译输出目录。如果你的游戏启动后资源没加载出来,可能就是这里的路径没有配置好。

  • dependencies里加入下面两行导入libcocos2dx(在这里是为项目导入libcocos2dx,名字可以在第二步修改):
    【Cocos2dx】如何将CocosCreator构建发布的Android平台工程整合到已有的Android项目中_第6张图片

此处贴一下我复制好后的app\build.gradle

import org.apache.tools.ant.taskdefs.condition.Os

apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'

android {
    compileSdkVersion 29
    buildToolsVersion "28.0.3"

    defaultConfig {
        applicationId "com.example.testmw"
        minSdkVersion 23
        targetSdkVersion 29
        versionCode 1
        versionName "1.0"
        multiDexEnabled true
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"

        externalNativeBuild {
            ndkBuild {
                if (!project.hasProperty("PROP_NDK_MODE") || PROP_NDK_MODE.compareTo('none') != 0) {
                    // skip the NDK Build step if PROP_NDK_MODE is none
                    targets 'cocos2djs'
                    arguments 'NDK_TOOLCHAIN_VERSION=clang'

                    def module_paths = [project.file("../cocos2d-x"),
                                        project.file("../cocos2d-x/cocos"),
                                        project.file("../cocos2d-x/external")]
                    if (Os.isFamily(Os.FAMILY_WINDOWS)) {
                        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})
                }
            }
        }


    }
    externalNativeBuild {
        ndkBuild {
            if (!project.hasProperty("PROP_NDK_MODE") || PROP_NDK_MODE.compareTo('none') != 0) {
                // skip the NDK Build step if PROP_NDK_MODE is none
                path "jni/Android.mk"
            }
        }
    }

    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'
                }
            }
        }
    }

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
    kotlinOptions {
        jvmTarget = '1.8'
    }

    sourceSets {
        main { jniLibs.srcDirs = ['libs'] }
    }
    packagingOptions {
        exclude 'META-INF/proguard/coroutines.pro'
        exclude 'META-INF/proguard/okhttp3.pro'
    }
}

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

    variant.mergeAssets.doLast {
        def sourceDir = "D:/build/jsb-default"
//
//        copy {
//            from "${sourceDir}/assets"
//            into "${outputDir}/assets"
//        }
//
//        copy {
//            from "${sourceDir}/src"
//            into "${outputDir}/src"
//        }
//
//        copy {
//            from "${sourceDir}/jsb-adapter"
//            into "${outputDir}/jsb-adapter"
//        }
//
//        copy {
//            from "${sourceDir}/main.js"
//            from "${sourceDir}/project.json"
//            into outputDir
//        }

// 新的拷贝文件的方法,在新版Gradle可用
        copy{
            from "${sourceDir}"
            include "assets/**"
            include "res/**"
            include "src/**"
            include "jsb-adapter/**"

            into outputDir
        }

        copy {
            from "${sourceDir}/main.js"
            from "${sourceDir}/project.json"
            into outputDir
        }
    }
}

dependencies {
    implementation fileTree(dir: "libs", include: ["*.jar"])
    implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
    ......
    ......

    implementation fileTree(dir: "../cocos2d-x/cocos/platform/android/java/libs", include: ['*.jar'])
    implementation project(':libcocos2dx')
}

3.复制jni文件夹

复制proj.android-studio/app/jni文件夹到自己安卓目录的app文件夹里
【Cocos2dx】如何将CocosCreator构建发布的Android平台工程整合到已有的Android项目中_第7张图片
【Cocos2dx】如何将CocosCreator构建发布的Android平台工程整合到已有的Android项目中_第8张图片

复制proj.android-studio\jni整个文件夹到自己的项目根目录里
【Cocos2dx】如何将CocosCreator构建发布的Android平台工程整合到已有的Android项目中_第9张图片

jsb-default\frameworks\runtime-src里Classes文件夹拷贝到项目根目录的jni文件夹里,因为jni文件夹里的CocosAndroid.mk定义了Classes的路径(LOCAL_C_INCLUDES和LOCAL_SRC_FILES),我们需要在这个文件里重新修改为我们刚刚Classes所在的相对路径,(或者不复制Classes文件夹里的内容,使用绝对路径):
修改前:
【Cocos2dx】如何将CocosCreator构建发布的Android平台工程整合到已有的Android项目中_第10张图片

修改后:
【Cocos2dx】如何将CocosCreator构建发布的Android平台工程整合到已有的Android项目中_第11张图片

这一步后,我们自己的项目根目录里多了个jni文件夹:
【Cocos2dx】如何将CocosCreator构建发布的Android平台工程整合到已有的Android项目中_第12张图片

app目录下多了个jni文件夹
【Cocos2dx】如何将CocosCreator构建发布的Android平台工程整合到已有的Android项目中_第13张图片

4. 复制Activity

修改版本
【Cocos2dx】如何将CocosCreator构建发布的Android平台工程整合到已有的Android项目中_第14张图片

复制路径proj.android-studio\src\org\cocos2dx\javascript下的文件到项目里,修改相关的import信息
【Cocos2dx】如何将CocosCreator构建发布的Android平台工程整合到已有的Android项目中_第15张图片

将proj.android-studio\app\AndroidManifest.xml里对Activity的注册和meta-data复制到我们自己的AndroidManifest.xml里


<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.example.testapp1002">

    <uses-feature android:glEsVersion="0x00020000" />

    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <meta-data android:name="android.app.lib_name"
            android:value="cocos2djs" />
        <activity
            android:name=".AppActivity"
            android:screenOrientation="sensorLandscape"
            android:configChanges="orientation|keyboardHidden|screenSize|screenLayout"
            android:label="@string/app_name"
            android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
            android:launchMode="singleTask"
            android:taskAffinity="" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            intent-filter>
        activity>
        <activity android:name=".MainActivity">
        activity>
    application>

manifest>

5.编译运行

上面的4步完成后可以开始在Android Studio里编译运行。
然后会发现main.cpp报错,这是因为AppDelegate.h文件的include路径错误,需要在/jni/hellojavascript/main.cpp源码里修改一下
【Cocos2dx】如何将CocosCreator构建发布的Android平台工程整合到已有的Android项目中_第16张图片

第一次编译会比较久
【Cocos2dx】如何将CocosCreator构建发布的Android平台工程整合到已有的Android项目中_第17张图片

6.出现的bug

当完成以上5个步骤后,我们可以在自己的项目里像使用Activity一样启动我们的游戏了。

Intent(that, AppActivity::class.java).apply {
      startActivity(this) }

但是可能会在打开这个Activity的时候闪退,我自己查看的日志显示的原因是Cocos2dxHelper.registerBatteryLevelReceiver(this);这一行代码出错了,找不到静态方法。我选择将这个和BatteryLevelReceiver相关的代码注释掉。

即修改路径cocos2d-x\cocos\platform\android\java\src\org\cocos2dx\lib下Cocos2dxActivity.java
注释以下两行代码:

 Cocos2dxHelper.registerBatteryLevelReceiver(this);
 Cocos2dxHelper.unregisterBatteryLevelReceiver(this);;

7.闪退(重点)

到了这步我们似乎已经能成功的从安卓项目进入到我们的游戏了,但是当我们选择退出游戏想要回到安卓App界面时,发现只闪了一下安卓App的界面,程序就自动退出了,日志的最后一行是:

Sending signal. PID: 18232 SIG: 9

这是因为我们游戏中调用cc.game.end();后,Cocos2dxActivity.java的onDestroy方法里调用了Cocos2dxHelper.terminateProcess();方法,其实现如下:

public static void terminateProcess() {
     
    android.os.Process.killProcess(android.os.Process.myPid());
}

在这里获取了当前App的线程Id然后直接杀死App,如果我们将这个方法注释掉,就不会出现App闪退的问题。
但是,进入游戏后退出虽然没问题了,再次进入游戏却会产生黑屏并闪退,这是因为finish掉游戏的AppActivity后,其中的runOnGlThread()中的线程还在执行,Cocos2dxGLSurfaceView并没有被销毁掉。
最终的解决方法是:在AndroidManifest中,在游戏所在的activity标签,设置独立的进程:android:process="com.exam.game"

<activity
    android:name=".cocos.AppActivity"
    android:process="com.exam.game"
    android:screenOrientation="sensorLandscape"
    android:configChanges="orientation|keyboardHidden|screenSize|screenLayout"
    android:label="@string/app_name"
    android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
    android:launchMode="singleTask"
    android:taskAffinity="" >
activity>

参考:Android app内接入cocos 2dx js 所遇问题

三、整合后的编译运行

当我们完成整合后,在CocosCreator中对游戏工程作出了修改,要同步到我们的安卓工程也非常方便。
在CocosCreator中作出修改并保存好后,点击“项目”->“构建发布”:
【Cocos2dx】如何将CocosCreator构建发布的Android平台工程整合到已有的Android项目中_第18张图片

在这里只需要点击“构建”并等待完成就行,无序再次进行编译。其作出的修改,就能同步到我们的安卓项目里(app\build.gradle中android.applicationVariants.all 的功劳)。

四、数据交互

当我们需要从游戏端获取安卓端的数据时,需要使用脚本调用安卓端的静态接口:

if(cc.sys.os == cc.sys.OS_ANDROID){
     
    if(cc.sys.isNative==true){
     
        var ojb = jsb.reflection.callStaticMethod("com/example/testmw/jni/JniTestHelper", "showTipDialog", "(Ljava/lang/String;Ljava/lang/String;)V","test", "testsss");
    }
}

此处调用了下面的接口:

package com.example.testmw.jni;
public class JniTestHelper {
     

    private static void showTipDialog(final String title, final String text)
    {
     
        ......
    }
}

具体信息参考:官方文档

但是当把游戏和Android App设置为不同的进程时,两个进程之间无法进行普通的数据共享,需要使用进程间数据交互的方式,参考:Android进程间通信方式,Android 进程间通信的几种实现方式

你可能感兴趣的:(项目,cocos2d,游戏开发,android)