You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Apache Cordova使用cordova-plugin-ble-central调用ble.write无法打印且无报错(Android)

问题描述

我开发了一款Apache Cordova应用,希望通过cordova-plugin-ble-central插件使用蓝牙打印机打印收据。我使用了以下测试代码,但无法打印数据,且未返回任何错误或响应。其中前三个变量为从设备自动获取的正确值,现将代码贴出,恳请提供建议或帮助:

var BT_device=57:4C:54:03:1D:0D;
var BT_service_id=18f0;
var BT_characteristic_id=2af1;

BT_test_template = function() {
    var data = [];  
    
    var $_line = BT_line(42);   
    
    data = [       
       //{"type":"command","value":HW_INIT},
      {"type":"command","value":TXT_BOLD_ON}, 
      {"type":"command","value":TXT_ALIGN_RT},
      {"type":"text","value":"Test receipt"},
      {"type":"command","value":TXT_BOLD_OFF},    
      {"type":"command","value":CTL_LF},
      {"type":"command","value":CTL_LF},     
      {"type":"command","value":TXT_ALIGN_LT},
      {"type":"command","value":TXT_FONT_B},
      {"type":"text","value": $_line },
      {"type":"command","value":CTL_LF},
      //{"type":"command","value":TXT_NORMAL},
      {"type":"text","value": "Cheese burger" },
      {"type":"command","value":CTL_LF},
      {"type":"text","value": "1 x 2.00" },
      {"type":"command","value":CTL_LF},
      //{"type":"command","value":TXT_FONT_B},
      {"type":"text","value": $_line },
      {"type":"command","value":CTL_LF},      
      {"type":"command","value":TXT_NORMAL},
      {"type":"command","value":TXT_BOLD_ON}, 
      {"type":"text","value": "TOTAL" },      
      {"type":"command","value":TXT_BOLD_OFF},
      {"type":"command","value":CTL_LF},
      {"type":"command","value":TXT_NORMAL},
      {"type":"text","value": "Cash" },
      {"type":"command","value":CTL_LF},
      {"type":"command","value":CTL_LF}   
    ];
    return data;
};

BT_print_test = function(){
    
    try {
    
        current_page_id = getCurrentPage();
        BT_device = $("#" + current_page_id +  " .mac_address").val();
        BT_service_id = $("#" + current_page_id +  " .data1").val();
        BT_characteristic_id = $("#" + current_page_id +  " .data2").val();
        
        BT_tpl = '';
        
        if( !empty(BT_device) && !empty(BT_service_id) && !empty(BT_characteristic_id) ){
            BT_tpl = BT_test_template();                
            checkBluetooth('BT_init_print');
        } else {
            showToast( t("No selected printer. please restart your printer"), 'danger' );
        }
    
    } catch(err) {
        dump2( err.message );
    }
};

checkBluetooth = function( $actions ){
    
    if( isdebug() ){    
        BT_actions( $actions ) ;    
        return ;
    }
    
    /*ANDROID*/
        cordova.plugins.diagnostic.hasBluetoothSupport(function(available){
            if(available){
                cordova.plugins.diagnostic.isBluetoothEnabled(function(enabled){
                    if(enabled){
                        BT_actions( $actions ) ;
                    } else {
                        ble.enable(function(){
                             setTimeout(function(){         
                                BT_actions( $actions ) ;
                             }, 1*500 );
                        }, function(){
                            checkBluetooth('');
                        });
                    }
                }, function(error){
                    showToast( t("The following error occurred:")  + " " + error , 'danger'  );
                });
            } else {
                showToast( t("Bluetooth not available on this device") , 'danger' );
            }
        }, function(error){     
            showToast( t("The following error occurred:")  + " " + error  , 'danger' );
        });
    
};

BT_actions = function( $run_funtions ){
    if( !empty($run_funtions) ){     
        switch ($run_funtions){
            case "BT_init_print":
              setTimeout(function(){    
                 BT_init_print();
              }, 1*500 );
            break;
            
            case "BT_startScan":
               setTimeout(function(){                   
                 BT_startScan();
              }, 1*500 );
            break;
        }
     }
};

BT_init_print = function(){
    showDialog(true,'printer_loader');

    BT_print_done = false;
    BT_command_count = 0;
    BT_connect_data = false;
    
    /*DEBUG*/
    if( isdebug() ){
                
        setTimeout(function(){  
           BT_set_status( t("Connecting")+ "..." );
        }, 1*500 );
                
        BT_connect( BT_device );
        
        BT_connect_status = setInterval(function(){
            if(BT_connect_data){
                BT_set_status( t("Printing") + "..." );
                $result = BT_connect_data;
                dump($result);
                BT_connect_data = false;
                
                BT_service_id = $result.service;
                BT_characteristic_id = $result.characteristic;
                BT_print( BT_tpl );
            }
        }, 1*1000 );
        
        return ;
    }
    /*END DEBUG*/
    
    
    ble.isConnected( BT_device , function(){
        setTimeout(function(){  
           BT_set_status( t("Printing")+ "..." );
        }, 1*500 );
        
        BT_print( BT_tpl );
        
    }, function(){
        setTimeout(function(){  
           BT_set_status( t("Connecting")+ "..." );
        }, 1*500 );
        
        BT_connect_data = false;
        BT_connect( BT_device );
        
        BT_connect_status = setInterval(function(){
            if(BT_connect_data){
                BT_set_status( t("Printing") + "..." );
                $result = BT_connect_data;
                dump($result);
                BT_connect_data = false;
                
                BT_service_id = $result.service;
                BT_characteristic_id = $result.characteristic;
                BT_print( BT_tpl );
            }
        }, 2*1000 );
            
    }); 
    
};

BT_set_status = function(message){
    $("#printer_loader h3").html( message );
};

BT_print = function(data){
    dump("BT_print");
    dump(data);
    
    BT_err_msg  = '';
    
    if(data.length>0){
        $.each( data  , function( data, val ) {         
            setTimeout(function(){  
                dump(val);
                switch (val.type){
                    case "command":
                      BT_command(val.value);
                    break
                    
                    case "text":
                      BT_text(val.value);
                    break
                    
                    case "image":
                      BT_image(val.value);
                     break;
                }
            }, 1*1000); 
        });                 
        
        BT_cron = setInterval( BT_cron_print , 1*1000);
        
    } else {
        BT_print_done = true;
        BT_err_msg = t("No data to print");
    }
};

BT_cron_print = function(){
    
    try {       
        
         if( isdebug() ){
             $time_out = 15*1000;
         } else {
             $time_out = 15*1000;
             if(cordova.platformId === "ios"){
                $time_out = 4*1000;         
             }  
         }
        
        BT_print_timeout = setTimeout(function(){      
            BT_command_count = 0;
            showDialog(false,'printer_loader');
            clearInterval(BT_cron); 
        }, $time_out );
        
        $tpl_count = BT_tpl.length; 
        if( isNaN($tpl_count)){
            BT_print_done = true;
        }
        
        if( BT_command_count >=  BT_tpl.length ){
            BT_print_done = true;
        }
        
        if(BT_print_done){      
            BT_command_count = 0;
            if(!empty(BT_err_msg)){
                showToast( BT_err_msg , 'danger' );                 
            }       
            showDialog(false,'printer_loader');
            clearInterval(BT_cron);
            clearTimeout(BT_print_timeout);
        }       
        
    
    } catch(err) {
        dump2( err.message );
    }
};


BT_text = function($text){      
    try {       
        var data = stringToBytes($text);
        ble.write( BT_device , BT_service_id , BT_characteristic_id , data, function(result){
            BT_command_count++;
        }, function(err){         
            BT_command_count++;  
            if ((typeof  err.errorMessage !== "undefined") && ( err.errorMessage !== null)) {
               BT_err_msg+= err.errorMessage;
               BT_err_msg+="\n";
            } else {
               BT_err_msg+= JSON.stringify(err);
               BT_err_msg+="\n";
            }
        });         
    } catch(err) {    
      BT_command_count++;     
      BT_err_msg+= err.message; 
      BT_err_msg+="\n";
    } 
};

BT_command = function( $command ){      
    try {                           
        
        data = new Uint8Array( $command.length );               
        $.each( $command  , function( key, val ) {      
            data[key]=val;
        });
                        
        ble.write( BT_device , BT_service_id , BT_characteristic_id , data.buffer, function(result){
            BT_command_count++;
        }, function(err){
            BT_command_count++;
            if ((typeof  err.errorMessage !== "undefined") && ( err.errorMessage !== null)) {
               BT_err_msg+= err.errorMessage; 
               BT_err_msg+="\n";
            } else {
               BT_err_msg+= JSON.stringify(err); 
               BT_err_msg+="\n";
            }
        });  

    } catch(err) {
       BT_command_count++;
       BT_err_msg+= err.message; 
       BT_err_msg+="\n";
    }        
};
排查与解决方案
  • 确认BLE特征可写属性
    蓝牙打印机的目标特征必须支持Write或Write Without Response属性。用BLE调试工具(如nRF Connect)扫描设备,查看2af1特征的属性,确保它具备写入权限,这是数据能发送到打印机的基础。

  • 修复异步写入的时序问题
    当前用固定延迟的setTimeout触发写入操作,会导致蓝牙队列拥堵或数据丢包。必须改成链式异步调用,等待前一个写入完成后再执行下一个:

    BT_print = function(data) {
        dump("BT_print");
        dump(data);
        BT_err_msg = '';
        let index = 0;
    
        function writeNext() {
            if (index >= data.length) {
                BT_print_done = true;
                return;
            }
            const val = data[index];
            dump(val);
            switch (val.type) {
                case "command":
                    BT_command(val.value, writeNext);
                    break;
                case "text":
                    BT_text(val.value, writeNext);
                    break;
                case "image":
                    BT_image(val.value, writeNext);
                    break;
            }
            index++;
        }
    
        if (data.length > 0) {
            writeNext();
            BT_cron = setInterval(BT_cron_print, 1 * 1000);
        } else {
            BT_print_done = true;
            BT_err_msg = t("No data to print");
        }
    };
    

    同时修改BT_text和BT_command,传入回调函数确保顺序执行:

    BT_text = function($text, callback) {      
        try {       
            var data = stringToBytes($text);
            ble.write(BT_device, BT_service_id, BT_characteristic_id, data, function(result){
                BT_command_count++;
                callback();
            }, function(err){         
                BT_command_count++;  
                BT_err_msg += err.errorMessage ? err.errorMessage + "\n" : JSON.stringify(err) + "\n";
                callback();
            });         
        } catch(err) {    
            BT_command_count++;     
            BT_err_msg += err.message + "\n";
            callback();
        } 
    };
    
    BT_command = function($command, callback) {      
        try {                           
            const data = new Uint8Array($command.length);               
            $.each($command, function(key, val) {      
                data[key] = val;
            });
                          
            ble.write(BT_device, BT_service_id, BT_characteristic_id, data.buffer, function(result){
                BT_command_count++;
                callback();
            }, function(err){
                BT_command_count++;
                BT_err_msg += err.errorMessage ? err.errorMessage + "\n" : JSON.stringify(err) + "\n";
                callback();
            });  
        } catch(err) {
            BT_command_count++;
            BT_err_msg += err.message + "\n";
            callback();
        }        
    };
    
  • 验证打印指令的兼容性
    TXT_BOLD_ON、CTL_LF等指令需要匹配打印机的ESC/POS指令集,不同品牌打印机指令可能有差异。比如标准ESC/POS的加粗开启指令是[0x1B, 0x45, 0x01],换行是[0x0A],请参考打印机官方文档替换对应指令。

  • 优化连接状态检测逻辑
    代码中BT_connect函数未实现完整,建议在连接成功的回调中直接触发打印,避免依赖定时器轮询BT_connect_data,减少不可预期的延迟或失败。

  • 增强调试日志
    打开dump3注释,或在ble.write的回调中打印写入的数据长度、设备响应结果,确认数据是否成功发送到打印机,定位无响应的具体环节。

内容的提问来源于stack exchange,提问作者shayan izadi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 07:49:52