【Cocos2dx】如何將CocosCreator構建釋出的Android平臺工程整合到已有的Android專案中

2020-10-04 11:00:15

一,前言

CocosCreator可以將開發的遊戲釋出到Android平臺,使用Android Studio可以構建和執行編譯目錄下(frameworks\runtime-src\proj.android-studio)的工程。但其生成的工程比較複雜,當我們需要從一個已有的Android專案啟動我們開發出的遊戲時,整合的過程極其繁瑣。筆者整理了整合過程,供有需要的同志參考,

二,教學

1. CocosCreator構建釋出

釋出平臺選擇Android,模板選擇default,方便後續整合。APP ABI筆者選擇的是arm64-v8a。依次點選下方的「構建」、「編譯「,編譯過程會比較慢。

在這裡插入圖片描述

編譯成功後會在釋出路徑生成jsb-default資料夾。
在這裡插入圖片描述

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

  • externalNativeBuild
    在這裡插入圖片描述

    externalNativeBuild這裡要修改路徑

  • 下面的externalNativeBuildbuildTypes照常複製過去
    在這裡插入圖片描述

  • 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,名字可以在第二步修改):
    在這裡插入圖片描述

此處貼一下我複製好後的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資料夾裡
在這裡插入圖片描述
在這裡插入圖片描述

複製proj.android-studio\jni整個資料夾到自己的專案根目錄裡
在這裡插入圖片描述

jsb-default\frameworks\runtime-src裡Classes資料夾拷貝到專案根目錄的jni資料夾裡,因為jni資料夾裡的CocosAndroid.mk定義了Classes的路徑(LOCAL_C_INCLUDES和LOCAL_SRC_FILES),我們需要在這個檔案裡重新修改為我們剛剛Classes所在的相對路徑,(或者不復制Classes資料夾裡的內容,使用絕對路徑):
修改前:
在這裡插入圖片描述

修改後:
在這裡插入圖片描述

這一步後,我們自己的專案根目錄裡多了個jni資料夾:
在這裡插入圖片描述

app目錄下多了個jni資料夾
在這裡插入圖片描述

4. 複製Activity

修改版本
在這裡插入圖片描述

複製路徑proj.android-studio\src\org\cocos2dx\javascript下的檔案到專案裡,修改相關的import資訊
在這裡插入圖片描述

將proj.android-studio\app\AndroidManifest.xml裡對Activity的註冊和meta-data複製到我們自己的AndroidManifest.xml裡

<?xml version="1.0" encoding="utf-8"?>
<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原始碼裡修改一下
在這裡插入圖片描述

第一次編譯會比較久
在這裡插入圖片描述

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);;