java - 导入的 Android native 模块始终为 'undefined'

标签 java android react-native native-module

我已经为 react-native 制作了原生 android 模块。我弹出了应用程序并添加了 native 代码以使用蓝牙热敏打印机进行打印。我已经使用 android studio 测试了 native 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)};
  }

...

BlueToothUtils.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 后,它没有打印图像。但它确实在大多数时间打印出来。但是现在它根本不打印,甚至不打印文本。谁能帮忙?提前致谢。

最佳答案

最后我发现问题出在原生模块的export上。我没有导出 native java 对象的实例,而是分别导出对象的每个方法和常量。并且我使用了export const

,而不是export default
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 时,事情开始起作用了。希望这会对某人有所帮助。

关于java - 导入的 Android native 模块始终为 'undefined',我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46243925/

相关文章:

android - 我看不到 ScrollView 中复选框的文本

javascript - 如何在Android中通过react-native-fs播放从网络下载的音频?

java - 如何模拟<嵌套:root> from Struts 1 in Struts 2?

java - 在构造函数中使用重写方法的替代方法,Java

java - BigInteger 阶乘 表 1-30

java - Android 中的光标是从 0 还是 1 引用列?

java - 为标记 LinearLayout (xmlns :tools ERROR)) 找到意外的命名空间前缀 "xmlns"

javascript - 如何根据React Native中的位置获取数据

javascript - 不再支持通过 UIManager ['getConstants' 直接从 UIManager 访问 View 管理器配置

java - OSX 中出现 NoSuchMethodError,但 Ubuntu 中没有