最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

簡(jiǎn)化Cocos和Native交互利器詳解

 更新時(shí)間:2022年12月09日 11:42:06   作者:我是黃大仙  
這篇文章主要為大家介紹了簡(jiǎn)化Cocos和Native交互利器詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

背景

我們?cè)谑褂?Cocos 和 Native 進(jìn)行交互的時(shí)候,發(fā)現(xiàn)體驗(yàn)并不是特別的友好。 如下所示,為我們項(xiàng)目當(dāng)中的一段代碼(代碼已脫敏),當(dāng)檢測(cè)到發(fā)生了 js 異常,我們需要通知 Native 端去做一些處理。

jsException: function (scence, msg, stack) {
    if (cc.sys.isNative && cc.sys.os === cc.sys.OS_ANDROID) {
        jsb.reflection.callStaticMethod(
            "xxx/xxx/xxx/xxx/xxx",
            "xxx",
            "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V",
            scence, msg, stack
        );
    } else if (cc.sys.isNative && cc.sys.os === cc.sys.OS_IOS) {
        jsb.reflection.callStaticMethod(
            "xxx",
            "xxx:xxx:xxx:",
            scence, msg, stack
        );
    }
}

從代碼當(dāng)中我們可以看出有以下問(wèn)題:

  • 方法調(diào)用非常麻煩,特別是 Android 端,需要明確的指出方法的路徑,方法名,參數(shù)類(lèi)型,特別容易出錯(cuò);
  • 一旦 Native 端的方法發(fā)生變化,Cocos層必須要同步修改,否則就會(huì)出現(xiàn)異常,甚至有可能 crash;
  • 不方便回調(diào);

我們嘗試著用注解的思路來(lái)解決這些問(wèn)題,從而設(shè)計(jì)并實(shí)現(xiàn)了 ABCBinding 。ABCBinding 能夠極大的簡(jiǎn)化 Cocos和 Native 的交互,方便維護(hù)。

ABCBinding 的結(jié)構(gòu)設(shè)計(jì)

ABCBinding 的結(jié)構(gòu)如下圖所示:

ABCBinding 包含 Native 和 TS 兩個(gè)部分,Native 負(fù)責(zé)約束本地的方法,TS 負(fù)責(zé)對(duì) Cocos 層提供調(diào)用 Native 方法的接口。 我們重新定義了一套 Cocos 和 Native 的交互模式:

  • 提供 Cocos 訪問(wèn)的 Native 方法必須為 public static,且參數(shù)必須為 Transfer(Transfer 為 SDK 提供的接口,能夠在 Cocos 層和 Native 層傳遞數(shù)據(jù));
  • 方法必須使用 ABCBinder 注解修飾,并在注解內(nèi)傳入約定好的 tag,此 tag 用于唯一標(biāo)識(shí)這個(gè)方法;
  • 使用 SDK 提供的 callNativeMethod 方法,傳入約定好的 tag 調(diào)用 Native 方法。

例子: 如下所示,為調(diào)用 Native 方法去下載,我們只需要傳入約定好的 tag:downloadFile,并傳入?yún)?shù),便可以進(jìn)行下載了。 TS 層:

Binding.callNativeMethod('downloadFile', { url: 'https://xxx.jpeg' }
).then((result) => {
    this.label.string = `下載成功:path=${result.path}`;
}).catch((error) => {
    this.label.string = error.msg;
});

Native 層:

@ABCBinder("downloadFile")
public static void download(Transfer transfer){
    new Thread(new Runnable() {
        @Override
        public void run() {
            String url = transfer.get("url","");
            try{
                //下載中
	        ...
                //下載成功
                TransferData data = new TransferData();
                data.put("path","/xxx/xxx.jpg");
                transfer.onSuccess(data);
            }catch (Exception e){
                //失敗
                transfer.onFailure(e);
            }
        }
    }).start();
}

通過(guò)例子可以看到,使用 ABCBinding 能夠讓 Cocos 和 Native 的交互簡(jiǎn)單很多,我們?cè)僖膊挥迷賯魅霃?fù)雜的路徑和參數(shù)了,而且回調(diào)也變得很優(yōu)雅。接下來(lái)我們來(lái)看看 ABCBinding 是如何實(shí)現(xiàn)的。

具體實(shí)現(xiàn)

從上面的例子我們可以看出,ABCBinding 是通過(guò) tag 來(lái)實(shí)現(xiàn) Cocos 和 Native 進(jìn)行交互的,那 SDK 是如何通過(guò) tag 來(lái)找到對(duì)應(yīng)的方法呢?

通過(guò) tag 找到 Native 方法

我們定義了編譯時(shí)注解 ABCBinder,

@Retention(RetentionPolicy.CLASS)//編譯時(shí)生效
@Target({ElementType.METHOD})//描述方法
public @interface ABCBinder {
    String value();
}

在編譯期間會(huì)生成一個(gè)類(lèi) ABCBindingProxy,成員變量 executors 包含了所有對(duì)應(yīng)的 tag 和方法。其中真正可執(zhí)行的方法被包裝在了 ExecutableMethod 接口當(dāng)中。

//以下為自動(dòng)生成的代碼
private Map executors = new java.util.HashMap();

private ABCBindingProxy() {
  executors.put("test2",new ExecutableMethod() {
    @Override
    public void execute(Transfer t) {
      com.example.abcbinding.MainActivity.test2(t);
    }
  });
  executors.put("test1",new ExecutableMethod() {
    @Override
    public void execute(Transfer t) {
      com.example.abcbinding.MainActivity.test1(t);
    }
  });
}
public interface ExecutableMethod {
    void execute(Transfer t);
}

因此我們只需要通過(guò) executors 和 tag 就可以找到了對(duì)應(yīng)的方法了,接著我們看看 TS 是如何與 Native 進(jìn)行交互的, 以下是 SDK 里面 TS 層的部分代碼,SDK 屏蔽了調(diào)用的具體細(xì)節(jié),將請(qǐng)求的參數(shù)轉(zhuǎn)變成為 json 字符串,并將相關(guān)的參數(shù)傳遞給 SDK 內(nèi)部的方法 execute,由 execute 將請(qǐng)求轉(zhuǎn)發(fā)給真正的方法。

public callNativeMethod(methodName: string, args ?: Record<string, string | number | boolean>): Promise < any > {
    ...
    if (cc.sys.isNative && cc.sys.os === cc.sys.OS_ANDROID) {
        let resultCode = jsb.reflection.callStaticMethod(
            'com/tencent/abckit/binding/ABCBinding', 
            'execute', 
            '(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I',
            methodName, 
            typeof args === 'object' ? JSON.stringify(args) : '', cbName);
        ...
    } else if (cc.sys.isNative && cc.sys.os === cc.sys.OS_IOS) {
        let retId = jsb.reflection.callStaticMethod(
            'ABCBinding', 
            'execute:methodName:args:callback:',
            methodName, 
            typeof args === 'object' ? JSON.stringify(args) : '', cbName);
        ...
    } else {
        let msg = 'no implemented on this platform';
        reject(msg);
    }
}

這樣,我們就解決了通過(guò) tag 找到對(duì)應(yīng)方法的問(wèn)題。但還有兩個(gè)問(wèn)題需要解決: 如何約束 Native 方法?以及如何保證 tag 的唯一性?

約束 Native 方法

ABCBinding 規(guī)定,提供 Cocos 訪問(wèn)的 Native 方法必須為 public static,參數(shù)必須為 Transfer,且 tag 必須要保持唯一性,那怎么來(lái)約束呢? 在代碼的編譯期間,我們會(huì)去檢查所有被 ABCBinder 修飾的方法,若發(fā)現(xiàn)這個(gè)方法并不符合我們的規(guī)范,則會(huì)直接報(bào)錯(cuò)。 如下所示: 1.參數(shù)錯(cuò)誤

@ABCBinder("test1")
public static void test1(Transfer transfer, int a) {
    Log.i("測(cè)試", "test()");
}

2.方法非 static

@ABCBinder("test2")
public void test2(Transfer transfer) {
    Log.i("測(cè)試", "test()");
}

3.方法非 public

@ABCBinder("test3")
protected static void test3(Transfer transfer) {
    Log.i("測(cè)試", "test()");
}

4.tag 重復(fù)

@ABCBinder("helloworld")
public static void test1(Transfer transfer) {
    Log.i("測(cè)試", "test()");
}

@ABCBinder("helloworld")
public static void test2(Transfer transfer) {
    Log.i("測(cè)試", "test()");
}

優(yōu)雅的回調(diào)

SDK 會(huì)在編譯期間自動(dòng)生成 callJs 方法,所有的回調(diào)都是通過(guò) callJs 方法實(shí)現(xiàn)。Native 方法只需要調(diào)用 Transfer 所提供的回調(diào)接口,便可以輕松的將結(jié)果回調(diào)給 Cocos。由于 callJs 代碼是自動(dòng)生成,所以 SDK 不需要直接依賴(lài) Cocos 庫(kù),只需要業(yè)務(wù)方依賴(lài)即可。

//以下為自動(dòng)生成的代碼
public void callJs(final String globalMethod, final TransferData params) {
  org.cocos2dx.lib.Cocos2dxHelper.runOnGLThread(new Runnable() {
    @Override
    public void run() {
      String command = String.format("window && window.%s && window.%s(%s);", 
	  globalMethod,globalMethod, params.parseJson());;
      org.cocos2dx.lib.Cocos2dxJavascriptJavaBridge.evalString(command);;
    }
  });
}

ABCBinding 提供了onProcess,onSuccess 和 onFailed 回調(diào)方法, 以下為 downloadFile 接口的的回調(diào)示例: TS 層:

Binding.withOptions({
    //回調(diào)onProcess
    onProgress: (progress) => {
        let current = progress.current;
        this.label.string = `progress:${current}`;
    }
}).callNativeMethod(
    'downloadFile',
    { url: 'https://xxxx.jpg' }
).then((result) => {
    //回調(diào)onSuccess
    this.label.string = `下載成功:path=${result.path}`;
}).catch((error) => {
    //回調(diào)onFailed
    if (error) {
        this.label.string = error.msg;
    }
});

Native 層:

@ABCBinder("downloadFile")
public static void download(Transfer transfer){
    new Thread(new Runnable() {
        @Override
        public void run() {
            String url = transfer.get("url","");
            try{
              	//模擬下載過(guò)程
                for(int i =0;i<100;i++) {
                     transfer.onProgress("current", i);
                }
	       //下載成功
                TransferData data = new TransferData();
                data.put("path","/xxx/xxx.jpg");
                transfer.onSuccess(data);
            }catch (Exception e){
                //失敗
                transfer.onFailure(e);
            }
        }
    }).start();
}

其他 feature

抹平系統(tǒng)差異

使用 ABCBinding 無(wú)須再判斷當(dāng)前系統(tǒng)是 Android 還是 IOS ,只需對(duì)應(yīng) Native 方法的 tag 保持一致即可。

Binding.callNativeMethod('isLowDevice').then(({isLowDevice}) => {
  console.log(isLowDevice);
})

無(wú)需關(guān)心線程切換

Native 方法使用 Transfer 回調(diào)時(shí),ABCBinding 會(huì)自動(dòng)切換到 Cocos 線程執(zhí)行,無(wú)需業(yè)務(wù)方關(guān)心。

@ABCBinding("getHardwareInfo")
public static void getHardwareInfo(Transfer transfer) {
    TransferData data = new TransferData();
    data.put("brand", Build.BRAND);
    data.put("model", Build.MODEL);
    data.put("OsVersion", Build.VERSION.RELEASE);
    data.put("SdkVersion", Build.VERSION.SDK);
    transfer.onSuccess(data);
}

支持超時(shí)

ABCBinding 支持設(shè)置超時(shí),其中超時(shí)的時(shí)間單位為秒,如下所示,超時(shí)會(huì)回調(diào)到 catch 方法當(dāng)中。

Binding.withOptions({
    timeout: 120,
    onProgress: (progress) => {
        let current = progress.current;
        this.label.string = `progress:${current}`;
    }
}).callNativeMethod(
    'downloadFile',
    { url: 'https://xxxx.jpg' }
).then((result) => {
    this.label.string = `下載成功:path=${result.path}`;
}).catch((error) => {
    if (error.code == ERROR_CODE_TIMEOUT) {
         console.log("超時(shí)");
    }
});

彩蛋:在熱更新當(dāng)中的應(yīng)用

我們?cè)谑褂?Cocos 熱更新服務(wù)的過(guò)程中發(fā)現(xiàn),怎么確定 Cocos 熱更新包能夠發(fā)布到哪個(gè) App 版本,是個(gè)難題。Cocos 熱更新包能不能在這個(gè) App 版本上正確運(yùn)行,跟兩個(gè)因素有關(guān),Cocos 版本和 Native 接口。

Cocos 版本 如果 App 和熱更包的 Cocos 版本不一致,那么很有可能這個(gè)熱更包無(wú)法在 App 上運(yùn)行,除非官方做了一些兼容處理。不過(guò)這個(gè)因素可控,Cocos 的版本不會(huì)頻繁的升級(jí),而且我們知道 Cocos 版本和 App 版本的對(duì)應(yīng)關(guān)系。

Native 接口 如果熱更包調(diào)用了某個(gè) Native 的接口,但是這個(gè)接口在有些版本上不存在,那該熱更包就無(wú)法在這個(gè)版本的 App 上運(yùn)行。 在我們的業(yè)務(wù)場(chǎng)景當(dāng)中,Cocos 版本不會(huì)頻繁變更,但是每個(gè)版本的 Native 代碼可能會(huì)相差較大,人工來(lái)核對(duì)每個(gè)版本的 Native 接口變更是一件極為費(fèi)時(shí)費(fèi)力的事情。 那么 ABCBinding 能幫助我們做什么呢?

讓熱更包兼容所有版本的 App

首先我們?nèi)コ?Cocos 版本的因素,因?yàn)檫@個(gè)因素可控,且業(yè)務(wù)方無(wú)法解決。 ABCBinding 知道本地有哪些接口可用,所以當(dāng) Cocos 調(diào)用了一個(gè)不存在的接口時(shí),我們會(huì)返回一個(gè)特殊的 code,這樣熱更包只需要在內(nèi)部做兼容處理就可以了。 如下所示:

Binding.callNativeMethod('downloadFile', { url: 'https://xxx.jpeg' }
).then((result) => {
     //處理邏輯
}).catch((error) => {
    if(error.code == ERROR_CODE_METHOD_NOT_DEFINED){
        console.log("未找到該方法");
    }
});

元素綁定

既然熱更新跟這兩個(gè)元素有關(guān),我們就可以通過(guò)這兩個(gè)元素,讓 App 和熱更包進(jìn)行匹配,如果能夠匹配,那么這個(gè)熱更包就可以下發(fā)到這個(gè)版本的 App 上。 Cocos 版本:我們?cè)诖虬臅r(shí)候就可以確定; Native 接口:在打包的過(guò)程中,ABCBinding 可以將當(dāng)前所支持的接口,按照約定的方式生成一個(gè)元素。 例如:本地的接口有 test1,test2,test3 我們可以將接口按照指定的方式排序拼接取 md5 值,生成第二個(gè)元素。 這樣當(dāng) App 和熱更新包的兩個(gè)元素能夠匹配時(shí),就能夠下發(fā)了。

以上就是簡(jiǎn)化Cocos和Native交互利器詳解的詳細(xì)內(nèi)容,更多關(guān)于Cocos Native交互簡(jiǎn)化的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • TypeScript在React中的應(yīng)用技術(shù)實(shí)例解析

    TypeScript在React中的應(yīng)用技術(shù)實(shí)例解析

    這篇文章主要為大家介紹了TypeScript在React中的應(yīng)用技術(shù)實(shí)例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-04-04
  • React大屏可視化腳手架教程示例

    React大屏可視化腳手架教程示例

    這篇文章主要為大家介紹了React大屏可視化腳手架教程示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-06-06
  • 歸納總結(jié)Remix?表單常用方法及示例詳解

    歸納總結(jié)Remix?表單常用方法及示例詳解

    這篇文章主要為大家歸納總結(jié)了Remix?表單常用方法及示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-03-03
  • React狀態(tài)提升案例介紹

    React狀態(tài)提升案例介紹

    這篇文章主要介紹了React狀態(tài)提升案例,所謂 狀態(tài)提升 就是將各個(gè)子組件的 公共state 提升到它們的父組件進(jìn)行統(tǒng)一存儲(chǔ)、處理,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)吧
    2023-04-04
  • React?Router掌握路由搭建與權(quán)限管控的操作方法(?從入門(mén)到精通)

    React?Router掌握路由搭建與權(quán)限管控的操作方法(?從入門(mén)到精通)

    本文詳細(xì)介紹了React?Router庫(kù)在React應(yīng)用開(kāi)發(fā)中的應(yīng)用,包括其核心功能、安裝使用、基礎(chǔ)使用、核心組件和功能、路由參數(shù)和嵌套路由、編程式導(dǎo)航以及路由權(quán)限管理等方面,感興趣的朋友一起看看吧
    2025-01-01
  • react高階組件添加和刪除props

    react高階組件添加和刪除props

    這篇文章主要介紹了react高階組件添加和刪除props,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-04-04
  • 詳解超簡(jiǎn)單的react服務(wù)器渲染(ssr)入坑指南

    詳解超簡(jiǎn)單的react服務(wù)器渲染(ssr)入坑指南

    這篇文章主要介紹了詳解超簡(jiǎn)單的react服務(wù)器渲染(ssr)入坑指南,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2019-02-02
  • 使用react+redux實(shí)現(xiàn)彈出框案例

    使用react+redux實(shí)現(xiàn)彈出框案例

    這篇文章主要為大家詳細(xì)介紹了使用react+redux實(shí)現(xiàn)彈出框案例,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-08-08
  • React如何使用錯(cuò)誤邊界(Error Boundaries)捕獲組件錯(cuò)誤

    React如何使用錯(cuò)誤邊界(Error Boundaries)捕獲組件錯(cuò)誤

    在 React 里,錯(cuò)誤邊界就像是一個(gè)“小衛(wèi)士”,專(zhuān)門(mén)負(fù)責(zé)在組件出現(xiàn)錯(cuò)誤時(shí)挺身而出,避免整個(gè)應(yīng)用因?yàn)橐粋€(gè)小錯(cuò)誤就崩潰掉,下面小編就來(lái)為大家介紹一下如何利用它捕獲組件錯(cuò)誤吧
    2025-03-03
  • React操作真實(shí)DOM實(shí)現(xiàn)動(dòng)態(tài)吸底部的示例

    React操作真實(shí)DOM實(shí)現(xiàn)動(dòng)態(tài)吸底部的示例

    本篇文章主要介紹了React操作真實(shí)DOM實(shí)現(xiàn)動(dòng)態(tài)吸底部的示例,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-10-10

最新評(píng)論

余干县| 大兴区| 酒泉市| 正阳县| 芦溪县| 蓬莱市| 桃园县| 绍兴市| 兴海县| 贵定县| 花莲市| 靖安县| 大悟县| 云龙县| 大同市| 乐业县| 舞阳县| 孝感市| 朝阳市| 伊吾县| 搜索| 绍兴县| 印江| 陕西省| 绥阳县| 静宁县| 康马县| 阳新县| 手游| 安庆市| 五指山市| 长垣县| 濮阳市| 横山县| 平定县| 白河县| 沛县| 红安县| 南京市| 东港市| 二连浩特市|