3

我已经为 react-native 制作了原生 android 模块。我退出了该应用程序并添加了本机代码以使用蓝牙热敏打印机进行打印。我已经使用 android studio 测试了本机 android 代码,并且打印效果很好。在我将模块添加到 react-native android 之后,它打印了几次文本。后来,它停止打印。我总是在 Javascript 中将导入的模块作为未定义的。

BlueToothUtils.java: 这个文件在 react-projectfolder\android\app\src\main\java\\thermal_printer\

import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.util.Log;

import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.Callback;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;

import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Set;
import java.util.UUID;

public class BlueToothUtils extends ReactContextBaseJavaModule {

    public static BluetoothAdapter bluetoothAdapter=null;
    public static BluetoothDevice chosen_printer=null;
    BluetoothSocket bt_socket = null;
    public static UUID DEFAULT_UUID = null;
    public UUID device_uuid=null;
    public OutputStream output_stream=null;
    boolean bluetooth_status=false;
    String error_message="";


    @Override
    public String getName() {
        return "BlueToothUtils";
    }

    public BlueToothUtils(ReactApplicationContext reactContext) {
        super(reactContext);
        context=reactContext;
    }

    @ReactMethod
    public void initAdapter(Callback returnStatus)
    {
        try {
            DEFAULT_UUID = UUID.fromString("00000000-0000-1000-8000-00805F9B34FB");
            bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
            if (bluetoothAdapter == null) {
                bluetooth_status = false;
                error_message = "Cannot access Bluetooth adapter. Make sure bluetooth is turned ON.";
            } else if (bluetoothAdapter.isEnabled())
                bluetooth_status = true;
            else {
                bluetooth_status = false;
                error_message = "Bluetooth not enabled.";
            }
            if(bluetooth_status)
                returnStatus.invoke(true,"");
            else
                returnStatus.invoke(false,error_message);
        }catch (Exception ex){returnStatus.invoke(false,ex.getMessage());}
    }

    @ReactMethod
    public void getPairedDevices(Callback returnCallback)
    {
        try {
            if (!bluetooth_status)
                returnCallback.invoke(false, "[]");
            else {
                PairedDevice paired_device;
                Set<BluetoothDevice> bonded_devices = bluetoothAdapter.getBondedDevices();
                String json = "[";
                boolean found = false;
                for (BluetoothDevice device : bonded_devices) {
                    found = true;
                    paired_device = new PairedDevice(device.getName(), device.getAddress());
                    json += paired_device.toString() + ",";
                }
                if (found)
                    json = json.substring(0, json.length() - 1) + "]";
                else
                    json = "[]";
                returnCallback.invoke(true, json);
            }
        }catch (Exception ex){returnCallback.invoke(false,ex.getMessage());}
    }

    @ReactMethod
    public void chooseDevice(String address,Callback returnCallback)
    {
        try {
            chosen_printer = bluetoothAdapter.getRemoteDevice(address);
            returnCallback.invoke(true,"Chosen Successfully");
        }catch (Exception ex){returnCallback.invoke(false,ex.getMessage());}
    }

    public static OutputStream getOutputStream() throws IOException {
        BluetoothSocket socket=null;
        UUID uuid= chosen_printer.getUuids()[0].getUuid();
        try {
            socket = chosen_printer.createInsecureRfcommSocketToServiceRecord(uuid);
        }catch (Exception ex){
            try{
                socket=chosen_printer.createInsecureRfcommSocketToServiceRecord(DEFAULT_UUID);
            }catch (Exception exc){exc.printStackTrace();Log.d("ttt", exc.toString());}
        }
        if (socket==null)
        {
            return  null;
        }
        bluetoothAdapter.cancelDiscovery();
        socket.connect();
        OutputStream os=socket.getOutputStream();
        return os;
    }
}

同一包中的另一个模块是 PrintUtils.java:

import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.util.Log;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.Callback;
import java.io.OutputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import android.content.res.AssetManager;

public class PrintUtils extends ReactContextBaseJavaModule {

    public static final int ALIGN_LEFT = 0;
    public static final int ALIGN_CENTER = 1;
    public static final int ALIGN_RIGHT = 2;

    public static final int FONT_NORMAL = 0;
    public static final int FONT_BOLD_AND_NORMAL_SIZE = 1;
    public static final int FONT_BOLD_AND_MEDIUM_SIZE = 2;
    public static final int FONT_BOLD_AND_LARGE_SIZE = 3;

    public static final byte[] ESC_ALIGN_LEFT = new byte[]{0x1b, 'a', 0x00};
    public static final byte[] ESC_ALIGN_RIGHT = new byte[]{0x1b, 'a', 0x02};
    public static final byte[] ESC_ALIGN_CENTER = new byte[]{0x1b, 'a', 0x01};
    public static final byte LF = 0x0A;
    public static byte[] FEED_LINE = {10};
    private static String[] binaryArray = {"0000", "0001", "0010", "0011",
            "0100", "0101", "0110", "0111", "1000", "1001", "1010", "1011",
            "1100", "1101", "1110", "1111"};
    private static String hexStr = "0123456789ABCDEF";
    public OutputStream outputStream = null;
    public boolean is_connected = false;
    public ReactApplicationContext context=null;

    public PrintUtils(ReactApplicationContext reactContext) {
        super(reactContext);
    }

    private static byte charToByte(char c) {
        return (byte) "0123456789ABCDEF".indexOf(c);
    }

    public static byte[] sysCopy(List<byte[]> srcArrays) {
        int len = 0;
        for (byte[] srcArray : srcArrays) {
            len += srcArray.length;
        }
        byte[] destArray = new byte[len];
        int destLen = 0;
        for (byte[] srcArray : srcArrays) {
            System.arraycopy(srcArray, 0, destArray, destLen, srcArray.length);
            destLen += srcArray.length;
        }
        return destArray;
    }

    public static byte[] hexStringToBytes(String hexString) {
        if (hexString == null || hexString.equals("")) {
            return null;
        }
        hexString = hexString.toUpperCase();
        int length = hexString.length() / 2;
        char[] hexChars = hexString.toCharArray();
        byte[] d = new byte[length];
        for (int i = 0; i < length; i++) {
            int pos = i * 2;
            d[i] = (byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1]));
        }
        return d;
    }

    public static String myBinaryStrToHexString(String binaryStr) {
        String hex = "";
        String f4 = binaryStr.substring(0, 4);
        String b4 = binaryStr.substring(4, 8);
        for (int i = 0; i < binaryArray.length; i++) {
            if (f4.equals(binaryArray[i]))
                hex += hexStr.substring(i, i + 1);
        }
        for (int i = 0; i < binaryArray.length; i++) {
            if (b4.equals(binaryArray[i]))
                hex += hexStr.substring(i, i + 1);
        }

        return hex;
    }

    public static byte[] hexList2Byte(List<String> list) {
        List<byte[]> commandList = new ArrayList<byte[]>();

        for (String hexStr : list) {
            commandList.add(hexStringToBytes(hexStr));
        }
        byte[] bytes = sysCopy(commandList);
        return bytes;
    }

    public static List<String> binaryListToHexStringList(List<String> list) {
        List<String> hexList = new ArrayList<String>();
        for (String binaryStr : list) {
            StringBuffer sb = new StringBuffer();
            for (int i = 0; i < binaryStr.length(); i += 8) {
                String str = binaryStr.substring(i, i + 8);

                String hexString = myBinaryStrToHexString(str);
                sb.append(hexString);
            }
            hexList.add(sb.toString());
        }
        return hexList;

    }

    public static byte[] decodeBitmap(Bitmap bmp) {
        int bmpWidth = bmp.getWidth();
        int bmpHeight = bmp.getHeight();

        List<String> list = new ArrayList<String>(); //binaryString list
        StringBuffer sb;


        int bitLen = bmpWidth / 8;
        int zeroCount = bmpWidth % 8;

        String zeroStr = "";
        if (zeroCount > 0) {
            bitLen = bmpWidth / 8 + 1;
            for (int i = 0; i < (8 - zeroCount); i++) {
                zeroStr = zeroStr + "0";
            }
        }

        for (int i = 0; i < bmpHeight; i++) {
            sb = new StringBuffer();
            for (int j = 0; j < bmpWidth; j++) {
                int color = bmp.getPixel(j, i);

                int r = (color >> 16) & 0xff;
                int g = (color >> 8) & 0xff;
                int b = color & 0xff;

                // if color close to white,bit='0', else bit='1'
                if (r > 160 && g > 160 && b > 160)
                    sb.append("0");
                else
                    sb.append("1");
            }
            if (zeroCount > 0) {
                sb.append(zeroStr);
            }
            list.add(sb.toString());
        }

        List<String> bmpHexList = binaryListToHexStringList(list);
        String commandHexString = "1D763000";
        String widthHexString = Integer
                .toHexString(bmpWidth % 8 == 0 ? bmpWidth / 8
                        : (bmpWidth / 8 + 1));
        if (widthHexString.length() > 2) {
            Log.e("decodeBitmap error", " width is too large");
            return null;
        } else if (widthHexString.length() == 1) {
            widthHexString = "0" + widthHexString;
        }
        widthHexString = widthHexString + "00";

        String heightHexString = Integer.toHexString(bmpHeight);
        if (heightHexString.length() > 2) {
            Log.e("decodeBitmap error", " height is too large");
            return null;
        } else if (heightHexString.length() == 1) {
            heightHexString = "0" + heightHexString;
        }
        heightHexString = heightHexString + "00";

        List<String> commandList = new ArrayList<String>();
        commandList.add(commandHexString + widthHexString + heightHexString);
        commandList.addAll(bmpHexList);

        return hexList2Byte(commandList);
    }

    @Override
    public Map<String, Object> getConstants() {
        final Map<String, Object> constants = new HashMap<>();
        constants.put("ALIGN_LEFT", ALIGN_LEFT);
        constants.put("ALIGN_CENTER", ALIGN_CENTER);
        constants.put("ALIGN_RIGHT", ALIGN_RIGHT);
        constants.put("FONT_NORMAL", FONT_NORMAL);
        constants.put("FONT_BOLD_AND_NORMAL_SIZE", FONT_BOLD_AND_NORMAL_SIZE);
        constants.put("FONT_BOLD_AND_MEDIUM_SIZE", FONT_BOLD_AND_MEDIUM_SIZE);
        constants.put("FONT_BOLD_AND_LARGE_SIZE", FONT_BOLD_AND_LARGE_SIZE);
        constants.put("ESC_ALIGN_LEFT", ESC_ALIGN_LEFT);
        constants.put("ESC_ALIGN_CENTER", ESC_ALIGN_CENTER);
        constants.put("ESC_ALIGN_RIGHT", ESC_ALIGN_RIGHT);
        constants.put("LF", LF);


        return constants;
    }

    @Override
    public String getName() {
        return "PrintUtils";
    }

    @ReactMethod
    public void printText(String text, int size, int align, Callback returnCallback) {
        try {
            if (is_connected == false) {
                outputStream = BlueToothUtils.getOutputStream();
                is_connected = true;
            }
            //Print config "mode"
            byte[] cc = new byte[]{0x1B, 0x21, 0x03};  // 0- normal size text
            byte[] bb = new byte[]{0x1B, 0x21, 0x08};  // 1- only bold text
            byte[] bb2 = new byte[]{0x1B, 0x21, 0x20}; // 2- bold with medium text
            byte[] bb3 = new byte[]{0x1B, 0x21, 0x10}; // 3- bold with large text
            switch (size) {
                case FONT_NORMAL:
                    outputStream.write(cc);
                    break;
                case FONT_BOLD_AND_NORMAL_SIZE:
                    outputStream.write(bb);
                    break;
                case FONT_BOLD_AND_MEDIUM_SIZE:
                    outputStream.write(bb2);
                    break;
                case FONT_BOLD_AND_LARGE_SIZE:
                    outputStream.write(bb3);
                    break;
            }

            switch (align) {
                case ALIGN_LEFT:
                    //left align
                    outputStream.write(ESC_ALIGN_LEFT);
                    break;
                case ALIGN_CENTER:
                    //center align
                    outputStream.write(ESC_ALIGN_CENTER);
                    break;
                case ALIGN_RIGHT:
                    //right align
                    outputStream.write(ESC_ALIGN_RIGHT);
                    break;
            }
            outputStream.write(text.getBytes());
            outputStream.write(LF);
            outputStream.flush();
            returnCallback.invoke(true, "success");
        } catch (Exception e) {
            returnCallback.invoke(false, "error:" + e.getMessage());
        }
    }

    @ReactMethod
    public void printPhoto(Callback returnCallback) {
        try {
            AssetManager assetmgr=getReactApplicationContext().getAssets();
            InputStream inp=assetmgr.open("pics/logo.bmp");
            Bitmap bmp=BitmapFactory.decodeStream(inp);
            if (bmp != null)
                {
                if (!is_connected)
                    {
                    outputStream = BlueToothUtils.getOutputStream();
                    is_connected = true;
                    }
                byte[] command = PrintUtils.decodeBitmap(bmp);
                outputStream.write(new byte[]{0x1b, 'a', 0x01});
                outputStream.write(command);
                returnCallback.invoke(true, "success");
                }
            else
                {
                returnCallback.invoke(false, "error:" + "Image not found");
                }
            }
        catch (Exception e)
            {
            returnCallback.invoke(false, "error: Exception" + e.getMessage());
            }
    }

    @ReactMethod
    public void cutPaper(Callback returnCallback) {
        try {
            outputStream.write(LF);
            outputStream.write(LF);
            outputStream.write(LF);
            outputStream.flush();
            returnCallback.invoke(true, "Success");
        } catch (Exception ex) {
            returnCallback.invoke(false, "error:" + ex.getMessage());
        }
    }

    @ReactMethod
    public void closeConnection(Callback returnCallback) {
        try {
            outputStream.close();
            is_connected = false;
            returnCallback.invoke(true, "Success");
        } catch (Exception e) {
            returnCallback.invoke(false, "error:" + e.getMessage());
        }
    }

}

在同一目录中还有另一个类 PairedDevice PairedDevice.java :

public class PairedDevice {
    public String name="Noname";
    public String address=null;

    public PairedDevice(String dev_name, String dev_address)    {
        name=dev_name;
        address=dev_address;
    }


    public String toString()
    {
        return "{\"name\":\""+name+"\",\"address\":\""+address+"\"}";
    }

}

同一目录中的包类是ThermalPrinterPackage

import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.JavaScriptModule;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import android.content.Context;

public class ThermalPrinterPackage implements ReactPackage {

    @Override
    public List<NativeModule> createNativeModules(ReactApplicationContext reactContext)
        {
        List<NativeModule> modules = new ArrayList<>();
        modules.add(new BlueToothUtils(reactContext));
        modules.add(new PrintUtils(reactContext));
        return modules;
        }

    @Override
    public List<Class<? extends JavaScriptModule>> createJSModules() {
        return Collections.emptyList();
    }

    @Override
    public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
        return Collections.emptyList();
    }
}

MainApplication.java文件现在如下:

import dcloud.codesap.com.thermal_printer.*;
import android.support.multidex.MultiDexApplication;
import com.facebook.react.shell.MainReactPackage;
import com.facebook.react.ReactPackage;

import java.util.Arrays;
import java.util.List;

// Needed for `react-native link`

import com.facebook.react.ReactApplication;

public class MainApplication extends MultiDexApplication {

  // Needed for `react-native link`

  public List<ReactPackage> getPackages() {

    return Arrays.<ReactPackage>asList(

        // Add your own packages here!
        // TODO: add cool native modules
        // Needed for `react-native link`
        new MainReactPackage(),
        new ThermalPrinterPackage(),
    );

}
}

我正在按如下方式导入和使用它:

import BlueToothUtils from '../../BluetoothUtils';
import PrintUtils from '../../PrintUtils';
class Signin extends Component {

  constructor(props) {
    super(props);
    this.state = { username: 'demo',
                  password: 'demo',
                  token: '1234'
                };
    this.getToken = this.getToken.bind(this);
    this.navIn = this.navIn.bind(this);
  }

  async componentDidMount() {
    try{
      await console.log(BlueToothUtils);
      await BlueToothUtils.initAdapter((boo,msg)=>{console.log(boo,msg);});
      await BlueToothUtils.getPairedDevices((boo,msg)=>{console.log(boo,'Paired devices:'+msg);});
      await BlueToothUtils.chooseDevice("0F:02:17:42:55:C7",(boo,msg)=>{console.log(boo,msg);});
      await PrintUtils.printText("Normal Text", PrintUtils.FONT_NORMAL, PrintUtils.ALIGN_LEFT,(boo,msg)=>{console.log(boo,msg);});
      await PrintUtils.printText("BOLD Normal text", PrintUtils.FONT_BOLD_AND_NORMAL_SIZE, PrintUtils.ALIGN_CENTER,(boo,msg)=>{console.log(boo,msg);});
      await PrintUtils.printText("BOLD Large text", PrintUtils.FONT_BOLD_AND_LARGE_SIZE, PrintUtils.ALIGN_RIGHT,(boo,msg)=>{console.log(boo,msg);});
      await PrintUtils.printPhoto((boo,msg)=>{console.log(boo,msg);});
      await PrintUtils.cutPaper();
    }catch(err){console.log('Error in index.js:componentWillMount: '+err.message)};
  }

...

蓝牙Utils.js

import { NativeModules } from 'react-native';
var bu= NativeModules.BlueToothUtils;
export default bu;

PrintUtils.js

import { NativeModules } from 'react-native';
var pu=NativeModules.PrintUtils;
export default pu;

它已经工作了几次。在我将模块添加到 react-native 后,它没有打印图像。但它确实打印了大部分时间。但现在它根本没有打印,甚至没有文本。任何人都可以帮忙吗?提前致谢。

4

1 回答 1

1

最后我发现问题出export在原生模块上。我没有导出本机 java 对象的实例,而是单独导出了对象的每个方法和常量。而不是export default,我用export const

import { NativeModules } from 'react-native';
var pu=NativeModules.PrintUtils;
export default pu;

代码变成了这样:

import { NativeModules } from 'react-native'


export const getPairedDevices = (callback) => {
  NativeModules.PrintUtils.getPairedDevices(callback);
}

export const printText = (text,size,align,mac_address,returnCallback) => {
  NativeModules.PrintUtils.printText(text,size,align,mac_address,returnCallback);
}

export const ALIGN_LEFT=NativeModules.PrintUtils.ALIGN_LEFT;

我不知道它与 react-native 有什么区别。但是当我摆脱export default. 希望这会对某人有所帮助。

于 2017-10-26T15:24:57.600 回答