protobufjs 在 安卓真机上 失败 黑屏

web浏览器上能正常运行,但是会有警告

android和模拟器上黑屏

找遍论坛,觉得这个解释靠谱

根源是protobufjs里面进行了尝试require,比如检查环境中是否有long模块来决定是使用哪种int64支持,就会require一下,没有require到long就用别的支持.
但creator在andoid上require失败会不让启动, 所以有这个问题.
protobuf上一共就几个尝试require.
一个buffer和两个fs,直接改成不require,置为null.
一个long,加入了dcodeIO的long.

但是我不知道要怎么改,这个搞不定,项目进行不下去啊。希望官方能帮忙解决

你不是用了谷歌的官方的protobuf么?这个不能用了?

不用官方的了。换了protobufjs,感觉也蛮好用的,还能用于ts。

哦,,,不过ts不是可以直接调用js代码么

这个可以有代码提示呢

protobufjs你可以参考我的这几篇博客
http://www.jianshu.com/p/c4b8a8e3077f
http://www.jianshu.com/p/e04ee7d4007d
http://www.jianshu.com/p/2b9791ae3eea
http://www.jianshu.com/p/1ae9ce39e8d7

也欢迎你使用cocos商店中的pbkiller插件

谢谢你的文章,我用的是 预编译proto文件 成js代码的方式。我用的是6.8版本

会有我上面说的问题。只能用 改源码和伪装的方式吗?

是不是直接导入 bytebuffer.js和long.js会更好?

一个方案是修改源码,一个方案是重写其中关键函数,绕开nodejs api的调用,例如fetch方法

let protobuf = require('protobufjs');
let fetch = protobuf.Util.fetch;
protobuf.Util.fetch = function myfetch(path, callbcak) {
    if (cc.sys.isNative) {
        let str = jsb.fileUtils.getStringFromFile(path);
        if (callbcak) {
            callbcak(str);
            return null;
         }
         return str;
    }
    return fetch.call(this, path, callbcak);
};

你预编译proto文件成js,上面函数不会被调用到,还需要重写,Builder的import方法

let protobuf = require('protobufjs');

function propagateSyntax(parent) {
    if (parent['messages']) {
        parent['messages'].forEach(function(child) {
            child["syntax"] = parent["syntax"];
            propagateSyntax(child);
        });
    }
    if (parent['enums']) {
        parent['enums'].forEach(function(child) {
            child["syntax"] = parent["syntax"];
        });
    }
}

protobuf.Builder.prototype['import'] = function(json, filename) {
    var delim = '/';
    // Make sure to skip duplicate imports

    if (typeof filename === 'string') {

        // if (ProtoBuf.Util.IS_NODE)
        //     filename = require("path")['resolve'](filename);
        if (this.files[filename] === true)
            return this.reset();
        this.files[filename] = true;

    } else if (typeof filename === 'object') { // Object with root, file.

        var root = filename.root;
        // if (ProtoBuf.Util.IS_NODE)
        //     root = require("path")['resolve'](root);
        if (root.indexOf("\\") >= 0 || filename.file.indexOf("\\") >= 0)
            delim = '\\';
        var fname;
        if (ProtoBuf.Util.IS_NODE)
            fname = cc.path.join(root, filename.file);
        else
            fname = root + delim + filename.file;
        if (this.files[fname] === true)
            return this.reset();
        this.files[fname] = true;
    }

    // Import imports

    if (json['imports'] && json['imports'].length > 0) {
        var importRoot,
            resetRoot = false;

        if (typeof filename === 'object') { // If an import root is specified, override

            this.importRoot = filename["root"]; resetRoot = true; // ... and reset afterwards
            importRoot = this.importRoot;
            filename = filename["file"];
            if (importRoot.indexOf("\\") >= 0 || filename.indexOf("\\") >= 0)
                delim = '\\';

        } else if (typeof filename === 'string') {

            if (this.importRoot) // If import root is overridden, use it
                importRoot = this.importRoot;
            else { // Otherwise compute from filename
                if (filename.indexOf("/") >= 0) { // Unix
                    importRoot = filename.replace(/\/[^\/]*$/, "");
                    if (/* /file.proto */ importRoot === "")
                        importRoot = "/";
                } else if (filename.indexOf("\\") >= 0) { // Windows
                    importRoot = filename.replace(/\\[^\\]*$/, "");
                    delim = '\\';
                } else
                    importRoot = ".";
            }

        } else
            importRoot = null;

        for (var i=0; i<json['imports'].length; i++) {
            if (typeof json['imports'][i] === 'string') { // Import file
                if (!importRoot)
                    throw Error("cannot determine import root");
                var importFilename = json['imports'][i];
                if (importFilename === "google/protobuf/descriptor.proto")
                    continue; // Not needed and therefore not used
                if (ProtoBuf.Util.IS_NODE)
                    importFilename = require("path")['join'](importRoot, importFilename);
                else
                    importFilename = importRoot + delim + importFilename;
                if (this.files[importFilename] === true)
                    continue; // Already imported
                if (/\.proto$/i.test(importFilename) && !ProtoBuf.DotProto)       // If this is a light build
                    importFilename = importFilename.replace(/\.proto$/, ".json"); // always load the JSON file
                var contents = ProtoBuf.Util.fetch(importFilename);
                if (contents === null)
                    throw Error("failed to import '"+importFilename+"' in '"+filename+"': file not found");
                if (/\.json$/i.test(importFilename)) // Always possible
                    this["import"](JSON.parse(contents+""), importFilename); // May throw
                else
                    this["import"](ProtoBuf.DotProto.Parser.parse(contents), importFilename); // May throw
            } else // Import structure
                if (!filename)
                    this["import"](json['imports'][i]);
                else if (/\.(\w+)$/.test(filename)) // With extension: Append _importN to the name portion to make it unique
                    this["import"](json['imports'][i], filename.replace(/^(.+)\.(\w+)$/, function($0, $1, $2) { return $1+"_import"+i+"."+$2; }));
                else // Without extension: Append _importN to make it unique
                    this["import"](json['imports'][i], filename+"_import"+i);
        }
        if (resetRoot) // Reset import root override when all imports are done
            this.importRoot = null;
    }

    // Import structures

    if (json['package'])
        this.define(json['package']);
    if (json['syntax'])
        propagateSyntax(json);
    var base = this.ptr;
    if (json['options'])
        Object.keys(json['options']).forEach(function(key) {
            base.options[key] = json['options'][key];
        });
    if (json['messages'])
        this.create(json['messages']),
        this.ptr = base;
    if (json['enums'])
        this.create(json['enums']),
        this.ptr = base;
    if (json['services'])
        this.create(json['services']),
        this.ptr = base;
    if (json['extends'])
        this.create(json['extends']);

    return this.reset();
};

通过上面重写的函数可以绕开nodejs 的API了。

关于你说的,6.8我了解到的是不需要bytebuffer.js和long.js了,具体情况你可以参考另一位网友的分享
http://www.jianshu.com/p/1b90dd4bcb0a

大神,你这些代码在哪个改呀?6.8好像没有这些代码
上传了个简单pbjs6.8的ts版 demo,我实在搞不定了。你有空帮忙看下吧
ts版的pb是可以用代码提示的,建议你更新下到6.8哈
assets.zip (104.2 KB)

你好 可以 加个 好友吗
有些 问题 请教

私信你了

不好意思,这两天有点事,没有看到你的提问。 你的代码我下载了,但Creator打开提示有报错。
能否提供一个相对能完整的工程。

protobufjs6.x 我下了也了解了一下,有结果了再告诉你。

ts2.zip (728.1 KB)c重新上传了,这是ts项目
我没看到私信啊

你的工程我任然要报错

我自己用Creator1.5.2新建了一个tc工程,用npm安装的protobufjs6.8,增加一行兼容代码,可以在jsb上加载proto和序列化,是比5.x版本简单了,兼容代码如下:

import { load, util } from "protobufjs";
//用cc.loader.load函数替换protobuf的fetch函数
util.fetch = cc.loader.load.bind(cc.loader);

下面是加载proto,并序列化、反序列化

   public click() {
        let url = cc.url.raw('resources/Package.proto');
        load(url, function(err, root) {
            if (err)
              throw err;
          
            // example code
            const Package = root.lookupType("Package");
          
            let message = Package.create({ name: "hello" });
            cc.log(`message = ${JSON.stringify(message)}`);
          
            let buffer = Package.encode(message).finish();
            cc.log(`buffer = ${Array.prototype.toString.call(buffer)}`);
          
            let decoded = Package.decode(buffer);
            cc.log(`decoded = ${JSON.stringify(decoded)}`);
          });    
    }

控制台能正确输出结果:

浏览器控制台:

模拟器控制台

感谢你的建议,6.8是比较好用,目前我了解的还比较少,等我熟悉一阵我再将pbkiller做一次升级

1.5好像是有这个报错。

我现在换1.7了,没报错, 1.61 也都没报错的。

我是用生成 静态代码的方式(js+ts)

你试试看这个方式 行不行

买了你的插件 请问如果preload加载正常 直接loadall加载就不正常

必须调用preload先将proto文件加载到内存,可以在引擎初始化完成时执行preload操作:

cc.game.once(cc.game.EVENT_ENGINE_INITED, function () { 
    pbkiller.preload();
});