改造CocosCreator3.x的安卓工程

CocosCreator3.x与AndroidStudio工程对比

熟悉安卓的小伙伴可能会注意到,CocosCreator3.x(下面简称C3D)打出来的安卓工程与AndroidStudio(下面简称AS)的标准工程有些出入,对照如下

AndroidStudio工程目录:
image2

CocosCreator3.x安卓工程目录
image1

可以明显看出,C3D这边src是直接做为java代码的根目录的,而AS工程的src下面还有一个main目录,main下面才是资源。

但是我们发现,虽然C3D与AS标准工程不一致,但是依然能够运行,是什么原因呢?稍加探索,不难发现,C3D是在gradle里单独指定了目录

    sourceSets.main {
        java.srcDirs "../src", "src"
        res.srcDirs "../res", 'res', "${RES_PATH}/proj/res"
        jniLibs.srcDirs "../libs", 'libs'
        manifest.srcFile "AndroidManifest.xml"
        assets.srcDir "${RES_PATH}/data"
        jniLibs {
            // Vulkan validation layer
            // srcDir "${android.ndkDirectory}/sources/third_party/vulkan/src/build-android/jniLibs"
        }
    }

这里,我们就初步知道了C3D和AS之间的差异。话又说回来,既然C3D的功能也能运行,那我们为什么要进行改造呢?下面来介绍两种场景,可能更依赖AS标准工程来实现(毕竟是在AS中开发的,很合理)

开发场景模拟

接入一些特定SDK

比如我们要接入信通院的oaid sdk,这个sdk就需要将supplierconfig.json这个文件拷贝到assets目录下,但C3D工程没有这个目录。
我们稍加查看路径设置,发现被指定到了${RES_PATH}/data目录,那么我们可以想到的最简单办法是将文件放到该目录下。
然而这里存在一个弊端就是每次构建data文件会被清空,需要手动重新操作,当然我们也可以写个构建插件,在钩子这里有命令移进去,但是始终不方便。
这里,我们就可以添加gradle的搜索路径来达到目的,如下

    sourceSets.main {
        java.srcDirs "../src", "src"
        res.srcDirs "../res", 'res', "${RES_PATH}/proj/res"
        jniLibs.srcDirs "../libs", 'libs'
        manifest.srcFile "AndroidManifest.xml"
        assets.srcDirs "${RES_PATH}/data", '自定义目录'
        jniLibs {
            // Vulkan validation layer
            // srcDir "${android.ndkDirectory}/sources/third_party/vulkan/src/build-android/jniLibs"
        }
    }

这里,我们需要稍微注意下,因为原来只有一个目录,所以是assets.srcDir,现在是多个目录,需要改成assets.srcDirs
这里介绍了assets文件夹的使用,当然如果有java、res等可以依此类推,这样就方便类似SDK接入了。

多渠道打包

针对单个目录修改,我们已经了解了,但如果我们的应用,需要上架多个渠道,我们通常不会建立多个项目,而是一个项目借助多渠道打包,比如上线各种硬核渠道,我们可以这样

productFlavors {
    huawei {
        // ...
    }
    xiaomi {
        // ...
    }
    oppo {
        // ...
    }
    vivo {
        // ...
    }
}

这里,我们就可以通过多渠道设置不同的参数,但有时候,我们在不同的渠道有不同的文件处理,比如icon不同等,按照上面介绍的思路,我们也可以通过修改目录的方式来设置

productFlavors {
    huawei {
        // ...
        sourcesets {
            // ...
        }
    }
    xiaomi {
        // ...
    }
    oppo {
        // ...
    }
    vivo {
        // ...
    }
}

但是,我们如果渠道过多,则每个渠道单独设置,将会极其麻烦。与此同时,我们发现,AS似乎就不需要单独配置的。对比发现其实默认AS是支持直接读取对应渠道文件的,但是因为我们(C3D)有自定义路径,造成了该功能失效了,那么我们是否可以改回as默认结构呢?

工程改造

下面,我们对C3D的安卓工程进行一定的改造,以便与AS工程尽量对齐。

适当破坏兼容性

第一种方法是,尽量与AS几乎一样,但是会破坏与C3D原有结构的一致性,当然破坏有限。具体方法可以参考以下方式:因为src文件被占用,所以我们要把src下面的java代码移到src/main/java下,然后将对应的文件路径设置好,如下

        java.srcDirs "../src", "src/main/java"
        res.srcDirs "../res", 'res', "${RES_PATH}/proj/res", "src/main/res"
        jniLibs.srcDirs "../libs", 'libs'
        manifest.srcFiles "AndroidManifest.xml"
        assets.srcDirs "${RES_PATH}/data", src/min/assets

这里,我们其实也只破坏了java代码位置的兼容性,如果项目没有对此进行额外处理,那其实也不受影响。另外,我们还可以对AndroidManifest.xml也对齐,即删除该处配置,将AndroidManifest.xml移到src/main目录下。

不破坏原有结构

当然,如果你想完全不破坏原有结构,也可以自己定义main的根目录,比如newsrc,则改后的配置为

    sourceSets.main {
        java.srcDirs "../src", "src", "newsrc/main/java"
        res.srcDirs "../res", 'res', "${RES_PATH}/proj/res", "newsrc/main/res"
        jniLibs.srcDirs "../libs", 'libs'
        manifest.srcFiles "AndroidManifest.xml"
        assets.srcDirs "${RES_PATH}/data", "newsrc/main/assets"
        jniLibs {
            // Vulkan validation layer
            // srcDir "${android.ndkDirectory}/sources/third_party/vulkan/src/build-android/jniLibs"
        }
    }

这样,多渠道打包,就可以单独设置文件夹,而不需要进行配置

app
    /src
        /main 
            /java、res、assets ....
        /channel1
            /java、res、assets


至此工程改造结束。考虑到第一种破坏性并不大,而且可以减少目录分散程度以及与AS工程更接近,所以我这边更推荐第一种方式,同时我也将方式1给提交了pr Android模板工程对齐官方默认模板

原文:博客 微信公众号

13赞

那么不同平台的sdk怎么办呢请问

如果确定sdk必定是多选一的话,借助多渠道,
比如播放视频,你可以在各渠道下新建一个文件 RewardedVideoAd,实现接口createRewardedVideoAd
然后你统一调用createRewardedVideoAd,在不同平台引用不同平台的sdk,比如

productFlavors {
    huawei {
        // ...
        sourcesets {
            // ...
        }
    }
    xiaomi {
        // ...
    }
}

// 那么在dependencies里面可以这样引用
huaweiImplementation 'xxx'
xiaomiImplementation 'xxx'

当然,你也可以将sdk封装成自己的,并且将接口统一化,比如我有多个module,一个是td,一个是友盟,他们的文件名不一样,但都继承一个类(或接口),实现方法onEvent,那么你在主文件,用反射判断是否集成,集成则调用初始化、上报等接口。效果大致为

    // 核心sdk
    implementation 'com.seeg.sdk:game:0.0.1.74'
    // 如果使用TD,请添加
    implementation 'com.seeg.external:td:0.0.1.6'
    // 如果使用友盟,请添加
    implementation 'com.seeg.external:um:0.0.1.0'

    // 如果上线vivo渠道,请添加
    vivoImplementation 'com.seeg.external:vivo:0.0.1.0'
    vivoImplementation fileTree(dir: 'src/vivo/libs', includes: ['*.jar', '*.aar'])

    // 如果上线小米渠道,请添加
    // 不同平台aar、jar的引入
    miImplementation 'com.seeg.external:mi:0.0.1.12'
    // 如果使用米盟,请添加
    miImplementation fileTree(dir: 'src/mi/libs', includes: ['*.jar', '*.aar'])

以上,是我在Cocos 长沙meeting的分享的补充~

但多渠道其实是个很广的东西,入门简单,可以做的事情却特别多,我这也只是介绍个皮毛

2赞

这么好的文章,要at官方看看

我提交了pr,官方认为破坏了一致性,在4.x的大版本合并该改动

1赞

那这样我这种打包仔岂不是要失业了