查看原文
其他

安卓SDK接入so easy,一文看懂Cocos Creator原生二次开发的正确姿势!

羽毛不会飞 COCOS 2023-03-16

引言:本文作者「羽毛先生」他将基于 v3.4.2,介绍 Cocos Creator 的 Android 原生二次开发流程以及 JSB 进行 Android 层与引擎 TS/JS 层进行相互调用的过程。Demo 源码见文末。


最近在开发的一个游戏进入到了安卓 SDK 接入的相关工作,但是构建安卓工程后,发现结构跟以往的 jsb-link 差别比较大,项目目录结构和以前也有所不同。本次就聊一聊 Cocos Creator 的安卓原生二次开发,为开发的小伙伴提供一些参考。


分析过程


首先查阅一下官方文档中对构建目录[1]、二次开发[2]的说明。


构建目录


二次开发


注意事项


接着查看本地文件。


/build/android/proj 目录:

  • 查看 /build/android/proj 未发现 AppActitivy.java 等文件,但是存在 build.gradle 等安卓相关文件。

  • 使用Android Studio 打开目录,可以成功打开并编译。


native 目录:

  • 查看 /native/engine/android/app 目录,存在 AndroidMainfest.xml,build.gradle 等文件。

  • 查看 /native/engine/android/app/com/cocos/game,可以看到有 AppActitivy.java 发现以上是熟悉的安卓工程目录结构。

  • 使用 Android Studio 打开目录,报错。


跟随文档,使用 Android Studio 打开 build/android/proj,发现找不到上述的 AndroidMainfest.xml,build.gradle,以及 /native/engine/android/app/com/cocos/game/Appactivity,这时候只要切换一下显示模式为 Android 即可。



切换后即可看到相关的原生文件。



通过 Android Studio 中使用 Windows 资源管理器打开  AppActivty.java 可以发现 AppActivity.java 位于 native/engine/android/app/src/com/cocos/game 目录中。



总结:build/android/proj 使用 Android Studio 进行开发,生效文件位于 native/engine/android 中,对 native 目录做版本管理,同时需去除 native 下的 build 目录(编译过程临时生成内容)。


build/android 目录中为 Cocos Creator 配置的 service 内容,随工程改变,不需要做单独的版本管理。


接入流程示例


接下来以 TalkingData SDK 为例,介绍一下完整的安卓原生工程二次开发流程。下载好 SDK 后打开 SDK 文档,参照文档指引进行接入。


TalkingData SDK 接入文档

https://doc.talkingdata.com/posts/1025


首先在编辑器中进行安卓原生构建。构建的相关选项请参考官方文档[3],文档有很详细的说明。



构建完成后,可在工程目录下看到 nativebuild/android 两个目录。



接着使用 Android Studio 打开 build/android/proj 并且切换到 Android 显示模式。



然后我们来根据 SDK 接入文档进行接入。


▶ 1、导入 SDK。



native/engine/android/app/ 目录下新建 libs 目录(可在 Android Studio 中通过 show in explore 使用 Windows 资源管理器打开,自动跳转到该目录)。



\native\engine\android\app 下创建 libs 目录,复制 SDK 中的 aar 等文件到 libs 下,并在 app module 所属的 build.gradle 中添加依赖。



此处需要注意 libs 目录的中的 aar/jar 文件并非 talkingdata 接入文档中的 TalkingdataSDK.jar而是 SaaS_TalkingDataSDK_Android_V5.0.3.jar(下载 SDK 时提供的文件名),在接入其他的 SDK 中也常常会有这样的细节问题,需要注意以免被坑。


▶ 2、配置混淆规则。



打开 app module 所属 proguard-rules.pro 添加混淆规则。



▶ 3、如上同理按照文档要求进行权限配置。



▶ 4、SDK 初始化、接口实现等,内容相似,则不赘述了。这里展示关键性的代码,详细内容见 Demo 源码。



TDSDK.java

package com.cocos.sdk;

import android.util.Log;

import com.cocos.game.AppActivity;
import com.cocos.lib.CocosHelper;
import com.cocos.lib.CocosJavascriptJavaBridge;
import com.tendcloud.tenddata.TalkingDataProfile;
import com.tendcloud.tenddata.TalkingDataProfileType;
import com.tendcloud.tenddata.TalkingDataSDK;

public class TDSDK {
    static String AppID = "xxxxxxxxx";
    static String Chanel = "test_channel";

    static  TDSDK s_self = null;

    public static TDSDK getInstance(){
        if (s_self == null){
            s_self  = new TDSDK();
        }
        return  s_self;
    }

    public void init(){
        TalkingDataSDK.init(AppActivity.getContext(),AppID,Chanel, "");
    }

    public static void onResgister(String accountId){
        if (accountId==""){
            accountId = TalkingDataSDK.getDeviceId(AppActivity.getContext());
        }
        TalkingDataProfile profile = TalkingDataProfile.createProfile();
        profile.setName("");
        profile.setType(TalkingDataProfileType.ANONYMOUS);
        TalkingDataSDK.onRegister(accountId, profile,"");
    }

    public static String js2JavaTest(String str1, String str2){
        Log.d("TDSDK"String.format( "js2JavaTest Success param1:%s param2: %s",str1, str2));
        if (s_self!= null) s_self.java2js();
        return "Java Test Success";
    }
    public void java2js(){
        CocosHelper.runOnGameThread (new Runnable() {
            @Override
            public void run() {
                String str1 = "param3";
                String str2 = "param4";

                String funcStr = String.format("window.tdsdk.java2js('%s','%s')",str1,str2);
                Log.d("-----------------------""Start Java2Js");
                CocosJavascriptJavaBridge.evalString(funcStr);
                Log.d("----------------------""End Java2Js");
            }
        });
    }
}


Appactivity.java,建议可以简单了解下 Android 各个生命周期函数执行时机以及机制:

 @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // DO OTHER INITIALIZATION BELOW
        SDKWrapper.shared().init(this);
        TDSDK.getInstance().init();
    }


▶ 5、接入完成后可以直接在 Android Studio 中进行打包。apk 生成路径:android-001\proj\build\sdkDemo\outputs\apk

android-001 为在 Creator 构建界面的构架任务名。



也可以在 Cocos Creator 构建工具中点击生成进行打包。apk 生成路径:\build\android-001\publish android-001 为在 Creator 构建界面的构架任务名。


如果进行了 JS 层代码修改,则还需要通过编辑器的构建流程进行工程构建,然后再进行生成,使代码生效。


按照引擎设计,native 目录生成后,再次构建将跳过这部分的生成,避免影响已经开发的 Android SDK、native C++ 等原生定制的内容,在此也建议将 native 目录加入 git/svn 版本控制。


▶ 6、打包测试,运行成功,后台可收到激活设备,大功告成!!!



JS/TS与Android方法互调


Android 层接入完毕后,则需要实现 Java 与 TS 的互调。查阅官方文档[4]可知:

  • TS 调用 Java:jsb.reflection.callStaticMethod

  • Java 调用 TS,使用 evalString请注意观察示例代码中的 evalString 函数中参数的单引号双引号使用,避免出错。


示例:


  • Cocos Creator TS 代码:

    const classPath = "com/cocos/sdk/TDSDK";
@ccclass('tdsdk')
export class tdsdk {
    private static _instance = null;
    static getInstance(): tdsdk {
        if (tdsdk._instance == null) {
            tdsdk._instance = new tdsdk();
        }
        return tdsdk._instance;
    }
    //js调用Java
    js2Java() {
        if (JSB) {
            log("********************start js2Java param1: title param2: content********************");
            let res = jsb.reflection.callStaticMethod(classPath, "js2JavaTest""(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;""title""content");
            log("返回值", res);
            log("********************end js2Java param1: title param2: content********************");
        }
    }
    //java调用js
    java2js(param1: string, param2: string) {
        if (!JSB) {
        }
        log("java2js success param3: %s param4:%s ", param1, param2);
    }
}

window.tdsdk = tdsdk.getInstance();


请注意代码末尾将 tdsdk 挂在 Window 上,并且在 Cocos Creator 根目录创建 .d.ts 文件对 tdsdk 进行全局声明(文件名随意,不跟已有的冲突即可),方便别处调用时可以进行代码提示。



global.d.ts

import { tdsdk } from "./assets/script/tdsdk";
declare global {
    interface Window {
        tdsdk: tdsdk
    }
}


  • Java 代码:

public static String js2JavaTest(String str1, String str2){
        Log.d("TDSDK"String.format( "js2JavaTest Success param1:%s param2: %s",str1, str2));
        if (s_self!= null) s_self.java2js();
        return "Java Test Success";
    }
    public void java2js(){
        CocosHelper.runOnGameThread (new Runnable() {
            @Override
            public void run() {
                String str1 = "param3";
                String str2 = "param4";

                String funcStr = String.format("window.tdsdk.java2js('%s','%s')",str1,str2);
                Log.d("-----------------------""Start Java2Js");
                CocosJavascriptJavaBridge.evalString(funcStr);
                Log.d("----------------------""End Java2Js");
            }
        });
    }


注意在 Java 调用 JS 代码时,如果需要操作 UI,请在规定线程中调用(runOnGameThread),避免崩溃,这里建立规范统一在规定线程中调用。


运行结果:



更高级的互调方式,请参考「腾讯在线教育部技术博客」中的 JSB 自动绑定方案,主要介绍了 C++ 与 JS 的互调:

http://docs.cocos.com/creator/manual/zh/advanced-topics/jsb-auto-binding.html?h=jsb


资源下载


点击文末【阅读原文】下载 Demo 源码

https://gitee.com/zenskcode/creatorDemo/tree/master/demos/AndroidSdkDemo-3.4.2


以上介绍完成了 SDK 接入以及 Java、TS 互调的相关用法,掌握后应该可以完成大部分安卓 SDK 的接入工作了,也可进行一些原生系统的调用。


参考链接

[1] 构建目录-官方文档

https://docs.cocos.com/creator/manual/zh/editor/publish/native-options.html?q=#%E6%9E%84%E5%BB%BA%E7%9B%AE%E5%BD%95

[2] 二次开发-官方文档

https://docs.cocos.com/creator/manual/zh/editor/publish/native-options.html?q=#%E4%BA%8C%E6%AC%A1%E5%BC%80%E5%8F%91

[3] 打包发布到原生平台-官方文档

http://docs.cocos.com/creator/manual/zh/editor/publish/native-options.html

[4] Java 反射-官方文档

http://docs.cocos.com/creator/manual/zh/advanced-topics/java-reflection.html

本文转载自公众号「羽毛不会飞」

欢迎关注作者!


往期精彩

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存